diff --git a/lib/handshake.c b/lib/handshake.c index 22453814..1ea51563 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -291,6 +291,11 @@ postbody_completion: break; } break; + + case LWSS_HTTP_DEFERRING_ACTION: + lwsl_debug("%s: LWSS_HTTP_DEFERRING_ACTION\n", __func__); + break; + default: lwsl_err("%s: Unhandled state %d\n", __func__, wsi->state); goto bail; diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index aa6a100e..8f3374b2 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -518,6 +518,9 @@ enum lws_connection_states { LWSS_HTTP2_DEFERRING_ACTION = _LSF_CCB | 18 | _LSF_POLLOUT, + + LWSS_HTTP_DEFERRING_ACTION = _LSF_CCB | 19 | + _LSF_POLLOUT, }; #define lws_state_is_ws(s) (!!(s & _LSF_WEBSOCKET)) diff --git a/lib/server/server.c b/lib/server/server.c index 89a978d3..d1f91f5f 100644 --- a/lib/server/server.c +++ b/lib/server/server.c @@ -1870,9 +1870,13 @@ lws_http_transaction_completed(struct lws *wsi) if (lws_bind_protocol(wsi, &wsi->vhost->protocols[0])) return 1; - /* otherwise set ourselves up ready to go again */ - wsi->state = LWSS_HTTP; - wsi->mode = LWSCM_HTTP_SERVING; + /* + * otherwise set ourselves up ready to go again, but because we have no + * idea about the wsi writability, we make put it in a holding state + * until we can verify POLLOUT. The part of this that confirms POLLOUT + * with no partials is in lws_server_socket_service() below. + */ + wsi->state = LWSS_HTTP_DEFERRING_ACTION; wsi->http.tx_content_length = 0; wsi->http.tx_content_remain = 0; wsi->hdr_parsing_completed = 0; @@ -1936,6 +1940,7 @@ lws_http_transaction_completed(struct lws *wsi) } lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi); + lws_callback_on_writable(wsi); return 0; } @@ -2452,6 +2457,19 @@ try_pollout: goto fail; } + /* clear back-to-back write detection */ + wsi->could_have_pending = 0; + + if (wsi->state == LWSS_HTTP_DEFERRING_ACTION) { + lwsl_debug("%s: LWSS_HTTP_DEFERRING_ACTION now writable\n", + __func__); + wsi->state = LWSS_HTTP; + if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) { + lwsl_info("failed at set pollfd\n"); + goto fail; + } + } + if (wsi->mode == LWSCM_RAW) { lws_stats_atomic_bump(wsi->context, pt, LWSSTATS_C_WRITEABLE_CB, 1); diff --git a/lib/service.c b/lib/service.c index 18d7cd33..940ed483 100644 --- a/lib/service.c +++ b/lib/service.c @@ -238,7 +238,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) goto bail_ok; } - /* Priority 6: user can get the callback + /* Priority 6: extensions */ m = lws_ext_cb_active(wsi, LWS_EXT_CB_IS_WRITEABLE, NULL, 0); if (m) @@ -330,6 +330,7 @@ lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd) #ifndef LWS_NO_EXTENSIONS wsi->extension_data_pending = 0; #endif + user_service: /* one shot */