/src/libwebsockets/lib/roles/h1/ops-h1.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 | | #ifndef min |
28 | 0 | #define min(a, b) ((a) < (b) ? (a) : (b)) |
29 | | #endif |
30 | | |
31 | | |
32 | | /* |
33 | | * We have to take care about parsing because the headers may be split |
34 | | * into multiple fragments. They may contain unknown headers with arbitrary |
35 | | * argument lengths. So, we parse using a single-character at a time state |
36 | | * machine that is completely independent of packet size. |
37 | | * |
38 | | * Returns <0 for error or length of chars consumed from buf (up to len) |
39 | | */ |
40 | | |
41 | | int |
42 | | lws_read_h1(struct lws *wsi, unsigned char *buf, lws_filepos_t len) |
43 | 0 | { |
44 | 0 | unsigned char *last_char, *oldbuf = buf; |
45 | 0 | lws_filepos_t body_chunk_len; |
46 | 0 | size_t n; |
47 | |
|
48 | 0 | lwsl_debug("%s: h1 path: wsi state 0x%x\n", __func__, lwsi_state(wsi)); |
49 | |
|
50 | 0 | switch (lwsi_state(wsi)) { |
51 | | |
52 | 0 | case LRS_ISSUING_FILE: |
53 | 0 | return 0; |
54 | | |
55 | 0 | case LRS_ESTABLISHED: |
56 | |
|
57 | 0 | if (lwsi_role_ws(wsi)) |
58 | 0 | goto ws_mode; |
59 | | |
60 | 0 | if (lwsi_role_client(wsi)) |
61 | 0 | break; |
62 | | |
63 | 0 | wsi->hdr_parsing_completed = 0; |
64 | | |
65 | | /* fallthru */ |
66 | |
|
67 | 0 | case LRS_HEADERS: |
68 | 0 | if (!wsi->http.ah) { |
69 | 0 | lwsl_err("%s: LRS_HEADERS: NULL ah\n", __func__); |
70 | 0 | assert(0); |
71 | 0 | } |
72 | 0 | lwsl_parser("issuing %d bytes to parser\n", (int)len); |
73 | 0 | #if defined(LWS_ROLE_WS) && defined(LWS_WITH_CLIENT) |
74 | 0 | if (lws_ws_handshake_client(wsi, &buf, (size_t)len) == LWS_HPI_RET_PLEASE_CLOSE_ME) |
75 | 0 | goto bail; |
76 | 0 | #endif |
77 | 0 | last_char = buf; |
78 | 0 | if (lws_handshake_server(wsi, &buf, (size_t)len)) |
79 | | /* Handshake indicates this session is done. */ |
80 | 0 | goto bail; |
81 | | |
82 | | /* we might have transitioned to RAW */ |
83 | 0 | if (wsi->role_ops == &role_ops_raw_skt |
84 | 0 | #if defined(LWS_ROLE_RAW_FILE) |
85 | 0 | || |
86 | 0 | wsi->role_ops == &role_ops_raw_file |
87 | 0 | #endif |
88 | 0 | ) |
89 | | /* we gave the read buffer to RAW handler already */ |
90 | 0 | goto read_ok; |
91 | | |
92 | | /* |
93 | | * It's possible that we've exhausted our data already, or |
94 | | * rx flow control has stopped us dealing with this early, |
95 | | * but lws_handshake_server doesn't update len for us. |
96 | | * Figure out how much was read, so that we can proceed |
97 | | * appropriately: |
98 | | */ |
99 | 0 | len -= (unsigned int)lws_ptr_diff(buf, last_char); |
100 | |
|
101 | 0 | if (!wsi->hdr_parsing_completed) |
102 | | /* More header content on the way */ |
103 | 0 | goto read_ok; |
104 | | |
105 | 0 | switch (lwsi_state(wsi)) { |
106 | 0 | case LRS_ESTABLISHED: |
107 | 0 | case LRS_HEADERS: |
108 | 0 | goto read_ok; |
109 | 0 | case LRS_ISSUING_FILE: |
110 | 0 | goto read_ok; |
111 | 0 | case LRS_DISCARD_BODY: |
112 | 0 | case LRS_BODY: |
113 | 0 | wsi->http.rx_content_remain = |
114 | 0 | wsi->http.rx_content_length; |
115 | 0 | if (wsi->http.rx_content_remain) |
116 | 0 | goto http_postbody; |
117 | | |
118 | | /* there is no POST content */ |
119 | 0 | goto postbody_completion; |
120 | 0 | default: |
121 | 0 | break; |
122 | 0 | } |
123 | 0 | break; |
124 | | |
125 | 0 | case LRS_DISCARD_BODY: |
126 | 0 | case LRS_BODY: |
127 | 0 | http_postbody: |
128 | 0 | lwsl_info("%s: http post body: cl set %d, remain %d, len %d\n", __func__, |
129 | 0 | (int)wsi->http.content_length_given, |
130 | 0 | (int)wsi->http.rx_content_remain, (int)len); |
131 | |
|
132 | 0 | if (wsi->http.content_length_given && !wsi->http.rx_content_remain) |
133 | 0 | goto postbody_completion; |
134 | | |
135 | 0 | while (len && (!wsi->http.content_length_given || wsi->http.rx_content_remain)) { |
136 | | /* Copy as much as possible, up to the limit of: |
137 | | * what we have in the read buffer (len) |
138 | | * remaining portion of the POST body (content_remain) |
139 | | */ |
140 | 0 | if (wsi->http.content_length_given) |
141 | 0 | body_chunk_len = min(wsi->http.rx_content_remain, len); |
142 | 0 | else |
143 | 0 | body_chunk_len = len; |
144 | 0 | wsi->http.rx_content_remain -= body_chunk_len; |
145 | | // len -= body_chunk_len; |
146 | | #ifdef LWS_WITH_CGI |
147 | | if (wsi->http.cgi) { |
148 | | struct lws_cgi_args args; |
149 | | |
150 | | args.ch = LWS_STDIN; |
151 | | args.stdwsi = &wsi->http.cgi->lsp->stdwsi[0]; |
152 | | args.data = buf; |
153 | | args.len = (int)(unsigned int)body_chunk_len; |
154 | | |
155 | | /* returns how much used */ |
156 | | n = (unsigned int)user_callback_handle_rxflow( |
157 | | wsi->a.protocol->callback, |
158 | | wsi, LWS_CALLBACK_CGI_STDIN_DATA, |
159 | | wsi->user_space, |
160 | | (void *)&args, 0); |
161 | | if ((int)n < 0) |
162 | | goto bail; |
163 | | } else { |
164 | | #endif |
165 | 0 | if (lwsi_state(wsi) != LRS_DISCARD_BODY) { |
166 | 0 | lwsl_info("%s: HTTP_BODY %d\n", __func__, (int)body_chunk_len); |
167 | 0 | n = (unsigned int)wsi->a.protocol->callback(wsi, |
168 | 0 | LWS_CALLBACK_HTTP_BODY, wsi->user_space, |
169 | 0 | buf, (size_t)body_chunk_len); |
170 | 0 | if (n) |
171 | 0 | goto bail; |
172 | 0 | } |
173 | 0 | n = (size_t)body_chunk_len; |
174 | | #ifdef LWS_WITH_CGI |
175 | | } |
176 | | #endif |
177 | 0 | lwsl_info("%s: advancing buf by %d\n", __func__, (int)n); |
178 | 0 | buf += n; |
179 | |
|
180 | 0 | #if defined(LWS_ROLE_H2) |
181 | 0 | if (lwsi_role_h2(wsi) && !wsi->http.content_length_given) { |
182 | 0 | struct lws *w = lws_get_network_wsi(wsi); |
183 | |
|
184 | 0 | if (w) |
185 | 0 | lwsl_info("%s: h2: nwsi h2 flags %d\n", __func__, |
186 | 0 | w->h2.h2n ? w->h2.h2n->flags: -1); |
187 | |
|
188 | 0 | if (w && w->h2.h2n && !(w->h2.h2n->flags & 1)) { |
189 | 0 | lwsl_info("%s: h2, no cl, not END_STREAM, continuing\n", __func__); |
190 | 0 | lws_set_timeout(wsi, |
191 | 0 | PENDING_TIMEOUT_HTTP_CONTENT, |
192 | 0 | (int)wsi->a.context->timeout_secs); |
193 | 0 | break; |
194 | 0 | } |
195 | 0 | goto postbody_completion; |
196 | 0 | } |
197 | 0 | #endif |
198 | | |
199 | 0 | if (wsi->http.rx_content_remain) { |
200 | 0 | lws_set_timeout(wsi, |
201 | 0 | PENDING_TIMEOUT_HTTP_CONTENT, |
202 | 0 | (int)wsi->a.context->timeout_secs); |
203 | 0 | break; |
204 | 0 | } |
205 | | /* he sent all the content in time */ |
206 | 0 | postbody_completion: |
207 | | #ifdef LWS_WITH_CGI |
208 | | /* |
209 | | * If we're running a cgi, we can't let him off the |
210 | | * hook just because he sent his POST data |
211 | | */ |
212 | | if (wsi->http.cgi) |
213 | | lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, |
214 | | (int)wsi->a.context->timeout_secs); |
215 | | else |
216 | | #endif |
217 | 0 | lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); |
218 | | #ifdef LWS_WITH_CGI |
219 | | if (!wsi->http.cgi) |
220 | | #endif |
221 | 0 | { |
222 | 0 | #if defined(LWS_WITH_SERVER) |
223 | 0 | if (lwsi_state(wsi) == LRS_DISCARD_BODY) { |
224 | | /* |
225 | | * repeat the transaction completed |
226 | | * that got us into this state, having |
227 | | * consumed the pending body now |
228 | | */ |
229 | |
|
230 | 0 | if (lws_http_transaction_completed(wsi)) |
231 | 0 | goto bail; |
232 | 0 | break; |
233 | 0 | } |
234 | 0 | #endif |
235 | 0 | lwsl_info("HTTP_BODY_COMPLETION: %s (%s)\n", |
236 | 0 | lws_wsi_tag(wsi), wsi->a.protocol->name); |
237 | |
|
238 | 0 | n = (unsigned int)wsi->a.protocol->callback(wsi, |
239 | 0 | LWS_CALLBACK_HTTP_BODY_COMPLETION, |
240 | 0 | wsi->user_space, NULL, 0); |
241 | 0 | if (n) { |
242 | 0 | lwsl_info("%s: bailing after BODY_COMPLETION\n", __func__); |
243 | 0 | goto bail; |
244 | 0 | } |
245 | | |
246 | 0 | if (wsi->mux_substream) |
247 | 0 | lwsi_set_state(wsi, LRS_ESTABLISHED); |
248 | 0 | } |
249 | | |
250 | 0 | break; |
251 | 0 | } |
252 | 0 | break; |
253 | | |
254 | 0 | case LRS_RETURNED_CLOSE: |
255 | 0 | case LRS_AWAITING_CLOSE_ACK: |
256 | 0 | case LRS_WAITING_TO_SEND_CLOSE: |
257 | 0 | case LRS_SHUTDOWN: |
258 | |
|
259 | 0 | ws_mode: |
260 | 0 | #if defined(LWS_WITH_CLIENT) && defined(LWS_ROLE_WS) |
261 | | // lwsl_notice("%s: ws_mode\n", __func__); |
262 | 0 | if (lws_ws_handshake_client(wsi, &buf, (size_t)len) == LWS_HPI_RET_PLEASE_CLOSE_ME) |
263 | 0 | goto bail; |
264 | 0 | #endif |
265 | 0 | #if defined(LWS_ROLE_WS) |
266 | 0 | if (lwsi_role_ws(wsi) && lwsi_role_server(wsi) && |
267 | | /* |
268 | | * for h2 we are on the swsi |
269 | | */ |
270 | 0 | lws_parse_ws(wsi, &buf, (size_t)len) < 0) { |
271 | 0 | lwsl_info("%s: lws_parse_ws bailed\n", __func__); |
272 | 0 | goto bail; |
273 | 0 | } |
274 | 0 | #endif |
275 | | // lwsl_notice("%s: ws_mode: buf moved on by %d\n", __func__, |
276 | | // lws_ptr_diff(buf, oldbuf)); |
277 | 0 | break; |
278 | | |
279 | 0 | case LRS_DEFERRING_ACTION: |
280 | 0 | lwsl_notice("%s: LRS_DEFERRING_ACTION\n", __func__); |
281 | 0 | break; |
282 | | |
283 | 0 | case LRS_SSL_ACK_PENDING: |
284 | 0 | break; |
285 | | |
286 | 0 | case LRS_FLUSHING_BEFORE_CLOSE: |
287 | 0 | break; |
288 | | |
289 | 0 | case LRS_DEAD_SOCKET: |
290 | 0 | lwsl_err("%s: Unhandled state LRS_DEAD_SOCKET\n", __func__); |
291 | 0 | goto bail; |
292 | | // assert(0); |
293 | | /* fallthru */ |
294 | | |
295 | 0 | case LRS_WAITING_CONNECT: /* observed on warmcat.com */ |
296 | 0 | break; |
297 | | |
298 | 0 | default: |
299 | 0 | lwsl_err("%s: Unhandled state %d\n", __func__, lwsi_state(wsi)); |
300 | 0 | goto bail; |
301 | 0 | } |
302 | | |
303 | 0 | read_ok: |
304 | | /* Nothing more to do for now */ |
305 | | // lwsl_info("%s: %p: read_ok, used %ld (len %d, state %d)\n", __func__, |
306 | | // wsi, (long)(buf - oldbuf), (int)len, wsi->state); |
307 | |
|
308 | 0 | return lws_ptr_diff(buf, oldbuf); |
309 | | |
310 | 0 | bail: |
311 | | /* |
312 | | * h2 / h2-ws calls us recursively in |
313 | | * |
314 | | * lws_read_h1()-> |
315 | | * lws_h2_parser()-> |
316 | | * lws_read_h1() |
317 | | * |
318 | | * pattern, having stripped the h2 framing in the middle. |
319 | | * |
320 | | * When taking down the whole connection, make sure that only the |
321 | | * outer lws_read() does the wsi close. |
322 | | */ |
323 | 0 | if (!wsi->outer_will_close) |
324 | 0 | lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, |
325 | 0 | "lws_read_h1 bail"); |
326 | |
|
327 | 0 | return -1; |
328 | 0 | } |
329 | | #if defined(LWS_WITH_SERVER) |
330 | | static lws_handling_result_t |
331 | | lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd) |
332 | 0 | { |
333 | 0 | struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; |
334 | 0 | struct lws_tokens ebuf; |
335 | 0 | int n, buffered; |
336 | |
|
337 | 0 | if (lwsi_state(wsi) == LRS_DEFERRING_ACTION) |
338 | 0 | goto try_pollout; |
339 | | |
340 | | /* any incoming data ready? */ |
341 | | |
342 | 0 | if (!(pollfd->revents & pollfd->events & LWS_POLLIN)) |
343 | 0 | goto try_pollout; |
344 | | |
345 | | /* |
346 | | * If we previously just did POLLIN when IN and OUT were signaled |
347 | | * (because POLLIN processing may have used up the POLLOUT), don't let |
348 | | * that happen twice in a row... next time we see the situation favour |
349 | | * POLLOUT |
350 | | */ |
351 | | |
352 | 0 | if (wsi->favoured_pollin && |
353 | 0 | (pollfd->revents & pollfd->events & LWS_POLLOUT)) { |
354 | | // lwsl_notice("favouring pollout\n"); |
355 | 0 | wsi->favoured_pollin = 0; |
356 | 0 | goto try_pollout; |
357 | 0 | } |
358 | | |
359 | | /* |
360 | | * We haven't processed that the tunnel is set up yet, so |
361 | | * defer reading |
362 | | */ |
363 | | |
364 | 0 | if (lwsi_state(wsi) == LRS_SSL_ACK_PENDING) |
365 | 0 | return LWS_HPI_RET_HANDLED; |
366 | | |
367 | | /* these states imply we MUST have an ah attached */ |
368 | | |
369 | 0 | if ((lwsi_state(wsi) == LRS_ESTABLISHED || |
370 | 0 | lwsi_state(wsi) == LRS_ISSUING_FILE || |
371 | 0 | lwsi_state(wsi) == LRS_HEADERS || |
372 | 0 | lwsi_state(wsi) == LRS_DOING_TRANSACTION || /* at least, SSE */ |
373 | 0 | lwsi_state(wsi) == LRS_DISCARD_BODY || |
374 | 0 | lwsi_state(wsi) == LRS_BODY)) { |
375 | |
|
376 | 0 | if (!wsi->http.ah && lws_header_table_attach(wsi, 0)) { |
377 | 0 | lwsl_info("%s: %s: ah not available\n", __func__, |
378 | 0 | lws_wsi_tag(wsi)); |
379 | 0 | goto try_pollout; |
380 | 0 | } |
381 | | |
382 | | /* |
383 | | * We got here because there was specifically POLLIN... |
384 | | * regardless of our buflist state, we need to get it, |
385 | | * and either use it, or append to the buflist and use |
386 | | * buflist head material. |
387 | | * |
388 | | * We will not notice a connection close until the buflist is |
389 | | * exhausted and we tried to do a read of some kind. |
390 | | */ |
391 | | |
392 | 0 | ebuf.token = NULL; |
393 | 0 | ebuf.len = 0; |
394 | 0 | buffered = lws_buflist_aware_read(pt, wsi, &ebuf, 0, __func__); |
395 | 0 | switch (ebuf.len) { |
396 | 0 | case 0: |
397 | 0 | lwsl_info("%s: read 0 len a\n", __func__); |
398 | 0 | wsi->seen_zero_length_recv = 1; |
399 | 0 | if (lws_change_pollfd(wsi, LWS_POLLIN, 0)) |
400 | 0 | goto fail; |
401 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
402 | | /* |
403 | | * autobahn requires us to win the race between close |
404 | | * and draining the extensions |
405 | | */ |
406 | | if (wsi->ws && |
407 | | (wsi->ws->rx_draining_ext || |
408 | | wsi->ws->tx_draining_ext)) |
409 | | goto try_pollout; |
410 | | #endif |
411 | | /* |
412 | | * normally, we respond to close with logically closing |
413 | | * our side immediately |
414 | | */ |
415 | 0 | goto fail; |
416 | | |
417 | 0 | case LWS_SSL_CAPABLE_ERROR: |
418 | 0 | goto fail; |
419 | 0 | case LWS_SSL_CAPABLE_MORE_SERVICE: |
420 | 0 | goto try_pollout; |
421 | 0 | } |
422 | | |
423 | | /* just ignore incoming if waiting for close */ |
424 | 0 | if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) { |
425 | 0 | lwsl_notice("%s: just ignoring\n", __func__); |
426 | 0 | goto try_pollout; |
427 | 0 | } |
428 | | |
429 | 0 | if (lwsi_state(wsi) == LRS_ISSUING_FILE) { |
430 | | // lwsl_notice("stashing: wsi %p: bd %d\n", wsi, buffered); |
431 | 0 | if (lws_buflist_aware_finished_consuming(wsi, &ebuf, 0, |
432 | 0 | buffered, __func__)) |
433 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
434 | | |
435 | 0 | goto try_pollout; |
436 | 0 | } |
437 | | |
438 | | /* |
439 | | * Otherwise give it to whoever wants it according to the |
440 | | * connection state |
441 | | */ |
442 | 0 | #if defined(LWS_ROLE_H2) |
443 | 0 | if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY) |
444 | 0 | n = lws_read_h2(wsi, ebuf.token, (unsigned int)ebuf.len); |
445 | 0 | else |
446 | 0 | #endif |
447 | 0 | n = lws_read_h1(wsi, ebuf.token, (unsigned int)ebuf.len); |
448 | 0 | if (n < 0) /* we closed wsi */ |
449 | 0 | return LWS_HPI_RET_WSI_ALREADY_DIED; |
450 | | |
451 | | // lwsl_notice("%s: consumed %d\n", __func__, n); |
452 | | |
453 | 0 | if (lws_buflist_aware_finished_consuming(wsi, &ebuf, n, |
454 | 0 | buffered, __func__)) |
455 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
456 | | |
457 | | /* |
458 | | * during the parsing our role changed to something non-http, |
459 | | * so the ah has no further meaning |
460 | | */ |
461 | | |
462 | 0 | if (wsi->http.ah && |
463 | 0 | !lwsi_role_h1(wsi) && |
464 | 0 | !lwsi_role_h2(wsi) && |
465 | 0 | !lwsi_role_cgi(wsi)) |
466 | 0 | lws_header_table_detach(wsi, 0); |
467 | | |
468 | | /* |
469 | | * He may have used up the writability above, if we will defer |
470 | | * POLLOUT processing in favour of POLLIN, note it |
471 | | */ |
472 | |
|
473 | 0 | if (pollfd->revents & LWS_POLLOUT) |
474 | 0 | wsi->favoured_pollin = 1; |
475 | |
|
476 | 0 | return LWS_HPI_RET_HANDLED; |
477 | 0 | } |
478 | | |
479 | | /* |
480 | | * He may have used up the writability above, if we will defer POLLOUT |
481 | | * processing in favour of POLLIN, note it |
482 | | */ |
483 | | |
484 | 0 | if (pollfd->revents & LWS_POLLOUT) |
485 | 0 | wsi->favoured_pollin = 1; |
486 | |
|
487 | 0 | try_pollout: |
488 | | |
489 | | /* this handles POLLOUT for http serving fragments */ |
490 | |
|
491 | 0 | if (!(pollfd->revents & LWS_POLLOUT)) |
492 | 0 | return LWS_HPI_RET_HANDLED; |
493 | | |
494 | | /* one shot */ |
495 | 0 | if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { |
496 | 0 | lwsl_notice("%s a\n", __func__); |
497 | 0 | goto fail; |
498 | 0 | } |
499 | | |
500 | | /* clear back-to-back write detection */ |
501 | 0 | wsi->could_have_pending = 0; |
502 | |
|
503 | 0 | if (lwsi_state(wsi) == LRS_DEFERRING_ACTION) { |
504 | 0 | lwsl_debug("%s: LRS_DEFERRING_ACTION now writable\n", __func__); |
505 | |
|
506 | 0 | lwsi_set_state(wsi, LRS_ESTABLISHED); |
507 | 0 | if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { |
508 | 0 | lwsl_info("failed at set pollfd\n"); |
509 | 0 | goto fail; |
510 | 0 | } |
511 | 0 | } |
512 | | |
513 | 0 | if (!wsi->hdr_parsing_completed) |
514 | 0 | return LWS_HPI_RET_HANDLED; |
515 | | |
516 | 0 | if (lwsi_state(wsi) != LRS_ISSUING_FILE) { |
517 | |
|
518 | 0 | if (lws_has_buffered_out(wsi)) { |
519 | | //lwsl_notice("%s: completing partial\n", __func__); |
520 | 0 | if (lws_issue_raw(wsi, NULL, 0) < 0) { |
521 | 0 | lwsl_info("%s signalling to close\n", __func__); |
522 | 0 | goto fail; |
523 | 0 | } |
524 | 0 | return LWS_HPI_RET_HANDLED; |
525 | 0 | } |
526 | | |
527 | 0 | n = user_callback_handle_rxflow(wsi->a.protocol->callback, wsi, |
528 | 0 | LWS_CALLBACK_HTTP_WRITEABLE, |
529 | 0 | wsi->user_space, NULL, 0); |
530 | 0 | if (n < 0) { |
531 | 0 | lwsl_info("writeable_fail\n"); |
532 | 0 | goto fail; |
533 | 0 | } |
534 | | |
535 | 0 | return LWS_HPI_RET_HANDLED; |
536 | 0 | } |
537 | | |
538 | 0 | #if defined(LWS_WITH_FILE_OPS) |
539 | | |
540 | | /* >0 == completion, <0 == error |
541 | | * |
542 | | * We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when |
543 | | * it's done. That's the case even if we just completed the |
544 | | * send, so wait for that. |
545 | | */ |
546 | 0 | n = lws_serve_http_file_fragment(wsi); |
547 | 0 | if (n < 0) |
548 | 0 | goto fail; |
549 | 0 | #endif |
550 | | |
551 | 0 | return LWS_HPI_RET_HANDLED; |
552 | | |
553 | | |
554 | 0 | fail: |
555 | 0 | lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, |
556 | 0 | "server socket svc fail"); |
557 | |
|
558 | 0 | return LWS_HPI_RET_WSI_ALREADY_DIED; |
559 | 0 | } |
560 | | #endif |
561 | | |
562 | | static lws_handling_result_t |
563 | | rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi, |
564 | | struct lws_pollfd *pollfd) |
565 | 0 | { |
566 | 0 | if (lwsi_state(wsi) == LRS_IDLING) { |
567 | 0 | uint8_t buf[1]; |
568 | 0 | int rlen; |
569 | | |
570 | | /* |
571 | | * h1 staggered spins here in IDLING if we don't close it. |
572 | | * It shows POLLIN but the tls connection returns ERROR if |
573 | | * you try to read it. |
574 | | */ |
575 | | |
576 | | // lwsl_notice("%s: %p: wsistate 0x%x %s, revents 0x%x\n", |
577 | | // __func__, wsi, wsi->wsistate, wsi->role_ops->name, |
578 | | // pollfd->revents); |
579 | |
|
580 | 0 | rlen = lws_ssl_capable_read(wsi, buf, sizeof(buf)); |
581 | 0 | if (rlen == LWS_SSL_CAPABLE_ERROR) |
582 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
583 | 0 | } |
584 | | |
585 | | #ifdef LWS_WITH_CGI |
586 | | if (wsi->http.cgi && (pollfd->revents & LWS_POLLOUT)) { |
587 | | if (lws_handle_POLLOUT_event(wsi, pollfd)) |
588 | | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
589 | | |
590 | | return LWS_HPI_RET_HANDLED; |
591 | | } |
592 | | #endif |
593 | | |
594 | | /* Priority 2: pre- compression transform */ |
595 | | |
596 | | #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) |
597 | | if (wsi->http.comp_ctx.buflist_comp || |
598 | | wsi->http.comp_ctx.may_have_more) { |
599 | | enum lws_write_protocol wp = LWS_WRITE_HTTP; |
600 | | |
601 | | lwsl_info("%s: completing comp partial (buflist_comp %p, may %d)\n", |
602 | | __func__, wsi->http.comp_ctx.buflist_comp, |
603 | | wsi->http.comp_ctx.may_have_more |
604 | | ); |
605 | | |
606 | | if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) && |
607 | | lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol). |
608 | | write_role_protocol(wsi, NULL, 0, &wp) < 0) { |
609 | | lwsl_info("%s signalling to close\n", __func__); |
610 | | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
611 | | } |
612 | | lws_callback_on_writable(wsi); |
613 | | |
614 | | if (!wsi->http.comp_ctx.buflist_comp && |
615 | | !wsi->http.comp_ctx.may_have_more && |
616 | | wsi->http.deferred_transaction_completed) { |
617 | | wsi->http.deferred_transaction_completed = 0; |
618 | | if (lws_http_transaction_completed(wsi)) |
619 | | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
620 | | } |
621 | | |
622 | | return LWS_HPI_RET_HANDLED; |
623 | | } |
624 | | #endif |
625 | | |
626 | 0 | if (lws_is_flowcontrolled(wsi)) |
627 | | /* We cannot deal with any kind of new RX because we are |
628 | | * RX-flowcontrolled. |
629 | | */ |
630 | 0 | return LWS_HPI_RET_HANDLED; |
631 | | |
632 | 0 | #if defined(LWS_WITH_SERVER) |
633 | 0 | if (!lwsi_role_client(wsi)) { |
634 | 0 | lws_handling_result_t hr; |
635 | |
|
636 | 0 | lwsl_debug("%s: %s: wsistate 0x%x\n", __func__, lws_wsi_tag(wsi), |
637 | 0 | (unsigned int)wsi->wsistate); |
638 | |
|
639 | 0 | if (pollfd->revents & LWS_POLLHUP && |
640 | 0 | !lws_buflist_total_len(&wsi->buflist)) |
641 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
642 | | |
643 | 0 | hr = lws_h1_server_socket_service(wsi, pollfd); |
644 | 0 | if (hr != LWS_HPI_RET_HANDLED) |
645 | 0 | return hr; |
646 | 0 | if (lwsi_state(wsi) != LRS_SSL_INIT) |
647 | 0 | if (lws_server_socket_service_ssl(wsi, |
648 | 0 | LWS_SOCK_INVALID, |
649 | 0 | !!(pollfd->revents & LWS_POLLIN))) |
650 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
651 | | |
652 | 0 | return LWS_HPI_RET_HANDLED; |
653 | 0 | } |
654 | 0 | #endif |
655 | | |
656 | 0 | #if defined(LWS_WITH_CLIENT) |
657 | 0 | if ((pollfd->revents & LWS_POLLIN) && |
658 | 0 | wsi->hdr_parsing_completed && !wsi->told_user_closed) { |
659 | | |
660 | | /* |
661 | | * In SSL mode we get POLLIN notification about |
662 | | * encrypted data in. |
663 | | * |
664 | | * But that is not necessarily related to decrypted |
665 | | * data out becoming available; in may need to perform |
666 | | * other in or out before that happens. |
667 | | * |
668 | | * simply mark ourselves as having readable data |
669 | | * and turn off our POLLIN |
670 | | */ |
671 | 0 | wsi->client_rx_avail = 1; |
672 | 0 | if (lws_change_pollfd(wsi, LWS_POLLIN, 0)) |
673 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
674 | | |
675 | | //lwsl_notice("calling back %s\n", wsi->a.protocol->name); |
676 | | |
677 | | /* let user code know, he'll usually ask for writeable |
678 | | * callback and drain / re-enable it there |
679 | | */ |
680 | 0 | if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi, |
681 | 0 | LWS_CALLBACK_RECEIVE_CLIENT_HTTP, |
682 | 0 | wsi->user_space, NULL, 0)) { |
683 | 0 | lwsl_info("RECEIVE_CLIENT_HTTP closed it\n"); |
684 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
685 | 0 | } |
686 | | |
687 | 0 | return LWS_HPI_RET_HANDLED; |
688 | 0 | } |
689 | 0 | #endif |
690 | | |
691 | | // if (lwsi_state(wsi) == LRS_ESTABLISHED) |
692 | | // return LWS_HPI_RET_HANDLED; |
693 | | |
694 | 0 | #if defined(LWS_WITH_CLIENT) |
695 | 0 | if ((pollfd->revents & LWS_POLLOUT) && |
696 | 0 | lws_handle_POLLOUT_event(wsi, pollfd)) { |
697 | 0 | lwsl_debug("POLLOUT event closed it\n"); |
698 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
699 | 0 | } |
700 | | |
701 | 0 | if (lws_http_client_socket_service(wsi, pollfd)) |
702 | 0 | return LWS_HPI_RET_WSI_ALREADY_DIED; |
703 | 0 | #endif |
704 | | |
705 | 0 | if (lwsi_state(wsi) == LRS_WAITING_CONNECT && |
706 | 0 | (pollfd->revents & LWS_POLLHUP)) |
707 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
708 | | |
709 | 0 | return LWS_HPI_RET_HANDLED; |
710 | 0 | } |
711 | | |
712 | | static lws_handling_result_t |
713 | | rops_handle_POLLOUT_h1(struct lws *wsi) |
714 | 0 | { |
715 | | |
716 | |
|
717 | 0 | if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY || |
718 | 0 | lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY) { |
719 | | #if defined(LWS_WITH_HTTP_PROXY) |
720 | | if (wsi->http.proxy_clientside) { |
721 | | unsigned char *buf, prebuf[LWS_PRE + 1024]; |
722 | | size_t len = lws_buflist_next_segment_len( |
723 | | &wsi->parent->http.buflist_post_body, &buf); |
724 | | int n; |
725 | | |
726 | | if (len > sizeof(prebuf) - LWS_PRE) |
727 | | len = sizeof(prebuf) - LWS_PRE; |
728 | | |
729 | | if (len) { |
730 | | memcpy(prebuf + LWS_PRE, buf, len); |
731 | | |
732 | | lwsl_debug("%s: %s: proxying body %d %d %d %d %d\n", |
733 | | __func__, lws_wsi_tag(wsi), (int)len, |
734 | | (int)wsi->http.tx_content_length, |
735 | | (int)wsi->http.tx_content_remain, |
736 | | (int)wsi->http.rx_content_length, |
737 | | (int)wsi->http.rx_content_remain |
738 | | ); |
739 | | |
740 | | n = lws_write(wsi, prebuf + LWS_PRE, len, LWS_WRITE_HTTP); |
741 | | if (n < 0) { |
742 | | lwsl_err("%s: PROXY_BODY: write %d failed\n", |
743 | | __func__, (int)len); |
744 | | return LWS_HP_RET_BAIL_DIE; |
745 | | } |
746 | | |
747 | | lws_buflist_use_segment(&wsi->parent->http.buflist_post_body, len); |
748 | | |
749 | | } |
750 | | |
751 | | if (wsi->parent->http.buflist_post_body) { |
752 | | lws_callback_on_writable(wsi); |
753 | | return LWS_HP_RET_DROP_POLLOUT; |
754 | | } |
755 | | |
756 | | lwsl_wsi_info(wsi, "nothing to send"); |
757 | | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) |
758 | | /* prepare ourselves to do the parsing */ |
759 | | wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART; |
760 | | wsi->http.ah->lextable_pos = 0; |
761 | | #if defined(LWS_WITH_CUSTOM_HEADERS) |
762 | | wsi->http.ah->unk_pos = 0; |
763 | | #endif |
764 | | #endif |
765 | | lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY); |
766 | | lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, |
767 | | (int)wsi->a.context->timeout_secs); |
768 | | |
769 | | return LWS_HP_RET_DROP_POLLOUT; |
770 | | } |
771 | | #endif |
772 | 0 | return LWS_HP_RET_USER_SERVICE; |
773 | 0 | } |
774 | | |
775 | 0 | if (lwsi_role_client(wsi)) |
776 | 0 | return LWS_HP_RET_USER_SERVICE; |
777 | | |
778 | 0 | return LWS_HP_RET_BAIL_OK; |
779 | 0 | } |
780 | | |
781 | | static int |
782 | | rops_write_role_protocol_h1(struct lws *wsi, unsigned char *buf, size_t len, |
783 | | enum lws_write_protocol *wp) |
784 | 0 | { |
785 | 0 | size_t olen = len; |
786 | 0 | int n; |
787 | |
|
788 | | #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) |
789 | | if (wsi->http.lcs && (((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL || |
790 | | ((*wp) & 0x1f) == LWS_WRITE_HTTP)) { |
791 | | unsigned char mtubuf[1500 + LWS_PRE + |
792 | | LWS_HTTP_CHUNK_HDR_MAX_SIZE + |
793 | | LWS_HTTP_CHUNK_TRL_MAX_SIZE], |
794 | | *out = mtubuf + LWS_PRE + |
795 | | LWS_HTTP_CHUNK_HDR_MAX_SIZE; |
796 | | size_t o = sizeof(mtubuf) - LWS_PRE - |
797 | | LWS_HTTP_CHUNK_HDR_MAX_SIZE - |
798 | | LWS_HTTP_CHUNK_TRL_MAX_SIZE; |
799 | | |
800 | | n = lws_http_compression_transform(wsi, buf, len, wp, &out, &o); |
801 | | if (n) |
802 | | return n; |
803 | | |
804 | | lwsl_info("%s: %s: transformed %d bytes to %d " |
805 | | "(wp 0x%x, more %d)\n", __func__, |
806 | | lws_wsi_tag(wsi), (int)len, |
807 | | (int)o, (int)*wp, wsi->http.comp_ctx.may_have_more); |
808 | | |
809 | | if (!o) |
810 | | return (int)olen; |
811 | | |
812 | | if (wsi->http.comp_ctx.chunking) { |
813 | | char c[LWS_HTTP_CHUNK_HDR_MAX_SIZE + 2]; |
814 | | /* |
815 | | * this only needs dealing with on http/1.1 to allow |
816 | | * pipelining |
817 | | */ |
818 | | n = lws_snprintf(c, sizeof(c), "%X\x0d\x0a", (int)o); |
819 | | lwsl_info("%s: chunk (%d) %s", __func__, (int)o, c); |
820 | | out -= n; |
821 | | o += (unsigned int)n; |
822 | | memcpy(out, c, (unsigned int)n); |
823 | | out[o++] = '\x0d'; |
824 | | out[o++] = '\x0a'; |
825 | | |
826 | | if (((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL) { |
827 | | lwsl_info("%s: final chunk\n", __func__); |
828 | | out[o++] = '0'; |
829 | | out[o++] = '\x0d'; |
830 | | out[o++] = '\x0a'; |
831 | | out[o++] = '\x0d'; |
832 | | out[o++] = '\x0a'; |
833 | | } |
834 | | } |
835 | | |
836 | | buf = out; |
837 | | len = o; |
838 | | } |
839 | | #endif |
840 | |
|
841 | 0 | n = lws_issue_raw(wsi, (unsigned char *)buf, len); |
842 | 0 | if (n < 0) |
843 | 0 | return n; |
844 | | |
845 | | /* hide there may have been compression */ |
846 | | |
847 | 0 | return (int)olen; |
848 | 0 | } |
849 | | |
850 | | static int |
851 | | rops_alpn_negotiated_h1(struct lws *wsi, const char *alpn) |
852 | 0 | { |
853 | 0 | lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi)); |
854 | 0 | #if defined(LWS_WITH_CLIENT) |
855 | 0 | if (lwsi_role_client(wsi)) { |
856 | | /* |
857 | | * If alpn asserts it is http/1.1, server support for KA is |
858 | | * mandatory. |
859 | | * |
860 | | * Knowing this lets us proceed with sending pipelined headers |
861 | | * before we received the first response headers. |
862 | | */ |
863 | 0 | wsi->keepalive_active = 1; |
864 | 0 | } |
865 | 0 | #endif |
866 | |
|
867 | 0 | return 0; |
868 | 0 | } |
869 | | |
870 | | static int |
871 | | rops_destroy_role_h1(struct lws *wsi) |
872 | 0 | { |
873 | 0 | struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; |
874 | 0 | struct allocated_headers *ah; |
875 | | |
876 | | /* we may not have an ah, but may be on the waiting list... */ |
877 | 0 | lwsl_info("%s: ah det due to close\n", __func__); |
878 | 0 | __lws_header_table_detach(wsi, 0); |
879 | |
|
880 | 0 | ah = pt->http.ah_list; |
881 | |
|
882 | 0 | while (ah) { |
883 | 0 | if (ah->in_use && ah->wsi == wsi) { |
884 | 0 | lwsl_err("%s: ah leak: wsi %s\n", __func__, |
885 | 0 | lws_wsi_tag(wsi)); |
886 | 0 | ah->in_use = 0; |
887 | 0 | ah->wsi = NULL; |
888 | 0 | pt->http.ah_count_in_use--; |
889 | 0 | break; |
890 | 0 | } |
891 | 0 | ah = ah->next; |
892 | 0 | } |
893 | |
|
894 | | #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) |
895 | | lws_http_compression_destroy(wsi); |
896 | | #endif |
897 | |
|
898 | 0 | #ifdef LWS_ROLE_WS |
899 | 0 | lws_free_set_NULL(wsi->ws); |
900 | 0 | #endif |
901 | 0 | return 0; |
902 | 0 | } |
903 | | |
904 | | #if defined(LWS_WITH_SERVER) |
905 | | |
906 | | static int |
907 | | rops_adoption_bind_h1(struct lws *wsi, int type, const char *vh_prot_name) |
908 | 0 | { |
909 | 0 | if (!(type & LWS_ADOPT_HTTP)) |
910 | 0 | return 0; /* no match */ |
911 | | |
912 | 0 | if (type & _LWS_ADOPT_FINISH && !lwsi_role_http(wsi)) |
913 | 0 | return 0; |
914 | | |
915 | 0 | if (type & _LWS_ADOPT_FINISH) { |
916 | 0 | if (!lws_header_table_attach(wsi, 0)) |
917 | 0 | lwsl_debug("Attached ah immediately\n"); |
918 | 0 | else |
919 | 0 | lwsl_info("%s: waiting for ah\n", __func__); |
920 | |
|
921 | 0 | return 1; |
922 | 0 | } |
923 | | |
924 | 0 | #if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS) |
925 | 0 | if (wsi->a.vhost->ss_handle && |
926 | 0 | wsi->a.vhost->ss_handle->policy->protocol == LWSSSP_RAW) { |
927 | 0 | lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ? |
928 | 0 | LRS_SSL_INIT : LRS_ESTABLISHED, &role_ops_raw_skt); |
929 | 0 | return 1; |
930 | 0 | } |
931 | 0 | #endif |
932 | | |
933 | | /* If Non-TLS and HTTP2 prior knowledge is enabled, skip to clear text HTTP2 */ |
934 | | |
935 | 0 | #if defined(LWS_WITH_HTTP2) |
936 | 0 | if ((!(type & LWS_ADOPT_ALLOW_SSL)) && (wsi->a.vhost->options & LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE)) { |
937 | 0 | lwsl_info("http/2 prior knowledge\n"); |
938 | 0 | lws_metrics_tag_wsi_add(wsi, "upg", "h2_prior"); |
939 | 0 | lws_role_call_alpn_negotiated(wsi, "h2"); |
940 | 0 | } |
941 | 0 | else |
942 | 0 | #endif |
943 | 0 | lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ? |
944 | 0 | LRS_SSL_INIT : LRS_HEADERS, &role_ops_h1); |
945 | | |
946 | | /* |
947 | | * Otherwise, we have to bind to h1 as a default even when we're actually going to |
948 | | * replace it as an h2 bind later. So don't take this seriously if the |
949 | | * default is disabled (ws upgrade caees properly about it) |
950 | | */ |
951 | |
|
952 | 0 | if (!vh_prot_name && wsi->a.vhost->default_protocol_index < |
953 | 0 | wsi->a.vhost->count_protocols) |
954 | 0 | wsi->a.protocol = &wsi->a.vhost->protocols[ |
955 | 0 | wsi->a.vhost->default_protocol_index]; |
956 | 0 | else |
957 | 0 | wsi->a.protocol = &wsi->a.vhost->protocols[0]; |
958 | | |
959 | | /* the transport is accepted... give him time to negotiate */ |
960 | 0 | lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, |
961 | 0 | (int)wsi->a.context->timeout_secs); |
962 | |
|
963 | 0 | return 1; /* bound */ |
964 | 0 | } |
965 | | |
966 | | #endif |
967 | | |
968 | | #if defined(LWS_WITH_CLIENT) |
969 | | |
970 | | static const char * const http_methods[] = { |
971 | | "GET", "POST", "OPTIONS", "HEAD", "PUT", "PATCH", "DELETE", "CONNECT" |
972 | | }; |
973 | | |
974 | | int |
975 | | _lws_is_http_method(const char *method) |
976 | 0 | { |
977 | 0 | if (method) |
978 | 0 | for (int n = 0; n < (int)LWS_ARRAY_SIZE(http_methods); n++) |
979 | 0 | if (!strcmp(method, http_methods[n])) |
980 | 0 | return 1; |
981 | | |
982 | 0 | return 0; |
983 | 0 | } |
984 | | |
985 | | static int |
986 | | rops_client_bind_h1(struct lws *wsi, const struct lws_client_connect_info *i) |
987 | 0 | { |
988 | 0 | if (!i) { |
989 | | /* we are finalizing an already-selected role */ |
990 | | |
991 | | /* |
992 | | * If we stay in http, assuming there wasn't already-set |
993 | | * external user_space, since we know our initial protocol |
994 | | * we can assign the user space now, otherwise do it after the |
995 | | * ws subprotocol negotiated |
996 | | */ |
997 | 0 | if (!wsi->user_space && wsi->stash->cis[CIS_METHOD]) |
998 | 0 | if (lws_ensure_user_space(wsi)) |
999 | 0 | return 1; |
1000 | | |
1001 | | /* |
1002 | | * For ws, default to http/1.1 only. If i->alpn had been set |
1003 | | * though, defer to whatever he has set in there (eg, "h2"). |
1004 | | * |
1005 | | * The problem is he has to commit to h2 before he can find |
1006 | | * out if the server has the SETTINGS for ws-over-h2 enabled; |
1007 | | * if not then ws is not possible on that connection. So we |
1008 | | * only try h2 if he assertively said to use h2 alpn, otherwise |
1009 | | * ws implies alpn restriction to h1. |
1010 | | */ |
1011 | 0 | if (!wsi->stash->cis[CIS_METHOD] && !wsi->stash->cis[CIS_ALPN]) |
1012 | 0 | wsi->stash->cis[CIS_ALPN] = "http/1.1"; |
1013 | | |
1014 | | /* if we went on the ah waiting list, it's ok, we can wait. |
1015 | | * |
1016 | | * When we do get the ah, now or later, he will end up at |
1017 | | * lws_http_client_connect_via_info2(). |
1018 | | */ |
1019 | 0 | if (lws_header_table_attach(wsi, 0) |
1020 | 0 | #if defined(LWS_WITH_CLIENT) |
1021 | 0 | < 0) |
1022 | | /* |
1023 | | * if we failed here, the connection is already closed |
1024 | | * and freed. |
1025 | | */ |
1026 | 0 | return -1; |
1027 | | #else |
1028 | | ) |
1029 | | return 0; |
1030 | | #endif |
1031 | | |
1032 | 0 | return 0; |
1033 | 0 | } |
1034 | | |
1035 | | /* |
1036 | | * Clients that want to be h1, h2, or ws all start out as h1 |
1037 | | * (we don't yet know if the server supports h2 or ws), unless their |
1038 | | * alpn is only "h2" |
1039 | | */ |
1040 | | |
1041 | | // if (i->alpn && !strcmp(i->alpn, "h2")) |
1042 | | // return 0; /* we are h1, he only wants h2 */ |
1043 | | |
1044 | 0 | if (!i->method) { /* websockets */ |
1045 | 0 | #if defined(LWS_ROLE_WS) |
1046 | 0 | if (lws_create_client_ws_object(i, wsi)) |
1047 | 0 | goto fail_wsi; |
1048 | | |
1049 | 0 | goto bind_h1; |
1050 | | #else |
1051 | | lwsl_err("%s: ws role not configured\n", __func__); |
1052 | | |
1053 | | goto fail_wsi; |
1054 | | #endif |
1055 | 0 | } |
1056 | | |
1057 | | /* if a recognized http method, bind to it */ |
1058 | 0 | if (_lws_is_http_method(i->method)) |
1059 | 0 | goto bind_h1; |
1060 | | |
1061 | | /* other roles may bind to it */ |
1062 | | |
1063 | 0 | return 0; /* no match */ |
1064 | | |
1065 | 0 | bind_h1: |
1066 | | /* assert the mode and union status (hdr) clearly */ |
1067 | 0 | lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED, &role_ops_h1); |
1068 | |
|
1069 | 0 | return 1; /* matched */ |
1070 | | |
1071 | 0 | fail_wsi: |
1072 | 0 | return -1; |
1073 | 0 | } |
1074 | | #endif |
1075 | | |
1076 | | static int |
1077 | | rops_close_kill_connection_h1(struct lws *wsi, enum lws_close_status reason) |
1078 | 0 | { |
1079 | | #if defined(LWS_WITH_HTTP_PROXY) |
1080 | | if (!wsi->http.proxy_clientside) |
1081 | | return 0; |
1082 | | |
1083 | | wsi->http.proxy_clientside = 0; |
1084 | | |
1085 | | if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi, |
1086 | | LWS_CALLBACK_COMPLETED_CLIENT_HTTP, |
1087 | | wsi->user_space, NULL, 0)) |
1088 | | return 0; |
1089 | | #endif |
1090 | 0 | return 0; |
1091 | 0 | } |
1092 | | |
1093 | | int |
1094 | | rops_pt_init_destroy_h1(struct lws_context *context, |
1095 | | const struct lws_context_creation_info *info, |
1096 | | struct lws_context_per_thread *pt, int destroy) |
1097 | 0 | { |
1098 | | /* |
1099 | | * We only want to do this once... we will do it if no h2 support |
1100 | | * otherwise let h2 ops do it. |
1101 | | */ |
1102 | | #if !defined(LWS_ROLE_H2) && defined(LWS_WITH_SERVER) |
1103 | | if (!destroy) { |
1104 | | |
1105 | | pt->sul_ah_lifecheck.cb = lws_sul_http_ah_lifecheck; |
1106 | | |
1107 | | __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], |
1108 | | &pt->sul_ah_lifecheck, 30 * LWS_US_PER_SEC); |
1109 | | } else |
1110 | | lws_dll2_remove(&pt->sul_ah_lifecheck.list); |
1111 | | #endif |
1112 | |
|
1113 | 0 | return 0; |
1114 | 0 | } |
1115 | | |
1116 | | static const lws_rops_t rops_table_h1[] = { |
1117 | | /* 1 */ { .pt_init_destroy = rops_pt_init_destroy_h1 }, |
1118 | | /* 2 */ { .handle_POLLIN = rops_handle_POLLIN_h1 }, |
1119 | | /* 3 */ { .handle_POLLOUT = rops_handle_POLLOUT_h1 }, |
1120 | | /* 4 */ { .write_role_protocol = rops_write_role_protocol_h1 }, |
1121 | | /* 5 */ { .alpn_negotiated = rops_alpn_negotiated_h1 }, |
1122 | | /* 6 */ { .close_kill_connection = rops_close_kill_connection_h1 }, |
1123 | | /* 7 */ { .destroy_role = rops_destroy_role_h1 }, |
1124 | | #if defined(LWS_WITH_SERVER) |
1125 | | /* 8 */ { .adoption_bind = rops_adoption_bind_h1 }, |
1126 | | #endif |
1127 | | #if defined(LWS_WITH_CLIENT) |
1128 | | /* 8 if client and no server */ |
1129 | | /* 9 */ { .client_bind = rops_client_bind_h1 }, |
1130 | | #endif |
1131 | | }; |
1132 | | |
1133 | | const struct lws_role_ops role_ops_h1 = { |
1134 | | /* role name */ "h1", |
1135 | | /* alpn id */ "http/1.1", |
1136 | | /* rops_table */ rops_table_h1, |
1137 | | /* rops_idx */ { |
1138 | | /* LWS_ROPS_check_upgrades */ |
1139 | | /* LWS_ROPS_pt_init_destroy */ 0x01, |
1140 | | /* LWS_ROPS_init_vhost */ |
1141 | | /* LWS_ROPS_destroy_vhost */ 0x00, |
1142 | | /* LWS_ROPS_service_flag_pending */ |
1143 | | /* LWS_ROPS_handle_POLLIN */ 0x02, |
1144 | | /* LWS_ROPS_handle_POLLOUT */ |
1145 | | /* LWS_ROPS_perform_user_POLLOUT */ 0x30, |
1146 | | /* LWS_ROPS_callback_on_writable */ |
1147 | | /* LWS_ROPS_tx_credit */ 0x00, |
1148 | | /* LWS_ROPS_write_role_protocol */ |
1149 | | /* LWS_ROPS_encapsulation_parent */ 0x40, |
1150 | | /* LWS_ROPS_alpn_negotiated */ |
1151 | | /* LWS_ROPS_close_via_role_protocol */ 0x50, |
1152 | | /* LWS_ROPS_close_role */ |
1153 | | /* LWS_ROPS_close_kill_connection */ 0x06, |
1154 | | /* LWS_ROPS_destroy_role */ |
1155 | | #if defined(LWS_WITH_SERVER) |
1156 | | /* LWS_ROPS_adoption_bind */ 0x78, |
1157 | | #else |
1158 | | /* LWS_ROPS_adoption_bind */ 0x70, |
1159 | | #endif |
1160 | | /* LWS_ROPS_client_bind */ |
1161 | | #if defined(LWS_WITH_CLIENT) |
1162 | | #if defined(LWS_WITH_SERVER) |
1163 | | /* LWS_ROPS_issue_keepalive */ 0x90, |
1164 | | #else |
1165 | | /* LWS_ROPS_issue_keepalive */ 0x80, |
1166 | | #endif |
1167 | | #else |
1168 | | /* LWS_ROPS_issue_keepalive */ 0x00, |
1169 | | #endif |
1170 | | }, |
1171 | | /* adoption_cb clnt, srv */ { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, |
1172 | | LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED }, |
1173 | | /* rx_cb clnt, srv */ { LWS_CALLBACK_RECEIVE_CLIENT_HTTP, |
1174 | | 0 /* may be POST, etc */ }, |
1175 | | /* writeable cb clnt, srv */ { LWS_CALLBACK_CLIENT_HTTP_WRITEABLE, |
1176 | | LWS_CALLBACK_HTTP_WRITEABLE }, |
1177 | | /* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP, |
1178 | | LWS_CALLBACK_CLOSED_HTTP }, |
1179 | | /* protocol_bind cb c, srv */ { LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL, |
1180 | | LWS_CALLBACK_HTTP_BIND_PROTOCOL }, |
1181 | | /* protocol_unbind cb c, srv */ { LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL, |
1182 | | LWS_CALLBACK_HTTP_DROP_PROTOCOL }, |
1183 | | /* file_handle */ 0, |
1184 | | }; |