diff --git a/CMakeLists.txt b/CMakeLists.txt index 43a559e2..45c7b7d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,10 @@ cmake_minimum_required(VERSION 2.8.9) +# General Advice +# +# For selecting between DEBUG / RELEASE, use -DCMAKE_BUILD_TYPE=DEBUG or =RELEASE +# debug builds include source level debug info and extra logging + if(NOT DEFINED CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type") endif() diff --git a/lib/http2/hpack.c b/lib/http2/hpack.c index f37d67a4..707de1f1 100644 --- a/lib/http2/hpack.c +++ b/lib/http2/hpack.c @@ -712,6 +712,38 @@ lws_hpack_use_idx_hdr(struct lws *wsi, int idx, int known_token) return 0; } +static uint8_t lws_header_implies_psuedoheader_map[] = { + 0x07, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00 /* <-64 */, + 0x0e /* <- 72 */, 0x04 /* <- 80 */, 0, 0, 0, 0 +}; + +static int +lws_hpack_handle_pseudo_rules(struct lws *nwsi, struct lws *wsi, int m) +{ + if (m == LWS_HPACK_IGNORE_ENTRY || m == -1) + return 0; + + if (wsi->seen_nonpseudoheader && + (lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7)))) { + + lwsl_notice("lws tok %d seems to be a pseudoheader\n", m); + + /* + * it's not legal to see a + * pseudoheader after normal + * headers + */ + lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, + "Pseudoheader after normal hdrs"); + return 1; + } + + if (!(lws_header_implies_psuedoheader_map[m >> 3] & (1 << (m & 7)))) + wsi->seen_nonpseudoheader = 1; + + return 0; +} + int lws_hpack_interpret(struct lws *wsi, unsigned char c) { struct lws *nwsi = lws_get_network_wsi(wsi); @@ -743,6 +775,7 @@ int lws_hpack_interpret(struct lws *wsi, unsigned char c) h2n->ext_count = 0; h2n->hpack_hdr_len = 0; h2n->unknown_header = 0; + wsi->u.hdr.parser_state = 255; if (c & 0x80) { /* 1.... indexed header field only */ /* just a possibly-extended integer */ @@ -762,6 +795,12 @@ int lws_hpack_interpret(struct lws *wsi, unsigned char c) "hdr index 0 seen"); return 1; } + + m = lws_token_from_index(wsi, h2n->hdr_idx, + NULL, NULL, NULL); + if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m)) + return 1; + lwsl_header("HPKT_INDEXED_HDR_7: hdr %d\n", c & 0x7f); if (lws_hpack_use_idx_hdr(wsi, c & 0x7f, -1)) { lwsl_header("%s: idx hdr wr fail\n", __func__); @@ -1113,6 +1152,7 @@ swallow: wsi->u.hdr.parser_state == WSI_TOKEN_SKIPPING) { h2n->unknown_header = 1; wsi->u.hdr.parser_state = -1; + wsi->seen_nonpseudoheader = 1; } } @@ -1132,6 +1172,7 @@ swallow: * we have got both the header and value */ + m = -1; switch (h2n->hpack_type) { /* * These are the only two that insert to the dyntable @@ -1187,39 +1228,26 @@ add_it: if (h2n->hdr_idx != LWS_HPACK_IGNORE_ENTRY && lws_frag_end(wsi)) return 1; - if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE || - h2n->hpack_type == HPKT_INDEXED_HDR_6_VALUE_INCR || - h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR || - h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) { - m = wsi->u.hdr.parser_state; - if (m == 255) - m = -1; - } else - m = lws_token_from_index(wsi, h2n->hdr_idx, NULL, NULL, - NULL); + if (h2n->hpack_type != HPKT_INDEXED_HDR_6_VALUE_INCR) { + + if (h2n->hpack_type == HPKT_LITERAL_HDR_VALUE || + h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_INCR || + h2n->hpack_type == HPKT_LITERAL_HDR_VALUE_NEVER) { + m = wsi->u.hdr.parser_state; + if (m == 255) + m = -1; + } else { + m = lws_token_from_index(wsi, h2n->hdr_idx, NULL, NULL, + NULL); + //lwsl_notice("token from index(%d) says %d\n", h2n->hdr_idx, m); + } + } + if (m != -1 && m != LWS_HPACK_IGNORE_ENTRY) lws_dump_header(wsi, m); - if (h2n->seen_nonpseudoheader && ( - m == WSI_TOKEN_HTTP_COLON_AUTHORITY || - m == WSI_TOKEN_HTTP_COLON_METHOD || - m == WSI_TOKEN_HTTP_COLON_PATH || - m == WSI_TOKEN_HTTP_COLON_SCHEME)) { - /* - * it's not legal to see a - * pseudoheader after normal - * headers - */ - lws_h2_goaway(nwsi, H2_ERR_PROTOCOL_ERROR, - "Pseudoheader after normal hdrs"); + if (lws_hpack_handle_pseudo_rules(nwsi, wsi, m)) return 1; - } - - if (m != WSI_TOKEN_HTTP_COLON_AUTHORITY && - m != WSI_TOKEN_HTTP_COLON_METHOD && - m != WSI_TOKEN_HTTP_COLON_PATH && - m != WSI_TOKEN_HTTP_COLON_SCHEME) - h2n->seen_nonpseudoheader = 1; h2n->is_first_header_char = 1; h2n->hpack = HPKS_TYPE; @@ -1229,6 +1257,8 @@ add_it: return 0; } + + static int lws_h2_num_start(int starting_bits, unsigned long num) { diff --git a/lib/http2/http2.c b/lib/http2/http2.c index 5df80d7c..a78e1613 100644 --- a/lib/http2/http2.c +++ b/lib/http2/http2.c @@ -170,6 +170,7 @@ lws_wsi_server_new(struct lws_vhost *vh, struct lws *parent_wsi, h2n->highest_sid_opened = sid; wsi->u.h2.my_sid = sid; wsi->http2_substream = 1; + wsi->seen_nonpseudoheader = 0; wsi->u.h2.parent_wsi = parent_wsi; /* new guy's sibling is whoever was the first child before */ @@ -1003,7 +1004,6 @@ lws_h2_parse_frame_header(struct lws *wsi) h2n->cont_exp = !(h2n->flags & LWS_H2_FLAG_END_HEADERS); h2n->cont_exp_sid = h2n->sid; h2n->cont_exp_headers = 1; - h2n->seen_nonpseudoheader = 0; lws_header_table_reset(h2n->swsi, 0); update_end_headers: diff --git a/lib/pollfd.c b/lib/pollfd.c index 38d6611e..8bd887fa 100644 --- a/lib/pollfd.c +++ b/lib/pollfd.c @@ -537,9 +537,14 @@ LWS_VISIBLE int lws_callback_on_writable_all_protocol(const struct lws_context *context, const struct lws_protocols *protocol) { - struct lws_vhost *vhost = context->vhost_list; + struct lws_vhost *vhost; int n; + if (!context) + return 0; + + vhost = context->vhost_list; + while (vhost) { for (n = 0; n < vhost->count_protocols; n++) if (protocol->callback == diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 2d325075..4911de70 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -1681,7 +1681,6 @@ struct lws_h2_netconn { unsigned int pad_length:1; unsigned int collected_priority:1; unsigned int is_first_header_char:1; - unsigned int seen_nonpseudoheader:1; unsigned int zero_huff_padding:1; unsigned int last_action_dyntable_resize:1; @@ -1970,6 +1969,7 @@ struct lws { unsigned int hdr_parsing_completed:1; unsigned int http2_substream:1; unsigned int upgraded_to_http2:1; + unsigned int seen_nonpseudoheader:1; unsigned int listener:1; unsigned int user_space_externally_allocated:1; unsigned int socket_is_permanently_unusable:1;