diff --git a/lib/client-handshake.c b/lib/client-handshake.c index 96854afe..264cca98 100644 --- a/lib/client-handshake.c +++ b/lib/client-handshake.c @@ -303,7 +303,7 @@ lws_client_connect_2(struct lws *wsi) oom4: /* we're closing, losing some rx is OK */ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; - lws_header_table_detach(wsi); + lws_header_table_detach(wsi, 0); lws_free(wsi); return NULL; @@ -405,7 +405,7 @@ lws_client_connect_via_info(struct lws_client_connect_info *i) } #endif - if (lws_header_table_attach(wsi)) + if (lws_header_table_attach(wsi, 0)) goto bail; /* @@ -470,7 +470,7 @@ lws_client_connect_via_info(struct lws_client_connect_info *i) bail1: /* we're closing, losing some rx is OK */ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; - lws_header_table_detach(wsi); + lws_header_table_detach(wsi, 0); bail: lws_free(wsi); diff --git a/lib/client.c b/lib/client.c index 33d990e4..94497e94 100644 --- a/lib/client.c +++ b/lib/client.c @@ -798,7 +798,7 @@ check_accept: lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); /* free up his parsing allocations */ - lws_header_table_detach(wsi); + lws_header_table_detach(wsi, 0); lws_union_transition(wsi, LWSCM_WS_CLIENT); wsi->state = LWSS_ESTABLISHED; diff --git a/lib/libuv.c b/lib/libuv.c index ac1ab6de..5400f315 100644 --- a/lib/libuv.c +++ b/lib/libuv.c @@ -80,7 +80,7 @@ lws_uv_timeout_cb(uv_timer_t *timer) struct lws_context_per_thread *pt = container_of(timer, struct lws_context_per_thread, uv_timeout_watcher); - lwsl_info("%s\n", __func__); + lwsl_debug("%s\n", __func__); /* do timeout check only */ lws_service_fd_tsi(pt->context, NULL, pt->tid); } @@ -119,8 +119,10 @@ lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, uv_signal_cb cb, */ if (wsi) { wsi->w_read.context = context; - uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher, pt->lserv_fd); - uv_poll_start(&wsi->w_read.uv_watcher, UV_READABLE, lws_accept_cb); + uv_poll_init(pt->io_loop_uv, &wsi->w_read.uv_watcher, + pt->lserv_fd); + uv_poll_start(&wsi->w_read.uv_watcher, UV_READABLE, + lws_accept_cb); } uv_timer_init(pt->io_loop_uv, &pt->uv_timeout_watcher); diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 00217f76..257d6b41 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -63,7 +63,7 @@ lws_free_wsi(struct lws *wsi) wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; /* we may not have an ah, but may be on the waiting list... */ - lws_header_table_detach(wsi); + lws_header_table_detach(wsi, 0); wsi->context->count_wsi_allocated--; lwsl_debug("%s: %p, remaining wsi %d\n", __func__, wsi, diff --git a/lib/parsers.c b/lib/parsers.c index e802e8ce..cb025414 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -61,9 +61,11 @@ lextable_decode(int pos, char c) } void -lws_header_table_reset(struct lws *wsi) +lws_header_table_reset(struct lws *wsi, int autoservice) { struct allocated_headers *ah = wsi->u.hdr.ah; + struct lws_context_per_thread *pt; + struct lws_pollfd *pfd; /* if we have the idea we're resetting 'our' ah, must be bound to one */ assert(ah); @@ -87,14 +89,29 @@ lws_header_table_reset(struct lws *wsi) * processing), apply and free it. */ if (wsi->u.hdr.preamble_rx) { - memcpy(ah->rx, wsi->u.hdr.preamble_rx, wsi->u.hdr.preamble_rx_len); + memcpy(ah->rx, wsi->u.hdr.preamble_rx, + wsi->u.hdr.preamble_rx_len); ah->rxlen = wsi->u.hdr.preamble_rx_len; lws_free_set_NULL(wsi->u.hdr.preamble_rx); + + if (autoservice) { + lwsl_notice("%s: calling service on readbuf ah\n", __func__); + + pt = &wsi->context->pt[(int)wsi->tsi]; + + /* unlike a normal connect, we have the headers already + * (or the first part of them anyway) + */ + pfd = &pt->fds[wsi->position_in_fds_table]; + pfd->revents |= LWS_POLLIN; + lwsl_err("%s: calling service\n", __func__); + lws_service_fd_tsi(wsi->context, pfd, wsi->tsi); + } } } int LWS_WARN_UNUSED_RESULT -lws_header_table_attach(struct lws *wsi) +lws_header_table_attach(struct lws *wsi, int autoservice) { struct lws_context *context = wsi->context; struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi]; @@ -165,7 +182,7 @@ lws_header_table_attach(struct lws *wsi) lws_pt_unlock(pt); reset: - lws_header_table_reset(wsi); + lws_header_table_reset(wsi, autoservice); time(&wsi->u.hdr.ah->assigned); return 0; @@ -176,7 +193,7 @@ bail: return 1; } -int lws_header_table_detach(struct lws *wsi) +int lws_header_table_detach(struct lws *wsi, int autoservice) { struct lws_context *context = wsi->context; struct allocated_headers *ah = wsi->u.hdr.ah; @@ -258,7 +275,7 @@ int lws_header_table_detach(struct lws *wsi) wsi->u.hdr.ah = ah; ah->wsi = wsi; /* new owner */ - lws_header_table_reset(wsi); + lws_header_table_reset(wsi, autoservice); time(&wsi->u.hdr.ah->assigned); assert(wsi->position_in_fds_table != -1); diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 5dd48178..d7a9389c 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -1296,13 +1296,13 @@ LWS_EXTERN int lws_plat_set_socket_options(struct lws_context *context, lws_sockfd_type fd); LWS_EXTERN int LWS_WARN_UNUSED_RESULT -lws_header_table_attach(struct lws *wsi); +lws_header_table_attach(struct lws *wsi, int autoservice); LWS_EXTERN int -lws_header_table_detach(struct lws *wsi); +lws_header_table_detach(struct lws *wsi, int autoservice); LWS_EXTERN void -lws_header_table_reset(struct lws *wsi); +lws_header_table_reset(struct lws *wsi, int autoservice); LWS_EXTERN char * LWS_WARN_UNUSED_RESULT lws_hdr_simple_ptr(struct lws *wsi, enum lws_token_indexes h); diff --git a/lib/server.c b/lib/server.c index bd57ad2e..eeb0b0d3 100644 --- a/lib/server.c +++ b/lib/server.c @@ -330,7 +330,7 @@ lws_http_action(struct lws *wsi) bail_nuke_ah: /* we're closing, losing some rx is OK */ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; - lws_header_table_detach(wsi); + lws_header_table_detach(wsi, 1); return 1; } @@ -628,7 +628,7 @@ bail_nuke_ah: /* drop the header info */ /* we're closing, losing some rx is OK */ wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; - lws_header_table_detach(wsi); + lws_header_table_detach(wsi, 1); return 1; } @@ -753,9 +753,9 @@ lws_http_transaction_completed(struct lws *wsi) if (!wsi->more_rx_waiting) { wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen; - lws_header_table_detach(wsi); + lws_header_table_detach(wsi, 1); } else - lws_header_table_reset(wsi); + lws_header_table_reset(wsi, 1); } /* If we're (re)starting on headers, need other implied init */ @@ -861,7 +861,9 @@ lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd, const char *readbuf, size_t len) { struct lws *wsi = lws_adopt_socket(context, accept_fd); + struct lws_context_per_thread *pt; struct allocated_headers *ah; + struct lws_pollfd *pfd; if (!wsi) return NULL; @@ -878,24 +880,42 @@ lws_adopt_socket_readbuf(struct lws_context *context, lws_sockfd_type accept_fd, * * if one is available, get it and place the data in his ah rxbuf... * wsi with ah that have pending rxbuf get auto-POLLIN service. + * + * no autoservice because we didn't get a chance to attach the + * readbuf data to wsi or ah yet, and we will do it next if we get + * the ah. */ - if (!lws_header_table_attach(wsi)) { + if (!lws_header_table_attach(wsi, 0)) { ah = wsi->u.hdr.ah; memcpy(ah->rx, readbuf, len); ah->rxpos = 0; ah->rxlen = len; + lwsl_notice("%s: calling service on readbuf ah\n", __func__); + pt = &context->pt[(int)wsi->tsi]; + + /* unlike a normal connect, we have the headers already + * (or the first part of them anyway). + * libuv won't come back and service us without a network + * event, so we need to do the header service right here. + */ + pfd = &pt->fds[wsi->position_in_fds_table]; + pfd->revents |= LWS_POLLIN; + lwsl_err("%s: calling service\n", __func__); + if (lws_service_fd_tsi(context, pfd, wsi->tsi)) + /* service closed us */ + return NULL; + return wsi; } - + lwsl_err("%s: deferring handling ah\n", __func__); /* * hum if no ah came, we are on the wait list and must defer * dealing with this until the ah arrives. * * later successful lws_header_table_attach() will apply the - * below to the rx buffer. + * below to the rx buffer (via lws_header_table_reset()). */ - wsi->u.hdr.preamble_rx = lws_malloc(len); memcpy(wsi->u.hdr.preamble_rx, readbuf, len); wsi->u.hdr.preamble_rx_len = len; @@ -958,7 +978,8 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, wsi->state == LWSS_HTTP_ISSUING_FILE || wsi->state == LWSS_HTTP_HEADERS) { if (!wsi->u.hdr.ah) - if (lws_header_table_attach(wsi)) + /* no autoservice beacuse we will do it next */ + if (lws_header_table_attach(wsi, 0)) goto try_pollout; ah = wsi->u.hdr.ah; @@ -1002,7 +1023,7 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi, (wsi->mode != LWSCM_HTTP_SERVING && wsi->mode != LWSCM_HTTP_SERVING_ACCEPTED && wsi->mode != LWSCM_HTTP2_SERVING)) - lws_header_table_detach(wsi); + lws_header_table_detach(wsi, 1); } break; } @@ -1052,6 +1073,9 @@ try_pollout: goto fail; } + if (!wsi->hdr_parsing_completed) + break; + if (wsi->state != LWSS_HTTP_ISSUING_FILE) { n = user_callback_handle_rxflow(wsi->protocol->callback, wsi, LWS_CALLBACK_HTTP_WRITEABLE, diff --git a/lib/service.c b/lib/service.c index 6ebd562d..c665f117 100644 --- a/lib/service.c +++ b/lib/service.c @@ -237,6 +237,9 @@ user_service: return 1; } + if (!wsi->hdr_parsing_completed) + return 0; + #ifdef LWS_USE_HTTP2 /* * we are the 'network wsi' for potentially many muxed child wsi with @@ -789,7 +792,7 @@ drain: /* we can run the normal ah detach flow despite * being in ws union mode, since all union members * start with hdr */ - lws_header_table_detach(wsi); + lws_header_table_detach(wsi, 0); } pending = lws_ssl_pending(wsi);