mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
POST: handle http/1 pipelined after body
Re-use wsi->preamble_rx to also hold leftover rx after dealing with POST body. Ensure ah->rx is always big enough to cope with what may have been read into the pt->serv_buf. Update the check for forced needed to also accept non-NULL wsi->preamble as well as ah->rxpos != ah->rxlen as indication forced needed. Disable autoservice on ah reset during transaction completed... it may close the wsi underneath us when it sees and processes the pending wsi->preamble_rx recursively otherwise.
This commit is contained in:
parent
0e24969f53
commit
93bc409ca1
5 changed files with 89 additions and 24 deletions
|
@ -1117,6 +1117,14 @@ lws_create_context(struct lws_context_creation_info *info)
|
|||
info->max_http_header_data2;
|
||||
else
|
||||
context->max_http_header_data = LWS_DEF_HEADER_LEN;
|
||||
|
||||
/*
|
||||
* HTTP/1 piplining after POST gets read in pt_serv_buf_size but
|
||||
* may need stashing in ah->rx, so ensure it's always big enough
|
||||
*/
|
||||
if ((int)context->max_http_header_data < (int)context->pt_serv_buf_size)
|
||||
context->max_http_header_data = context->pt_serv_buf_size;
|
||||
|
||||
if (info->max_http_header_pool)
|
||||
context->max_http_header_pool = info->max_http_header_pool;
|
||||
else
|
||||
|
|
|
@ -152,6 +152,8 @@ lws_header_table_reset(struct lws *wsi, int autoservice)
|
|||
memcpy(ah->rx, wsi->preamble_rx, wsi->preamble_rx_len);
|
||||
ah->rxlen = wsi->preamble_rx_len;
|
||||
lws_free_set_NULL(wsi->preamble_rx);
|
||||
wsi->preamble_rx_len = 0;
|
||||
ah->rxpos = 0;
|
||||
|
||||
if (autoservice) {
|
||||
lwsl_debug("%s: service on readbuf ah\n", __func__);
|
||||
|
@ -345,8 +347,10 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
|
|||
(void *)wsi, (void *)ah, wsi->tsi,
|
||||
pt->ah_count_in_use);
|
||||
|
||||
if (wsi->preamble_rx)
|
||||
if (wsi->preamble_rx) {
|
||||
lws_free_set_NULL(wsi->preamble_rx);
|
||||
wsi->preamble_rx_len = 0;
|
||||
}
|
||||
|
||||
/* may not be detached while he still has unprocessed rx */
|
||||
if (!lws_header_table_is_in_detachable_state(wsi)) {
|
||||
|
|
|
@ -1842,7 +1842,8 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
int n = NO_PENDING_TIMEOUT;
|
||||
|
||||
lwsl_info("%s: wsi %p\n", __func__, wsi);
|
||||
|
||||
if (wsi->ah)
|
||||
lwsl_info("ah attached, pos %d, len %d\n", wsi->ah->rxpos, wsi->ah->rxlen);
|
||||
lws_access_log(wsi);
|
||||
|
||||
if (!wsi->hdr_parsing_completed) {
|
||||
|
@ -1850,7 +1851,6 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
lwsl_debug("%s: wsi %p\n", __func__, wsi);
|
||||
/* if we can't go back to accept new headers, drop the connection */
|
||||
if (wsi->http2_substream)
|
||||
return 0;
|
||||
|
@ -1917,7 +1917,7 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
}
|
||||
#endif
|
||||
} else {
|
||||
lws_header_table_reset(wsi, 1);
|
||||
lws_header_table_reset(wsi, 0);
|
||||
/*
|
||||
* If we kept the ah, we should restrict the amount
|
||||
* of time we are willing to keep it. Otherwise it
|
||||
|
@ -1930,7 +1930,11 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
/* If we're (re)starting on headers, need other implied init */
|
||||
if (wsi->ah)
|
||||
wsi->ah->ues = URIES_IDLE;
|
||||
}
|
||||
} else
|
||||
if (wsi->preamble_rx)
|
||||
if (lws_header_table_attach(wsi, 0))
|
||||
lwsl_debug("acquired ah\n");
|
||||
|
||||
|
||||
lwsl_info("%s: %p: keep-alive await new transaction\n", __func__, wsi);
|
||||
lws_callback_on_writable(wsi);
|
||||
|
@ -2313,10 +2317,19 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
}
|
||||
ah = wsi->ah;
|
||||
|
||||
assert(ah->rxpos <= ah->rxlen);
|
||||
/* if nothing in ah rx buffer, get some fresh rx */
|
||||
if (ah->rxpos == ah->rxlen) {
|
||||
ah->rxlen = lws_ssl_capable_read(wsi, ah->rx,
|
||||
|
||||
if (wsi->preamble_rx) {
|
||||
memcpy(ah->rx, wsi->preamble_rx, wsi->preamble_rx_len);
|
||||
lws_free_set_NULL(wsi->preamble_rx);
|
||||
ah->rxlen = wsi->preamble_rx_len;
|
||||
wsi->preamble_rx_len = 0;
|
||||
} else {
|
||||
ah->rxlen = lws_ssl_capable_read(wsi, ah->rx,
|
||||
sizeof(ah->rx));
|
||||
}
|
||||
ah->rxpos = 0;
|
||||
switch (ah->rxlen) {
|
||||
case 0:
|
||||
|
@ -2377,23 +2390,36 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
break;
|
||||
}
|
||||
|
||||
len = lws_ssl_capable_read(wsi, pt->serv_buf,
|
||||
context->pt_serv_buf_size);
|
||||
lwsl_debug("%s: wsi %p read %d\r\n", __func__, wsi, len);
|
||||
switch (len) {
|
||||
case 0:
|
||||
lwsl_info("%s: read 0 len b\n", __func__);
|
||||
if (wsi->preamble_rx && wsi->preamble_rx_len) {
|
||||
memcpy(pt->serv_buf, wsi->preamble_rx, wsi->preamble_rx_len);
|
||||
lws_free_set_NULL(wsi->preamble_rx);
|
||||
len = wsi->preamble_rx_len;
|
||||
lwsl_debug("bringing %d out of stash\n", wsi->preamble_rx_len);
|
||||
wsi->preamble_rx_len = 0;
|
||||
} else {
|
||||
|
||||
/* fallthru */
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
goto fail;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
goto try_pollout;
|
||||
/*
|
||||
* ... in the case of pipelined HTTP, this may be
|
||||
* POST data followed by next headers...
|
||||
*/
|
||||
|
||||
len = lws_ssl_capable_read(wsi, pt->serv_buf,
|
||||
context->pt_serv_buf_size);
|
||||
lwsl_debug("%s: wsi %p read %d\r\n", __func__, wsi, len);
|
||||
switch (len) {
|
||||
case 0:
|
||||
lwsl_info("%s: read 0 len b\n", __func__);
|
||||
|
||||
/* fallthru */
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
goto fail;
|
||||
case LWS_SSL_CAPABLE_MORE_SERVICE:
|
||||
goto try_pollout;
|
||||
}
|
||||
|
||||
if (len < 0) /* coverity */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (len < 0) /* coverity */
|
||||
goto fail;
|
||||
|
||||
if (wsi->mode == LWSCM_RAW) {
|
||||
n = user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_RAW_RX,
|
||||
|
@ -2412,10 +2438,31 @@ lws_server_socket_service(struct lws_context *context, struct lws *wsi,
|
|||
/*
|
||||
* this may want to send
|
||||
* (via HTTP callback for example)
|
||||
*
|
||||
* returns number of bytes used
|
||||
*/
|
||||
|
||||
n = lws_read(wsi, pt->serv_buf, len);
|
||||
if (n < 0) /* we closed wsi */
|
||||
return 1;
|
||||
|
||||
if (n != len) {
|
||||
if (wsi->preamble_rx) {
|
||||
lwsl_err("DISCARDING %d (ah %p)\n", len - n, wsi->ah);
|
||||
|
||||
goto fail;
|
||||
}
|
||||
assert(n < len);
|
||||
wsi->preamble_rx = lws_malloc(len - n, "preamble_rx");
|
||||
if (!wsi->preamble_rx) {
|
||||
lwsl_err("OOM\n");
|
||||
goto fail;
|
||||
}
|
||||
memcpy(wsi->preamble_rx, pt->serv_buf + n, len - n);
|
||||
wsi->preamble_rx_len = (int)len - n;
|
||||
lwsl_debug("stashed %d\n", (int)wsi->preamble_rx_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* he may have used up the
|
||||
* writability above, if we will defer POLLOUT
|
||||
|
@ -2452,6 +2499,10 @@ try_pollout:
|
|||
if (wsi->state == LWSS_HTTP_DEFERRING_ACTION) {
|
||||
lwsl_debug("%s: LWSS_HTTP_DEFERRING_ACTION now writable\n",
|
||||
__func__);
|
||||
|
||||
if (wsi->ah)
|
||||
lwsl_debug(" existing ah rxpos %d / rxlen %d\n",
|
||||
wsi->ah->rxpos, wsi->ah->rxlen);
|
||||
wsi->state = LWSS_HTTP;
|
||||
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) {
|
||||
lwsl_info("failed at set pollfd\n");
|
||||
|
|
|
@ -770,10 +770,11 @@ lws_service_adjust_timeout(struct lws_context *context, int timeout_ms, int tsi)
|
|||
/* 3) if any ah has pending rx, do not wait in poll */
|
||||
ah = pt->ah_list;
|
||||
while (ah) {
|
||||
if (ah->rxpos != ah->rxlen) {
|
||||
if (ah->rxpos != ah->rxlen || (ah->wsi && ah->wsi->preamble_rx)) {
|
||||
if (!ah->wsi) {
|
||||
assert(0);
|
||||
}
|
||||
// lwsl_debug("ah pending force\n");
|
||||
return 0;
|
||||
}
|
||||
ah = ah->next;
|
||||
|
@ -850,7 +851,8 @@ lws_service_flag_pending(struct lws_context *context, int tsi)
|
|||
*/
|
||||
ah = pt->ah_list;
|
||||
while (ah) {
|
||||
if (ah->rxpos != ah->rxlen && !ah->wsi->hdr_parsing_completed) {
|
||||
if ((ah->rxpos != ah->rxlen &&
|
||||
!ah->wsi->hdr_parsing_completed) || ah->wsi->preamble_rx) {
|
||||
pt->fds[ah->wsi->position_in_fds_table].revents |=
|
||||
pt->fds[ah->wsi->position_in_fds_table].events &
|
||||
LWS_POLLIN;
|
||||
|
|
|
@ -107,7 +107,7 @@ function check {
|
|||
|
||||
rm -rf $LOG
|
||||
killall libwebsockets-test-server 2>/dev/null
|
||||
libwebsockets-test-server -d127 2>> $LOG &
|
||||
libwebsockets-test-server -d1023 2>> $LOG &
|
||||
CPID=$!
|
||||
|
||||
echo "Started server on PID $CPID"
|
||||
|
|
Loading…
Add table
Reference in a new issue