/src/libwebsockets/lib/roles/h1/ops-h1.c
Line | Count | Source |
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 | wsi->http.deferred_transaction_completed) |
339 | 0 | goto try_pollout; |
340 | | |
341 | | /* any incoming data ready? */ |
342 | | |
343 | 0 | if (!(pollfd->revents & pollfd->events & LWS_POLLIN)) |
344 | 0 | goto try_pollout; |
345 | | |
346 | | /* |
347 | | * If we previously just did POLLIN when IN and OUT were signaled |
348 | | * (because POLLIN processing may have used up the POLLOUT), don't let |
349 | | * that happen twice in a row... next time we see the situation favour |
350 | | * POLLOUT |
351 | | */ |
352 | | |
353 | 0 | if (wsi->favoured_pollin && |
354 | 0 | (pollfd->revents & pollfd->events & LWS_POLLOUT)) { |
355 | | // lwsl_notice("favouring pollout\n"); |
356 | 0 | wsi->favoured_pollin = 0; |
357 | 0 | goto try_pollout; |
358 | 0 | } |
359 | | |
360 | | /* |
361 | | * We haven't processed that the tunnel is set up yet, so |
362 | | * defer reading |
363 | | */ |
364 | | |
365 | 0 | if (lwsi_state(wsi) == LRS_SSL_ACK_PENDING) |
366 | 0 | return LWS_HPI_RET_HANDLED; |
367 | | |
368 | | /* these states imply we MUST have an ah attached */ |
369 | | |
370 | 0 | if ((lwsi_state(wsi) == LRS_ESTABLISHED || |
371 | 0 | lwsi_state(wsi) == LRS_ISSUING_FILE || |
372 | 0 | lwsi_state(wsi) == LRS_HEADERS || |
373 | 0 | lwsi_state(wsi) == LRS_DOING_TRANSACTION || /* at least, SSE */ |
374 | 0 | lwsi_state(wsi) == LRS_DISCARD_BODY || |
375 | 0 | lwsi_state(wsi) == LRS_BODY)) { |
376 | |
|
377 | 0 | if (!wsi->http.ah && lws_header_table_attach(wsi, 0)) { |
378 | 0 | lwsl_info("%s: %s: ah not available\n", __func__, |
379 | 0 | lws_wsi_tag(wsi)); |
380 | 0 | goto try_pollout; |
381 | 0 | } |
382 | | |
383 | | /* |
384 | | * We got here because there was specifically POLLIN... |
385 | | * regardless of our buflist state, we need to get it, |
386 | | * and either use it, or append to the buflist and use |
387 | | * buflist head material. |
388 | | * |
389 | | * We will not notice a connection close until the buflist is |
390 | | * exhausted and we tried to do a read of some kind. |
391 | | */ |
392 | | |
393 | 0 | ebuf.token = NULL; |
394 | 0 | ebuf.len = 0; |
395 | 0 | buffered = lws_buflist_aware_read(pt, wsi, &ebuf, 0, __func__); |
396 | 0 | switch (ebuf.len) { |
397 | 0 | case 0: |
398 | 0 | lwsl_info("%s: read 0 len a\n", __func__); |
399 | 0 | wsi->seen_zero_length_recv = 1; |
400 | 0 | if (lws_change_pollfd(wsi, LWS_POLLIN, 0)) |
401 | 0 | goto fail; |
402 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
403 | | /* |
404 | | * autobahn requires us to win the race between close |
405 | | * and draining the extensions |
406 | | */ |
407 | | if (wsi->ws && |
408 | | (wsi->ws->rx_draining_ext || |
409 | | wsi->ws->tx_draining_ext)) |
410 | | goto try_pollout; |
411 | | #endif |
412 | | /* |
413 | | * normally, we respond to close with logically closing |
414 | | * our side immediately |
415 | | */ |
416 | 0 | goto fail; |
417 | | |
418 | 0 | case LWS_SSL_CAPABLE_ERROR: |
419 | 0 | goto fail; |
420 | 0 | case LWS_SSL_CAPABLE_MORE_SERVICE: |
421 | 0 | goto try_pollout; |
422 | 0 | } |
423 | | |
424 | | /* just ignore incoming if waiting for close */ |
425 | 0 | if (lwsi_state(wsi) == LRS_FLUSHING_BEFORE_CLOSE) { |
426 | 0 | lwsl_notice("%s: just ignoring\n", __func__); |
427 | 0 | goto try_pollout; |
428 | 0 | } |
429 | | |
430 | 0 | if (lwsi_state(wsi) == LRS_ISSUING_FILE) { |
431 | | // lwsl_notice("stashing: wsi %p: bd %d\n", wsi, buffered); |
432 | 0 | if (lws_buflist_aware_finished_consuming(wsi, &ebuf, 0, |
433 | 0 | buffered, __func__)) |
434 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
435 | | |
436 | 0 | goto try_pollout; |
437 | 0 | } |
438 | | |
439 | | /* |
440 | | * Otherwise give it to whoever wants it according to the |
441 | | * connection state |
442 | | */ |
443 | | #if defined(LWS_WITH_LATENCY) |
444 | | lws_usec_t _h1_read_start = lws_now_usecs(); |
445 | | #endif |
446 | 0 | #if defined(LWS_ROLE_H2) |
447 | 0 | if (lwsi_role_h2(wsi) && lwsi_state(wsi) != LRS_BODY) |
448 | 0 | n = lws_read_h2(wsi, ebuf.token, (unsigned int)ebuf.len); |
449 | 0 | else |
450 | 0 | #endif |
451 | 0 | n = lws_read_h1(wsi, ebuf.token, (unsigned int)ebuf.len); |
452 | |
|
453 | | #if defined(LWS_WITH_LATENCY) |
454 | | { |
455 | | unsigned int ms = (unsigned int)((lws_now_usecs() - _h1_read_start) / 1000); |
456 | | if (ms > 2) |
457 | | lws_latency_note(pt, _h1_read_start, 2000, "h1read:%dms", ms); |
458 | | } |
459 | | #endif |
460 | 0 | if (n < 0) /* we closed wsi */ |
461 | | |
462 | 0 | return LWS_HPI_RET_WSI_ALREADY_DIED; |
463 | | |
464 | | // lwsl_notice("%s: consumed %d\n", __func__, n); |
465 | | |
466 | 0 | if (lws_buflist_aware_finished_consuming(wsi, &ebuf, n, |
467 | 0 | buffered, __func__)) |
468 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
469 | | |
470 | | /* |
471 | | * during the parsing our role changed to something non-http, |
472 | | * so the ah has no further meaning |
473 | | */ |
474 | | |
475 | 0 | if (wsi->http.ah && |
476 | 0 | !lwsi_role_h1(wsi) && |
477 | 0 | !lwsi_role_h2(wsi) && |
478 | 0 | !lwsi_role_cgi(wsi)) |
479 | 0 | lws_header_table_detach(wsi, 0); |
480 | | |
481 | | /* |
482 | | * He may have used up the writability above, if we will defer |
483 | | * POLLOUT processing in favour of POLLIN, note it |
484 | | */ |
485 | |
|
486 | 0 | if (pollfd->revents & LWS_POLLOUT) |
487 | 0 | wsi->favoured_pollin = 1; |
488 | |
|
489 | 0 | return LWS_HPI_RET_HANDLED; |
490 | 0 | } |
491 | | |
492 | | /* |
493 | | * He may have used up the writability above, if we will defer POLLOUT |
494 | | * processing in favour of POLLIN, note it |
495 | | */ |
496 | | |
497 | 0 | if (pollfd->revents & LWS_POLLOUT) |
498 | 0 | wsi->favoured_pollin = 1; |
499 | |
|
500 | 0 | try_pollout: |
501 | | |
502 | | /* this handles POLLOUT for http serving fragments */ |
503 | |
|
504 | 0 | if (!(pollfd->revents & LWS_POLLOUT)) |
505 | 0 | return LWS_HPI_RET_HANDLED; |
506 | | |
507 | | /* one shot */ |
508 | 0 | if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { |
509 | 0 | lwsl_notice("%s a\n", __func__); |
510 | 0 | goto fail; |
511 | 0 | } |
512 | | |
513 | | /* clear back-to-back write detection */ |
514 | 0 | wsi->could_have_pending = 0; |
515 | |
|
516 | 0 | if (lwsi_state(wsi) == LRS_DEFERRING_ACTION) { |
517 | 0 | lwsl_debug("%s: LRS_DEFERRING_ACTION now writable\n", __func__); |
518 | |
|
519 | 0 | lwsi_set_state(wsi, LRS_ESTABLISHED); |
520 | 0 | if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { |
521 | 0 | lwsl_info("failed at set pollfd\n"); |
522 | 0 | goto fail; |
523 | 0 | } |
524 | 0 | } |
525 | | |
526 | 0 | if (!wsi->hdr_parsing_completed) |
527 | 0 | return LWS_HPI_RET_HANDLED; |
528 | | |
529 | 0 | if (lwsi_state(wsi) == LRS_AWAITING_FILE_READ) { |
530 | 0 | return LWS_HPI_RET_HANDLED; |
531 | 0 | } |
532 | | |
533 | 0 | if (lwsi_state(wsi) != LRS_ISSUING_FILE) { |
534 | |
|
535 | 0 | if (lws_has_buffered_out(wsi)) { |
536 | | //lwsl_notice("%s: completing partial\n", __func__); |
537 | 0 | if (lws_issue_raw(wsi, NULL, 0) < 0) { |
538 | 0 | lwsl_info("%s signalling to close\n", __func__); |
539 | 0 | goto fail; |
540 | 0 | } |
541 | 0 | return LWS_HPI_RET_HANDLED; |
542 | 0 | } |
543 | | |
544 | 0 | n = user_callback_handle_rxflow(wsi->a.protocol->callback, wsi, |
545 | 0 | LWS_CALLBACK_HTTP_WRITEABLE, |
546 | 0 | wsi->user_space, NULL, 0); |
547 | 0 | if (n < 0) { |
548 | 0 | lwsl_info("writeable_fail\n"); |
549 | 0 | goto fail; |
550 | 0 | } |
551 | | |
552 | 0 | return LWS_HPI_RET_HANDLED; |
553 | 0 | } |
554 | | |
555 | 0 | #if defined(LWS_WITH_FILE_OPS) |
556 | | |
557 | | /* >0 == completion, <0 == error |
558 | | * |
559 | | * We'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when |
560 | | * it's done. That's the case even if we just completed the |
561 | | * send, so wait for that. |
562 | | */ |
563 | 0 | n = lws_serve_http_file_fragment(wsi); |
564 | 0 | if (n < 0) |
565 | 0 | goto fail; |
566 | 0 | #endif |
567 | | |
568 | 0 | return LWS_HPI_RET_HANDLED; |
569 | | |
570 | | |
571 | 0 | fail: |
572 | 0 | lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, |
573 | 0 | "server socket svc fail"); |
574 | |
|
575 | 0 | return LWS_HPI_RET_WSI_ALREADY_DIED; |
576 | 0 | } |
577 | | #endif |
578 | | |
579 | | static lws_handling_result_t |
580 | | rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi, |
581 | | struct lws_pollfd *pollfd) |
582 | 0 | { |
583 | 0 | if (lwsi_state(wsi) == LRS_IDLING) { |
584 | 0 | uint8_t buf[1]; |
585 | 0 | int rlen; |
586 | | |
587 | | /* |
588 | | * h1 staggered spins here in IDLING if we don't close it. |
589 | | * It shows POLLIN but the tls connection returns ERROR if |
590 | | * you try to read it. |
591 | | */ |
592 | | |
593 | | // lwsl_notice("%s: %p: wsistate 0x%x %s, revents 0x%x\n", |
594 | | // __func__, wsi, wsi->wsistate, wsi->role_ops->name, |
595 | | // pollfd->revents); |
596 | |
|
597 | 0 | rlen = lws_ssl_capable_read(wsi, buf, sizeof(buf)); |
598 | 0 | if (rlen == LWS_SSL_CAPABLE_ERROR) |
599 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
600 | 0 | } |
601 | | |
602 | | #ifdef LWS_WITH_CGI |
603 | | if (wsi->http.cgi && (pollfd->revents & LWS_POLLOUT)) { |
604 | | if (lws_handle_POLLOUT_event(wsi, pollfd)) |
605 | | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
606 | | |
607 | | return LWS_HPI_RET_HANDLED; |
608 | | } |
609 | | #endif |
610 | | |
611 | | /* Priority 2: pre- compression transform */ |
612 | | |
613 | | #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) |
614 | | if (wsi->http.comp_ctx.buflist_comp || |
615 | | wsi->http.comp_ctx.may_have_more) { |
616 | | enum lws_write_protocol wp = LWS_WRITE_HTTP; |
617 | | |
618 | | lwsl_info("%s: completing comp partial (buflist_comp %p, may %d)\n", |
619 | | __func__, wsi->http.comp_ctx.buflist_comp, |
620 | | wsi->http.comp_ctx.may_have_more |
621 | | ); |
622 | | |
623 | | if (lws_rops_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol) && |
624 | | lws_rops_func_fidx(wsi->role_ops, LWS_ROPS_write_role_protocol). |
625 | | write_role_protocol(wsi, NULL, 0, &wp) < 0) { |
626 | | lwsl_info("%s signalling to close\n", __func__); |
627 | | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
628 | | } |
629 | | lws_callback_on_writable(wsi); |
630 | | |
631 | | if (!wsi->http.comp_ctx.buflist_comp && |
632 | | !wsi->http.comp_ctx.may_have_more && |
633 | | wsi->http.deferred_transaction_completed) { |
634 | | wsi->http.deferred_transaction_completed = 0; |
635 | | if (lws_http_transaction_completed(wsi)) |
636 | | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
637 | | } |
638 | | |
639 | | return LWS_HPI_RET_HANDLED; |
640 | | } |
641 | | #endif |
642 | | |
643 | 0 | if (lws_is_flowcontrolled(wsi)) |
644 | | /* We cannot deal with any kind of new RX because we are |
645 | | * RX-flowcontrolled. |
646 | | */ |
647 | 0 | return LWS_HPI_RET_HANDLED; |
648 | | |
649 | 0 | #if defined(LWS_WITH_SERVER) |
650 | 0 | if (!lwsi_role_client(wsi)) { |
651 | 0 | lws_handling_result_t hr; |
652 | |
|
653 | 0 | lwsl_debug("%s: %s: wsistate 0x%x\n", __func__, lws_wsi_tag(wsi), |
654 | 0 | (unsigned int)wsi->wsistate); |
655 | |
|
656 | 0 | if (pollfd->revents & LWS_POLLHUP && |
657 | 0 | !lws_buflist_total_len(&wsi->buflist)) |
658 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
659 | | |
660 | | #if defined(LWS_WITH_LATENCY) |
661 | | lws_usec_t _h1s_start = lws_now_usecs(); |
662 | | #endif |
663 | | |
664 | 0 | hr = lws_h1_server_socket_service(wsi, pollfd); |
665 | |
|
666 | | #if defined(LWS_WITH_LATENCY) |
667 | | { |
668 | | unsigned int ms = (unsigned int)((lws_now_usecs() - _h1s_start) / 1000); |
669 | | if (ms > 2) |
670 | | lws_latency_note(pt, _h1s_start, 2000, "h1sv:%dms", ms); |
671 | | } |
672 | | #endif |
673 | |
|
674 | 0 | if (hr != LWS_HPI_RET_HANDLED) |
675 | 0 | return hr; |
676 | 0 | if (lwsi_state(wsi) != LRS_SSL_INIT) |
677 | 0 | if (lws_server_socket_service_ssl(wsi, |
678 | 0 | LWS_SOCK_INVALID, |
679 | 0 | !!(pollfd->revents & LWS_POLLIN))) |
680 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
681 | | |
682 | 0 | return LWS_HPI_RET_HANDLED; |
683 | 0 | } |
684 | 0 | #endif |
685 | | |
686 | 0 | #if defined(LWS_WITH_CLIENT) |
687 | 0 | if ((pollfd->revents & LWS_POLLIN) && |
688 | 0 | wsi->hdr_parsing_completed && !wsi->told_user_closed) { |
689 | | |
690 | | /* |
691 | | * In SSL mode we get POLLIN notification about |
692 | | * encrypted data in. |
693 | | * |
694 | | * But that is not necessarily related to decrypted |
695 | | * data out becoming available; in may need to perform |
696 | | * other in or out before that happens. |
697 | | * |
698 | | * simply mark ourselves as having readable data |
699 | | * and turn off our POLLIN |
700 | | */ |
701 | 0 | wsi->client_rx_avail = 1; |
702 | 0 | if (lws_change_pollfd(wsi, LWS_POLLIN, 0)) |
703 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
704 | | |
705 | | //lwsl_notice("calling back %s\n", wsi->a.protocol->name); |
706 | | |
707 | | /* let user code know, he'll usually ask for writeable |
708 | | * callback and drain / re-enable it there |
709 | | */ |
710 | 0 | if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi, |
711 | 0 | LWS_CALLBACK_RECEIVE_CLIENT_HTTP, |
712 | 0 | wsi->user_space, NULL, 0)) { |
713 | 0 | lwsl_info("RECEIVE_CLIENT_HTTP closed it\n"); |
714 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
715 | 0 | } |
716 | | |
717 | 0 | return LWS_HPI_RET_HANDLED; |
718 | 0 | } |
719 | 0 | #endif |
720 | | |
721 | | // if (lwsi_state(wsi) == LRS_ESTABLISHED) |
722 | | // return LWS_HPI_RET_HANDLED; |
723 | | |
724 | 0 | #if defined(LWS_WITH_CLIENT) |
725 | 0 | if ((pollfd->revents & LWS_POLLOUT) && |
726 | 0 | lws_handle_POLLOUT_event(wsi, pollfd)) { |
727 | 0 | lwsl_debug("POLLOUT event closed it\n"); |
728 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
729 | 0 | } |
730 | | |
731 | 0 | if (lws_http_client_socket_service(wsi, pollfd)) |
732 | 0 | return LWS_HPI_RET_WSI_ALREADY_DIED; |
733 | 0 | #endif |
734 | | |
735 | 0 | if (lwsi_state(wsi) == LRS_WAITING_CONNECT && |
736 | 0 | (pollfd->revents & LWS_POLLHUP)) |
737 | 0 | return LWS_HPI_RET_PLEASE_CLOSE_ME; |
738 | | |
739 | 0 | return LWS_HPI_RET_HANDLED; |
740 | 0 | } |
741 | | |
742 | | static lws_handling_result_t |
743 | | rops_handle_POLLOUT_h1(struct lws *wsi) |
744 | 0 | { |
745 | | |
746 | |
|
747 | 0 | if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY || |
748 | 0 | lwsi_state(wsi) == LRS_WAITING_SERVER_REPLY) { |
749 | | #if defined(LWS_WITH_HTTP_PROXY) |
750 | | if (wsi->http.proxy_clientside) { |
751 | | unsigned char *buf, prebuf[LWS_PRE + 1024]; |
752 | | size_t len = lws_buflist_next_segment_len( |
753 | | &wsi->parent->http.buflist_post_body, &buf); |
754 | | int n; |
755 | | |
756 | | if (len > sizeof(prebuf) - LWS_PRE) |
757 | | len = sizeof(prebuf) - LWS_PRE; |
758 | | |
759 | | if (len) { |
760 | | memcpy(prebuf + LWS_PRE, buf, len); |
761 | | |
762 | | lwsl_debug("%s: %s: proxying body %d %d %d %d %d\n", |
763 | | __func__, lws_wsi_tag(wsi), (int)len, |
764 | | (int)wsi->http.tx_content_length, |
765 | | (int)wsi->http.tx_content_remain, |
766 | | (int)wsi->http.rx_content_length, |
767 | | (int)wsi->http.rx_content_remain |
768 | | ); |
769 | | |
770 | | n = lws_write(wsi, prebuf + LWS_PRE, len, LWS_WRITE_HTTP); |
771 | | if (n < 0) { |
772 | | lwsl_err("%s: PROXY_BODY: write %d failed\n", |
773 | | __func__, (int)len); |
774 | | return LWS_HP_RET_BAIL_DIE; |
775 | | } |
776 | | |
777 | | lws_buflist_use_segment(&wsi->parent->http.buflist_post_body, len); |
778 | | |
779 | | } |
780 | | |
781 | | if (wsi->parent->http.buflist_post_body) { |
782 | | lws_callback_on_writable(wsi); |
783 | | return LWS_HP_RET_DROP_POLLOUT; |
784 | | } |
785 | | |
786 | | lwsl_wsi_info(wsi, "nothing to send"); |
787 | | #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) |
788 | | /* prepare ourselves to do the parsing */ |
789 | | wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART; |
790 | | wsi->http.ah->lextable_pos = 0; |
791 | | #if defined(LWS_WITH_CUSTOM_HEADERS) |
792 | | wsi->http.ah->unk_pos = 0; |
793 | | #endif |
794 | | #endif |
795 | | lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY); |
796 | | lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE, |
797 | | (int)wsi->a.context->timeout_secs); |
798 | | |
799 | | return LWS_HP_RET_DROP_POLLOUT; |
800 | | } |
801 | | #endif |
802 | 0 | return LWS_HP_RET_USER_SERVICE; |
803 | 0 | } |
804 | | |
805 | 0 | if (lwsi_role_client(wsi)) |
806 | 0 | return LWS_HP_RET_USER_SERVICE; |
807 | | |
808 | 0 | if (lwsi_state(wsi) == LRS_AWAITING_FILE_READ) { |
809 | 0 | return LWS_HP_RET_DROP_POLLOUT; |
810 | 0 | } |
811 | | |
812 | 0 | return LWS_HP_RET_BAIL_OK; |
813 | 0 | } |
814 | | |
815 | | static int |
816 | | rops_write_role_protocol_h1(struct lws *wsi, unsigned char *buf, size_t len, |
817 | | enum lws_write_protocol *wp) |
818 | 0 | { |
819 | 0 | size_t olen = len; |
820 | 0 | int n; |
821 | |
|
822 | | #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) |
823 | | if (wsi->http.lcs && (((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL || |
824 | | ((*wp) & 0x1f) == LWS_WRITE_HTTP)) { |
825 | | unsigned char mtubuf[1500 + LWS_PRE + |
826 | | LWS_HTTP_CHUNK_HDR_MAX_SIZE + |
827 | | LWS_HTTP_CHUNK_TRL_MAX_SIZE], |
828 | | *out = mtubuf + LWS_PRE + |
829 | | LWS_HTTP_CHUNK_HDR_MAX_SIZE; |
830 | | size_t o = sizeof(mtubuf) - LWS_PRE - |
831 | | LWS_HTTP_CHUNK_HDR_MAX_SIZE - |
832 | | LWS_HTTP_CHUNK_TRL_MAX_SIZE; |
833 | | |
834 | | #if defined(LWS_WITH_LATENCY) |
835 | | lws_usec_t _h1comp_start = lws_now_usecs(); |
836 | | #endif |
837 | | |
838 | | n = lws_http_compression_transform(wsi, buf, len, wp, &out, &o); |
839 | | |
840 | | #if defined(LWS_WITH_LATENCY) |
841 | | { |
842 | | unsigned int ms = (unsigned int)((lws_now_usecs() - _h1comp_start) / 1000); |
843 | | if (ms > 2) |
844 | | lws_latency_note((&wsi->a.context->pt[(int)wsi->tsi]), _h1comp_start, 2000, "h1comp:%dms", ms); |
845 | | } |
846 | | #endif |
847 | | |
848 | | if (n) |
849 | | return n; |
850 | | |
851 | | lwsl_info("%s: %s: transformed %d bytes to %d " |
852 | | "(wp 0x%x, more %d)\n", __func__, |
853 | | lws_wsi_tag(wsi), (int)len, |
854 | | (int)o, (int)*wp, wsi->http.comp_ctx.may_have_more); |
855 | | |
856 | | if (!o) |
857 | | return (int)olen; |
858 | | |
859 | | if (wsi->http.comp_ctx.chunking) { |
860 | | char c[LWS_HTTP_CHUNK_HDR_MAX_SIZE + 2]; |
861 | | /* |
862 | | * this only needs dealing with on http/1.1 to allow |
863 | | * pipelining |
864 | | */ |
865 | | n = lws_snprintf(c, sizeof(c), "%X\x0d\x0a", (int)o); |
866 | | lwsl_info("%s: chunk (%d) %s", __func__, (int)o, c); |
867 | | out -= n; |
868 | | o += (unsigned int)n; |
869 | | memcpy(out, c, (unsigned int)n); |
870 | | out[o++] = '\x0d'; |
871 | | out[o++] = '\x0a'; |
872 | | |
873 | | if (((*wp) & 0x1f) == LWS_WRITE_HTTP_FINAL) { |
874 | | lwsl_info("%s: final chunk\n", __func__); |
875 | | out[o++] = '0'; |
876 | | out[o++] = '\x0d'; |
877 | | out[o++] = '\x0a'; |
878 | | out[o++] = '\x0d'; |
879 | | out[o++] = '\x0a'; |
880 | | } |
881 | | } |
882 | | |
883 | | buf = out; |
884 | | len = o; |
885 | | } |
886 | | #endif |
887 | |
|
888 | 0 | n = lws_issue_raw(wsi, (unsigned char *)buf, len); |
889 | 0 | if (n < 0) |
890 | 0 | return n; |
891 | | |
892 | | /* hide there may have been compression */ |
893 | | |
894 | 0 | return (int)olen; |
895 | 0 | } |
896 | | |
897 | | static int |
898 | | rops_alpn_negotiated_h1(struct lws *wsi, const char *alpn) |
899 | 0 | { |
900 | 0 | lwsl_debug("%s: client %d\n", __func__, lwsi_role_client(wsi)); |
901 | 0 | #if defined(LWS_WITH_CLIENT) |
902 | 0 | if (lwsi_role_client(wsi)) { |
903 | | /* |
904 | | * If alpn asserts it is http/1.1, server support for KA is |
905 | | * mandatory. |
906 | | * |
907 | | * Knowing this lets us proceed with sending pipelined headers |
908 | | * before we received the first response headers. |
909 | | */ |
910 | 0 | wsi->keepalive_active = 1; |
911 | 0 | } |
912 | 0 | #endif |
913 | |
|
914 | 0 | return 0; |
915 | 0 | } |
916 | | |
917 | | static int |
918 | | rops_destroy_role_h1(struct lws *wsi) |
919 | 0 | { |
920 | 0 | struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; |
921 | 0 | struct allocated_headers *ah; |
922 | | |
923 | | /* we may not have an ah, but may be on the waiting list... */ |
924 | 0 | lwsl_info("%s: ah det due to close\n", __func__); |
925 | 0 | __lws_header_table_detach(wsi, 0); |
926 | |
|
927 | 0 | ah = pt->http.ah_list; |
928 | |
|
929 | 0 | while (ah) { |
930 | 0 | if (ah->in_use && ah->wsi == wsi) { |
931 | 0 | lwsl_err("%s: ah leak: wsi %s\n", __func__, |
932 | 0 | lws_wsi_tag(wsi)); |
933 | 0 | ah->in_use = 0; |
934 | 0 | ah->wsi = NULL; |
935 | 0 | pt->http.ah_count_in_use--; |
936 | 0 | break; |
937 | 0 | } |
938 | 0 | ah = ah->next; |
939 | 0 | } |
940 | |
|
941 | | #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) |
942 | | lws_http_compression_destroy(wsi); |
943 | | #endif |
944 | |
|
945 | 0 | #ifdef LWS_ROLE_WS |
946 | 0 | lws_free_set_NULL(wsi->ws); |
947 | 0 | #endif |
948 | 0 | return 0; |
949 | 0 | } |
950 | | |
951 | | #if defined(LWS_WITH_SERVER) |
952 | | |
953 | | static int |
954 | | rops_adoption_bind_h1(struct lws *wsi, int type, const char *vh_prot_name) |
955 | 0 | { |
956 | 0 | if (!(type & LWS_ADOPT_HTTP)) |
957 | 0 | return 0; /* no match */ |
958 | | |
959 | 0 | if (type & _LWS_ADOPT_FINISH && !lwsi_role_http(wsi)) |
960 | 0 | return 0; |
961 | | |
962 | 0 | if (type & _LWS_ADOPT_FINISH) { |
963 | 0 | if (!lws_header_table_attach(wsi, 0)) |
964 | 0 | lwsl_debug("Attached ah immediately\n"); |
965 | 0 | else |
966 | 0 | lwsl_info("%s: waiting for ah\n", __func__); |
967 | |
|
968 | 0 | return 1; |
969 | 0 | } |
970 | | |
971 | 0 | #if defined(LWS_WITH_SERVER) && defined(LWS_WITH_SECURE_STREAMS) |
972 | 0 | if (wsi->a.vhost->ss_handle && |
973 | 0 | wsi->a.vhost->ss_handle->policy->protocol == LWSSSP_RAW) { |
974 | 0 | lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ? |
975 | 0 | LRS_SSL_INIT : LRS_ESTABLISHED, &role_ops_raw_skt); |
976 | 0 | return 1; |
977 | 0 | } |
978 | 0 | #endif |
979 | | |
980 | | /* If Non-TLS and HTTP2 prior knowledge is enabled, skip to clear text HTTP2 */ |
981 | | |
982 | 0 | #if defined(LWS_WITH_HTTP2) |
983 | 0 | if ((!(type & LWS_ADOPT_ALLOW_SSL)) && (wsi->a.vhost->options & LWS_SERVER_OPTION_H2_PRIOR_KNOWLEDGE)) { |
984 | 0 | lwsl_info("http/2 prior knowledge\n"); |
985 | 0 | lws_metrics_tag_wsi_add(wsi, "upg", "h2_prior"); |
986 | 0 | lws_role_call_alpn_negotiated(wsi, "h2"); |
987 | 0 | } |
988 | 0 | else |
989 | 0 | #endif |
990 | 0 | lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ? |
991 | 0 | LRS_SSL_INIT : LRS_HEADERS, &role_ops_h1); |
992 | | |
993 | | /* |
994 | | * Otherwise, we have to bind to h1 as a default even when we're actually going to |
995 | | * replace it as an h2 bind later. So don't take this seriously if the |
996 | | * default is disabled (ws upgrade caees properly about it) |
997 | | */ |
998 | |
|
999 | 0 | if (!vh_prot_name && wsi->a.vhost->default_protocol_index < |
1000 | 0 | wsi->a.vhost->count_protocols) |
1001 | 0 | wsi->a.protocol = &wsi->a.vhost->protocols[ |
1002 | 0 | wsi->a.vhost->default_protocol_index]; |
1003 | 0 | else |
1004 | 0 | wsi->a.protocol = &wsi->a.vhost->protocols[0]; |
1005 | | |
1006 | | /* the transport is accepted... give him time to negotiate */ |
1007 | 0 | lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, |
1008 | 0 | (int)wsi->a.context->timeout_secs); |
1009 | |
|
1010 | 0 | return 1; /* bound */ |
1011 | 0 | } |
1012 | | |
1013 | | #endif |
1014 | | |
1015 | | #if defined(LWS_WITH_CLIENT) |
1016 | | |
1017 | | static const char * const http_methods[] = { |
1018 | | "GET", "POST", "OPTIONS", "HEAD", "PUT", "PATCH", "DELETE", "CONNECT" |
1019 | | }; |
1020 | | |
1021 | | int |
1022 | | _lws_is_http_method(const char *method) |
1023 | 0 | { |
1024 | 0 | if (method) |
1025 | 0 | for (int n = 0; n < (int)LWS_ARRAY_SIZE(http_methods); n++) |
1026 | 0 | if (!strcmp(method, http_methods[n])) |
1027 | 0 | return 1; |
1028 | | |
1029 | 0 | return 0; |
1030 | 0 | } |
1031 | | |
1032 | | static int |
1033 | | rops_client_bind_h1(struct lws *wsi, const struct lws_client_connect_info *i) |
1034 | 0 | { |
1035 | 0 | if (!i) { |
1036 | | /* we are finalizing an already-selected role */ |
1037 | | |
1038 | | /* |
1039 | | * If we stay in http, assuming there wasn't already-set |
1040 | | * external user_space, since we know our initial protocol |
1041 | | * we can assign the user space now, otherwise do it after the |
1042 | | * ws subprotocol negotiated |
1043 | | */ |
1044 | 0 | if (!wsi->user_space && wsi->stash->cis[CIS_METHOD]) |
1045 | 0 | if (lws_ensure_user_space(wsi)) |
1046 | 0 | return 1; |
1047 | | |
1048 | | /* |
1049 | | * For ws, default to http/1.1 only. If i->alpn had been set |
1050 | | * though, defer to whatever he has set in there (eg, "h2"). |
1051 | | * |
1052 | | * The problem is he has to commit to h2 before he can find |
1053 | | * out if the server has the SETTINGS for ws-over-h2 enabled; |
1054 | | * if not then ws is not possible on that connection. So we |
1055 | | * only try h2 if he assertively said to use h2 alpn, otherwise |
1056 | | * ws implies alpn restriction to h1. |
1057 | | */ |
1058 | 0 | if (!wsi->stash->cis[CIS_METHOD] && !wsi->stash->cis[CIS_ALPN]) |
1059 | 0 | wsi->stash->cis[CIS_ALPN] = "http/1.1"; |
1060 | | |
1061 | | /* if we went on the ah waiting list, it's ok, we can wait. |
1062 | | * |
1063 | | * When we do get the ah, now or later, he will end up at |
1064 | | * lws_http_client_connect_via_info2(). |
1065 | | */ |
1066 | 0 | if (lws_header_table_attach(wsi, 0) |
1067 | 0 | #if defined(LWS_WITH_CLIENT) |
1068 | 0 | < 0) |
1069 | | /* |
1070 | | * if we failed here, the connection is already closed |
1071 | | * and freed. |
1072 | | */ |
1073 | 0 | return -1; |
1074 | | #else |
1075 | | ) |
1076 | | return 0; |
1077 | | #endif |
1078 | | |
1079 | 0 | return 0; |
1080 | 0 | } |
1081 | | |
1082 | | /* |
1083 | | * Clients that want to be h1, h2, or ws all start out as h1 |
1084 | | * (we don't yet know if the server supports h2 or ws), unless their |
1085 | | * alpn is only "h2" |
1086 | | */ |
1087 | | |
1088 | | // if (i->alpn && !strcmp(i->alpn, "h2")) |
1089 | | // return 0; /* we are h1, he only wants h2 */ |
1090 | | |
1091 | 0 | if (!i->method) { /* websockets */ |
1092 | 0 | #if defined(LWS_ROLE_WS) |
1093 | 0 | if (lws_create_client_ws_object(i, wsi)) |
1094 | 0 | goto fail_wsi; |
1095 | | |
1096 | 0 | goto bind_h1; |
1097 | | #else |
1098 | | lwsl_err("%s: ws role not configured\n", __func__); |
1099 | | |
1100 | | goto fail_wsi; |
1101 | | #endif |
1102 | 0 | } |
1103 | | |
1104 | | /* if a recognized http method, bind to it */ |
1105 | 0 | if (_lws_is_http_method(i->method)) |
1106 | 0 | goto bind_h1; |
1107 | | |
1108 | | /* other roles may bind to it */ |
1109 | | |
1110 | 0 | return 0; /* no match */ |
1111 | | |
1112 | 0 | bind_h1: |
1113 | | /* assert the mode and union status (hdr) clearly */ |
1114 | 0 | lws_role_transition(wsi, LWSIFR_CLIENT, LRS_UNCONNECTED, &role_ops_h1); |
1115 | |
|
1116 | 0 | return 1; /* matched */ |
1117 | | |
1118 | 0 | fail_wsi: |
1119 | 0 | return -1; |
1120 | 0 | } |
1121 | | #endif |
1122 | | |
1123 | | static int |
1124 | | rops_close_kill_connection_h1(struct lws *wsi, enum lws_close_status reason) |
1125 | 0 | { |
1126 | | #if defined(LWS_WITH_HTTP_PROXY) |
1127 | | if (!wsi->http.proxy_clientside) |
1128 | | return 0; |
1129 | | |
1130 | | wsi->http.proxy_clientside = 0; |
1131 | | |
1132 | | if (user_callback_handle_rxflow(wsi->a.protocol->callback, wsi, |
1133 | | LWS_CALLBACK_COMPLETED_CLIENT_HTTP, |
1134 | | wsi->user_space, NULL, 0)) |
1135 | | return 0; |
1136 | | #endif |
1137 | 0 | return 0; |
1138 | 0 | } |
1139 | | |
1140 | | int |
1141 | | rops_pt_init_destroy_h1(struct lws_context *context, |
1142 | | const struct lws_context_creation_info *info, |
1143 | | struct lws_context_per_thread *pt, int destroy) |
1144 | 0 | { |
1145 | | /* |
1146 | | * We only want to do this once... we will do it if no h2 support |
1147 | | * otherwise let h2 ops do it. |
1148 | | */ |
1149 | | #if !defined(LWS_ROLE_H2) && defined(LWS_WITH_SERVER) |
1150 | | if (!destroy) { |
1151 | | |
1152 | | pt->sul_ah_lifecheck.cb = lws_sul_http_ah_lifecheck; |
1153 | | |
1154 | | __lws_sul_insert_us(&pt->pt_sul_owner[LWSSULLI_MISS_IF_SUSPENDED], |
1155 | | &pt->sul_ah_lifecheck, 30 * LWS_US_PER_SEC); |
1156 | | } else |
1157 | | lws_dll2_remove(&pt->sul_ah_lifecheck.list); |
1158 | | #endif |
1159 | |
|
1160 | 0 | return 0; |
1161 | 0 | } |
1162 | | |
1163 | | static const lws_rops_t rops_table_h1[] = { |
1164 | | /* 1 */ { .pt_init_destroy = rops_pt_init_destroy_h1 }, |
1165 | | /* 2 */ { .handle_POLLIN = rops_handle_POLLIN_h1 }, |
1166 | | /* 3 */ { .handle_POLLOUT = rops_handle_POLLOUT_h1 }, |
1167 | | /* 4 */ { .write_role_protocol = rops_write_role_protocol_h1 }, |
1168 | | /* 5 */ { .alpn_negotiated = rops_alpn_negotiated_h1 }, |
1169 | | /* 6 */ { .close_kill_connection = rops_close_kill_connection_h1 }, |
1170 | | /* 7 */ { .destroy_role = rops_destroy_role_h1 }, |
1171 | | #if defined(LWS_WITH_SERVER) |
1172 | | /* 8 */ { .adoption_bind = rops_adoption_bind_h1 }, |
1173 | | #endif |
1174 | | #if defined(LWS_WITH_CLIENT) |
1175 | | /* 8 if client and no server */ |
1176 | | /* 9 */ { .client_bind = rops_client_bind_h1 }, |
1177 | | #endif |
1178 | | }; |
1179 | | |
1180 | | const struct lws_role_ops role_ops_h1 = { |
1181 | | /* role name */ "h1", |
1182 | | /* alpn id */ "http/1.1", |
1183 | | /* rops_table */ rops_table_h1, |
1184 | | /* rops_idx */ { |
1185 | | /* LWS_ROPS_check_upgrades */ |
1186 | | /* LWS_ROPS_pt_init_destroy */ 0x01, |
1187 | | /* LWS_ROPS_init_vhost */ |
1188 | | /* LWS_ROPS_destroy_vhost */ 0x00, |
1189 | | /* LWS_ROPS_service_flag_pending */ |
1190 | | /* LWS_ROPS_handle_POLLIN */ 0x02, |
1191 | | /* LWS_ROPS_handle_POLLOUT */ |
1192 | | /* LWS_ROPS_perform_user_POLLOUT */ 0x30, |
1193 | | /* LWS_ROPS_callback_on_writable */ |
1194 | | /* LWS_ROPS_tx_credit */ 0x00, |
1195 | | /* LWS_ROPS_write_role_protocol */ |
1196 | | /* LWS_ROPS_encapsulation_parent */ 0x40, |
1197 | | /* LWS_ROPS_alpn_negotiated */ |
1198 | | /* LWS_ROPS_close_via_role_protocol */ 0x50, |
1199 | | /* LWS_ROPS_close_role */ |
1200 | | /* LWS_ROPS_close_kill_connection */ 0x06, |
1201 | | /* LWS_ROPS_destroy_role */ |
1202 | | #if defined(LWS_WITH_SERVER) |
1203 | | /* LWS_ROPS_adoption_bind */ 0x78, |
1204 | | #else |
1205 | | /* LWS_ROPS_adoption_bind */ 0x70, |
1206 | | #endif |
1207 | | /* LWS_ROPS_client_bind */ |
1208 | | #if defined(LWS_WITH_CLIENT) |
1209 | | #if defined(LWS_WITH_SERVER) |
1210 | | /* LWS_ROPS_issue_keepalive */ 0x90, |
1211 | | #else |
1212 | | /* LWS_ROPS_issue_keepalive */ 0x80, |
1213 | | #endif |
1214 | | #else |
1215 | | /* LWS_ROPS_issue_keepalive */ 0x00, |
1216 | | #endif |
1217 | | }, |
1218 | | /* adoption_cb clnt, srv */ { LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, |
1219 | | LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED }, |
1220 | | /* rx_cb clnt, srv */ { LWS_CALLBACK_RECEIVE_CLIENT_HTTP, |
1221 | | 0 /* may be POST, etc */ }, |
1222 | | /* writeable cb clnt, srv */ { LWS_CALLBACK_CLIENT_HTTP_WRITEABLE, |
1223 | | LWS_CALLBACK_HTTP_WRITEABLE }, |
1224 | | /* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP, |
1225 | | LWS_CALLBACK_CLOSED_HTTP }, |
1226 | | /* protocol_bind cb c, srv */ { LWS_CALLBACK_CLIENT_HTTP_BIND_PROTOCOL, |
1227 | | LWS_CALLBACK_HTTP_BIND_PROTOCOL }, |
1228 | | /* protocol_unbind cb c, srv */ { LWS_CALLBACK_CLIENT_HTTP_DROP_PROTOCOL, |
1229 | | LWS_CALLBACK_HTTP_DROP_PROTOCOL }, |
1230 | | /* file_handle */ 0, |
1231 | | }; |