2 * libwebsockets - small server side websockets and web server implementation
4 * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 #include "private-libwebsockets.h"
25 const struct http2_settings lws_http2_default_settings = { {
27 /* LWS_HTTP2_SETTINGS__HEADER_TABLE_SIZE */ 4096,
28 /* LWS_HTTP2_SETTINGS__ENABLE_PUSH */ 1,
29 /* LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS */ 100,
30 /* LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE */ 65535,
31 /* LWS_HTTP2_SETTINGS__MAX_FRAME_SIZE */ 16384,
32 /* LWS_HTTP2_SETTINGS__MAX_HEADER_LIST_SIZE */ ~0,
36 void lws_http2_init(struct http2_settings *settings)
38 memcpy(settings, lws_http2_default_settings.setting, sizeof(*settings));
42 lws_http2_wsi_from_id(struct libwebsocket *wsi, unsigned int sid)
45 if (wsi->u.http2.my_stream_id == sid)
48 wsi = wsi->u.http2.next_child_wsi;
55 lws_create_server_child_wsi(struct libwebsocket_context *context, struct libwebsocket *parent_wsi, unsigned int sid)
57 struct libwebsocket *wsi = libwebsocket_create_new_server_wsi(context);
62 /* no more children allowed by parent */
63 if (parent_wsi->u.http2.child_count + 1 == parent_wsi->u.http2.peer_settings.setting[LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS])
66 lws_http2_init(&wsi->u.http2.peer_settings);
67 lws_http2_init(&wsi->u.http2.my_settings);
68 wsi->u.http2.stream_id = sid;
70 wsi->u.http2.parent_wsi = parent_wsi;
71 wsi->u.http2.next_child_wsi = parent_wsi->u.http2.next_child_wsi;
72 parent_wsi->u.http2.next_child_wsi = wsi;
73 parent_wsi->u.http2.child_count++;
75 wsi->u.http2.my_priority = 16;
77 wsi->state = WSI_STATE_HTTP2_ESTABLISHED;
78 wsi->mode = parent_wsi->mode;
80 lwsl_info("%s: %p new child %p, sid %d\n", __func__, parent_wsi, wsi, sid);
85 int lws_remove_server_child_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi)
87 struct libwebsocket **w = &wsi->u.http2.parent_wsi;
90 *w = wsi->u.http2.next_child_wsi;
91 (wsi->u.http2.parent_wsi)->u.http2.child_count--;
95 w = &((*w)->u.http2.next_child_wsi);
98 lwsl_err("%s: can't find %p\n", __func__, wsi);
103 lws_http2_interpret_settings_payload(struct http2_settings *settings, unsigned char *buf, int len)
110 if (len < LWS_HTTP2_SETTINGS_LENGTH)
113 while (len >= LWS_HTTP2_SETTINGS_LENGTH) {
114 a = (buf[0] << 8) | buf[1];
115 if (a < LWS_HTTP2_SETTINGS__COUNT) {
116 b = buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5];
117 settings->setting[a] = b;
118 lwsl_info("http2 settings %d <- 0x%x\n", a, b);
120 len -= LWS_HTTP2_SETTINGS_LENGTH;
121 buf += LWS_HTTP2_SETTINGS_LENGTH;
130 int lws_http2_frame_write(struct libwebsocket *wsi, int type, int flags, unsigned int sid, unsigned int len, unsigned char *buf)
132 unsigned char *p = &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH];
145 lwsl_info("%s: %p. type %d, flags 0x%x, sid=%d, len=%d\n",
146 __func__, wsi, type, flags, sid, len);
148 n = lws_issue_raw(wsi, &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH], len + LWS_HTTP2_FRAME_HEADER_LENGTH);
149 if (n >= LWS_HTTP2_FRAME_HEADER_LENGTH)
150 return n - LWS_HTTP2_FRAME_HEADER_LENGTH;
155 static void lws_http2_settings_write(struct libwebsocket *wsi, int n, unsigned char *buf)
159 *buf++ = wsi->u.http2.my_settings.setting[n] >> 24;
160 *buf++ = wsi->u.http2.my_settings.setting[n] >> 16;
161 *buf++ = wsi->u.http2.my_settings.setting[n] >> 8;
162 *buf = wsi->u.http2.my_settings.setting[n];
165 static const char const * https_client_preface =
166 "PRI * HTTP/2.0\x0d\x0a\x0d\x0aSM\x0d\x0a\x0d\x0a";
169 lws_http2_parser(struct libwebsocket_context *context,
170 struct libwebsocket *wsi, unsigned char c)
172 struct libwebsocket *wsi_new;
174 switch (wsi->state) {
175 case WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE:
176 if (https_client_preface[wsi->u.http2.count++] != c)
179 if (!https_client_preface[wsi->u.http2.count]) {
180 lwsl_err("http2: %p: established\n", wsi);
181 wsi->state = WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS;
182 wsi->u.http2.count = 0;
185 * we must send a settings frame -- empty one is OK...
186 * that must be the first thing sent by server
187 * and the peer must send a SETTINGS with ACK flag...
190 lws_set_protocol_write_pending(context, wsi, LWS_PPS_HTTP2_MY_SETTINGS);
194 case WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS:
195 case WSI_STATE_HTTP2_ESTABLISHED:
196 if (wsi->u.http2.frame_state == LWS_HTTP2_FRAME_HEADER_LENGTH) { // payload
197 /* applies to wsi->u.http2.stream_wsi which may be wsi*/
198 switch(wsi->u.http2.type) {
199 case LWS_HTTP2_FRAME_TYPE_SETTINGS:
200 wsi->u.http2.stream_wsi->u.http2.one_setting[wsi->u.http2.count % LWS_HTTP2_SETTINGS_LENGTH] = c;
201 if (wsi->u.http2.count % LWS_HTTP2_SETTINGS_LENGTH == LWS_HTTP2_SETTINGS_LENGTH - 1)
202 if (lws_http2_interpret_settings_payload(
203 &wsi->u.http2.stream_wsi->u.http2.peer_settings,
204 wsi->u.http2.one_setting,
205 LWS_HTTP2_SETTINGS_LENGTH))
208 case LWS_HTTP2_FRAME_TYPE_HEADERS:
212 wsi->u.http2.count++;
213 if (wsi->u.http2.count == wsi->u.http2.length) {
214 wsi->u.http2.frame_state = 0;
215 wsi->u.http2.count = 0;
216 /* set our initial window size */
217 if (!wsi->u.http2.initialized) {
218 wsi->u.http2.tx_credit = wsi->u.http2.peer_settings.setting[LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE];
219 lwsl_info("initial tx credit on master conn %p: %d\n", wsi, wsi->u.http2.tx_credit);
220 wsi->u.http2.initialized = 1;
225 switch (wsi->u.http2.frame_state++) {
227 wsi->u.http2.length = c;
231 wsi->u.http2.length <<= 8;
232 wsi->u.http2.length |= c;
235 wsi->u.http2.type = c;
238 wsi->u.http2.flags = c;
244 wsi->u.http2.stream_id <<= 8;
245 wsi->u.http2.stream_id |= c;
246 wsi->u.http2.stream_wsi = wsi;
249 if (wsi->u.http2.frame_state == LWS_HTTP2_FRAME_HEADER_LENGTH) { /* frame header complete */
250 lwsl_info("frame: type 0x%x, flags 0x%x, sid 0x%x, len 0x%x\n",
251 wsi->u.http2.type, wsi->u.http2.flags, wsi->u.http2.stream_id, wsi->u.http2.length);
252 wsi->u.http2.count = 0;
255 switch (wsi->u.http2.type) {
256 case LWS_HTTP2_FRAME_TYPE_SETTINGS:
257 /* nonzero sid on settings is illegal */
258 if (wsi->u.http2.stream_id)
261 if (wsi->u.http2.flags & 1) { // ack
263 lws_set_protocol_write_pending(context, wsi, LWS_PPS_HTTP2_ACK_SETTINGS);
266 case LWS_HTTP2_FRAME_TYPE_HEADERS:
267 if (!wsi->u.http2.stream_id)
269 wsi->u.http2.stream_wsi = lws_http2_wsi_from_id(wsi, wsi->u.http2.stream_id);
270 if (!wsi->u.http2.stream_wsi)
271 wsi->u.http2.stream_wsi = lws_create_server_child_wsi(context, wsi, wsi->u.http2.stream_id);
273 if (!wsi->u.http2.stream_wsi)
276 if (wsi->u.http2.length == 0)
277 wsi->u.http2.frame_state = 0;
286 int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsocket *wsi)
288 unsigned char settings[LWS_SEND_BUFFER_PRE_PADDING + 6 * LWS_HTTP2_SETTINGS__COUNT];
292 case LWS_PPS_HTTP2_MY_SETTINGS:
293 for (n = 1; n < LWS_HTTP2_SETTINGS__COUNT; n++)
294 if (wsi->u.http2.my_settings.setting[n] != lws_http2_default_settings.setting[n]) {
295 lws_http2_settings_write(wsi, n,
296 &settings[LWS_SEND_BUFFER_PRE_PADDING + m]);
297 m += sizeof(wsi->u.http2.one_setting);
299 n = lws_http2_frame_write(wsi, LWS_HTTP2_FRAME_TYPE_SETTINGS,
300 0, LWS_HTTP2_STREAM_ID_MASTER, m,
301 &settings[LWS_SEND_BUFFER_PRE_PADDING]);
303 lwsl_info("send %d %d\n", n, m);
307 case LWS_PPS_HTTP2_ACK_SETTINGS:
308 /* send ack ... always empty */
309 n = lws_http2_frame_write(wsi, LWS_HTTP2_FRAME_TYPE_SETTINGS,
310 1, LWS_HTTP2_STREAM_ID_MASTER, 0,
311 &settings[LWS_SEND_BUFFER_PRE_PADDING]);
313 lwsl_err("ack tells %d\n", n);
316 /* this is the end of the preface dance then? */
317 if (wsi->state == WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS) {
318 wsi->state = WSI_STATE_HTTP2_ESTABLISHED;
320 wsi->u.http.fd = LWS_INVALID_FILE;
322 /* service the http request itself */
323 //lwsl_info("servicing initial http request\n");
324 //n = lws_http_action(context, wsi);