diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index 79e85a250..bd3656855 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -746,6 +746,7 @@ struct lws { unsigned int client_pipeline:1; unsigned int client_h2_alpn:1; unsigned int client_h2_substream:1; + unsigned int client_h2_migrated:1; #endif #ifdef _WIN32 diff --git a/lib/roles/h2/hpack.c b/lib/roles/h2/hpack.c index 199818776..f5493f7f2 100644 --- a/lib/roles/h2/hpack.c +++ b/lib/roles/h2/hpack.c @@ -396,7 +396,7 @@ lws_token_from_index(struct lws *wsi, int index, const char **arg, int *len, if (index >= (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries) { lwsl_info(" %s: adjusted index %d >= %d\n", __func__, index, - dyn->used_entries); + (int)LWS_ARRAY_SIZE(static_token) + dyn->used_entries); lws_h2_goaway(wsi, H2_ERR_COMPRESSION_ERROR, "index out of range"); return -1; @@ -1002,6 +1002,13 @@ int lws_hpack_interpret(struct lws *wsi, unsigned char c) h2n->hpack = HPKS_HLEN_EXT; break; } + + if (h2n->value && !h2n->hpack_len) { + lwsl_debug("%s: zero-length header data\n", __func__); + h2n->hpack = HPKS_TYPE; + goto fin; + } + pre_data: h2n->hpack = HPKS_DATA; if (!h2n->value || !h2n->hdr_idx) { @@ -1179,7 +1186,7 @@ swallow: "Huffman padding excessive or wrong"); return 1; } - +fin: if (!h2n->value && ( h2n->hpack_type == HPKT_LITERAL_HDR_VALUE || h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR || diff --git a/lib/roles/h2/http2.c b/lib/roles/h2/http2.c index 002dbaf90..363e5586b 100644 --- a/lib/roles/h2/http2.c +++ b/lib/roles/h2/http2.c @@ -166,7 +166,8 @@ lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi, * connection error (Section 5.4.1) of type PROTOCOL_ERROR. */ if (sid <= h2n->highest_sid_opened) { - lwsl_info("%s: tried to open lower sid %d\n", __func__, sid); + lwsl_info("%s: tried to open lower sid %d (%d)\n", __func__, + sid, h2n->highest_sid_opened); lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, "Bad sid"); return NULL; } @@ -1306,7 +1307,7 @@ lws_h2_parse_end_of_frame(struct lws *wsi) case LWS_H2_FRAME_TYPE_SETTINGS: #if defined(LWS_WITH_CLIENT) - if (wsi->client_h2_alpn && + if (wsi->client_h2_alpn && !wsi->client_h2_migrated && !(h2n->flags & LWS_H2_FLAG_SETTINGS_ACK)) { struct lws_h2_protocol_send *pps; @@ -1314,7 +1315,8 @@ lws_h2_parse_end_of_frame(struct lws *wsi) #if defined(LWS_WITH_FILE_OPS) wsi->http.fop_fd = NULL; #endif - + lwsl_info("%s: migrating\n", __func__); + wsi->client_h2_migrated = 1; /* * we need to treat the headers from the upgrade as the * first job. So these need to get shifted to sid 1. diff --git a/lib/roles/http/parsers.c b/lib/roles/http/parsers.c index 1897aa867..51ff6b9bb 100644 --- a/lib/roles/http/parsers.c +++ b/lib/roles/http/parsers.c @@ -1078,13 +1078,14 @@ swallow: c += 'a' - 'A'; #if defined(LWS_WITH_CUSTOM_HEADERS) + /* * ...in case it's an unknown header, speculatively * store it as the name comes in. If we recognize it as * a known header, we'll snip this. */ - if (!ah->unk_pos) { + if (!wsi->http2_substream && !ah->unk_pos) { ah->unk_pos = ah->pos; /* * Prepare new unknown header linked-list entry @@ -1106,7 +1107,7 @@ swallow: pos = ah->lextable_pos; #if defined(LWS_WITH_CUSTOM_HEADERS) - if (pos < 0 && c == ':') { + if (!wsi->http2_substream && pos < 0 && c == ':') { /* * process unknown headers * @@ -1170,13 +1171,16 @@ nope: /* b7 = 0, end or 3-byte */ if (lextable[pos] < FAIL_CHAR) { #if defined(LWS_WITH_CUSTOM_HEADERS) - /* - * We hit a terminal marker, so we - * recognized this header... drop the - * speculative name part storage - */ - ah->pos = ah->unk_pos; - ah->unk_pos = 0; + if (!wsi->http2_substream) { + /* + * We hit a terminal marker, so + * we recognized this header... + * drop the speculative name + * part storage + */ + ah->pos = ah->unk_pos; + ah->unk_pos = 0; + } #endif ah->lextable_pos = pos; break; @@ -1213,19 +1217,25 @@ nope: #if !defined(LWS_WITH_CUSTOM_HEADERS) ah->parser_state = WSI_TOKEN_SKIPPING; #endif + if (wsi->http2_substream) + ah->parser_state = WSI_TOKEN_SKIPPING; break; } - if (m != LWS_ARRAY_SIZE(methods)) + if (m != LWS_ARRAY_SIZE(methods)) { #if defined(LWS_WITH_CUSTOM_HEADERS) /* * We have the method, this is just an * unknown header then */ - goto unknown_hdr; + if (!wsi->http2_substream) + goto unknown_hdr; + else + break; #else break; #endif + } /* * ...it's an unknown http method from a client * in fact, it cannot be valid http. @@ -1246,15 +1256,15 @@ nope: } if (ah->lextable_pos < 0) { #if defined(LWS_WITH_CUSTOM_HEADERS) - goto unknown_hdr; -#else + if (!wsi->http2_substream) + goto unknown_hdr; +#endif /* * ...otherwise for a client, let him ignore * unknown headers coming from the server */ ah->parser_state = WSI_TOKEN_SKIPPING; break; -#endif } if (lextable[ah->lextable_pos] < FAIL_CHAR) { @@ -1301,7 +1311,8 @@ nope: unknown_hdr: //ah->parser_state = WSI_TOKEN_SKIPPING; //break; - break; + if (!wsi->http2_substream) + break; #endif start_fragment: