diff --git a/lib/roles/h1/ops-h1.c b/lib/roles/h1/ops-h1.c index 8afd6268..d3b16f4d 100644 --- a/lib/roles/h1/ops-h1.c +++ b/lib/roles/h1/ops-h1.c @@ -308,9 +308,9 @@ lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd) lwsi_state(wsi) == LRS_ISSUING_FILE || lwsi_state(wsi) == LRS_HEADERS || lwsi_state(wsi) == LRS_BODY)) { - if (!wsi->http.ah && - lws_header_table_attach(wsi, 0)) { - lwsl_info("wsi %p: ah get fail\n", wsi); + + if (!wsi->http.ah && lws_header_table_attach(wsi, 0)) { + lwsl_info("%s: wsi %p: ah not available\n", __func__, wsi); goto try_pollout; } @@ -319,6 +319,9 @@ lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd) * regardless of our buflist state, we need to get it, * and either use it, or append to the buflist and use * buflist head material. + * + * We will not notice a connection close until the buflist is + * exhausted and we tried to do a read of some kind. */ buffered = lws_buflist_aware_read(pt, wsi, &ebuf); @@ -327,8 +330,20 @@ lws_h1_server_socket_service(struct lws *wsi, struct lws_pollfd *pollfd) lwsl_info("%s: read 0 len a\n", __func__); wsi->seen_zero_length_recv = 1; lws_change_pollfd(wsi, LWS_POLLIN, 0); - goto try_pollout; - //goto fail; +#if !defined(LWS_WITHOUT_EXTENSIONS) + /* + * autobahn requires us to win the race between close + * and draining the extensions + */ + if (wsi->ws && + (wsi->ws->rx_draining_ext || wsi->ws->tx_draining_ext)) + goto try_pollout; +#endif + /* + * normally, we respond to close with logically closing + * our side immediately + */ + goto fail; case LWS_SSL_CAPABLE_ERROR: goto fail; @@ -469,7 +484,8 @@ try_pollout: fail: - lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "server socket svc fail"); + lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, + "server socket svc fail"); return LWS_HPI_RET_WSI_ALREADY_DIED; } diff --git a/lib/roles/http/server/parsers.c b/lib/roles/http/server/parsers.c index 5754f909..054a839b 100644 --- a/lib/roles/http/server/parsers.c +++ b/lib/roles/http/server/parsers.c @@ -81,6 +81,8 @@ _lws_header_table_reset(struct allocated_headers *ah) ah->nfrag = 0; ah->pos = 0; ah->http_response = 0; + ah->parser_state = WSI_TOKEN_NAME_PART; + ah->lextable_pos = 0; } // doesn't scrub the ah rxbuffer by default, parent must do if needed @@ -99,9 +101,6 @@ __lws_header_table_reset(struct lws *wsi, int autoservice) _lws_header_table_reset(ah); - ah->parser_state = WSI_TOKEN_NAME_PART; - ah->lextable_pos = 0; - /* since we will restart the ah, our new headers are not completed */ wsi->hdr_parsing_completed = 0; @@ -353,7 +352,7 @@ int __lws_header_table_detach(struct lws *wsi, int autoservice) if (!wsi) /* everybody waiting already has too many ah... */ goto nobody_usable_waiting; - lwsl_info("%s: last eligible wsi in wait list %p\n", __func__, wsi); + lwsl_info("%s: transferring ah to last eligible wsi in wait list %p (wsistate 0x%x)\n", __func__, wsi, wsi->wsistate); wsi->http.ah = ah; ah->wsi = wsi; /* new owner */ diff --git a/lib/roles/http/server/server.c b/lib/roles/http/server/server.c index a308683f..f55a1371 100644 --- a/lib/roles/http/server/server.c +++ b/lib/roles/http/server/server.c @@ -330,8 +330,8 @@ lws_select_vhost(struct lws_context *context, int port, const char *servername) vhost = context->vhost_list; while (vhost) { if (port == vhost->listen_port) { - lwsl_info("vhost match to %s based on port %d\n", - vhost->name, port); + lwsl_info("%s: vhost match to %s based on port %d\n", + __func__, vhost->name, port); return vhost; } vhost = vhost->vhost_next; @@ -991,6 +991,8 @@ lws_http_action(struct lws *wsi) if (lws_bind_protocol(wsi, &wsi->vhost->protocols[0])) return 1; + lwsi_set_state(wsi, LRS_DOING_TRANSACTION); + n = wsi->protocol->callback(wsi, LWS_CALLBACK_HTTP, wsi->user_space, uri_ptr, uri_len); @@ -1547,7 +1549,7 @@ raw_transition: /* no upgrade ack... he remained as HTTP */ - lwsl_info("No upgrade\n"); + lwsl_info("%s: %p: No upgrade\n", __func__, wsi); lwsi_set_state(wsi, LRS_ESTABLISHED); wsi->http.fop_fd = NULL; @@ -1742,7 +1744,8 @@ lws_http_transaction_completed(struct lws *wsi) * until we can verify POLLOUT. The part of this that confirms POLLOUT * with no partials is in lws_server_socket_service() below. */ - lwsl_debug("%s: setting DEF_ACT from 0x%x\n", __func__, wsi->wsistate); + lwsl_debug("%s: %p: setting DEF_ACT from 0x%x\n", __func__, + wsi, wsi->wsistate); lwsi_set_state(wsi, LRS_DEFERRING_ACTION); wsi->http.tx_content_length = 0; wsi->http.tx_content_remain = 0; @@ -1770,7 +1773,8 @@ lws_http_transaction_completed(struct lws *wsi) if (wsi->http.ah) { // lws_buflist_describe(&wsi->buflist, wsi); if (!lws_buflist_next_segment_len(&wsi->buflist, NULL)) { - lwsl_debug("%s: nothing in buflist so detaching ah\n", __func__); + lwsl_info("%s: %p: nothing in buflist so detaching ah\n", + __func__, wsi); lws_header_table_detach(wsi, 1); #ifdef LWS_WITH_TLS /* @@ -1789,8 +1793,8 @@ lws_http_transaction_completed(struct lws *wsi) } #endif } else { - lwsl_debug("%s: resetting and keeping ah as pipeline\n", - __func__); + lwsl_info("%s: %p: resetting and keeping ah as pipeline\n", + __func__, wsi); lws_header_table_reset(wsi, 0); /* * If we kept the ah, we should restrict the amount diff --git a/lib/roles/private.h b/lib/roles/private.h index 4e0b3126..ae4278b5 100644 --- a/lib/roles/private.h +++ b/lib/roles/private.h @@ -122,18 +122,27 @@ enum lwsi_state { LRS_HEADERS = 21, LRS_BODY = 22, LRS_ESTABLISHED = LWSIFS_POCB | 23, + /* we are established, but we have embarked on serving a single + * transaction. Other transaction input may be pending, but we will + * not service it while we are busy dealing with the current + * transaction. + * + * When we complete the current transaction, we would reset our state + * back to ESTABLISHED and start to process the next transaction. + */ + LRS_DOING_TRANSACTION = LWSIFS_POCB | 24, /* Phase 6: finishing */ - LRS_WAITING_TO_SEND_CLOSE = LWSIFS_POCB | 24, - LRS_RETURNED_CLOSE = LWSIFS_POCB | 25, - LRS_AWAITING_CLOSE_ACK = LWSIFS_POCB | 26, - LRS_FLUSHING_BEFORE_CLOSE = LWSIFS_POCB | 27, - LRS_SHUTDOWN = 28, + LRS_WAITING_TO_SEND_CLOSE = LWSIFS_POCB | 25, + LRS_RETURNED_CLOSE = LWSIFS_POCB | 26, + LRS_AWAITING_CLOSE_ACK = LWSIFS_POCB | 27, + LRS_FLUSHING_BEFORE_CLOSE = LWSIFS_POCB | 28, + LRS_SHUTDOWN = 29, /* Phase 7: dead */ - LRS_DEAD_SOCKET = 29, + LRS_DEAD_SOCKET = 30, LRS_MASK = 0xffff }; diff --git a/minimal-examples/http-server/minimal-http-server-dynamic/minimal-http-server-dynamic.c b/minimal-examples/http-server/minimal-http-server-dynamic/minimal-http-server-dynamic.c index 2b7fa4cc..b7bdaac1 100644 --- a/minimal-examples/http-server/minimal-http-server-dynamic/minimal-http-server-dynamic.c +++ b/minimal-examples/http-server/minimal-http-server-dynamic/minimal-http-server-dynamic.c @@ -177,6 +177,10 @@ int main(int argc, const char **argv) info.protocols = protocols; info.mounts = &mount; + /* for testing ah queue, not useful in real world */ + if (lws_cmdline_option(argc, argv, "--ah1")) + info.max_http_header_pool = 1; + context = lws_create_context(&info); if (!context) { lwsl_err("lws init failed\n"); diff --git a/minimal-examples/raw/minimal-raw-netcat/minimal-raw-netcat.c b/minimal-examples/raw/minimal-raw-netcat/minimal-raw-netcat.c index faffaa56..5bdf1be6 100644 --- a/minimal-examples/raw/minimal-raw-netcat/minimal-raw-netcat.c +++ b/minimal-examples/raw/minimal-raw-netcat/minimal-raw-netcat.c @@ -31,6 +31,7 @@ static struct lws *raw_wsi, *stdin_wsi; static uint8_t buf[LWS_PRE + 4096]; static int waiting, interrupted; static struct lws_context *context; +static int us_wait_after_input_close = LWS_USEC_PER_SEC / 10; static int callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, @@ -50,7 +51,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, /* stdin close, wait 1s then close the raw skt */ stdin_wsi = NULL; /* invalid now we close */ if (raw_wsi) - lws_set_timer_usecs(raw_wsi, LWS_USEC_PER_SEC / 10); + lws_set_timer_usecs(raw_wsi, us_wait_after_input_close); else { interrupted = 1; lws_cancel_service(context); @@ -153,7 +154,7 @@ int main(int argc, const char **argv) logs = atoi(p); lws_set_log_level(logs, NULL); - lwsl_user("LWS minimal raw netcat [--server ip] [--port port]\n"); + lwsl_user("LWS minimal raw netcat [--server ip] [--port port] [-w ms]\n"); memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */ info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS; @@ -193,6 +194,9 @@ int main(int argc, const char **argv) if ((p = lws_cmdline_option(argc, argv, "--server"))) server = p; + if ((p = lws_cmdline_option(argc, argv, "-w"))) + us_wait_after_input_close = 1000 * atoi(p); + n = getaddrinfo(server, port, &h, &r); if (n) { lwsl_err("%s: problem resolving %s: %s\n", __func__,