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