Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 88 additions & 2 deletions lib/roles/h2/hpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,27 @@
ah->parser_state = WSI_TOKEN_NAME_PART;
ah->lextable_pos = 0;
h2n->unknown_header = 0;
#if defined(LWS_WITH_CUSTOM_HEADERS)
/*
* h2 doesn't use the h1 header text parser to lay down
* the unknown-header storage (the name comes in via
* hpack one char at a time and the value never passes
* through the h1 value collector). So for substreams
* we build the UHO entry ourselves as the name/value
* are decoded: speculatively reserve the entry header
* before the name now, then finalize (or abandon, if it
* turns out to be a header lws knows) at name complete.
*/
if (wsi->mux_substream && !h2n->value) {
ah->unk_pos = 0;
if (ah->pos + UHO_NAME <

Check failure on line 1086 in lib/roles/h2/hpack.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=warmcat_libwebsockets&issues=AZ7fGXLV0X-JifGO74hy&open=AZ7fGXLV0X-JifGO74hy&pullRequest=3616
wsi->a.context->max_http_header_data) {
ah->unk_pos = ah->pos;
for (n = 0; n < UHO_NAME; n++)
ah->data[ah->pos++] = 0;
}
}
#endif
break;
}

Expand Down Expand Up @@ -1181,8 +1202,14 @@
__func__);
return 1;
}
} //else
//lwsl_header("ignoring %c\n", c1);
}
#if defined(LWS_WITH_CUSTOM_HEADERS)
else if (wsi->mux_substream && ah->unk_pos &&
ah->unk_value_pos && ah->pos + 1 <
wsi->a.context->max_http_header_data)
/* collect unknown-header value byte */
ah->data[ah->pos++] = (char)c1;
#endif
} else {
/*
* Convert name using existing parser,
Expand All @@ -1206,6 +1233,19 @@
"Uppercase literal hpack hdr");
return 1;
}
#if defined(LWS_WITH_CUSTOM_HEADERS)
/*
* Speculatively collect the name into the UHO
* entry we reserved. We must do this before
* lws_parse() below: if it recognizes a known
* header it does lws_frag_start() using the
* current ah->pos, which has to already point
* past the name we are stashing here.
*/
if (ah->unk_pos &&

Check failure on line 1245 in lib/roles/h2/hpack.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=warmcat_libwebsockets&issues=AZ7fGXLV0X-JifGO74hz&open=AZ7fGXLV0X-JifGO74hz&pullRequest=3616
ah->pos + 1 < wsi->a.context->max_http_header_data)
ah->data[ah->pos++] = (char)c1;
#endif
plen = 1;
if (!h2n->unknown_header &&
lws_parse(wsi, &c1, &plen))
Expand Down Expand Up @@ -1259,6 +1299,38 @@
}
}

#if defined(LWS_WITH_CUSTOM_HEADERS)
/*
* The name part just completed. If lws didn't recognize it,
* finalize the UHO entry we have been building (the name is
* stored with a trailing ':' to match the h1 storage format,
* which is what the lws_hdr_custom_*() accessors expect) and
* link it into the unknown-header list. Otherwise drop the
* speculative name (the recognized header's value frag was
* already located past it by the lws header parser).
*/
if (wsi->mux_substream && ah->unk_pos && !h2n->value) {
if (h2n->unknown_header &&
ah->pos + 1 < wsi->a.context->max_http_header_data) {
ah->data[ah->pos++] = ':';
lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos +
UHO_NLEN],
(uint16_t)((ah->pos - ah->unk_pos) -
UHO_NAME));
if (!ah->unk_ll_head)

Check failure on line 1320 in lib/roles/h2/hpack.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=warmcat_libwebsockets&issues=AZ7fGXLV0X-JifGO74h0&open=AZ7fGXLV0X-JifGO74h0&pullRequest=3616
ah->unk_ll_head = ah->unk_pos;
if (ah->unk_ll_tail)

Check failure on line 1322 in lib/roles/h2/hpack.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=warmcat_libwebsockets&issues=AZ7fGXLV0X-JifGO74h1&open=AZ7fGXLV0X-JifGO74h1&pullRequest=3616
lws_ser_wu32be((uint8_t *)&ah->data[
ah->unk_ll_tail + UHO_LL],
ah->unk_pos);
ah->unk_ll_tail = ah->unk_pos;
ah->unk_value_pos = ah->pos;
} else
/* known header, or no room: drop capture */
ah->unk_pos = 0;
}
#endif

/* we have the header */
if (!h2n->value) {
h2n->value = 1;
Expand Down Expand Up @@ -1355,6 +1427,20 @@
if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m))
return 1;

#if defined(LWS_WITH_CUSTOM_HEADERS)
/*
* Value part complete: if we were collecting an unknown
* header, record the value length to finish the UHO entry.
*/
if (wsi->mux_substream && ah->unk_pos && ah->unk_value_pos) {
lws_ser_wu16be((uint8_t *)&ah->data[ah->unk_pos +
UHO_VLEN],
(uint16_t)(ah->pos - ah->unk_value_pos));
ah->unk_pos = 0;
ah->unk_value_pos = 0;
}
#endif

h2n->is_first_header_char = 1;
h2n->hpack = HPKS_TYPE;
break;
Expand Down
15 changes: 15 additions & 0 deletions lib/roles/h2/ops-h2.c
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,21 @@ lws_h2_bind_for_post_before_action(struct lws *wsi)
lws_buflist_use_segment(&wsi->buflist, blen);

wsi->http.rx_content_length -= blen;
/*
* Keep rx_content_remain in step with the body we just
* delivered from the deferred buflist. The inline DATA path in
* lws_read_h1() and the HTTP_BODY_COMPLETION decision both track
* rx_content_remain (initialized to the full content-length);
* if we only decrement rx_content_length here, a body that is
* split across the DEFERRING_ACTION boundary (some stashed here,
* the rest arriving later inline) leaves rx_content_remain stuck
* at the stashed byte count, so completion never fires and the
* request times out.
*/
if (wsi->http.rx_content_remain >= blen)
wsi->http.rx_content_remain -= blen;
else
wsi->http.rx_content_remain = 0;
}

if (!wsi->buflist)
Expand Down
21 changes: 15 additions & 6 deletions lib/roles/http/parsers.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
ah->lextable_pos = 0;
ah->unk_pos = 0;
#if defined(LWS_WITH_CUSTOM_HEADERS)
ah->unk_value_pos = 0;
ah->unk_ll_head = 0;
ah->unk_ll_tail = 0;
#endif
Expand Down Expand Up @@ -612,7 +613,7 @@
{
ah_data_idx_t ll;

if (!wsi->http.ah || wsi->mux_substream)
if (!wsi->http.ah)
return -1;

ll = wsi->http.ah->unk_ll_head;
Expand All @@ -638,7 +639,7 @@
ah_data_idx_t ll;
int n;

if (!wsi->http.ah || wsi->mux_substream)
if (!wsi->http.ah)
return -1;

*dst = '\0';
Expand Down Expand Up @@ -671,7 +672,7 @@
{
ah_data_idx_t ll;

if (!wsi->http.ah || wsi->mux_substream)
if (!wsi->http.ah)
return -1;

ll = wsi->http.ah->unk_ll_head;
Expand Down Expand Up @@ -1221,10 +1222,18 @@
#endif
}

if (lws_pos_in_bounds(wsi))
return LPR_FAIL;
/*
* For mux (h2) substreams the hpack decoder captures
* the header name itself (including building the
* unknown-header storage), so we must not also lay the
* name bytes down here and double-advance ah->pos.
*/
if (!wsi->mux_substream) {
if (lws_pos_in_bounds(wsi))

Check failure on line 1232 in lib/roles/http/parsers.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=warmcat_libwebsockets&issues=AZ7fGXG50X-JifGO74hx&open=AZ7fGXG50X-JifGO74hx&pullRequest=3616
return LPR_FAIL;

ah->data[ah->pos++] = (char)c;
ah->data[ah->pos++] = (char)c;
}
pos = ah->lextable_pos;

#if defined(LWS_WITH_CUSTOM_HEADERS)
Expand Down
18 changes: 18 additions & 0 deletions lib/roles/http/server/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -1910,6 +1910,24 @@
lwsl_debug("%s: explicit 0 content-length\n", __func__);
}
}
#if defined(LWS_ROLE_H2)
else if (lwsi_role_h2(wsi) && wsi->mux_substream && wsi->h2.END_STREAM) {
/*
* h2 with no Content-Length, but END_STREAM already arrived on
* the HEADERS: the request body is empty and complete. Without
* this, a body-bearing method (POST/PUT/PATCH) would be left
* waiting on the 100MB default above for a body that will never
* come, stalling the request until it times out. Treat it as an
* explicit zero-length body, exactly as an explicit
* "Content-Length: 0" would (h3 does the equivalent in ops-h3.c).
*/
wsi->http.rx_content_remain = wsi->http.rx_content_length = 0;

Check warning on line 1924 in lib/roles/http/server/server.c

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Extract the assignment from this expression.

See more on https://sonarcloud.io/project/issues?id=warmcat_libwebsockets&issues=AZ7fGXCg0X-JifGO74hw&open=AZ7fGXCg0X-JifGO74hw&pullRequest=3616
wsi->http.content_length_given = 1;
wsi->http.content_length_explicitly_zero = 1;
lwsl_debug("%s: h2 END_STREAM, no content-length: empty body\n",
__func__);
}
#endif

if (wsi->mux_substream) {
wsi->http.request_version = HTTP_VERSION_2;
Expand Down
Loading