/src/libwebsockets/lib/roles/h2/http2.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * libwebsockets - small server side websockets and web server implementation |
3 | | * |
4 | | * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | * of this software and associated documentation files (the "Software"), to |
8 | | * deal in the Software without restriction, including without limitation the |
9 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
10 | | * sell copies of the Software, and to permit persons to whom the Software is |
11 | | * furnished to do so, subject to the following conditions: |
12 | | * |
13 | | * The above copyright notice and this permission notice shall be included in |
14 | | * all copies or substantial portions of the Software. |
15 | | * |
16 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
21 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
22 | | * IN THE SOFTWARE. |
23 | | */ |
24 | | |
25 | | #include "private-lib-core.h" |
26 | | |
27 | | /* |
28 | | * bitmap of control messages that are valid to receive for each http2 state |
29 | | */ |
30 | | |
31 | | static const uint16_t http2_rx_validity[] = { |
32 | | /* LWS_H2S_IDLE */ |
33 | | (1 << LWS_H2_FRAME_TYPE_SETTINGS) | |
34 | | (1 << LWS_H2_FRAME_TYPE_PRIORITY) | |
35 | | // (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE)| /* ignore */ |
36 | | (1 << LWS_H2_FRAME_TYPE_HEADERS) | |
37 | | (1 << LWS_H2_FRAME_TYPE_CONTINUATION), |
38 | | /* LWS_H2S_RESERVED_LOCAL */ |
39 | | (1 << LWS_H2_FRAME_TYPE_SETTINGS) | |
40 | | (1 << LWS_H2_FRAME_TYPE_RST_STREAM) | |
41 | | (1 << LWS_H2_FRAME_TYPE_PRIORITY) | |
42 | | (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE), |
43 | | /* LWS_H2S_RESERVED_REMOTE */ |
44 | | (1 << LWS_H2_FRAME_TYPE_SETTINGS) | |
45 | | (1 << LWS_H2_FRAME_TYPE_HEADERS) | |
46 | | (1 << LWS_H2_FRAME_TYPE_CONTINUATION) | |
47 | | (1 << LWS_H2_FRAME_TYPE_RST_STREAM) | |
48 | | (1 << LWS_H2_FRAME_TYPE_PRIORITY), |
49 | | /* LWS_H2S_OPEN */ |
50 | | (1 << LWS_H2_FRAME_TYPE_DATA) | |
51 | | (1 << LWS_H2_FRAME_TYPE_HEADERS) | |
52 | | (1 << LWS_H2_FRAME_TYPE_PRIORITY) | |
53 | | (1 << LWS_H2_FRAME_TYPE_RST_STREAM) | |
54 | | (1 << LWS_H2_FRAME_TYPE_SETTINGS) | |
55 | | (1 << LWS_H2_FRAME_TYPE_PUSH_PROMISE) | |
56 | | (1 << LWS_H2_FRAME_TYPE_PING) | |
57 | | (1 << LWS_H2_FRAME_TYPE_GOAWAY) | |
58 | | (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) | |
59 | | (1 << LWS_H2_FRAME_TYPE_CONTINUATION), |
60 | | /* LWS_H2S_HALF_CLOSED_REMOTE */ |
61 | | (1 << LWS_H2_FRAME_TYPE_SETTINGS) | |
62 | | (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) | |
63 | | (1 << LWS_H2_FRAME_TYPE_PRIORITY) | |
64 | | (1 << LWS_H2_FRAME_TYPE_RST_STREAM), |
65 | | /* LWS_H2S_HALF_CLOSED_LOCAL */ |
66 | | (1 << LWS_H2_FRAME_TYPE_DATA) | |
67 | | (1 << LWS_H2_FRAME_TYPE_HEADERS) | |
68 | | (1 << LWS_H2_FRAME_TYPE_PRIORITY) | |
69 | | (1 << LWS_H2_FRAME_TYPE_RST_STREAM) | |
70 | | (1 << LWS_H2_FRAME_TYPE_SETTINGS) | |
71 | | (1 << LWS_H2_FRAME_TYPE_PUSH_PROMISE) | |
72 | | (1 << LWS_H2_FRAME_TYPE_PING) | |
73 | | (1 << LWS_H2_FRAME_TYPE_GOAWAY) | |
74 | | (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) | |
75 | | (1 << LWS_H2_FRAME_TYPE_CONTINUATION), |
76 | | /* LWS_H2S_CLOSED */ |
77 | | (1 << LWS_H2_FRAME_TYPE_SETTINGS) | |
78 | | (1 << LWS_H2_FRAME_TYPE_PRIORITY) | |
79 | | (1 << LWS_H2_FRAME_TYPE_WINDOW_UPDATE) | |
80 | | (1 << LWS_H2_FRAME_TYPE_RST_STREAM), |
81 | | }; |
82 | | |
83 | | static const char *preface = "PRI * HTTP/2.0\x0d\x0a\x0d\x0aSM\x0d\x0a\x0d\x0a"; |
84 | | |
85 | | static const char * const h2_state_names[] = { |
86 | | "LWS_H2S_IDLE", |
87 | | "LWS_H2S_RESERVED_LOCAL", |
88 | | "LWS_H2S_RESERVED_REMOTE", |
89 | | "LWS_H2S_OPEN", |
90 | | "LWS_H2S_HALF_CLOSED_REMOTE", |
91 | | "LWS_H2S_HALF_CLOSED_LOCAL", |
92 | | "LWS_H2S_CLOSED", |
93 | | }; |
94 | | |
95 | | #if 0 |
96 | | static const char * const h2_setting_names[] = { |
97 | | "", |
98 | | "H2SET_HEADER_TABLE_SIZE", |
99 | | "H2SET_ENABLE_PUSH", |
100 | | "H2SET_MAX_CONCURRENT_STREAMS", |
101 | | "H2SET_INITIAL_WINDOW_SIZE", |
102 | | "H2SET_MAX_FRAME_SIZE", |
103 | | "H2SET_MAX_HEADER_LIST_SIZE", |
104 | | "reserved", |
105 | | "H2SET_ENABLE_CONNECT_PROTOCOL" |
106 | | }; |
107 | | |
108 | | void |
109 | | lws_h2_dump_settings(struct http2_settings *set) |
110 | | { |
111 | | int n; |
112 | | |
113 | | for (n = 1; n < H2SET_COUNT; n++) |
114 | | lwsl_notice(" %30s: %10d\n", h2_setting_names[n], set->s[n]); |
115 | | } |
116 | | #else |
117 | | void |
118 | | lws_h2_dump_settings(struct http2_settings *set) |
119 | 0 | { |
120 | 0 | } |
121 | | #endif |
122 | | |
123 | | struct lws_h2_protocol_send * |
124 | | lws_h2_new_pps(enum lws_h2_protocol_send_type type) |
125 | 0 | { |
126 | 0 | struct lws_h2_protocol_send *pps = lws_malloc(sizeof(*pps), "pps"); |
127 | |
|
128 | 0 | if (pps) |
129 | 0 | pps->type = type; |
130 | |
|
131 | 0 | return pps; |
132 | 0 | } |
133 | | |
134 | | void lws_h2_init(struct lws *wsi) |
135 | 0 | { |
136 | 0 | wsi->h2.h2n->our_set = wsi->a.vhost->h2.set; |
137 | 0 | wsi->h2.h2n->peer_set = lws_h2_defaults; |
138 | 0 | } |
139 | | |
140 | | void |
141 | | lws_h2_state(struct lws *wsi, enum lws_h2_states s) |
142 | 0 | { |
143 | 0 | if (!wsi) |
144 | 0 | return; |
145 | 0 | lwsl_info("%s: %s: state %s -> %s\n", __func__, lws_wsi_tag(wsi), |
146 | 0 | h2_state_names[wsi->h2.h2_state], |
147 | 0 | h2_state_names[s]); |
148 | | |
149 | 0 | (void)h2_state_names; |
150 | 0 | wsi->h2.h2_state = (uint8_t)s; |
151 | 0 | } |
152 | | |
153 | | int |
154 | | lws_h2_update_peer_txcredit(struct lws *wsi, unsigned int sid, int bump) |
155 | 0 | { |
156 | 0 | struct lws *nwsi = lws_get_network_wsi(wsi); |
157 | 0 | struct lws_h2_protocol_send *pps; |
158 | |
|
159 | 0 | assert(wsi); |
160 | | |
161 | 0 | if (!bump) |
162 | 0 | return 0; |
163 | | |
164 | 0 | if (sid == (unsigned int)-1) |
165 | 0 | sid = wsi->mux.my_sid; |
166 | |
|
167 | 0 | lwsl_info("%s: sid %d: bump %d -> %d\n", __func__, sid, bump, |
168 | 0 | (int)wsi->txc.peer_tx_cr_est + bump); |
169 | |
|
170 | 0 | pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW); |
171 | 0 | if (!pps) |
172 | 0 | return 1; |
173 | | |
174 | 0 | pps->u.update_window.sid = (unsigned int)sid; |
175 | 0 | pps->u.update_window.credit = (unsigned int)bump; |
176 | 0 | wsi->txc.peer_tx_cr_est += bump; |
177 | |
|
178 | 0 | lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid); |
179 | |
|
180 | 0 | lws_pps_schedule(wsi, pps); |
181 | |
|
182 | 0 | pps = lws_h2_new_pps(LWS_H2_PPS_UPDATE_WINDOW); |
183 | 0 | if (!pps) |
184 | 0 | return 1; |
185 | | |
186 | 0 | pps->u.update_window.sid = 0; |
187 | 0 | pps->u.update_window.credit = (unsigned int)bump; |
188 | 0 | nwsi->txc.peer_tx_cr_est += bump; |
189 | |
|
190 | 0 | lws_wsi_txc_describe(&nwsi->txc, __func__, nwsi->mux.my_sid); |
191 | |
|
192 | 0 | lws_pps_schedule(nwsi, pps); |
193 | |
|
194 | 0 | return 0; |
195 | 0 | } |
196 | | |
197 | | int |
198 | | lws_h2_get_peer_txcredit_estimate(struct lws *wsi) |
199 | 0 | { |
200 | 0 | lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid); |
201 | 0 | return (int)wsi->txc.peer_tx_cr_est; |
202 | 0 | } |
203 | | |
204 | | static int |
205 | | lws_h2_update_peer_txcredit_thresh(struct lws *wsi, unsigned int sid, int threshold, int bump) |
206 | 0 | { |
207 | 0 | if (wsi->txc.peer_tx_cr_est > threshold) |
208 | 0 | return 0; |
209 | | |
210 | 0 | return lws_h2_update_peer_txcredit(wsi, sid, bump); |
211 | 0 | } |
212 | | |
213 | | /* cx + vh lock */ |
214 | | |
215 | | static struct lws * |
216 | | __lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi, |
217 | | unsigned int sid) |
218 | 0 | { |
219 | 0 | struct lws *nwsi = lws_get_network_wsi(parent_wsi); |
220 | 0 | struct lws_h2_netconn *h2n = nwsi->h2.h2n; |
221 | 0 | char tmp[50], tmp1[50]; |
222 | 0 | unsigned int n, b = 0; |
223 | 0 | struct lws *wsi; |
224 | 0 | const char *p; |
225 | |
|
226 | 0 | lws_context_assert_lock_held(vh->context); |
227 | 0 | lws_vhost_assert_lock_held(vh); |
228 | | |
229 | | /* |
230 | | * The identifier of a newly established stream MUST be numerically |
231 | | * greater than all streams that the initiating endpoint has opened or |
232 | | * reserved. This governs streams that are opened using a HEADERS frame |
233 | | * and streams that are reserved using PUSH_PROMISE. An endpoint that |
234 | | * receives an unexpected stream identifier MUST respond with a |
235 | | * connection error (Section 5.4.1) of type PROTOCOL_ERROR. |
236 | | */ |
237 | 0 | if (sid <= h2n->highest_sid_opened) { |
238 | 0 | lwsl_info("%s: tried to open lower sid %d (%d)\n", __func__, |
239 | 0 | sid, (int)h2n->highest_sid_opened); |
240 | 0 | lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, "Bad sid"); |
241 | 0 | return NULL; |
242 | 0 | } |
243 | | |
244 | | /* no more children allowed by parent */ |
245 | 0 | if (parent_wsi->mux.child_count + 1 > |
246 | 0 | parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) { |
247 | 0 | lwsl_notice("reached concurrent stream limit\n"); |
248 | 0 | return NULL; |
249 | 0 | } |
250 | | |
251 | 0 | n = 0; |
252 | 0 | p = &parent_wsi->lc.gutag[1]; |
253 | 0 | do { |
254 | 0 | if (*p == '|') { |
255 | 0 | b++; |
256 | 0 | if (b == 3) |
257 | 0 | continue; |
258 | 0 | } |
259 | 0 | tmp1[n++] = *p++; |
260 | 0 | } while (b < 3 && n < sizeof(tmp1) - 2); |
261 | 0 | tmp1[n] = '\0'; |
262 | 0 | lws_snprintf(tmp, sizeof(tmp), "h2_sid%u_(%s)", sid, tmp1); |
263 | 0 | wsi = lws_create_new_server_wsi(vh, parent_wsi->tsi, LWSLCG_WSI_MUX, tmp); |
264 | 0 | if (!wsi) { |
265 | 0 | lwsl_notice("new server wsi failed (%s)\n", lws_vh_tag(vh)); |
266 | 0 | return NULL; |
267 | 0 | } |
268 | | |
269 | 0 | #if defined(LWS_WITH_SERVER) |
270 | 0 | if (lwsi_role_server(parent_wsi)) { |
271 | 0 | lws_metrics_caliper_bind(wsi->cal_conn, wsi->a.context->mth_srv); |
272 | 0 | } |
273 | 0 | #endif |
274 | |
|
275 | 0 | h2n->highest_sid_opened = sid; |
276 | |
|
277 | 0 | lws_wsi_mux_insert(wsi, parent_wsi, sid); |
278 | 0 | if (sid >= h2n->highest_sid) |
279 | 0 | h2n->highest_sid = sid + 2; |
280 | |
|
281 | 0 | wsi->mux_substream = 1; |
282 | 0 | wsi->seen_nonpseudoheader = 0; |
283 | |
|
284 | 0 | wsi->txc.tx_cr = (int32_t)nwsi->h2.h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE]; |
285 | 0 | wsi->txc.peer_tx_cr_est = |
286 | 0 | (int32_t)nwsi->h2.h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE]; |
287 | |
|
288 | 0 | lwsi_set_state(wsi, LRS_ESTABLISHED); |
289 | 0 | lwsi_set_role(wsi, lwsi_role(parent_wsi)); |
290 | |
|
291 | 0 | wsi->a.protocol = &vh->protocols[0]; |
292 | 0 | if (lws_ensure_user_space(wsi)) |
293 | 0 | goto bail1; |
294 | | |
295 | 0 | #if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS) |
296 | 0 | if (lws_adopt_ss_server_accept(wsi)) |
297 | 0 | goto bail1; |
298 | 0 | #endif |
299 | | |
300 | | /* get the ball rolling */ |
301 | 0 | lws_validity_confirmed(wsi); |
302 | |
|
303 | 0 | lwsl_info("%s: %s new ch %s, sid %d, usersp=%p\n", __func__, |
304 | 0 | lws_wsi_tag(parent_wsi), lws_wsi_tag(wsi), sid, wsi->user_space); |
305 | |
|
306 | 0 | lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid); |
307 | 0 | lws_wsi_txc_describe(&nwsi->txc, __func__, 0); |
308 | |
|
309 | 0 | return wsi; |
310 | | |
311 | 0 | bail1: |
312 | | /* undo the insert */ |
313 | 0 | parent_wsi->mux.child_list = wsi->mux.sibling_list; |
314 | 0 | parent_wsi->mux.child_count--; |
315 | |
|
316 | 0 | if (wsi->user_space) |
317 | 0 | lws_free_set_NULL(wsi->user_space); |
318 | 0 | vh->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0); |
319 | 0 | __lws_vhost_unbind_wsi(wsi); |
320 | 0 | lws_free(wsi); |
321 | |
|
322 | 0 | return NULL; |
323 | 0 | } |
324 | | |
325 | | struct lws * |
326 | | lws_wsi_h2_adopt(struct lws *parent_wsi, struct lws *wsi) |
327 | 0 | { |
328 | 0 | struct lws *nwsi = lws_get_network_wsi(parent_wsi); |
329 | | |
330 | | /* no more children allowed by parent */ |
331 | 0 | if (parent_wsi->mux.child_count + 1 > |
332 | 0 | parent_wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) { |
333 | 0 | lwsl_notice("reached concurrent stream limit\n"); |
334 | 0 | return NULL; |
335 | 0 | } |
336 | | |
337 | | /* sid is set just before issuing the headers, ensuring monoticity */ |
338 | | |
339 | 0 | wsi->seen_nonpseudoheader = 0; |
340 | 0 | #if defined(LWS_WITH_CLIENT) |
341 | 0 | wsi->client_mux_substream = 1; |
342 | 0 | #endif |
343 | 0 | wsi->h2.initialized = 1; |
344 | |
|
345 | | #if 0 |
346 | | /* only assign sid at header send time when we know it */ |
347 | | if (!wsi->mux.my_sid) { |
348 | | wsi->mux.my_sid = nwsi->h2.h2n->highest_sid; |
349 | | nwsi->h2.h2n->highest_sid += 2; |
350 | | } |
351 | | #endif |
352 | |
|
353 | 0 | lwsl_info("%s: binding wsi %s to sid %d (next %d)\n", __func__, |
354 | 0 | lws_wsi_tag(wsi), (int)wsi->mux.my_sid, (int)nwsi->h2.h2n->highest_sid); |
355 | |
|
356 | 0 | lws_wsi_mux_insert(wsi, parent_wsi, wsi->mux.my_sid); |
357 | |
|
358 | 0 | wsi->txc.tx_cr = (int32_t)nwsi->h2.h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE]; |
359 | 0 | wsi->txc.peer_tx_cr_est = (int32_t) |
360 | 0 | nwsi->h2.h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE]; |
361 | |
|
362 | 0 | lws_wsi_txc_describe(&wsi->txc, __func__, wsi->mux.my_sid); |
363 | |
|
364 | 0 | if (lws_ensure_user_space(wsi)) |
365 | 0 | goto bail1; |
366 | | |
367 | 0 | lws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS, |
368 | 0 | &role_ops_h2); |
369 | |
|
370 | 0 | lws_callback_on_writable(wsi); |
371 | |
|
372 | 0 | return wsi; |
373 | | |
374 | 0 | bail1: |
375 | | /* undo the insert */ |
376 | 0 | parent_wsi->mux.child_list = wsi->mux.sibling_list; |
377 | 0 | parent_wsi->mux.child_count--; |
378 | |
|
379 | 0 | if (wsi->user_space) |
380 | 0 | lws_free_set_NULL(wsi->user_space); |
381 | 0 | wsi->a.protocol->callback(wsi, LWS_CALLBACK_WSI_DESTROY, NULL, NULL, 0); |
382 | 0 | lws_free(wsi); |
383 | |
|
384 | 0 | return NULL; |
385 | 0 | } |
386 | | |
387 | | |
388 | | int |
389 | | lws_h2_issue_preface(struct lws *wsi) |
390 | 0 | { |
391 | 0 | struct lws_h2_netconn *h2n = wsi->h2.h2n; |
392 | 0 | struct lws_h2_protocol_send *pps; |
393 | |
|
394 | 0 | if (!h2n) { |
395 | 0 | lwsl_warn("%s: no valid h2n\n", __func__); |
396 | 0 | return 1; |
397 | 0 | } |
398 | | |
399 | 0 | if (h2n->sent_preface) |
400 | 0 | return 1; |
401 | | |
402 | 0 | lwsl_debug("%s: %s: fd %d\n", __func__, lws_wsi_tag(wsi), (int)wsi->desc.sockfd); |
403 | |
|
404 | 0 | if (lws_issue_raw(wsi, (uint8_t *)preface, strlen(preface)) != |
405 | 0 | (int)strlen(preface)) |
406 | 0 | return 1; |
407 | | |
408 | 0 | h2n->sent_preface = 1; |
409 | |
|
410 | 0 | lws_role_transition(wsi, LWSIFR_CLIENT, LRS_H2_WAITING_TO_SEND_HEADERS, |
411 | 0 | &role_ops_h2); |
412 | |
|
413 | 0 | h2n->count = 0; |
414 | 0 | wsi->txc.tx_cr = 65535; |
415 | | |
416 | | /* |
417 | | * we must send a settings frame |
418 | | */ |
419 | 0 | pps = lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS); |
420 | 0 | if (!pps) |
421 | 0 | return 1; |
422 | 0 | lws_pps_schedule(wsi, pps); |
423 | 0 | lwsl_info("%s: h2 client sending settings\n", __func__); |
424 | |
|
425 | 0 | return 0; |
426 | 0 | } |
427 | | |
428 | | void |
429 | | lws_pps_schedule(struct lws *wsi, struct lws_h2_protocol_send *pps) |
430 | 0 | { |
431 | 0 | struct lws *nwsi = lws_get_network_wsi(wsi); |
432 | 0 | struct lws_h2_netconn *h2n = nwsi->h2.h2n; |
433 | |
|
434 | 0 | if (!h2n) { |
435 | 0 | lwsl_warn("%s: null h2n\n", __func__); |
436 | 0 | lws_free(pps); |
437 | 0 | return; |
438 | 0 | } |
439 | | |
440 | 0 | pps->next = h2n->pps; |
441 | 0 | h2n->pps = pps; |
442 | 0 | lws_rx_flow_control(wsi, LWS_RXFLOW_REASON_APPLIES_DISABLE | |
443 | 0 | LWS_RXFLOW_REASON_H2_PPS_PENDING); |
444 | 0 | lws_callback_on_writable(wsi); |
445 | 0 | } |
446 | | |
447 | | int |
448 | | lws_h2_goaway(struct lws *wsi, uint32_t err, const char *reason) |
449 | 0 | { |
450 | 0 | struct lws_h2_netconn *h2n = wsi->h2.h2n; |
451 | 0 | struct lws_h2_protocol_send *pps; |
452 | |
|
453 | 0 | if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) |
454 | 0 | return 0; |
455 | | |
456 | 0 | pps = lws_h2_new_pps(LWS_H2_PPS_GOAWAY); |
457 | 0 | if (!pps) |
458 | 0 | return 1; |
459 | | |
460 | 0 | lwsl_info("%s: %s: ERR 0x%x, '%s'\n", __func__, lws_wsi_tag(wsi), (int)err, reason); |
461 | |
|
462 | 0 | pps->u.ga.err = err; |
463 | 0 | pps->u.ga.highest_sid = h2n->highest_sid; |
464 | 0 | lws_strncpy(pps->u.ga.str, reason, sizeof(pps->u.ga.str)); |
465 | 0 | lws_pps_schedule(wsi, pps); |
466 | |
|
467 | 0 | h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */ |
468 | |
|
469 | 0 | return 0; |
470 | 0 | } |
471 | | |
472 | | int |
473 | | lws_h2_rst_stream(struct lws *wsi, uint32_t err, const char *reason) |
474 | 0 | { |
475 | 0 | struct lws *nwsi = lws_get_network_wsi(wsi); |
476 | 0 | struct lws_h2_netconn *h2n = nwsi->h2.h2n; |
477 | 0 | struct lws_h2_protocol_send *pps; |
478 | |
|
479 | 0 | if (!h2n) |
480 | 0 | return 0; |
481 | | |
482 | 0 | if (!wsi->h2_stream_carries_ws && h2n->type == LWS_H2_FRAME_TYPE_COUNT) |
483 | 0 | return 0; |
484 | | |
485 | 0 | pps = lws_h2_new_pps(LWS_H2_PPS_RST_STREAM); |
486 | 0 | if (!pps) |
487 | 0 | return 1; |
488 | | |
489 | 0 | lwsl_info("%s: RST_STREAM 0x%x, sid %d, REASON '%s'\n", __func__, |
490 | 0 | (int)err, wsi->mux.my_sid, reason); |
491 | |
|
492 | 0 | pps->u.rs.sid = wsi->mux.my_sid; |
493 | 0 | pps->u.rs.err = err; |
494 | |
|
495 | 0 | lws_pps_schedule(wsi, pps); |
496 | |
|
497 | 0 | h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */ |
498 | 0 | lws_h2_state(wsi, LWS_H2_STATE_CLOSED); |
499 | |
|
500 | 0 | return 0; |
501 | 0 | } |
502 | | |
503 | | int |
504 | | lws_h2_settings(struct lws *wsi, struct http2_settings *settings, |
505 | | unsigned char *buf, int len) |
506 | 0 | { |
507 | 0 | struct lws *nwsi = lws_get_network_wsi(wsi); |
508 | 0 | unsigned int a, b; |
509 | |
|
510 | 0 | if (!len) |
511 | 0 | return 0; |
512 | | |
513 | 0 | if (len < LWS_H2_SETTINGS_LEN) |
514 | 0 | return 1; |
515 | | |
516 | 0 | while (len >= LWS_H2_SETTINGS_LEN) { |
517 | 0 | a = (unsigned int)((buf[0] << 8) | buf[1]); |
518 | 0 | if (!a || a >= H2SET_COUNT) |
519 | 0 | goto skip; |
520 | 0 | b = (unsigned int)(buf[2] << 24 | buf[3] << 16 | buf[4] << 8 | buf[5]); |
521 | |
|
522 | 0 | switch (a) { |
523 | 0 | case H2SET_HEADER_TABLE_SIZE: |
524 | 0 | break; |
525 | 0 | case H2SET_ENABLE_PUSH: |
526 | 0 | if (b > 1) { |
527 | 0 | lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, |
528 | 0 | "ENABLE_PUSH invalid arg"); |
529 | 0 | return 1; |
530 | 0 | } |
531 | 0 | break; |
532 | 0 | case H2SET_MAX_CONCURRENT_STREAMS: |
533 | 0 | break; |
534 | 0 | case H2SET_INITIAL_WINDOW_SIZE: |
535 | 0 | if (b > 0x7fffffff) { |
536 | 0 | lws_h2_goaway(nwsi, H2_ERR_FLOW_CONTROL_ERROR, |
537 | 0 | "Initial Window beyond max"); |
538 | 0 | return 1; |
539 | 0 | } |
540 | | |
541 | 0 | #if defined(LWS_WITH_CLIENT) |
542 | | #if defined(LWS_AMAZON_RTOS) || defined(LWS_AMAZON_LINUX) |
543 | | if ( |
544 | | #else |
545 | 0 | if (wsi->flags & LCCSCF_H2_QUIRK_OVERFLOWS_TXCR && |
546 | 0 | #endif |
547 | 0 | b == 0x7fffffff) { |
548 | 0 | b >>= 4; |
549 | |
|
550 | 0 | break; |
551 | 0 | } |
552 | 0 | #endif |
553 | | |
554 | | /* |
555 | | * In addition to changing the flow-control window for |
556 | | * streams that are not yet active, a SETTINGS frame |
557 | | * can alter the initial flow-control window size for |
558 | | * streams with active flow-control windows (that is, |
559 | | * streams in the "open" or "half-closed (remote)" |
560 | | * state). When the value of |
561 | | * SETTINGS_INITIAL_WINDOW_SIZE changes, a receiver |
562 | | * MUST adjust the size of all stream flow-control |
563 | | * windows that it maintains by the difference between |
564 | | * the new value and the old value. |
565 | | */ |
566 | | |
567 | 0 | lws_start_foreach_ll(struct lws *, w, |
568 | 0 | nwsi->mux.child_list) { |
569 | 0 | lwsl_info("%s: adi child tc cr %d +%d -> %d", |
570 | 0 | __func__, (int)w->txc.tx_cr, |
571 | 0 | b - (unsigned int)settings->s[a], |
572 | 0 | (int)(w->txc.tx_cr + (int)b - |
573 | 0 | (int)settings->s[a])); |
574 | 0 | w->txc.tx_cr += (int)b - (int)settings->s[a]; |
575 | 0 | if (w->txc.tx_cr > 0 && |
576 | 0 | w->txc.tx_cr <= |
577 | 0 | (int32_t)(b - settings->s[a])) |
578 | | |
579 | 0 | lws_callback_on_writable(w); |
580 | 0 | } lws_end_foreach_ll(w, mux.sibling_list); |
581 | |
|
582 | 0 | break; |
583 | 0 | case H2SET_MAX_FRAME_SIZE: |
584 | 0 | if (b < wsi->a.vhost->h2.set.s[H2SET_MAX_FRAME_SIZE]) { |
585 | 0 | lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, |
586 | 0 | "Frame size < initial"); |
587 | 0 | return 1; |
588 | 0 | } |
589 | 0 | if (b > 0x00ffffff) { |
590 | 0 | lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, |
591 | 0 | "Settings Frame size above max"); |
592 | 0 | return 1; |
593 | 0 | } |
594 | 0 | break; |
595 | 0 | case H2SET_MAX_HEADER_LIST_SIZE: |
596 | 0 | break; |
597 | 0 | } |
598 | 0 | settings->s[a] = b; |
599 | 0 | lwsl_info("http2 settings %d <- 0x%x\n", a, b); |
600 | 0 | skip: |
601 | 0 | len -= LWS_H2_SETTINGS_LEN; |
602 | 0 | buf += LWS_H2_SETTINGS_LEN; |
603 | 0 | } |
604 | | |
605 | 0 | if (len) |
606 | 0 | return 1; |
607 | | |
608 | 0 | lws_h2_dump_settings(settings); |
609 | |
|
610 | 0 | return 0; |
611 | 0 | } |
612 | | |
613 | | /* RFC7640 Sect 6.9 |
614 | | * |
615 | | * The WINDOW_UPDATE frame can be specific to a stream or to the entire |
616 | | * connection. In the former case, the frame's stream identifier |
617 | | * indicates the affected stream; in the latter, the value "0" indicates |
618 | | * that the entire connection is the subject of the frame. |
619 | | * |
620 | | * ... |
621 | | * |
622 | | * Two flow-control windows are applicable: the stream flow-control |
623 | | * window and the connection flow-control window. The sender MUST NOT |
624 | | * send a flow-controlled frame with a length that exceeds the space |
625 | | * available in either of the flow-control windows advertised by the |
626 | | * receiver. Frames with zero length with the END_STREAM flag set (that |
627 | | * is, an empty DATA frame) MAY be sent if there is no available space |
628 | | * in either flow-control window. |
629 | | */ |
630 | | |
631 | | int |
632 | | lws_h2_tx_cr_get(struct lws *wsi) |
633 | 0 | { |
634 | 0 | int c = wsi->txc.tx_cr; |
635 | 0 | struct lws *nwsi = lws_get_network_wsi(wsi); |
636 | |
|
637 | 0 | if (!wsi->mux_substream && !nwsi->upgraded_to_http2) |
638 | 0 | return ~0x80000000; |
639 | | |
640 | 0 | lwsl_info ("%s: %s: own tx credit %d: nwsi credit %d\n", |
641 | 0 | __func__, lws_wsi_tag(wsi), c, (int)nwsi->txc.tx_cr); |
642 | |
|
643 | 0 | if (nwsi->txc.tx_cr < c) |
644 | 0 | c = nwsi->txc.tx_cr; |
645 | |
|
646 | 0 | if (c < 0) |
647 | 0 | return 0; |
648 | | |
649 | 0 | return c; |
650 | 0 | } |
651 | | |
652 | | void |
653 | | lws_h2_tx_cr_consume(struct lws *wsi, int consumed) |
654 | 0 | { |
655 | 0 | struct lws *nwsi = lws_get_network_wsi(wsi); |
656 | |
|
657 | 0 | wsi->txc.tx_cr -= consumed; |
658 | |
|
659 | 0 | if (nwsi != wsi) |
660 | 0 | nwsi->txc.tx_cr -= consumed; |
661 | 0 | } |
662 | | |
663 | | int lws_h2_frame_write(struct lws *wsi, int type, int flags, |
664 | | unsigned int sid, unsigned int len, unsigned char *buf) |
665 | 0 | { |
666 | 0 | struct lws *nwsi = lws_get_network_wsi(wsi); |
667 | 0 | unsigned char *p = &buf[-LWS_H2_FRAME_HEADER_LENGTH]; |
668 | 0 | int n; |
669 | | |
670 | | //if (wsi->h2_stream_carries_ws) |
671 | | // lwsl_hexdump_level(LLL_NOTICE, buf, len); |
672 | |
|
673 | 0 | *p++ = (uint8_t)(len >> 16); |
674 | 0 | *p++ = (uint8_t)(len >> 8); |
675 | 0 | *p++ = (uint8_t)len; |
676 | 0 | *p++ = (uint8_t)type; |
677 | 0 | *p++ = (uint8_t)flags; |
678 | 0 | *p++ = (uint8_t)(sid >> 24); |
679 | 0 | *p++ = (uint8_t)(sid >> 16); |
680 | 0 | *p++ = (uint8_t)(sid >> 8); |
681 | 0 | *p++ = (uint8_t)sid; |
682 | |
|
683 | 0 | lwsl_debug("%s: %s (eff %s). typ %d, fl 0x%x, sid=%d, len=%d, " |
684 | 0 | "txcr=%d, nwsi->txcr=%d\n", __func__, lws_wsi_tag(wsi), |
685 | 0 | lws_wsi_tag(nwsi), type, flags, |
686 | 0 | sid, len, (int)wsi->txc.tx_cr, (int)nwsi->txc.tx_cr); |
687 | |
|
688 | 0 | if (type == LWS_H2_FRAME_TYPE_DATA) { |
689 | 0 | if (wsi->txc.tx_cr < (int)len) |
690 | | |
691 | 0 | lwsl_info("%s: %s: sending payload len %d" |
692 | 0 | " but tx_cr only %d!\n", __func__, |
693 | 0 | lws_wsi_tag(wsi), len, (int)wsi->txc.tx_cr); |
694 | 0 | lws_h2_tx_cr_consume(wsi, (int)len); |
695 | 0 | } |
696 | |
|
697 | 0 | n = lws_issue_raw(nwsi, &buf[-LWS_H2_FRAME_HEADER_LENGTH], |
698 | 0 | len + LWS_H2_FRAME_HEADER_LENGTH); |
699 | 0 | if (n < 0) |
700 | 0 | return n; |
701 | | |
702 | 0 | if (n >= LWS_H2_FRAME_HEADER_LENGTH) |
703 | 0 | return n - LWS_H2_FRAME_HEADER_LENGTH; |
704 | | |
705 | 0 | return n; |
706 | 0 | } |
707 | | |
708 | | static void lws_h2_set_bin(struct lws *wsi, int n, unsigned char *buf) |
709 | 0 | { |
710 | 0 | *buf++ = (uint8_t)(n >> 8); |
711 | 0 | *buf++ = (uint8_t)n; |
712 | 0 | *buf++ = (uint8_t)(wsi->h2.h2n->our_set.s[n] >> 24); |
713 | 0 | *buf++ = (uint8_t)(wsi->h2.h2n->our_set.s[n] >> 16); |
714 | 0 | *buf++ = (uint8_t)(wsi->h2.h2n->our_set.s[n] >> 8); |
715 | 0 | *buf = (uint8_t)wsi->h2.h2n->our_set.s[n]; |
716 | 0 | } |
717 | | |
718 | | /* we get called on the network connection */ |
719 | | |
720 | | int lws_h2_do_pps_send(struct lws *wsi) |
721 | 0 | { |
722 | 0 | struct lws_h2_netconn *h2n = wsi->h2.h2n; |
723 | 0 | struct lws_h2_protocol_send *pps = NULL; |
724 | 0 | struct lws *cwsi; |
725 | 0 | uint8_t set[LWS_PRE + 64], *p = &set[LWS_PRE], *q; |
726 | 0 | int n, m = 0, flags = 0; |
727 | |
|
728 | 0 | if (!h2n) |
729 | 0 | return 1; |
730 | | |
731 | | /* get the oldest pps */ |
732 | | |
733 | 0 | lws_start_foreach_llp(struct lws_h2_protocol_send **, pps1, h2n->pps) { |
734 | 0 | if ((*pps1)->next == NULL) { /* we are the oldest in the list */ |
735 | 0 | pps = *pps1; /* remove us from the list */ |
736 | 0 | *pps1 = NULL; |
737 | 0 | continue; |
738 | 0 | } |
739 | 0 | } lws_end_foreach_llp(pps1, next); |
740 | |
|
741 | 0 | if (!pps) |
742 | 0 | return 1; |
743 | | |
744 | 0 | lwsl_info("%s: %s: %d\n", __func__, lws_wsi_tag(wsi), pps->type); |
745 | |
|
746 | 0 | switch (pps->type) { |
747 | | |
748 | 0 | case LWS_H2_PPS_MY_SETTINGS: |
749 | | |
750 | | /* |
751 | | * if any of our settings varies from h2 "default defaults" |
752 | | * then we must inform the peer |
753 | | */ |
754 | 0 | for (n = 1; n < H2SET_COUNT; n++) |
755 | 0 | if (h2n->our_set.s[n] != lws_h2_defaults.s[n]) { |
756 | 0 | lwsl_debug("sending SETTING %d 0x%x\n", n, |
757 | 0 | (unsigned int) |
758 | 0 | wsi->h2.h2n->our_set.s[n]); |
759 | |
|
760 | 0 | lws_h2_set_bin(wsi, n, &set[LWS_PRE + m]); |
761 | 0 | m += (int)sizeof(h2n->one_setting); |
762 | 0 | } |
763 | 0 | n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS, |
764 | 0 | flags, LWS_H2_STREAM_ID_MASTER, (unsigned int)m, |
765 | 0 | &set[LWS_PRE]); |
766 | 0 | if (n != m) { |
767 | 0 | lwsl_info("send %d %d\n", n, m); |
768 | 0 | goto bail; |
769 | 0 | } |
770 | 0 | break; |
771 | | |
772 | 0 | case LWS_H2_PPS_SETTINGS_INITIAL_UPDATE_WINDOW: |
773 | 0 | q = &set[LWS_PRE]; |
774 | 0 | *q++ = (uint8_t)(H2SET_INITIAL_WINDOW_SIZE >> 8); |
775 | 0 | *q++ = (uint8_t)(H2SET_INITIAL_WINDOW_SIZE); |
776 | 0 | *q++ = (uint8_t)(pps->u.update_window.credit >> 24); |
777 | 0 | *q++ = (uint8_t)(pps->u.update_window.credit >> 16); |
778 | 0 | *q++ = (uint8_t)(pps->u.update_window.credit >> 8); |
779 | 0 | *q = (uint8_t)(pps->u.update_window.credit); |
780 | |
|
781 | 0 | lwsl_debug("%s: resetting initial window to %d\n", __func__, |
782 | 0 | (int)pps->u.update_window.credit); |
783 | |
|
784 | 0 | n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS, |
785 | 0 | flags, LWS_H2_STREAM_ID_MASTER, 6, |
786 | 0 | &set[LWS_PRE]); |
787 | 0 | if (n != 6) { |
788 | 0 | lwsl_info("send %d %d\n", n, m); |
789 | 0 | goto bail; |
790 | 0 | } |
791 | 0 | break; |
792 | | |
793 | 0 | case LWS_H2_PPS_ACK_SETTINGS: |
794 | | /* send ack ... always empty */ |
795 | 0 | n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_SETTINGS, 1, |
796 | 0 | LWS_H2_STREAM_ID_MASTER, 0, |
797 | 0 | &set[LWS_PRE]); |
798 | 0 | if (n) { |
799 | 0 | lwsl_err("%s: writing settings ack frame failed %d\n", __func__, n); |
800 | 0 | goto bail; |
801 | 0 | } |
802 | 0 | wsi->h2_acked_settings = 0; |
803 | | /* this is the end of the preface dance then? */ |
804 | 0 | if (lwsi_state(wsi) == LRS_H2_AWAIT_SETTINGS) { |
805 | 0 | lwsi_set_state(wsi, LRS_ESTABLISHED); |
806 | 0 | #if defined(LWS_WITH_FILE_OPS) |
807 | 0 | wsi->http.fop_fd = NULL; |
808 | 0 | #endif |
809 | 0 | if (lws_is_ssl(lws_get_network_wsi(wsi))) |
810 | 0 | break; |
811 | | |
812 | 0 | if (wsi->a.vhost->options & |
813 | 0 | LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE) |
814 | 0 | break; |
815 | | |
816 | | /* |
817 | | * we need to treat the headers from the upgrade as the |
818 | | * first job. So these need to get shifted to sid 1. |
819 | | */ |
820 | | |
821 | 0 | lws_context_lock(wsi->a.context, "h2 mig"); |
822 | 0 | lws_vhost_lock(wsi->a.vhost); |
823 | |
|
824 | 0 | h2n->swsi = __lws_wsi_server_new(wsi->a.vhost, wsi, 1); |
825 | |
|
826 | 0 | lws_vhost_unlock(wsi->a.vhost); |
827 | 0 | lws_context_unlock(wsi->a.context); |
828 | |
|
829 | 0 | if (!h2n->swsi) |
830 | 0 | goto bail; |
831 | | |
832 | | /* pass on the initial headers to SID 1 */ |
833 | 0 | h2n->swsi->http.ah = wsi->http.ah; |
834 | 0 | wsi->http.ah = NULL; |
835 | |
|
836 | 0 | lwsl_info("%s: inherited headers %p\n", __func__, |
837 | 0 | h2n->swsi->http.ah); |
838 | 0 | h2n->swsi->txc.tx_cr = (int32_t) |
839 | 0 | h2n->our_set.s[H2SET_INITIAL_WINDOW_SIZE]; |
840 | 0 | lwsl_info("initial tx credit on %s: %d\n", |
841 | 0 | lws_wsi_tag(h2n->swsi), |
842 | 0 | (int)h2n->swsi->txc.tx_cr); |
843 | 0 | h2n->swsi->h2.initialized = 1; |
844 | | /* demanded by HTTP2 */ |
845 | 0 | h2n->swsi->h2.END_STREAM = 1; |
846 | 0 | lwsl_info("servicing initial http request\n"); |
847 | |
|
848 | 0 | #if defined(LWS_WITH_SERVER) |
849 | 0 | if (lws_http_action(h2n->swsi)) |
850 | 0 | goto bail; |
851 | 0 | #endif |
852 | 0 | break; |
853 | 0 | } |
854 | 0 | break; |
855 | | |
856 | | /* |
857 | | * h2 only has PING... ACK = 0 = ping, ACK = 1 = pong |
858 | | */ |
859 | | |
860 | 0 | case LWS_H2_PPS_PING: |
861 | 0 | case LWS_H2_PPS_PONG: |
862 | 0 | if (pps->type == LWS_H2_PPS_PING) |
863 | 0 | lwsl_info("sending PING\n"); |
864 | 0 | else { |
865 | 0 | lwsl_info("sending PONG\n"); |
866 | 0 | flags = LWS_H2_FLAG_SETTINGS_ACK; |
867 | 0 | } |
868 | |
|
869 | 0 | memcpy(&set[LWS_PRE], pps->u.ping.ping_payload, 8); |
870 | 0 | n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_PING, flags, |
871 | 0 | LWS_H2_STREAM_ID_MASTER, 8, |
872 | 0 | &set[LWS_PRE]); |
873 | 0 | if (n != 8) |
874 | 0 | goto bail; |
875 | | |
876 | 0 | break; |
877 | | |
878 | 0 | case LWS_H2_PPS_GOAWAY: |
879 | 0 | lwsl_info("LWS_H2_PPS_GOAWAY\n"); |
880 | 0 | *p++ = (uint8_t)(pps->u.ga.highest_sid >> 24); |
881 | 0 | *p++ = (uint8_t)(pps->u.ga.highest_sid >> 16); |
882 | 0 | *p++ = (uint8_t)(pps->u.ga.highest_sid >> 8); |
883 | 0 | *p++ = (uint8_t)(pps->u.ga.highest_sid); |
884 | 0 | *p++ = (uint8_t)(pps->u.ga.err >> 24); |
885 | 0 | *p++ = (uint8_t)(pps->u.ga.err >> 16); |
886 | 0 | *p++ = (uint8_t)(pps->u.ga.err >> 8); |
887 | 0 | *p++ = (uint8_t)(pps->u.ga.err); |
888 | 0 | q = (unsigned char *)pps->u.ga.str; |
889 | 0 | n = 0; |
890 | 0 | while (*q && n++ < (int)sizeof(pps->u.ga.str)) |
891 | 0 | *p++ = *q++; |
892 | 0 | h2n->we_told_goaway = 1; |
893 | 0 | n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_GOAWAY, 0, |
894 | 0 | LWS_H2_STREAM_ID_MASTER, |
895 | 0 | (unsigned int)lws_ptr_diff(p, &set[LWS_PRE]), |
896 | 0 | &set[LWS_PRE]); |
897 | 0 | if (n != 4) { |
898 | 0 | lwsl_info("send %d %d\n", n, m); |
899 | 0 | goto bail; |
900 | 0 | } |
901 | 0 | goto bail; |
902 | | |
903 | 0 | case LWS_H2_PPS_RST_STREAM: |
904 | 0 | lwsl_info("LWS_H2_PPS_RST_STREAM\n"); |
905 | 0 | *p++ = (uint8_t)(pps->u.rs.err >> 24); |
906 | 0 | *p++ = (uint8_t)(pps->u.rs.err >> 16); |
907 | 0 | *p++ = (uint8_t)(pps->u.rs.err >> 8); |
908 | 0 | *p++ = (uint8_t)(pps->u.rs.err); |
909 | 0 | n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_RST_STREAM, |
910 | 0 | 0, pps->u.rs.sid, 4, &set[LWS_PRE]); |
911 | 0 | if (n != 4) { |
912 | 0 | lwsl_info("send %d %d\n", n, m); |
913 | 0 | goto bail; |
914 | 0 | } |
915 | 0 | cwsi = lws_wsi_mux_from_id(wsi, pps->u.rs.sid); |
916 | 0 | if (cwsi) { |
917 | 0 | lwsl_debug("%s: closing cwsi %s %s %s (wsi %s)\n", |
918 | 0 | __func__, lws_wsi_tag(cwsi), |
919 | 0 | cwsi->role_ops->name, |
920 | 0 | cwsi->a.protocol->name, lws_wsi_tag(wsi)); |
921 | 0 | lws_close_free_wsi(cwsi, 0, "reset stream"); |
922 | 0 | } |
923 | 0 | break; |
924 | | |
925 | 0 | case LWS_H2_PPS_UPDATE_WINDOW: |
926 | 0 | lwsl_info("Issuing LWS_H2_PPS_UPDATE_WINDOW: sid %d: add %d\n", |
927 | 0 | (int)pps->u.update_window.sid, |
928 | 0 | (int)pps->u.update_window.credit); |
929 | 0 | *p++ = (uint8_t)((pps->u.update_window.credit >> 24) & 0x7f); /* 31b */ |
930 | 0 | *p++ = (uint8_t)(pps->u.update_window.credit >> 16); |
931 | 0 | *p++ = (uint8_t)(pps->u.update_window.credit >> 8); |
932 | 0 | *p++ = (uint8_t)(pps->u.update_window.credit); |
933 | 0 | n = lws_h2_frame_write(wsi, LWS_H2_FRAME_TYPE_WINDOW_UPDATE, |
934 | 0 | 0, pps->u.update_window.sid, 4, |
935 | 0 | &set[LWS_PRE]); |
936 | 0 | if (n != 4) { |
937 | 0 | lwsl_info("send %d %d\n", n, m); |
938 | 0 | goto bail; |
939 | 0 | } |
940 | 0 | break; |
941 | | |
942 | 0 | default: |
943 | 0 | break; |
944 | 0 | } |
945 | | |
946 | 0 | lws_free(pps); |
947 | |
|
948 | 0 | return 0; |
949 | | |
950 | 0 | bail: |
951 | 0 | lws_free(pps); |
952 | |
|
953 | 0 | return 1; |
954 | 0 | } |
955 | | |
956 | | static int |
957 | | lws_h2_parse_end_of_frame(struct lws *wsi); |
958 | | |
959 | | /* |
960 | | * The frame header part has just completely arrived. |
961 | | * Perform actions for header completion. |
962 | | */ |
963 | | static int |
964 | | lws_h2_parse_frame_header(struct lws *wsi) |
965 | 0 | { |
966 | 0 | struct lws_h2_netconn *h2n = wsi->h2.h2n; |
967 | 0 | struct lws_h2_protocol_send *pps; |
968 | 0 | int n; |
969 | | |
970 | | /* |
971 | | * We just got the frame header |
972 | | */ |
973 | 0 | h2n->count = 0; |
974 | 0 | h2n->swsi = wsi; |
975 | | /* b31 is a reserved bit */ |
976 | 0 | h2n->sid = h2n->sid & 0x7fffffff; |
977 | |
|
978 | 0 | if (h2n->sid && !(h2n->sid & 1)) { |
979 | 0 | char pes[32]; |
980 | 0 | lws_snprintf(pes, sizeof(pes), "Even Stream ID 0x%x", (unsigned int)h2n->sid); |
981 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, pes); |
982 | |
|
983 | 0 | return 0; |
984 | 0 | } |
985 | | |
986 | | /* let the network wsi live a bit longer if subs are active */ |
987 | | |
988 | 0 | if (!wsi->immortal_substream_count) { |
989 | 0 | int ds = lws_wsi_keepalive_timeout_eff(wsi); |
990 | | |
991 | | /* |
992 | | * A short (5s) timeout here affects the reverse proxy if |
993 | | * the onward box takes a long time to respond, eg to a POST. |
994 | | * The mount can override the keepalive timeout, eg, to give |
995 | | * the right behaviour depending on reverse proxy for a particular |
996 | | * server. |
997 | | */ |
998 | 0 | lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, ds); |
999 | 0 | } |
1000 | 0 | if (h2n->sid) |
1001 | 0 | h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid); |
1002 | |
|
1003 | 0 | lwsl_debug("%s (%s): fr hdr: typ 0x%x, fla 0x%x, sid 0x%x, len 0x%x\n", |
1004 | 0 | lws_wsi_tag(wsi), lws_wsi_tag(h2n->swsi), h2n->type, |
1005 | 0 | h2n->flags, (unsigned int)h2n->sid, (unsigned int)h2n->length); |
1006 | |
|
1007 | 0 | if (h2n->we_told_goaway && h2n->sid > h2n->highest_sid) |
1008 | 0 | h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */ |
1009 | |
|
1010 | 0 | if (h2n->type >= LWS_H2_FRAME_TYPE_COUNT) { |
1011 | 0 | lwsl_info("%s: ignoring unknown frame type %d (len %d)\n", __func__, h2n->type, (unsigned int)h2n->length); |
1012 | | /* we MUST ignore frames we don't understand */ |
1013 | 0 | h2n->type = LWS_H2_FRAME_TYPE_COUNT; |
1014 | 0 | } |
1015 | | |
1016 | | /* |
1017 | | * Even if we have decided to logically ignore this frame, we must |
1018 | | * consume the correct "frame length" amount of data to retain sync |
1019 | | */ |
1020 | |
|
1021 | 0 | if (h2n->length > h2n->our_set.s[H2SET_MAX_FRAME_SIZE]) { |
1022 | | /* |
1023 | | * peer sent us something bigger than we told |
1024 | | * it we would allow |
1025 | | */ |
1026 | 0 | lwsl_info("%s: received oversize frame %d\n", __func__, |
1027 | 0 | (unsigned int)h2n->length); |
1028 | 0 | lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR, |
1029 | 0 | "Peer ignored our frame size setting"); |
1030 | 0 | return 1; |
1031 | 0 | } |
1032 | | |
1033 | 0 | if (h2n->swsi) |
1034 | 0 | lwsl_info("%s: %s, State: %s, received cmd %d\n", |
1035 | 0 | __func__, lws_wsi_tag(h2n->swsi), |
1036 | 0 | h2_state_names[h2n->swsi->h2.h2_state], h2n->type); |
1037 | 0 | else { |
1038 | | /* if it's data, either way no swsi means CLOSED state */ |
1039 | 0 | if (h2n->type == LWS_H2_FRAME_TYPE_DATA) { |
1040 | 0 | if (h2n->sid <= h2n->highest_sid_opened |
1041 | 0 | #if defined(LWS_WITH_CLIENT) |
1042 | 0 | && wsi->client_h2_alpn |
1043 | 0 | #endif |
1044 | 0 | ) { |
1045 | 0 | if (h2n->flags & LWS_H2_FLAG_END_STREAM) |
1046 | 0 | lwsl_notice("%s: stragging EOS\n", __func__); |
1047 | 0 | else { |
1048 | 0 | lwsl_wsi_notice(wsi, "ignoring straggling " |
1049 | 0 | "DATA (flags 0x%x, length %d)", |
1050 | 0 | h2n->flags, (int)h2n->length); |
1051 | | /* ie, IGNORE */ |
1052 | 0 | h2n->type = LWS_H2_FRAME_TYPE_COUNT; |
1053 | 0 | } |
1054 | 0 | } else { |
1055 | 0 | lwsl_info("%s: received %d bytes data for unknown sid %d, highest known %d\n", |
1056 | 0 | __func__, (int)h2n->length, (int)h2n->sid, (int)h2n->highest_sid_opened); |
1057 | | |
1058 | | // if (h2n->sid > h2n->highest_sid_opened) { |
1059 | 0 | lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, |
1060 | 0 | "Data for nonexistent sid"); |
1061 | 0 | return 0; |
1062 | | // } |
1063 | 0 | } |
1064 | 0 | } |
1065 | | /* if the sid is credible, treat as wsi for it closed */ |
1066 | 0 | if (h2n->sid > h2n->highest_sid_opened && |
1067 | 0 | h2n->type != LWS_H2_FRAME_TYPE_HEADERS && |
1068 | 0 | h2n->type != LWS_H2_FRAME_TYPE_PRIORITY) { |
1069 | | /* if not credible, reject it */ |
1070 | 0 | lwsl_info("%s: %s, No child for sid %d, rxcmd %d\n", |
1071 | 0 | __func__, lws_wsi_tag(h2n->swsi), (unsigned int)h2n->sid, h2n->type); |
1072 | 0 | lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, |
1073 | 0 | "Data for nonexistent sid"); |
1074 | 0 | return 0; |
1075 | 0 | } |
1076 | 0 | } |
1077 | | |
1078 | 0 | if (h2n->swsi && h2n->sid && h2n->type != LWS_H2_FRAME_TYPE_COUNT && |
1079 | 0 | !(http2_rx_validity[h2n->swsi->h2.h2_state] & (1 << h2n->type))) { |
1080 | 0 | lwsl_info("%s: %s, State: %s, ILLEGAL cmdrx %d (OK 0x%x)\n", |
1081 | 0 | __func__, lws_wsi_tag(h2n->swsi), |
1082 | 0 | h2_state_names[h2n->swsi->h2.h2_state], h2n->type, |
1083 | 0 | http2_rx_validity[h2n->swsi->h2.h2_state]); |
1084 | |
|
1085 | 0 | if (h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED || |
1086 | 0 | h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE) |
1087 | 0 | n = H2_ERR_STREAM_CLOSED; |
1088 | 0 | else |
1089 | 0 | n = H2_ERR_PROTOCOL_ERROR; |
1090 | 0 | lws_h2_goaway(wsi, (unsigned int)n, "invalid rx for state"); |
1091 | |
|
1092 | 0 | return 0; |
1093 | 0 | } |
1094 | | |
1095 | 0 | if (h2n->cont_exp && h2n->type != LWS_H2_FRAME_TYPE_COUNT && |
1096 | 0 | (h2n->cont_exp_sid != h2n->sid || |
1097 | 0 | h2n->type != LWS_H2_FRAME_TYPE_CONTINUATION)) { |
1098 | 0 | lwsl_info("%s: expected cont on sid %u (got %d on sid %u)\n", |
1099 | 0 | __func__, (unsigned int)h2n->cont_exp_sid, h2n->type, |
1100 | 0 | (unsigned int)h2n->sid); |
1101 | 0 | h2n->cont_exp = 0; |
1102 | 0 | if (h2n->cont_exp_headers) |
1103 | 0 | n = H2_ERR_COMPRESSION_ERROR; |
1104 | 0 | else |
1105 | 0 | n = H2_ERR_PROTOCOL_ERROR; |
1106 | 0 | lws_h2_goaway(wsi, (unsigned int)n, "Continuation hdrs State"); |
1107 | |
|
1108 | 0 | return 0; |
1109 | 0 | } |
1110 | | |
1111 | 0 | switch (h2n->type) { |
1112 | 0 | case LWS_H2_FRAME_TYPE_DATA: |
1113 | 0 | lwsl_info("seen incoming LWS_H2_FRAME_TYPE_DATA start\n"); |
1114 | 0 | if (!h2n->sid) { |
1115 | 0 | lwsl_info("DATA: 0 sid\n"); |
1116 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "DATA 0 sid"); |
1117 | 0 | break; |
1118 | 0 | } |
1119 | 0 | lwsl_info("Frame header DATA: sid %u, flags 0x%x, len %u\n", |
1120 | 0 | (unsigned int)h2n->sid, h2n->flags, |
1121 | 0 | (unsigned int)h2n->length); |
1122 | |
|
1123 | 0 | if (!h2n->swsi) { |
1124 | 0 | lwsl_notice("DATA: NULL swsi\n"); |
1125 | 0 | break; |
1126 | 0 | } |
1127 | | |
1128 | 0 | lwsl_info("DATA rx on state %d\n", h2n->swsi->h2.h2_state); |
1129 | |
|
1130 | 0 | if ( |
1131 | 0 | h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE || |
1132 | 0 | h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED) { |
1133 | 0 | lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, "conn closed"); |
1134 | 0 | break; |
1135 | 0 | } |
1136 | | |
1137 | 0 | if (h2n->length == 0) |
1138 | 0 | lws_h2_parse_end_of_frame(wsi); |
1139 | |
|
1140 | 0 | break; |
1141 | | |
1142 | 0 | case LWS_H2_FRAME_TYPE_PRIORITY: |
1143 | 0 | lwsl_info("LWS_H2_FRAME_TYPE_PRIORITY complete frame\n"); |
1144 | 0 | if (!h2n->sid) { |
1145 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1146 | 0 | "Priority has 0 sid"); |
1147 | 0 | break; |
1148 | 0 | } |
1149 | 0 | if (h2n->length != 5) { |
1150 | 0 | lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR, |
1151 | 0 | "Priority has length other than 5"); |
1152 | 0 | break; |
1153 | 0 | } |
1154 | 0 | break; |
1155 | 0 | case LWS_H2_FRAME_TYPE_PUSH_PROMISE: |
1156 | 0 | lwsl_info("LWS_H2_FRAME_TYPE_PUSH_PROMISE complete frame\n"); |
1157 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "Server only"); |
1158 | 0 | break; |
1159 | | |
1160 | 0 | case LWS_H2_FRAME_TYPE_GOAWAY: |
1161 | 0 | lwsl_debug("LWS_H2_FRAME_TYPE_GOAWAY received\n"); |
1162 | 0 | break; |
1163 | | |
1164 | 0 | case LWS_H2_FRAME_TYPE_RST_STREAM: |
1165 | 0 | if (!h2n->sid) |
1166 | 0 | return 1; |
1167 | 0 | if (!h2n->swsi) { |
1168 | 0 | if (h2n->sid <= h2n->highest_sid_opened) |
1169 | 0 | break; |
1170 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1171 | 0 | "crazy sid on RST_STREAM"); |
1172 | 0 | return 1; |
1173 | 0 | } |
1174 | 0 | if (h2n->length != 4) { |
1175 | 0 | lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR, |
1176 | 0 | "RST_STREAM can only be length 4"); |
1177 | 0 | break; |
1178 | 0 | } |
1179 | 0 | lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED); |
1180 | 0 | break; |
1181 | | |
1182 | 0 | case LWS_H2_FRAME_TYPE_SETTINGS: |
1183 | 0 | lwsl_info("LWS_H2_FRAME_TYPE_SETTINGS complete frame\n"); |
1184 | | /* nonzero sid on settings is illegal */ |
1185 | 0 | if (h2n->sid) { |
1186 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1187 | 0 | "Settings has nonzero sid"); |
1188 | 0 | break; |
1189 | 0 | } |
1190 | | |
1191 | 0 | if (!(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) { |
1192 | 0 | if (h2n->length % 6) { |
1193 | 0 | lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR, |
1194 | 0 | "Settings length error"); |
1195 | 0 | break; |
1196 | 0 | } |
1197 | | |
1198 | 0 | if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) |
1199 | 0 | return 0; |
1200 | | |
1201 | 0 | if (wsi->upgraded_to_http2 && |
1202 | 0 | #if defined(LWS_WITH_CLIENT) |
1203 | 0 | (!(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) || |
1204 | | #else |
1205 | | ( |
1206 | | #endif |
1207 | 0 | !wsi->h2_acked_settings)) { |
1208 | |
|
1209 | 0 | pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS); |
1210 | 0 | if (!pps) |
1211 | 0 | return 1; |
1212 | 0 | lws_pps_schedule(wsi, pps); |
1213 | 0 | wsi->h2_acked_settings = 1; |
1214 | 0 | } |
1215 | 0 | break; |
1216 | 0 | } |
1217 | | /* came to us with ACK set... not allowed to have payload */ |
1218 | | |
1219 | 0 | if (h2n->length) { |
1220 | 0 | lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR, |
1221 | 0 | "Settings with ACK not allowed payload"); |
1222 | 0 | break; |
1223 | 0 | } |
1224 | 0 | break; |
1225 | 0 | case LWS_H2_FRAME_TYPE_PING: |
1226 | 0 | if (h2n->sid) { |
1227 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1228 | 0 | "Ping has nonzero sid"); |
1229 | 0 | break; |
1230 | 0 | } |
1231 | 0 | if (h2n->length != 8) { |
1232 | 0 | lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR, |
1233 | 0 | "Ping payload can only be 8"); |
1234 | 0 | break; |
1235 | 0 | } |
1236 | 0 | break; |
1237 | 0 | case LWS_H2_FRAME_TYPE_CONTINUATION: |
1238 | 0 | lwsl_info("LWS_H2_FRAME_TYPE_CONTINUATION: sid = %u %d %d\n", |
1239 | 0 | (unsigned int)h2n->sid, (int)h2n->cont_exp, |
1240 | 0 | (int)h2n->cont_exp_sid); |
1241 | |
|
1242 | 0 | if (!h2n->cont_exp || |
1243 | 0 | h2n->cont_exp_sid != h2n->sid || |
1244 | 0 | !h2n->sid || |
1245 | 0 | !h2n->swsi) { |
1246 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1247 | 0 | "unexpected CONTINUATION"); |
1248 | 0 | break; |
1249 | 0 | } |
1250 | | |
1251 | 0 | if (h2n->swsi->h2.END_HEADERS) { |
1252 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1253 | 0 | "END_HEADERS already seen"); |
1254 | 0 | break; |
1255 | 0 | } |
1256 | | /* END_STREAM is in HEADERS, skip resetting it */ |
1257 | 0 | goto update_end_headers; |
1258 | | |
1259 | 0 | case LWS_H2_FRAME_TYPE_HEADERS: |
1260 | 0 | lwsl_info("HEADERS: frame header: sid = %u\n", |
1261 | 0 | (unsigned int)h2n->sid); |
1262 | 0 | if (!h2n->sid) { |
1263 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "sid 0"); |
1264 | 0 | return 1; |
1265 | 0 | } |
1266 | | |
1267 | 0 | if (h2n->swsi && !h2n->swsi->h2.END_STREAM && |
1268 | 0 | h2n->swsi->h2.END_HEADERS && |
1269 | 0 | !(h2n->flags & LWS_H2_FLAG_END_STREAM)) { |
1270 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1271 | 0 | "extra HEADERS together"); |
1272 | 0 | return 1; |
1273 | 0 | } |
1274 | | |
1275 | 0 | #if defined(LWS_WITH_CLIENT) |
1276 | 0 | if (wsi->client_h2_alpn) { |
1277 | 0 | if (h2n->sid) { |
1278 | 0 | h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid); |
1279 | 0 | lwsl_info("HEADERS: nwsi %s: sid %u mapped " |
1280 | 0 | "to wsi %s\n", lws_wsi_tag(wsi), |
1281 | 0 | (unsigned int)h2n->sid, |
1282 | 0 | lws_wsi_tag(h2n->swsi)); |
1283 | 0 | if (!h2n->swsi) |
1284 | 0 | break; |
1285 | 0 | } |
1286 | 0 | goto update_end_headers; |
1287 | 0 | } |
1288 | 0 | #endif |
1289 | | |
1290 | 0 | if (!h2n->swsi) { |
1291 | | /* no more children allowed by parent */ |
1292 | 0 | if (wsi->mux.child_count + 1 > |
1293 | 0 | wsi->h2.h2n->our_set.s[H2SET_MAX_CONCURRENT_STREAMS]) { |
1294 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1295 | 0 | "Another stream not allowed"); |
1296 | |
|
1297 | 0 | return 1; |
1298 | 0 | } |
1299 | | |
1300 | | /* |
1301 | | * The peer has sent us a HEADERS implying the creation |
1302 | | * of a new stream |
1303 | | */ |
1304 | | |
1305 | 0 | lws_context_lock(wsi->a.context, "h2 new str"); |
1306 | 0 | lws_vhost_lock(wsi->a.vhost); |
1307 | |
|
1308 | 0 | h2n->swsi = __lws_wsi_server_new(wsi->a.vhost, wsi, |
1309 | 0 | h2n->sid); |
1310 | |
|
1311 | 0 | lws_vhost_unlock(wsi->a.vhost); |
1312 | 0 | lws_context_unlock(wsi->a.context); |
1313 | |
|
1314 | 0 | if (!h2n->swsi) { |
1315 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1316 | 0 | "OOM"); |
1317 | |
|
1318 | 0 | return 1; |
1319 | 0 | } |
1320 | | |
1321 | 0 | if (h2n->sid >= h2n->highest_sid) |
1322 | 0 | h2n->highest_sid = h2n->sid + 2; |
1323 | |
|
1324 | 0 | h2n->swsi->h2.initialized = 1; |
1325 | |
|
1326 | 0 | if (lws_h2_update_peer_txcredit(h2n->swsi, |
1327 | 0 | h2n->swsi->mux.my_sid, 4 * 65536)) |
1328 | 0 | goto cleanup_wsi; |
1329 | 0 | } |
1330 | | |
1331 | | /* |
1332 | | * ah needs attaching to child wsi, even though |
1333 | | * we only fill it from network wsi |
1334 | | */ |
1335 | 0 | if (!h2n->swsi->http.ah) |
1336 | 0 | if (lws_header_table_attach(h2n->swsi, 0)) { |
1337 | 0 | lwsl_err("%s: Failed to get ah\n", __func__); |
1338 | 0 | return 1; |
1339 | 0 | } |
1340 | | |
1341 | | /* |
1342 | | * The first use of a new stream identifier implicitly closes |
1343 | | * all streams in the "idle" state that might have been |
1344 | | * initiated by that peer with a lower-valued stream identifier. |
1345 | | * |
1346 | | * For example, if a client sends a HEADERS frame on stream 7 |
1347 | | * without ever sending a frame on stream 5, then stream 5 |
1348 | | * transitions to the "closed" state when the first frame for |
1349 | | * stream 7 is sent or received. |
1350 | | */ |
1351 | 0 | lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) { |
1352 | 0 | if (w->mux.my_sid < h2n->sid && |
1353 | 0 | w->h2.h2_state == LWS_H2_STATE_IDLE) |
1354 | 0 | lws_close_free_wsi(w, 0, "h2 sid close"); |
1355 | 0 | assert(w->mux.sibling_list != w); |
1356 | 0 | } lws_end_foreach_ll(w, mux.sibling_list); |
1357 | |
|
1358 | 0 | h2n->cont_exp = !(h2n->flags & LWS_H2_FLAG_END_HEADERS); |
1359 | 0 | h2n->cont_exp_sid = h2n->sid; |
1360 | 0 | h2n->cont_exp_headers = 1; |
1361 | | // lws_header_table_reset(h2n->swsi, 0); |
1362 | |
|
1363 | 0 | update_end_headers: |
1364 | 0 | if (lws_check_opt(h2n->swsi->a.vhost->options, |
1365 | 0 | LWS_SERVER_OPTION_VH_H2_HALF_CLOSED_LONG_POLL)) { |
1366 | | |
1367 | | /* |
1368 | | * We don't directly timeout streams that enter the |
1369 | | * half-closed remote state, allowing immortal long |
1370 | | * poll |
1371 | | */ |
1372 | 0 | lws_mux_mark_immortal(h2n->swsi); |
1373 | 0 | lwsl_info("%s: %s: h2 stream entering long poll\n", |
1374 | 0 | __func__, lws_wsi_tag(h2n->swsi)); |
1375 | |
|
1376 | 0 | } else { |
1377 | 0 | h2n->swsi->h2.END_STREAM = |
1378 | 0 | !!(h2n->flags & LWS_H2_FLAG_END_STREAM); |
1379 | 0 | lwsl_debug("%s: hdr END_STREAM = %d\n",__func__, |
1380 | 0 | h2n->swsi->h2.END_STREAM); |
1381 | 0 | } |
1382 | | |
1383 | | /* no END_HEADERS means CONTINUATION must come */ |
1384 | 0 | h2n->swsi->h2.END_HEADERS = |
1385 | 0 | !!(h2n->flags & LWS_H2_FLAG_END_HEADERS); |
1386 | 0 | lwsl_info("%s: %s: END_HEADERS %d\n", __func__, lws_wsi_tag(h2n->swsi), |
1387 | 0 | h2n->swsi->h2.END_HEADERS); |
1388 | 0 | if (h2n->swsi->h2.END_HEADERS) |
1389 | 0 | h2n->cont_exp = 0; |
1390 | 0 | lwsl_debug("END_HEADERS %d\n", h2n->swsi->h2.END_HEADERS); |
1391 | 0 | break; |
1392 | | |
1393 | 0 | cleanup_wsi: |
1394 | |
|
1395 | 0 | return 1; |
1396 | | |
1397 | 0 | case LWS_H2_FRAME_TYPE_WINDOW_UPDATE: |
1398 | 0 | if (h2n->length != 4) { |
1399 | 0 | lws_h2_goaway(wsi, H2_ERR_FRAME_SIZE_ERROR, |
1400 | 0 | "window update frame not 4"); |
1401 | 0 | break; |
1402 | 0 | } |
1403 | 0 | lwsl_info("LWS_H2_FRAME_TYPE_WINDOW_UPDATE\n"); |
1404 | 0 | break; |
1405 | 0 | case LWS_H2_FRAME_TYPE_COUNT: |
1406 | 0 | if (h2n->length == 0) |
1407 | 0 | lws_h2_parse_end_of_frame(wsi); |
1408 | 0 | else |
1409 | 0 | lwsl_debug("%s: going on to deal with unknown frame remaining len %d\n", __func__, (unsigned int)h2n->length); |
1410 | 0 | break; |
1411 | 0 | default: |
1412 | 0 | lwsl_info("%s: ILLEGAL FRAME TYPE %d\n", __func__, h2n->type); |
1413 | 0 | h2n->type = LWS_H2_FRAME_TYPE_COUNT; /* ie, IGNORE */ |
1414 | 0 | break; |
1415 | 0 | } |
1416 | 0 | if (h2n->length == 0) |
1417 | 0 | h2n->frame_state = 0; |
1418 | |
|
1419 | 0 | return 0; |
1420 | 0 | } |
1421 | | |
1422 | | static const char * const method_names[] = { |
1423 | | "GET", "POST", |
1424 | | #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) |
1425 | | "OPTIONS", "PUT", "PATCH", "DELETE", |
1426 | | #endif |
1427 | | "CONNECT", "HEAD" |
1428 | | }; |
1429 | | static unsigned char method_index[] = { |
1430 | | WSI_TOKEN_GET_URI, |
1431 | | WSI_TOKEN_POST_URI, |
1432 | | #if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) |
1433 | | WSI_TOKEN_OPTIONS_URI, |
1434 | | WSI_TOKEN_PUT_URI, |
1435 | | WSI_TOKEN_PATCH_URI, |
1436 | | WSI_TOKEN_DELETE_URI, |
1437 | | #endif |
1438 | | WSI_TOKEN_CONNECT, |
1439 | | WSI_TOKEN_HEAD_URI, |
1440 | | }; |
1441 | | |
1442 | | /* |
1443 | | * The last byte of the whole frame has been handled. |
1444 | | * Perform actions for frame completion. |
1445 | | * |
1446 | | * This is the crunch time for parsing that may have occured on a network |
1447 | | * wsi with a pending partial send... we may call lws_http_action() to send |
1448 | | * a response, conflicting with the partial. |
1449 | | * |
1450 | | * So in that case we change the wsi state and do the lws_http_action() in the |
1451 | | * WRITABLE handler as a priority. |
1452 | | */ |
1453 | | static int |
1454 | | lws_h2_parse_end_of_frame(struct lws *wsi) |
1455 | 0 | { |
1456 | 0 | struct lws_h2_netconn *h2n = wsi->h2.h2n; |
1457 | 0 | struct lws *eff_wsi = wsi; |
1458 | 0 | const char *p; |
1459 | 0 | int n; |
1460 | |
|
1461 | 0 | h2n->frame_state = 0; |
1462 | 0 | h2n->count = 0; |
1463 | |
|
1464 | 0 | if (h2n->sid) |
1465 | 0 | h2n->swsi = lws_wsi_mux_from_id(wsi, h2n->sid); |
1466 | |
|
1467 | 0 | if (h2n->sid > h2n->highest_sid) |
1468 | 0 | h2n->highest_sid = h2n->sid; |
1469 | |
|
1470 | 0 | if (h2n->collected_priority && (h2n->dep & ~(1u << 31)) == h2n->sid) { |
1471 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, "depends on own sid"); |
1472 | 0 | return 0; |
1473 | 0 | } |
1474 | | |
1475 | 0 | switch (h2n->type) { |
1476 | | |
1477 | 0 | case LWS_H2_FRAME_TYPE_SETTINGS: |
1478 | |
|
1479 | 0 | #if defined(LWS_WITH_CLIENT) |
1480 | 0 | if (wsi->client_h2_alpn && !wsi->client_mux_migrated && |
1481 | 0 | !(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) { |
1482 | 0 | struct lws_h2_protocol_send *pps; |
1483 | | |
1484 | | /* migrate original client ask on to substream 1 */ |
1485 | 0 | #if defined(LWS_WITH_FILE_OPS) |
1486 | 0 | wsi->http.fop_fd = NULL; |
1487 | 0 | #endif |
1488 | 0 | lwsl_info("%s: migrating\n", __func__); |
1489 | 0 | wsi->client_mux_migrated = 1; |
1490 | | /* |
1491 | | * we need to treat the headers from the upgrade as the |
1492 | | * first job. So these need to get shifted to sid 1. |
1493 | | */ |
1494 | 0 | lws_context_lock(wsi->a.context, "h2 mig"); |
1495 | 0 | lws_vhost_lock(wsi->a.vhost); |
1496 | |
|
1497 | 0 | h2n->swsi = __lws_wsi_server_new(wsi->a.vhost, wsi, 1); |
1498 | |
|
1499 | 0 | lws_vhost_unlock(wsi->a.vhost); |
1500 | 0 | lws_context_unlock(wsi->a.context); |
1501 | |
|
1502 | 0 | if (!h2n->swsi) |
1503 | 0 | return 1; |
1504 | 0 | h2n->sid = 1; |
1505 | |
|
1506 | 0 | assert(lws_wsi_mux_from_id(wsi, 1) == h2n->swsi); |
1507 | | |
1508 | | // lws_role_transition(wsi, LWSIFR_CLIENT, |
1509 | | // LRS_H2_WAITING_TO_SEND_HEADERS, |
1510 | | // &role_ops_h2); |
1511 | | |
1512 | 0 | lws_role_transition(h2n->swsi, LWSIFR_CLIENT, |
1513 | 0 | LRS_H2_WAITING_TO_SEND_HEADERS, |
1514 | 0 | &role_ops_h2); |
1515 | | |
1516 | | /* pass on the initial headers to SID 1 */ |
1517 | 0 | h2n->swsi->http.ah = wsi->http.ah; |
1518 | | #if defined(LWS_WITH_SYS_FAULT_INJECTION) |
1519 | | lws_fi_import(&h2n->swsi->fic, &wsi->fic); |
1520 | | #endif |
1521 | 0 | h2n->swsi->client_mux_substream = 1; |
1522 | 0 | h2n->swsi->client_h2_alpn = 1; |
1523 | 0 | #if defined(LWS_WITH_CLIENT) |
1524 | 0 | h2n->swsi->flags = wsi->flags; |
1525 | 0 | #if defined(LWS_WITH_CONMON) |
1526 | | /* sid1 needs to represent the connection experience |
1527 | | * ... we take over responsibility for the DNS list |
1528 | | * copy as well |
1529 | | */ |
1530 | 0 | h2n->swsi->conmon = wsi->conmon; |
1531 | 0 | h2n->swsi->conmon_datum = wsi->conmon_datum; |
1532 | 0 | h2n->swsi->sa46_peer = wsi->sa46_peer; |
1533 | 0 | wsi->conmon.dns_results_copy = NULL; |
1534 | 0 | #endif |
1535 | 0 | #endif /* CLIENT */ |
1536 | |
|
1537 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) |
1538 | 0 | if (wsi->for_ss) { |
1539 | 0 | lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); |
1540 | |
|
1541 | 0 | if (!h) |
1542 | 0 | return 1; |
1543 | 0 | h2n->swsi->for_ss = 1; |
1544 | 0 | wsi->for_ss = 0; |
1545 | |
|
1546 | 0 | if (h->wsi == wsi) |
1547 | 0 | h->wsi = h2n->swsi; |
1548 | 0 | } |
1549 | 0 | #endif |
1550 | | |
1551 | 0 | h2n->swsi->a.protocol = wsi->a.protocol; |
1552 | 0 | if (h2n->swsi->user_space && |
1553 | 0 | !h2n->swsi->user_space_externally_allocated) |
1554 | 0 | lws_free(h2n->swsi->user_space); |
1555 | 0 | h2n->swsi->user_space = wsi->user_space; |
1556 | 0 | h2n->swsi->user_space_externally_allocated = |
1557 | 0 | wsi->user_space_externally_allocated; |
1558 | 0 | h2n->swsi->a.opaque_user_data = wsi->a.opaque_user_data; |
1559 | 0 | wsi->a.opaque_user_data = NULL; |
1560 | 0 | h2n->swsi->txc.manual_initial_tx_credit = |
1561 | 0 | wsi->txc.manual_initial_tx_credit; |
1562 | |
|
1563 | 0 | #if defined(LWS_WITH_TLS) |
1564 | 0 | lws_strncpy(h2n->swsi->alpn, wsi->alpn, |
1565 | 0 | sizeof(wsi->alpn)); |
1566 | 0 | #endif |
1567 | |
|
1568 | 0 | wsi->user_space = NULL; |
1569 | |
|
1570 | 0 | if (h2n->swsi->http.ah) |
1571 | 0 | h2n->swsi->http.ah->wsi = h2n->swsi; |
1572 | 0 | wsi->http.ah = NULL; |
1573 | |
|
1574 | 0 | lwsl_info("%s: MIGRATING nwsi %s -> swsi %s\n", __func__, |
1575 | 0 | lws_wsi_tag(wsi), lws_wsi_tag(h2n->swsi)); |
1576 | 0 | h2n->swsi->txc.tx_cr = (int32_t) |
1577 | 0 | h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE]; |
1578 | 0 | lwsl_info("%s: initial tx credit on %s: %d\n", |
1579 | 0 | __func__, lws_wsi_tag(h2n->swsi), |
1580 | 0 | (int)h2n->swsi->txc.tx_cr); |
1581 | 0 | h2n->swsi->h2.initialized = 1; |
1582 | | |
1583 | | /* set our initial window size */ |
1584 | 0 | if (!wsi->h2.initialized) { |
1585 | 0 | wsi->txc.tx_cr = (int32_t) |
1586 | 0 | h2n->peer_set.s[H2SET_INITIAL_WINDOW_SIZE]; |
1587 | |
|
1588 | 0 | lwsl_info("%s: initial tx credit for us to " |
1589 | 0 | "write on nwsi %s: %d\n", __func__, |
1590 | 0 | lws_wsi_tag(wsi), (int)wsi->txc.tx_cr); |
1591 | 0 | wsi->h2.initialized = 1; |
1592 | 0 | } |
1593 | |
|
1594 | 0 | lws_callback_on_writable(h2n->swsi); |
1595 | |
|
1596 | 0 | if (!wsi->h2_acked_settings || |
1597 | 0 | !(wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) |
1598 | 0 | ) { |
1599 | 0 | pps = lws_h2_new_pps(LWS_H2_PPS_ACK_SETTINGS); |
1600 | 0 | if (!pps) |
1601 | 0 | return 1; |
1602 | 0 | lws_pps_schedule(wsi, pps); |
1603 | 0 | lwsl_info("%s: SETTINGS ack PPS\n", __func__); |
1604 | 0 | wsi->h2_acked_settings = 1; |
1605 | 0 | } |
1606 | | |
1607 | | /* also attach any queued guys */ |
1608 | | |
1609 | 0 | lws_wsi_mux_apply_queue(wsi); |
1610 | 0 | } |
1611 | 0 | #endif |
1612 | 0 | break; |
1613 | | |
1614 | 0 | case LWS_H2_FRAME_TYPE_CONTINUATION: |
1615 | 0 | case LWS_H2_FRAME_TYPE_HEADERS: |
1616 | |
|
1617 | 0 | if (!h2n->swsi) |
1618 | 0 | break; |
1619 | | |
1620 | | /* service the http request itself */ |
1621 | | |
1622 | 0 | if (h2n->last_action_dyntable_resize) { |
1623 | 0 | lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR, |
1624 | 0 | "dyntable resize last in headers"); |
1625 | 0 | break; |
1626 | 0 | } |
1627 | | |
1628 | 0 | if (!h2n->swsi->h2.END_HEADERS) { |
1629 | | /* we are not finished yet */ |
1630 | 0 | lwsl_info("withholding http action for continuation\n"); |
1631 | 0 | h2n->cont_exp_sid = h2n->sid; |
1632 | 0 | h2n->cont_exp = 1; |
1633 | 0 | break; |
1634 | 0 | } |
1635 | | |
1636 | | /* confirm the hpack stream state is reasonable for finishing */ |
1637 | | |
1638 | 0 | if (h2n->hpack != HPKS_TYPE) { |
1639 | | /* hpack incomplete */ |
1640 | 0 | lwsl_info("hpack incomplete %d (type %d, len %u)\n", |
1641 | 0 | h2n->hpack, h2n->type, |
1642 | 0 | (unsigned int)h2n->hpack_len); |
1643 | 0 | lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR, |
1644 | 0 | "hpack incomplete"); |
1645 | 0 | break; |
1646 | 0 | } |
1647 | | |
1648 | | /* this is the last part of HEADERS */ |
1649 | 0 | switch (h2n->swsi->h2.h2_state) { |
1650 | 0 | case LWS_H2_STATE_IDLE: |
1651 | 0 | lws_h2_state(h2n->swsi, LWS_H2_STATE_OPEN); |
1652 | 0 | break; |
1653 | 0 | case LWS_H2_STATE_RESERVED_REMOTE: |
1654 | 0 | lws_h2_state(h2n->swsi, LWS_H2_STATE_HALF_CLOSED_LOCAL); |
1655 | 0 | break; |
1656 | 0 | } |
1657 | | |
1658 | 0 | lwsl_info("http req, %s, h2n->swsi=%s\n", lws_wsi_tag(wsi), |
1659 | 0 | lws_wsi_tag(h2n->swsi)); |
1660 | 0 | h2n->swsi->hdr_parsing_completed = 1; |
1661 | |
|
1662 | 0 | #if defined(LWS_WITH_CLIENT) |
1663 | 0 | if (h2n->swsi->client_mux_substream && |
1664 | 0 | lws_client_interpret_server_handshake(h2n->swsi)) { |
1665 | | /* |
1666 | | * This is more complicated than it looks, one exit from |
1667 | | * interpret_server_handshake() is to do a close that |
1668 | | * turns into a redirect. |
1669 | | * |
1670 | | * In that case, the wsi survives having being reset |
1671 | | * and detached from any h2 identity. We need to get |
1672 | | * our parents out from touching it any more |
1673 | | */ |
1674 | 0 | lwsl_info("%s: cli int serv hs closed, or redir\n", __func__); |
1675 | 0 | return 2; |
1676 | 0 | } |
1677 | 0 | #endif |
1678 | | |
1679 | 0 | if (lws_hdr_extant(h2n->swsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) { |
1680 | 0 | const char *simp = lws_hdr_simple_ptr(h2n->swsi, |
1681 | 0 | WSI_TOKEN_HTTP_CONTENT_LENGTH); |
1682 | |
|
1683 | 0 | if (!simp) /* coverity */ |
1684 | 0 | return 1; |
1685 | 0 | h2n->swsi->http.rx_content_length = (unsigned long long)atoll(simp); |
1686 | 0 | h2n->swsi->http.rx_content_remain = |
1687 | 0 | h2n->swsi->http.rx_content_length; |
1688 | 0 | h2n->swsi->http.content_length_given = 1; |
1689 | 0 | lwsl_info("setting rx_content_length %lld\n", |
1690 | 0 | (long long)h2n->swsi->http.rx_content_length); |
1691 | 0 | } |
1692 | | |
1693 | 0 | { |
1694 | 0 | int n = 0, len; |
1695 | 0 | char buf[256]; |
1696 | 0 | const unsigned char *c; |
1697 | |
|
1698 | 0 | do { |
1699 | 0 | c = lws_token_to_string((enum lws_token_indexes)n); |
1700 | 0 | if (!c) { |
1701 | 0 | n++; |
1702 | 0 | continue; |
1703 | 0 | } |
1704 | | |
1705 | 0 | len = lws_hdr_total_length(h2n->swsi, (enum lws_token_indexes)n); |
1706 | 0 | if (!len || len > (int)sizeof(buf) - 1) { |
1707 | 0 | n++; |
1708 | 0 | continue; |
1709 | 0 | } |
1710 | | |
1711 | 0 | if (lws_hdr_copy(h2n->swsi, buf, sizeof buf, |
1712 | 0 | (enum lws_token_indexes)n) < 0) { |
1713 | 0 | lwsl_info(" %s !oversize!\n", |
1714 | 0 | (char *)c); |
1715 | 0 | } else { |
1716 | 0 | buf[sizeof(buf) - 1] = '\0'; |
1717 | |
|
1718 | 0 | lwsl_info(" %s = %s\n", |
1719 | 0 | (char *)c, buf); |
1720 | 0 | } |
1721 | 0 | n++; |
1722 | 0 | } while (c); |
1723 | 0 | } |
1724 | | |
1725 | 0 | if (h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_REMOTE || |
1726 | 0 | h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED) { |
1727 | 0 | lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, |
1728 | 0 | "Banning service on CLOSED_REMOTE"); |
1729 | 0 | break; |
1730 | 0 | } |
1731 | | |
1732 | 0 | switch (h2n->swsi->h2.h2_state) { |
1733 | 0 | case LWS_H2_STATE_IDLE: |
1734 | 0 | lws_h2_state(h2n->swsi, LWS_H2_STATE_OPEN); |
1735 | 0 | break; |
1736 | 0 | case LWS_H2_STATE_OPEN: |
1737 | 0 | if (h2n->swsi->h2.END_STREAM) |
1738 | 0 | lws_h2_state(h2n->swsi, |
1739 | 0 | LWS_H2_STATE_HALF_CLOSED_REMOTE); |
1740 | 0 | break; |
1741 | 0 | case LWS_H2_STATE_HALF_CLOSED_LOCAL: |
1742 | 0 | if (h2n->swsi->h2.END_STREAM) |
1743 | | /* |
1744 | | * action the END_STREAM |
1745 | | */ |
1746 | 0 | lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED); |
1747 | 0 | break; |
1748 | 0 | } |
1749 | | |
1750 | 0 | #if defined(LWS_WITH_CLIENT) |
1751 | | |
1752 | | /* |
1753 | | * If we already had the END_STREAM along with the END_HEADERS, |
1754 | | * we have already transitioned to STATE_CLOSED and we are not |
1755 | | * going to be doing anything further on this stream. |
1756 | | * |
1757 | | * In that case handle the transaction completion and |
1758 | | * finalize the stream for the peer |
1759 | | */ |
1760 | | |
1761 | 0 | if (h2n->swsi->h2.h2_state == LWS_H2_STATE_CLOSED && |
1762 | 0 | h2n->swsi->client_mux_substream) { |
1763 | |
|
1764 | 0 | lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR, |
1765 | 0 | "client done"); |
1766 | |
|
1767 | 0 | if (lws_http_transaction_completed_client(h2n->swsi)) |
1768 | 0 | lwsl_debug("tx completed returned close\n"); |
1769 | 0 | break; |
1770 | 0 | } |
1771 | | |
1772 | 0 | if (h2n->swsi->client_mux_substream) { |
1773 | 0 | lwsl_info("%s: %s: headers: client path (h2 state %s)\n", |
1774 | 0 | __func__, lws_wsi_tag(wsi), |
1775 | 0 | h2_state_names[h2n->swsi->h2.h2_state]); |
1776 | 0 | break; |
1777 | 0 | } |
1778 | 0 | #endif |
1779 | | |
1780 | 0 | if (!lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_PATH) || |
1781 | 0 | !lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_METHOD) || |
1782 | 0 | !lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_SCHEME) || |
1783 | 0 | lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_COLON_STATUS) || |
1784 | 0 | lws_hdr_extant(h2n->swsi, WSI_TOKEN_CONNECTION)) { |
1785 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1786 | 0 | "Pseudoheader checks"); |
1787 | 0 | break; |
1788 | 0 | } |
1789 | | |
1790 | 0 | if (lws_hdr_extant(h2n->swsi, WSI_TOKEN_TE)) { |
1791 | 0 | n = lws_hdr_total_length(h2n->swsi, WSI_TOKEN_TE); |
1792 | |
|
1793 | 0 | if (n != 8 || |
1794 | 0 | !lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_TE) || |
1795 | 0 | strncmp(lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_TE), |
1796 | 0 | "trailers", (unsigned int)n)) { |
1797 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1798 | 0 | "Illegal transfer-encoding"); |
1799 | 0 | break; |
1800 | 0 | } |
1801 | 0 | } |
1802 | | |
1803 | | #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) |
1804 | | lws_http_compression_validate(h2n->swsi); |
1805 | | #endif |
1806 | | |
1807 | 0 | p = lws_hdr_simple_ptr(h2n->swsi, WSI_TOKEN_HTTP_COLON_METHOD); |
1808 | | /* |
1809 | | * duplicate :path into the individual method uri header |
1810 | | * index, so that it looks the same as h1 in the ah |
1811 | | */ |
1812 | 0 | for (n = 0; n < (int)LWS_ARRAY_SIZE(method_names); n++) |
1813 | 0 | if (p && !strcasecmp(p, method_names[n])) { |
1814 | 0 | h2n->swsi->http.ah->frag_index[method_index[n]] = |
1815 | 0 | h2n->swsi->http.ah->frag_index[ |
1816 | 0 | WSI_TOKEN_HTTP_COLON_PATH]; |
1817 | 0 | break; |
1818 | 0 | } |
1819 | |
|
1820 | 0 | { |
1821 | 0 | lwsl_debug("%s: setting DEF_ACT from 0x%x\n", __func__, |
1822 | 0 | (unsigned int)h2n->swsi->wsistate); |
1823 | 0 | lwsi_set_state(h2n->swsi, LRS_DEFERRING_ACTION); |
1824 | 0 | lws_callback_on_writable(h2n->swsi); |
1825 | 0 | } |
1826 | 0 | break; |
1827 | | |
1828 | 0 | case LWS_H2_FRAME_TYPE_DATA: |
1829 | 0 | lwsl_info("%s: DATA flags 0x%x\n", __func__, h2n->flags); |
1830 | 0 | if (!h2n->swsi) |
1831 | 0 | break; |
1832 | | |
1833 | 0 | if (lws_hdr_total_length(h2n->swsi, |
1834 | 0 | WSI_TOKEN_HTTP_CONTENT_LENGTH) && |
1835 | 0 | h2n->swsi->h2.END_STREAM && |
1836 | 0 | h2n->swsi->http.rx_content_length && |
1837 | 0 | h2n->swsi->http.rx_content_remain) { |
1838 | 0 | lws_h2_rst_stream(h2n->swsi, H2_ERR_PROTOCOL_ERROR, |
1839 | 0 | "Not enough rx content"); |
1840 | 0 | break; |
1841 | 0 | } |
1842 | | |
1843 | 0 | if (h2n->swsi->h2.END_STREAM && |
1844 | 0 | h2n->swsi->h2.h2_state == LWS_H2_STATE_OPEN) |
1845 | 0 | lws_h2_state(h2n->swsi, |
1846 | 0 | LWS_H2_STATE_HALF_CLOSED_REMOTE); |
1847 | |
|
1848 | 0 | if (h2n->swsi->h2.END_STREAM && |
1849 | 0 | h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_LOCAL) |
1850 | 0 | lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED); |
1851 | |
|
1852 | 0 | #if defined(LWS_WITH_CLIENT) |
1853 | | /* |
1854 | | * client... remote END_STREAM implies we weren't going to |
1855 | | * send anything else anyway. |
1856 | | */ |
1857 | |
|
1858 | 0 | if (h2n->swsi->client_mux_substream && |
1859 | 0 | (h2n->flags & LWS_H2_FLAG_END_STREAM)) { |
1860 | 0 | lwsl_info("%s: %s: DATA: end stream\n", |
1861 | 0 | __func__, lws_wsi_tag(h2n->swsi)); |
1862 | |
|
1863 | 0 | if (h2n->swsi->h2.h2_state == LWS_H2_STATE_OPEN) { |
1864 | 0 | lws_h2_state(h2n->swsi, |
1865 | 0 | LWS_H2_STATE_HALF_CLOSED_REMOTE); |
1866 | | // lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR, |
1867 | | // "client done"); |
1868 | | |
1869 | | // if (lws_http_transaction_completed_client(h2n->swsi)) |
1870 | | // lwsl_debug("tx completed returned close\n"); |
1871 | 0 | } |
1872 | | |
1873 | | //if (h2n->swsi->h2.h2_state == LWS_H2_STATE_HALF_CLOSED_LOCAL) |
1874 | 0 | { |
1875 | 0 | lws_h2_state(h2n->swsi, LWS_H2_STATE_CLOSED); |
1876 | |
|
1877 | 0 | lws_h2_rst_stream(h2n->swsi, H2_ERR_NO_ERROR, |
1878 | 0 | "client done"); |
1879 | |
|
1880 | 0 | if (lws_http_transaction_completed_client(h2n->swsi)) |
1881 | 0 | lwsl_debug("tx completed returned close\n"); |
1882 | 0 | } |
1883 | 0 | } |
1884 | 0 | #endif |
1885 | 0 | break; |
1886 | | |
1887 | 0 | case LWS_H2_FRAME_TYPE_PING: |
1888 | 0 | if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK) |
1889 | 0 | lws_validity_confirmed(wsi); |
1890 | 0 | else { |
1891 | | /* they're sending us a ping request */ |
1892 | 0 | struct lws_h2_protocol_send *pps = |
1893 | 0 | lws_h2_new_pps(LWS_H2_PPS_PONG); |
1894 | 0 | if (!pps) |
1895 | 0 | return 1; |
1896 | | |
1897 | 0 | lwsl_info("rx ping, preparing pong\n"); |
1898 | |
|
1899 | 0 | memcpy(pps->u.ping.ping_payload, h2n->ping_payload, 8); |
1900 | 0 | lws_pps_schedule(wsi, pps); |
1901 | 0 | } |
1902 | | |
1903 | 0 | break; |
1904 | | |
1905 | 0 | case LWS_H2_FRAME_TYPE_WINDOW_UPDATE: |
1906 | | /* |
1907 | | * We only have an unsigned 31-bit (positive) increment possible |
1908 | | */ |
1909 | 0 | h2n->hpack_e_dep &= ~(1u << 31); |
1910 | 0 | lwsl_info("WINDOW_UPDATE: sid %u %u (0x%x)\n", |
1911 | 0 | (unsigned int)h2n->sid, |
1912 | 0 | (unsigned int)h2n->hpack_e_dep, |
1913 | 0 | (unsigned int)h2n->hpack_e_dep); |
1914 | |
|
1915 | 0 | if (h2n->sid) |
1916 | 0 | eff_wsi = h2n->swsi; |
1917 | |
|
1918 | 0 | if (!eff_wsi) { |
1919 | 0 | if (h2n->sid > h2n->highest_sid_opened) |
1920 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1921 | 0 | "alien sid"); |
1922 | 0 | break; /* ignore */ |
1923 | 0 | } |
1924 | | |
1925 | 0 | if (eff_wsi->a.vhost->options & |
1926 | 0 | LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW && |
1927 | 0 | (uint64_t)eff_wsi->txc.tx_cr + (uint64_t)h2n->hpack_e_dep > |
1928 | 0 | (uint64_t)0x7fffffff) |
1929 | 0 | h2n->hpack_e_dep = (uint32_t)(0x7fffffff - eff_wsi->txc.tx_cr); |
1930 | |
|
1931 | 0 | if ((uint64_t)eff_wsi->txc.tx_cr + (uint64_t)h2n->hpack_e_dep > |
1932 | 0 | (uint64_t)0x7fffffff) { |
1933 | 0 | lwsl_warn("%s: WINDOW_UPDATE 0x%llx + 0x%llx = 0x%llx, too high\n", |
1934 | 0 | __func__, (unsigned long long)eff_wsi->txc.tx_cr, |
1935 | 0 | (unsigned long long)h2n->hpack_e_dep, |
1936 | 0 | (unsigned long long)eff_wsi->txc.tx_cr + (unsigned long long)h2n->hpack_e_dep); |
1937 | 0 | if (h2n->sid) |
1938 | 0 | lws_h2_rst_stream(h2n->swsi, |
1939 | 0 | H2_ERR_FLOW_CONTROL_ERROR, |
1940 | 0 | "Flow control exceeded max"); |
1941 | 0 | else |
1942 | 0 | lws_h2_goaway(wsi, H2_ERR_FLOW_CONTROL_ERROR, |
1943 | 0 | "Flow control exceeded max"); |
1944 | 0 | break; |
1945 | 0 | } |
1946 | | |
1947 | 0 | if (!h2n->hpack_e_dep) { |
1948 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
1949 | 0 | "Zero length window update"); |
1950 | 0 | break; |
1951 | 0 | } |
1952 | 0 | n = eff_wsi->txc.tx_cr; |
1953 | 0 | eff_wsi->txc.tx_cr += (int32_t)h2n->hpack_e_dep; |
1954 | |
|
1955 | 0 | lws_wsi_txc_report_manual_txcr_in(eff_wsi, |
1956 | 0 | (int32_t)h2n->hpack_e_dep); |
1957 | |
|
1958 | 0 | lws_wsi_txc_describe(&eff_wsi->txc, "WINDOW_UPDATE in", |
1959 | 0 | eff_wsi->mux.my_sid); |
1960 | |
|
1961 | 0 | if (n <= 0 && eff_wsi->txc.tx_cr <= 0) |
1962 | | /* it helps, but won't change sendability for anyone */ |
1963 | 0 | break; |
1964 | | |
1965 | | /* |
1966 | | * It may have changed sendability (depends on SID 0 tx credit |
1967 | | * too)... for us and any children waiting on us... reassess |
1968 | | * blockage for all children first |
1969 | | */ |
1970 | 0 | lws_start_foreach_ll(struct lws *, w, wsi->mux.child_list) { |
1971 | 0 | lws_callback_on_writable(w); |
1972 | 0 | } lws_end_foreach_ll(w, mux.sibling_list); |
1973 | |
|
1974 | 0 | if (eff_wsi->txc.skint && |
1975 | 0 | !lws_wsi_txc_check_skint(&eff_wsi->txc, |
1976 | 0 | lws_h2_tx_cr_get(eff_wsi))) |
1977 | | /* |
1978 | | * This one became un-skint, schedule a writeable |
1979 | | * callback |
1980 | | */ |
1981 | 0 | lws_callback_on_writable(eff_wsi); |
1982 | |
|
1983 | 0 | break; |
1984 | | |
1985 | 0 | case LWS_H2_FRAME_TYPE_GOAWAY: |
1986 | 0 | lwsl_notice("GOAWAY: last sid %u, error 0x%08X, string '%s'\n", |
1987 | 0 | (unsigned int)h2n->goaway_last_sid, |
1988 | 0 | (unsigned int)h2n->goaway_err, h2n->goaway_str); |
1989 | |
|
1990 | 0 | return 1; |
1991 | | |
1992 | 0 | case LWS_H2_FRAME_TYPE_RST_STREAM: |
1993 | 0 | lwsl_info("LWS_H2_FRAME_TYPE_RST_STREAM: sid %u: reason 0x%x\n", |
1994 | 0 | (unsigned int)h2n->sid, |
1995 | 0 | (unsigned int)h2n->hpack_e_dep); |
1996 | 0 | break; |
1997 | | |
1998 | 0 | case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */ |
1999 | 0 | break; |
2000 | 0 | } |
2001 | | |
2002 | 0 | return 0; |
2003 | 0 | } |
2004 | | |
2005 | | /* |
2006 | | * This may want to send something on the network wsi, which may be in the |
2007 | | * middle of a partial send. PPS sends are OK because they are queued to |
2008 | | * go through the WRITABLE handler already. |
2009 | | * |
2010 | | * The read parser for the network wsi has no choice but to parse its stream |
2011 | | * anyway, because otherwise it will not be able to get tx credit window |
2012 | | * messages. |
2013 | | * |
2014 | | * Therefore if we will send non-PPS, ie, lws_http_action() for a stream |
2015 | | * wsi, we must change its state and handle it as a priority in the |
2016 | | * POLLOUT handler instead of writing it here. |
2017 | | * |
2018 | | * About closing... for the main network wsi, it should return nonzero to |
2019 | | * close it all. If it needs to close an swsi, it can do it here. |
2020 | | */ |
2021 | | int |
2022 | | lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t _inlen, |
2023 | | lws_filepos_t *inused) |
2024 | 0 | { |
2025 | 0 | struct lws_h2_netconn *h2n = wsi->h2.h2n; |
2026 | 0 | struct lws_h2_protocol_send *pps; |
2027 | 0 | unsigned char c, *oldin = in, *iend = in + (size_t)_inlen; |
2028 | 0 | int n, m; |
2029 | |
|
2030 | 0 | if (!h2n) |
2031 | 0 | goto fail; |
2032 | | |
2033 | 0 | while (in < iend) { |
2034 | |
|
2035 | 0 | c = *in++; |
2036 | |
|
2037 | 0 | switch (lwsi_state(wsi)) { |
2038 | 0 | case LRS_H2_AWAIT_PREFACE: |
2039 | 0 | if (preface[h2n->count++] != c) |
2040 | 0 | goto fail; |
2041 | | |
2042 | 0 | if (preface[h2n->count]) |
2043 | 0 | break; |
2044 | | |
2045 | 0 | lwsl_info("http2: %s: established\n", lws_wsi_tag(wsi)); |
2046 | 0 | lwsi_set_state(wsi, LRS_H2_AWAIT_SETTINGS); |
2047 | 0 | lws_validity_confirmed(wsi); |
2048 | 0 | h2n->count = 0; |
2049 | 0 | wsi->txc.tx_cr = 65535; |
2050 | | |
2051 | | /* |
2052 | | * we must send a settings frame -- empty one is OK... |
2053 | | * that must be the first thing sent by server |
2054 | | * and the peer must send a SETTINGS with ACK flag... |
2055 | | */ |
2056 | 0 | pps = lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS); |
2057 | 0 | if (!pps) |
2058 | 0 | goto fail; |
2059 | 0 | lws_pps_schedule(wsi, pps); |
2060 | 0 | break; |
2061 | | |
2062 | 0 | case LRS_H2_WAITING_TO_SEND_HEADERS: |
2063 | 0 | case LRS_ESTABLISHED: |
2064 | 0 | case LRS_H2_AWAIT_SETTINGS: |
2065 | |
|
2066 | 0 | if (h2n->frame_state != LWS_H2_FRAME_HEADER_LENGTH) |
2067 | 0 | goto try_frame_start; |
2068 | | |
2069 | | /* |
2070 | | * post-header, preamble / payload / padding part |
2071 | | */ |
2072 | 0 | h2n->count++; |
2073 | |
|
2074 | 0 | if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */ |
2075 | | //lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length); |
2076 | 0 | goto frame_end; |
2077 | 0 | } |
2078 | | |
2079 | | |
2080 | 0 | if (h2n->flags & LWS_H2_FLAG_PADDED && |
2081 | 0 | !h2n->pad_length) { |
2082 | | /* |
2083 | | * Get the padding count... actual padding is |
2084 | | * at the end of the frame. |
2085 | | */ |
2086 | 0 | h2n->padding = c; |
2087 | 0 | h2n->pad_length = 1; |
2088 | 0 | h2n->preamble++; |
2089 | |
|
2090 | 0 | if (h2n->padding > h2n->length - 1) |
2091 | 0 | lws_h2_goaway(wsi, |
2092 | 0 | H2_ERR_PROTOCOL_ERROR, |
2093 | 0 | "execssive padding"); |
2094 | 0 | break; /* we consumed this */ |
2095 | 0 | } |
2096 | | |
2097 | 0 | if (h2n->flags & LWS_H2_FLAG_PRIORITY && |
2098 | 0 | !h2n->collected_priority) { |
2099 | | /* going to be 5 preamble bytes */ |
2100 | |
|
2101 | 0 | lwsl_debug("PRIORITY FLAG: 0x%x\n", c); |
2102 | |
|
2103 | 0 | if (h2n->preamble++ - h2n->pad_length < 4) { |
2104 | 0 | h2n->dep = ((h2n->dep) << 8) | c; |
2105 | 0 | break; /* we consumed this */ |
2106 | 0 | } |
2107 | 0 | h2n->weight_temp = c; |
2108 | 0 | h2n->collected_priority = 1; |
2109 | 0 | lwsl_debug("PRI FL: dep 0x%x, weight 0x%02X\n", |
2110 | 0 | (unsigned int)h2n->dep, |
2111 | 0 | h2n->weight_temp); |
2112 | 0 | break; /* we consumed this */ |
2113 | 0 | } |
2114 | 0 | if (h2n->padding && h2n->count > |
2115 | 0 | (h2n->length - h2n->padding)) { |
2116 | 0 | if (c) { |
2117 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
2118 | 0 | "nonzero padding"); |
2119 | 0 | break; |
2120 | 0 | } |
2121 | 0 | goto frame_end; |
2122 | 0 | } |
2123 | | |
2124 | | /* applies to wsi->h2.swsi which may be wsi */ |
2125 | 0 | switch(h2n->type) { |
2126 | | |
2127 | 0 | case LWS_H2_FRAME_TYPE_SETTINGS: |
2128 | 0 | n = (int)(h2n->count - 1u - h2n->preamble) % |
2129 | 0 | LWS_H2_SETTINGS_LEN; |
2130 | 0 | h2n->one_setting[n] = c; |
2131 | 0 | if (n != LWS_H2_SETTINGS_LEN - 1) |
2132 | 0 | break; |
2133 | 0 | lws_h2_settings(wsi, &h2n->peer_set, |
2134 | 0 | h2n->one_setting, |
2135 | 0 | LWS_H2_SETTINGS_LEN); |
2136 | 0 | break; |
2137 | | |
2138 | 0 | case LWS_H2_FRAME_TYPE_CONTINUATION: |
2139 | 0 | case LWS_H2_FRAME_TYPE_HEADERS: |
2140 | 0 | if (!h2n->swsi) |
2141 | 0 | break; |
2142 | 0 | if (lws_hpack_interpret(h2n->swsi, c)) { |
2143 | 0 | lwsl_info("%s: hpack failed\n", |
2144 | 0 | __func__); |
2145 | 0 | goto fail; |
2146 | 0 | } |
2147 | 0 | break; |
2148 | | |
2149 | 0 | case LWS_H2_FRAME_TYPE_GOAWAY: |
2150 | 0 | switch (h2n->inside++) { |
2151 | 0 | case 0: |
2152 | 0 | case 1: |
2153 | 0 | case 2: |
2154 | 0 | case 3: |
2155 | 0 | h2n->goaway_last_sid <<= 8; |
2156 | 0 | h2n->goaway_last_sid |= c; |
2157 | 0 | h2n->goaway_str[0] = '\0'; |
2158 | 0 | break; |
2159 | | |
2160 | 0 | case 4: |
2161 | 0 | case 5: |
2162 | 0 | case 6: |
2163 | 0 | case 7: |
2164 | 0 | h2n->goaway_err <<= 8; |
2165 | 0 | h2n->goaway_err |= c; |
2166 | 0 | break; |
2167 | | |
2168 | 0 | default: |
2169 | 0 | if (h2n->inside - 9 < |
2170 | 0 | sizeof(h2n->goaway_str) - 1) |
2171 | 0 | h2n->goaway_str[ |
2172 | 0 | h2n->inside - 9] = (char)c; |
2173 | 0 | h2n->goaway_str[ |
2174 | 0 | sizeof(h2n->goaway_str) - 1] = '\0'; |
2175 | 0 | break; |
2176 | 0 | } |
2177 | 0 | break; |
2178 | | |
2179 | 0 | case LWS_H2_FRAME_TYPE_DATA: |
2180 | | |
2181 | | // lwsl_info("%s: LWS_H2_FRAME_TYPE_DATA: fl 0x%x\n", |
2182 | | // __func__, h2n->flags); |
2183 | | |
2184 | | /* |
2185 | | * let the network wsi live a bit longer if |
2186 | | * subs are active... our frame may take a long |
2187 | | * time to chew through |
2188 | | */ |
2189 | 0 | if (!wsi->immortal_substream_count) |
2190 | 0 | lws_set_timeout(wsi, |
2191 | 0 | PENDING_TIMEOUT_HTTP_KEEPALIVE_IDLE, |
2192 | 0 | lws_wsi_keepalive_timeout_eff(wsi)); |
2193 | |
|
2194 | 0 | if (!h2n->swsi) |
2195 | 0 | break; |
2196 | | |
2197 | 0 | if (lws_buflist_next_segment_len( |
2198 | 0 | &h2n->swsi->buflist, NULL)) |
2199 | 0 | lwsl_info("%s: substream has pending\n", |
2200 | 0 | __func__); |
2201 | |
|
2202 | 0 | if (lwsi_role_http(h2n->swsi) && |
2203 | 0 | lwsi_state(h2n->swsi) == LRS_ESTABLISHED) { |
2204 | 0 | lwsi_set_state(h2n->swsi, LRS_BODY); |
2205 | 0 | lwsl_info("%s: %s to LRS_BODY\n", |
2206 | 0 | __func__, lws_wsi_tag(h2n->swsi)); |
2207 | 0 | } |
2208 | | |
2209 | | /* |
2210 | | * in + length may cover multiple frames, we |
2211 | | * can only consider the length of the DATA |
2212 | | * in front of us |
2213 | | */ |
2214 | |
|
2215 | 0 | if (lws_hdr_total_length(h2n->swsi, |
2216 | 0 | WSI_TOKEN_HTTP_CONTENT_LENGTH) && |
2217 | 0 | h2n->swsi->http.rx_content_length && |
2218 | 0 | h2n->swsi->http.rx_content_remain < |
2219 | 0 | h2n->length - h2n->inside && /* last */ |
2220 | 0 | h2n->inside < h2n->length) { |
2221 | |
|
2222 | 0 | lwsl_warn("%s: rx.cl: %lu, rx.content_remain: %lu, buf left: %lu, " |
2223 | 0 | "h2->inside: %lu, h2->length: %lu\n", __func__, |
2224 | 0 | (unsigned long)h2n->swsi->http.rx_content_length, |
2225 | 0 | (unsigned long)h2n->swsi->http.rx_content_remain, |
2226 | 0 | (unsigned long)(lws_ptr_diff_size_t(iend, in) + 1), |
2227 | 0 | (unsigned long)h2n->inside, (unsigned long)h2n->length); |
2228 | | |
2229 | | /* unread data in frame */ |
2230 | 0 | lws_h2_goaway(wsi, |
2231 | 0 | H2_ERR_PROTOCOL_ERROR, |
2232 | 0 | "More rx than content_length told"); |
2233 | 0 | break; |
2234 | 0 | } |
2235 | | |
2236 | | /* |
2237 | | * We operate on a frame. The RX we have at |
2238 | | * hand may exceed the current frame. |
2239 | | */ |
2240 | | |
2241 | 0 | n = (int)lws_ptr_diff_size_t(iend, in) + 1; |
2242 | 0 | if (n > (int)(h2n->length - h2n->count + 1)) { |
2243 | 0 | if (h2n->count > h2n->length) |
2244 | 0 | goto close_swsi_and_return; |
2245 | 0 | n = (int)(h2n->length - h2n->count) + 1; |
2246 | 0 | lwsl_debug("---- restricting len to %d " |
2247 | 0 | "\n", n); |
2248 | 0 | } |
2249 | 0 | #if defined(LWS_WITH_CLIENT) |
2250 | 0 | if (h2n->swsi->client_mux_substream) { |
2251 | 0 | if (!h2n->swsi->a.protocol) { |
2252 | 0 | lwsl_err("%s: %p doesn't have protocol\n", |
2253 | 0 | __func__, lws_wsi_tag(h2n->swsi)); |
2254 | 0 | m = 1; |
2255 | 0 | } else { |
2256 | 0 | h2n->swsi->txc.peer_tx_cr_est -= n; |
2257 | 0 | wsi->txc.peer_tx_cr_est -= n; |
2258 | 0 | lws_wsi_txc_describe(&h2n->swsi->txc, |
2259 | 0 | __func__, |
2260 | 0 | h2n->swsi->mux.my_sid); |
2261 | 0 | m = user_callback_handle_rxflow( |
2262 | 0 | h2n->swsi->a.protocol->callback, |
2263 | 0 | h2n->swsi, |
2264 | 0 | LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ, |
2265 | 0 | h2n->swsi->user_space, |
2266 | 0 | in - 1, (unsigned int)n); |
2267 | 0 | } |
2268 | |
|
2269 | 0 | in += n - 1; |
2270 | 0 | h2n->inside += (unsigned int)n; |
2271 | 0 | h2n->count += (unsigned int)n - 1; |
2272 | |
|
2273 | 0 | if (m) { |
2274 | 0 | lwsl_info("RECEIVE_CLIENT_HTTP " |
2275 | 0 | "closed it\n"); |
2276 | 0 | goto close_swsi_and_return; |
2277 | 0 | } |
2278 | | |
2279 | 0 | goto do_windows; |
2280 | 0 | } |
2281 | 0 | #endif |
2282 | 0 | if (lwsi_state(h2n->swsi) == LRS_DEFERRING_ACTION) { |
2283 | 0 | m = lws_buflist_append_segment( |
2284 | 0 | &h2n->swsi->buflist, in - 1, (unsigned int)n); |
2285 | 0 | if (m < 0) |
2286 | 0 | return -1; |
2287 | | |
2288 | | /* |
2289 | | * Since we're in an open-ended |
2290 | | * DEFERRING_ACTION, don't add this swsi |
2291 | | * to the pt list of wsi holding buflist |
2292 | | * content yet, we are not in a position |
2293 | | * to consume it until we get out of |
2294 | | * DEFERRING_ACTION. |
2295 | | */ |
2296 | | |
2297 | 0 | in += n - 1; |
2298 | 0 | h2n->inside += (unsigned int)n; |
2299 | 0 | h2n->count += (unsigned int)n - 1; |
2300 | |
|
2301 | 0 | lwsl_debug("%s: deferred %d\n", __func__, n); |
2302 | 0 | goto do_windows; |
2303 | 0 | } |
2304 | | |
2305 | 0 | h2n->swsi->outer_will_close = 1; |
2306 | | /* |
2307 | | * choose the length for this go so that we end at |
2308 | | * the frame boundary, in the case there is already |
2309 | | * more waiting leave it for next time around |
2310 | | */ |
2311 | |
|
2312 | 0 | n = lws_read_h1(h2n->swsi, in - 1, (unsigned int)n); |
2313 | | // lwsl_notice("%s: lws_read_h1 %d\n", __func__, n); |
2314 | 0 | h2n->swsi->outer_will_close = 0; |
2315 | | /* |
2316 | | * can return 0 in POST body with |
2317 | | * content len exhausted somehow. |
2318 | | */ |
2319 | 0 | if (n < 0 || |
2320 | 0 | (!n && h2n->swsi->http.content_length_given && !lws_buflist_next_segment_len( |
2321 | 0 | &wsi->buflist, NULL))) { |
2322 | 0 | lwsl_info("%s: lws_read_h1 told %d %u / %u\n", |
2323 | 0 | __func__, n, |
2324 | 0 | (unsigned int)h2n->count, |
2325 | 0 | (unsigned int)h2n->length); |
2326 | 0 | in += h2n->length - h2n->count; |
2327 | 0 | h2n->inside = h2n->length; |
2328 | 0 | h2n->count = h2n->length - 1; |
2329 | | |
2330 | | //if (n < 0) |
2331 | | // goto already_closed_swsi; |
2332 | 0 | goto close_swsi_and_return; |
2333 | 0 | } |
2334 | | |
2335 | 0 | lwsl_info("%s: lws_read_h1 telling %d %u / %u\n", |
2336 | 0 | __func__, n, |
2337 | 0 | (unsigned int)h2n->count, |
2338 | 0 | (unsigned int)h2n->length); |
2339 | |
|
2340 | 0 | if (n) { |
2341 | 0 | in += (unsigned int)n - 1; |
2342 | 0 | h2n->inside += (unsigned int)n; |
2343 | 0 | h2n->count += (unsigned int)n - 1; |
2344 | |
|
2345 | 0 | h2n->swsi->txc.peer_tx_cr_est -= n; |
2346 | 0 | wsi->txc.peer_tx_cr_est -= n; |
2347 | 0 | } |
2348 | |
|
2349 | 0 | do_windows: |
2350 | |
|
2351 | 0 | #if defined(LWS_WITH_CLIENT) |
2352 | 0 | if (!(h2n->swsi->flags & LCCSCF_H2_MANUAL_RXFLOW)) |
2353 | 0 | #endif |
2354 | 0 | { |
2355 | | /* |
2356 | | * The default behaviour is we just keep |
2357 | | * cranking the other side's tx credit |
2358 | | * back up, for simple bulk transfer as |
2359 | | * fast as we can take it |
2360 | | */ |
2361 | |
|
2362 | 0 | m = n + 65536; |
2363 | | |
2364 | | /* update both the stream and nwsi */ |
2365 | |
|
2366 | 0 | lws_h2_update_peer_txcredit_thresh(h2n->swsi, |
2367 | 0 | h2n->sid, m, m); |
2368 | 0 | } |
2369 | 0 | #if defined(LWS_WITH_CLIENT) |
2370 | 0 | else { |
2371 | | /* |
2372 | | * If he's handling it himself, only |
2373 | | * repair the nwsi credit but allow the |
2374 | | * stream credit to run down until the |
2375 | | * user code deals with it |
2376 | | */ |
2377 | 0 | lws_h2_update_peer_txcredit(wsi, (unsigned int)0, n); |
2378 | 0 | h2n->swsi->txc.manual = 1; |
2379 | 0 | } |
2380 | 0 | #endif |
2381 | 0 | break; |
2382 | | |
2383 | 0 | case LWS_H2_FRAME_TYPE_PRIORITY: |
2384 | 0 | if (h2n->count <= 4) { |
2385 | 0 | h2n->dep <<= 8; |
2386 | 0 | h2n->dep |= c; |
2387 | 0 | break; |
2388 | 0 | } |
2389 | 0 | h2n->weight_temp = c; |
2390 | 0 | lwsl_info("PRIORITY: dep 0x%x, weight 0x%02X\n", |
2391 | 0 | (unsigned int)h2n->dep, h2n->weight_temp); |
2392 | |
|
2393 | 0 | if ((h2n->dep & ~(1u << 31)) == h2n->sid) { |
2394 | 0 | lws_h2_goaway(wsi, H2_ERR_PROTOCOL_ERROR, |
2395 | 0 | "cant depend on own sid"); |
2396 | 0 | break; |
2397 | 0 | } |
2398 | 0 | break; |
2399 | | |
2400 | 0 | case LWS_H2_FRAME_TYPE_RST_STREAM: |
2401 | 0 | h2n->hpack_e_dep <<= 8; |
2402 | 0 | h2n->hpack_e_dep |= c; |
2403 | 0 | break; |
2404 | | |
2405 | 0 | case LWS_H2_FRAME_TYPE_PUSH_PROMISE: |
2406 | 0 | break; |
2407 | | |
2408 | 0 | case LWS_H2_FRAME_TYPE_PING: |
2409 | 0 | if (h2n->flags & LWS_H2_FLAG_SETTINGS_ACK) { // ack |
2410 | 0 | } else { /* they're sending us a ping request */ |
2411 | 0 | if (h2n->count > 8) |
2412 | 0 | return 1; |
2413 | 0 | h2n->ping_payload[h2n->count - 1] = c; |
2414 | 0 | } |
2415 | 0 | break; |
2416 | | |
2417 | 0 | case LWS_H2_FRAME_TYPE_WINDOW_UPDATE: |
2418 | 0 | h2n->hpack_e_dep <<= 8; |
2419 | 0 | h2n->hpack_e_dep |= c; |
2420 | 0 | break; |
2421 | | |
2422 | 0 | case LWS_H2_FRAME_TYPE_COUNT: /* IGNORING FRAME */ |
2423 | | //lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length); |
2424 | 0 | h2n->count++; |
2425 | 0 | break; |
2426 | | |
2427 | 0 | default: |
2428 | 0 | lwsl_notice("%s: unhandled frame type %d\n", |
2429 | 0 | __func__, h2n->type); |
2430 | |
|
2431 | 0 | goto fail; |
2432 | 0 | } |
2433 | | |
2434 | 0 | frame_end: |
2435 | 0 | if (h2n->count > h2n->length) { |
2436 | 0 | lwsl_notice("%s: count > length %u %u (type %d)\n", |
2437 | 0 | __func__, (unsigned int)h2n->count, |
2438 | 0 | (unsigned int)h2n->length, h2n->type); |
2439 | |
|
2440 | 0 | } else |
2441 | 0 | if (h2n->count != h2n->length) |
2442 | 0 | break; |
2443 | | |
2444 | | /* |
2445 | | * end of frame just happened |
2446 | | */ |
2447 | 0 | n = lws_h2_parse_end_of_frame(wsi); |
2448 | 0 | if (n == 2) { |
2449 | 0 | *inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin); |
2450 | |
|
2451 | 0 | return 2; |
2452 | 0 | } |
2453 | 0 | if (n) |
2454 | 0 | goto fail; |
2455 | | |
2456 | 0 | break; |
2457 | | |
2458 | 0 | try_frame_start: |
2459 | 0 | if (h2n->frame_state <= 8) { |
2460 | |
|
2461 | 0 | switch (h2n->frame_state++) { |
2462 | 0 | case 0: |
2463 | 0 | h2n->pad_length = 0; |
2464 | 0 | h2n->collected_priority = 0; |
2465 | 0 | h2n->padding = 0; |
2466 | 0 | h2n->preamble = 0; |
2467 | 0 | h2n->length = c; |
2468 | 0 | h2n->inside = 0; |
2469 | 0 | break; |
2470 | 0 | case 1: |
2471 | 0 | case 2: |
2472 | 0 | h2n->length <<= 8; |
2473 | 0 | h2n->length |= c; |
2474 | 0 | break; |
2475 | 0 | case 3: |
2476 | 0 | h2n->type = c; |
2477 | 0 | break; |
2478 | 0 | case 4: |
2479 | 0 | h2n->flags = c; |
2480 | 0 | break; |
2481 | | |
2482 | 0 | case 5: |
2483 | 0 | case 6: |
2484 | 0 | case 7: |
2485 | 0 | case 8: |
2486 | 0 | h2n->sid <<= 8; |
2487 | 0 | h2n->sid |= c; |
2488 | 0 | break; |
2489 | 0 | } |
2490 | 0 | } |
2491 | | |
2492 | 0 | if (h2n->frame_state == LWS_H2_FRAME_HEADER_LENGTH && |
2493 | 0 | lws_h2_parse_frame_header(wsi)) |
2494 | 0 | goto fail; |
2495 | 0 | break; |
2496 | | |
2497 | 0 | default: |
2498 | 0 | if (h2n->type == LWS_H2_FRAME_TYPE_COUNT) { /* IGNORING FRAME */ |
2499 | | //lwsl_debug("%s: consuming for ignored %u %u\n", __func__, (unsigned int)h2n->count, (unsigned int)h2n->length); |
2500 | 0 | h2n->count++; |
2501 | 0 | } |
2502 | 0 | break; |
2503 | 0 | } |
2504 | 0 | } |
2505 | | |
2506 | 0 | *inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin); |
2507 | |
|
2508 | 0 | return 0; |
2509 | | |
2510 | 0 | close_swsi_and_return: |
2511 | |
|
2512 | 0 | lws_close_free_wsi(h2n->swsi, 0, "close_swsi_and_return"); |
2513 | 0 | h2n->swsi = NULL; |
2514 | 0 | h2n->frame_state = 0; |
2515 | 0 | h2n->count = 0; |
2516 | | |
2517 | | // already_closed_swsi: |
2518 | 0 | *inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin); |
2519 | |
|
2520 | 0 | return 2; |
2521 | | |
2522 | 0 | fail: |
2523 | 0 | *inused = (lws_filepos_t)lws_ptr_diff_size_t(in, oldin); |
2524 | |
|
2525 | 0 | return 1; |
2526 | 0 | } |
2527 | | |
2528 | | #if defined(LWS_WITH_CLIENT) |
2529 | | int |
2530 | | lws_h2_client_handshake(struct lws *wsi) |
2531 | 0 | { |
2532 | 0 | struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; |
2533 | 0 | uint8_t *buf, *start, *p, *p1, *end; |
2534 | 0 | char *meth = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_METHOD), |
2535 | 0 | *uri = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI), *simp; |
2536 | 0 | struct lws *nwsi = lws_get_network_wsi(wsi); |
2537 | 0 | const char *path = "/"; |
2538 | 0 | int n, m; |
2539 | | /* |
2540 | | * The identifier of a newly established stream MUST be numerically |
2541 | | * greater than all streams that the initiating endpoint has opened or |
2542 | | * reserved. This governs streams that are opened using a HEADERS frame |
2543 | | * and streams that are reserved using PUSH_PROMISE. An endpoint that |
2544 | | * receives an unexpected stream identifier MUST respond with a |
2545 | | * connection error (Section 5.4.1) of type PROTOCOL_ERROR. |
2546 | | */ |
2547 | 0 | unsigned int sid = nwsi->h2.h2n->highest_sid_opened + 2; |
2548 | |
|
2549 | 0 | lwsl_debug("%s\n", __func__); |
2550 | | |
2551 | | /* |
2552 | | * We MUST allocate our sid here at the point we're about to send the |
2553 | | * stream open. It's because we don't know the order in which multiple |
2554 | | * open streams will send their headers... in h2, sending the headers |
2555 | | * is the point the stream is opened. The peer requires that we only |
2556 | | * open streams in ascending sid order |
2557 | | */ |
2558 | |
|
2559 | 0 | wsi->mux.my_sid = nwsi->h2.h2n->highest_sid_opened = sid; |
2560 | 0 | lwsl_info("%s: %s: assigning SID %d at header send\n", __func__, |
2561 | 0 | lws_wsi_tag(wsi), sid); |
2562 | | |
2563 | |
|
2564 | 0 | lwsl_info("%s: CLIENT_WAITING_TO_SEND_HEADERS: pollout (sid %d)\n", |
2565 | 0 | __func__, wsi->mux.my_sid); |
2566 | |
|
2567 | 0 | p = start = buf = pt->serv_buf + LWS_PRE; |
2568 | 0 | end = start + (wsi->a.context->pt_serv_buf_size / 2) - LWS_PRE - 1; |
2569 | | |
2570 | | /* it's time for us to send our client stream headers */ |
2571 | |
|
2572 | 0 | if (!meth) |
2573 | 0 | meth = "GET"; |
2574 | | |
2575 | | /* h2 pseudoheaders must be in a bunch at the start */ |
2576 | |
|
2577 | 0 | if (lws_add_http_header_by_token(wsi, |
2578 | 0 | WSI_TOKEN_HTTP_COLON_METHOD, |
2579 | 0 | (unsigned char *)meth, |
2580 | 0 | (int)strlen(meth), &p, end)) |
2581 | 0 | goto fail_length; |
2582 | | |
2583 | 0 | if (lws_add_http_header_by_token(wsi, |
2584 | 0 | WSI_TOKEN_HTTP_COLON_SCHEME, |
2585 | 0 | (unsigned char *)"https", 5, |
2586 | 0 | &p, end)) |
2587 | 0 | goto fail_length; |
2588 | | |
2589 | | |
2590 | 0 | n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_URI); |
2591 | 0 | if (n) |
2592 | 0 | path = uri; |
2593 | 0 | else |
2594 | 0 | if (wsi->stash && wsi->stash->cis[CIS_PATH]) { |
2595 | 0 | path = wsi->stash->cis[CIS_PATH]; |
2596 | 0 | n = (int)strlen(path); |
2597 | 0 | } else |
2598 | 0 | n = 1; |
2599 | |
|
2600 | 0 | if (n > 1 && path[0] == '/' && path[1] == '/') { |
2601 | 0 | path++; |
2602 | 0 | n--; |
2603 | 0 | } |
2604 | | |
2605 | | // lwsl_hexdump_notice(path, (size_t)n); |
2606 | |
|
2607 | 0 | if (n && lws_add_http_header_by_token(wsi, |
2608 | 0 | WSI_TOKEN_HTTP_COLON_PATH, |
2609 | 0 | (unsigned char *)path, n, &p, end)) |
2610 | 0 | goto fail_length; |
2611 | | |
2612 | 0 | n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_HOST); |
2613 | 0 | simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST); |
2614 | 0 | if (!n && wsi->stash && wsi->stash->cis[CIS_ADDRESS]) { |
2615 | 0 | n = (int)strlen(wsi->stash->cis[CIS_ADDRESS]); |
2616 | 0 | simp = wsi->stash->cis[CIS_ADDRESS]; |
2617 | 0 | } |
2618 | | |
2619 | | // n = lws_hdr_total_length(wsi, _WSI_TOKEN_CLIENT_ORIGIN); |
2620 | | // simp = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN); |
2621 | | #if 0 |
2622 | | if (n && simp && lws_add_http_header_by_token(wsi, |
2623 | | WSI_TOKEN_HTTP_COLON_AUTHORITY, |
2624 | | (unsigned char *)simp, n, &p, end)) |
2625 | | goto fail_length; |
2626 | | #endif |
2627 | | |
2628 | |
|
2629 | 0 | if (/*!wsi->client_h2_alpn && */n && simp && |
2630 | 0 | lws_add_http_header_by_token(wsi, WSI_TOKEN_HOST, |
2631 | 0 | (unsigned char *)simp, n, &p, end)) |
2632 | 0 | goto fail_length; |
2633 | | |
2634 | | |
2635 | 0 | if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME) { |
2636 | 0 | p1 = lws_http_multipart_headers(wsi, p); |
2637 | 0 | if (!p1) |
2638 | 0 | goto fail_length; |
2639 | 0 | p = p1; |
2640 | 0 | } |
2641 | | |
2642 | 0 | if (wsi->flags & LCCSCF_HTTP_X_WWW_FORM_URLENCODED) { |
2643 | 0 | if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, |
2644 | 0 | (unsigned char *)"application/x-www-form-urlencoded", |
2645 | 0 | 33, &p, end)) |
2646 | 0 | goto fail_length; |
2647 | 0 | lws_client_http_body_pending(wsi, 1); |
2648 | 0 | } |
2649 | | |
2650 | | /* give userland a chance to append, eg, cookies */ |
2651 | | |
2652 | 0 | #if defined(LWS_WITH_CACHE_NSCOOKIEJAR) && defined(LWS_WITH_CLIENT) |
2653 | 0 | if (wsi->flags & LCCSCF_CACHE_COOKIES) |
2654 | 0 | lws_cookie_send_cookies(wsi, (char **)&p, (char *)end); |
2655 | 0 | #endif |
2656 | |
|
2657 | 0 | if (wsi->a.protocol->callback(wsi, |
2658 | 0 | LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER, |
2659 | 0 | wsi->user_space, &p, lws_ptr_diff_size_t(end, p) - 12)) |
2660 | 0 | goto fail_length; |
2661 | | |
2662 | 0 | if (lws_finalize_http_header(wsi, &p, end)) |
2663 | 0 | goto fail_length; |
2664 | | |
2665 | 0 | m = LWS_WRITE_HTTP_HEADERS; |
2666 | 0 | #if defined(LWS_WITH_CLIENT) |
2667 | | /* below is not needed in spec, indeed it destroys the long poll |
2668 | | * feature, but required by nghttp2 */ |
2669 | 0 | if ((wsi->flags & LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM) && |
2670 | 0 | !(wsi->client_http_body_pending || lws_has_buffered_out(wsi))) |
2671 | 0 | m |= LWS_WRITE_H2_STREAM_END; |
2672 | 0 | #endif |
2673 | | |
2674 | | // lwsl_hexdump_notice(start, p - start); |
2675 | |
|
2676 | 0 | n = lws_write(wsi, start, lws_ptr_diff_size_t(p, start), (enum lws_write_protocol)m); |
2677 | |
|
2678 | 0 | if (n != lws_ptr_diff(p, start)) { |
2679 | 0 | lwsl_err("_write returned %d from %ld\n", n, |
2680 | 0 | (long)(p - start)); |
2681 | 0 | return -1; |
2682 | 0 | } |
2683 | | |
2684 | | /* |
2685 | | * Normally let's charge up the peer tx credit a bit. But if |
2686 | | * MANUAL_REFLOW is set, just set it to the initial credit given in |
2687 | | * the client create info |
2688 | | */ |
2689 | | |
2690 | 0 | n = 4 * 65536; |
2691 | 0 | if (wsi->flags & LCCSCF_H2_MANUAL_RXFLOW) { |
2692 | 0 | n = wsi->txc.manual_initial_tx_credit; |
2693 | 0 | wsi->txc.manual = 1; |
2694 | 0 | } |
2695 | |
|
2696 | 0 | if (lws_h2_update_peer_txcredit(wsi, wsi->mux.my_sid, n)) |
2697 | 0 | return 1; |
2698 | | |
2699 | 0 | lws_h2_state(wsi, LWS_H2_STATE_OPEN); |
2700 | 0 | lwsi_set_state(wsi, LRS_ESTABLISHED); |
2701 | |
|
2702 | 0 | if (wsi->flags & LCCSCF_HTTP_MULTIPART_MIME) |
2703 | 0 | lws_callback_on_writable(wsi); |
2704 | |
|
2705 | 0 | return 0; |
2706 | | |
2707 | 0 | fail_length: |
2708 | 0 | lwsl_err("Client hdrs too long: incr context info.pt_serv_buf_size\n"); |
2709 | |
|
2710 | 0 | return -1; |
2711 | 0 | } |
2712 | | #endif |
2713 | | |
2714 | | #if defined(LWS_ROLE_WS) && defined(LWS_WITH_SERVER) |
2715 | | int |
2716 | | lws_h2_ws_handshake(struct lws *wsi) |
2717 | 0 | { |
2718 | 0 | uint8_t buf[LWS_PRE + 2048], *p = buf + LWS_PRE, *start = p, |
2719 | 0 | *end = &buf[sizeof(buf) - 1]; |
2720 | 0 | const struct lws_http_mount *hit; |
2721 | 0 | const char * uri_ptr; |
2722 | 0 | size_t m; |
2723 | 0 | int n; |
2724 | |
|
2725 | 0 | if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end)) |
2726 | 0 | return -1; |
2727 | | |
2728 | 0 | if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) > 64) |
2729 | 0 | return -1; |
2730 | | |
2731 | 0 | if (wsi->proxied_ws_parent && wsi->child_list) { |
2732 | 0 | if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL)) { |
2733 | 0 | if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL, |
2734 | 0 | (uint8_t *)lws_hdr_simple_ptr(wsi, |
2735 | 0 | WSI_TOKEN_PROTOCOL), |
2736 | 0 | (int)strlen(lws_hdr_simple_ptr(wsi, |
2737 | 0 | WSI_TOKEN_PROTOCOL)), |
2738 | 0 | &p, end)) |
2739 | 0 | return -1; |
2740 | 0 | } |
2741 | 0 | } else { |
2742 | | |
2743 | | /* we can only return the protocol header if: |
2744 | | * - one came in, and ... */ |
2745 | 0 | if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL) && |
2746 | | /* - it is not an empty string */ |
2747 | 0 | wsi->a.protocol->name && wsi->a.protocol->name[0]) { |
2748 | |
|
2749 | 0 | #if defined(LWS_WITH_SECURE_STREAMS) && defined(LWS_WITH_SERVER) |
2750 | | |
2751 | | /* |
2752 | | * This is the h2 version of server-ws.c understanding that it |
2753 | | * did the ws upgrade on a ss server object, therefore it needs |
2754 | | * to pass back to the peer the policy ws-protocol name, not |
2755 | | * the generic ss-ws.c protocol name |
2756 | | */ |
2757 | |
|
2758 | 0 | if (wsi->a.vhost && wsi->a.vhost->ss_handle && |
2759 | 0 | wsi->a.vhost->ss_handle->policy->u.http.u.ws.subprotocol) { |
2760 | 0 | lws_ss_handle_t *h = |
2761 | 0 | (lws_ss_handle_t *)wsi->a.opaque_user_data; |
2762 | |
|
2763 | 0 | lwsl_notice("%s: Server SS %s .wsi %s switching to ws protocol\n", |
2764 | 0 | __func__, lws_ss_tag(h), lws_wsi_tag(h->wsi)); |
2765 | |
|
2766 | 0 | wsi->a.protocol = &protocol_secstream_ws; |
2767 | | |
2768 | | /* |
2769 | | * inform the SS user code that this has done a one-way |
2770 | | * upgrade to some other protocol... it will likely |
2771 | | * want to treat subsequent payloads differently |
2772 | | */ |
2773 | |
|
2774 | 0 | lws_ss_event_helper(h, LWSSSCS_SERVER_UPGRADE); |
2775 | |
|
2776 | 0 | lws_mux_mark_immortal(wsi); |
2777 | |
|
2778 | 0 | if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL, |
2779 | 0 | (unsigned char *)wsi->a.vhost->ss_handle->policy-> |
2780 | 0 | u.http.u.ws.subprotocol, |
2781 | 0 | (int)strlen(wsi->a.vhost->ss_handle->policy-> |
2782 | 0 | u.http.u.ws.subprotocol), &p, end)) |
2783 | 0 | return -1; |
2784 | 0 | } else |
2785 | 0 | #endif |
2786 | | |
2787 | 0 | if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL, |
2788 | 0 | (unsigned char *)wsi->a.protocol->name, |
2789 | 0 | (int)strlen(wsi->a.protocol->name), &p, end)) |
2790 | 0 | return -1; |
2791 | 0 | } |
2792 | 0 | } |
2793 | | |
2794 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
2795 | | /* |
2796 | | * Figure out which extensions the client has that we want to |
2797 | | * enable on this connection, and give him back the list. |
2798 | | * |
2799 | | * Give him a limited write bugdet |
2800 | | */ |
2801 | | if (lws_extension_server_handshake(wsi, (char **)&p, 192)) |
2802 | | return -1; |
2803 | | #endif |
2804 | | |
2805 | 0 | if (lws_finalize_http_header(wsi, &p, end)) |
2806 | 0 | return -1; |
2807 | | |
2808 | 0 | m = lws_ptr_diff_size_t(p, start); |
2809 | | // lwsl_hexdump_notice(start, m); |
2810 | 0 | n = lws_write(wsi, start, m, LWS_WRITE_HTTP_HEADERS); |
2811 | 0 | if (n != (int)m) { |
2812 | 0 | lwsl_err("_write returned %d from %d\n", n, (int)m); |
2813 | |
|
2814 | 0 | return -1; |
2815 | 0 | } |
2816 | | |
2817 | | /* |
2818 | | * alright clean up, set our state to generic ws established, the |
2819 | | * mode / state of the nwsi will get the h2 processing done. |
2820 | | */ |
2821 | | |
2822 | 0 | lwsi_set_state(wsi, LRS_ESTABLISHED); |
2823 | 0 | wsi->lws_rx_parse_state = 0; // ==LWS_RXPS_NEW; |
2824 | |
|
2825 | 0 | uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_PATH); |
2826 | 0 | n = lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COLON_PATH); |
2827 | 0 | hit = lws_find_mount(wsi, uri_ptr, n); |
2828 | |
|
2829 | 0 | if (hit && hit->cgienv && |
2830 | 0 | wsi->a.protocol->callback(wsi, LWS_CALLBACK_HTTP_PMO, wsi->user_space, |
2831 | 0 | (void *)hit->cgienv, 0)) |
2832 | 0 | return 1; |
2833 | | |
2834 | 0 | lws_validity_confirmed(wsi); |
2835 | |
|
2836 | 0 | return 0; |
2837 | 0 | } |
2838 | | #endif |
2839 | | |
2840 | | int |
2841 | | lws_read_h2(struct lws *wsi, unsigned char *buf, lws_filepos_t len) |
2842 | 0 | { |
2843 | 0 | unsigned char *oldbuf = buf; |
2844 | | |
2845 | | // lwsl_notice("%s: h2 path: wsistate 0x%x len %d\n", __func__, |
2846 | | // wsi->wsistate, (int)len); |
2847 | | |
2848 | | /* |
2849 | | * wsi here is always the network connection wsi, not a stream |
2850 | | * wsi. Once we unpicked the framing we will find the right |
2851 | | * swsi and make it the target of the frame. |
2852 | | * |
2853 | | * If it's ws over h2, the nwsi will get us here to do the h2 |
2854 | | * processing, and that will call us back with the swsi + |
2855 | | * ESTABLISHED state for the inner payload, handled in a later |
2856 | | * case. |
2857 | | */ |
2858 | 0 | while (len) { |
2859 | 0 | lws_filepos_t body_chunk_len = 0; |
2860 | 0 | int m; |
2861 | | |
2862 | | /* |
2863 | | * we were accepting input but now we stopped doing so |
2864 | | */ |
2865 | 0 | if (lws_is_flowcontrolled(wsi)) { |
2866 | 0 | lws_rxflow_cache(wsi, buf, 0, (size_t)len); |
2867 | 0 | buf += len; |
2868 | 0 | break; |
2869 | 0 | } |
2870 | | |
2871 | | /* |
2872 | | * lws_h2_parser() may send something; when it gets the |
2873 | | * whole frame, it will want to perform some action |
2874 | | * involving a reply. But we may be in a partial send |
2875 | | * situation on the network wsi... |
2876 | | * |
2877 | | * Even though we may be in a partial send and unable to |
2878 | | * send anything new, we still have to parse the network |
2879 | | * wsi in order to gain tx credit to send, which is |
2880 | | * potentially necessary to clear the old partial send. |
2881 | | * |
2882 | | * ALL network wsi-specific frames are sent by PPS |
2883 | | * already, these are sent as a priority on the writable |
2884 | | * handler, and so respect partial sends. The only |
2885 | | * problem is when a stream wsi wants to send an, eg, |
2886 | | * reply headers frame in response to the parsing |
2887 | | * we will do now... the *stream wsi* must stall in a |
2888 | | * different state until it is able to do so from a |
2889 | | * priority on the WRITABLE callback, same way that |
2890 | | * file transfers operate. |
2891 | | */ |
2892 | | |
2893 | 0 | m = lws_h2_parser(wsi, buf, len, &body_chunk_len); |
2894 | |
|
2895 | 0 | body_chunk_len &= 0xffffffff; /* attempt workaround for finding len=7167 --> len = 0xffffffff00001bff on lws.org */ |
2896 | |
|
2897 | 0 | if (m && m != 2) { |
2898 | 0 | lwsl_debug("%s: http2_parser bail: %d\n", __func__, m); |
2899 | 0 | lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, |
2900 | 0 | "lws_read_h2 bail"); |
2901 | |
|
2902 | 0 | return -1; |
2903 | 0 | } |
2904 | 0 | if (m == 2) { |
2905 | | /* swsi has been closed */ |
2906 | 0 | buf += body_chunk_len; |
2907 | 0 | break; |
2908 | 0 | } |
2909 | | |
2910 | 0 | buf += body_chunk_len; |
2911 | 0 | len -= body_chunk_len; |
2912 | 0 | } |
2913 | | |
2914 | 0 | return lws_ptr_diff(buf, oldbuf); |
2915 | 0 | } |
2916 | | |
2917 | | int |
2918 | | lws_h2_client_stream_long_poll_rxonly(struct lws *wsi) |
2919 | 0 | { |
2920 | |
|
2921 | 0 | if (!wsi->mux_substream) |
2922 | 0 | return 1; |
2923 | | |
2924 | | /* |
2925 | | * Elect to send an empty DATA with END_STREAM, to force the stream |
2926 | | * into HALF_CLOSED LOCAL |
2927 | | */ |
2928 | 0 | wsi->h2.long_poll = 1; |
2929 | 0 | wsi->h2.send_END_STREAM = 1; |
2930 | | |
2931 | | // lws_header_table_detach(wsi, 0); |
2932 | |
|
2933 | 0 | lws_callback_on_writable(wsi); |
2934 | |
|
2935 | 0 | return 0; |
2936 | 0 | } |