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