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