From 5afc77b044f8d57ded3c399eb08ec009a87267fa Mon Sep 17 00:00:00 2001 From: James M Snell Date: Fri, 5 Oct 2018 13:09:10 -0700 Subject: [PATCH] deps: update nghttp2 to 1.34.0 Key new feature: RFC 8441 `:protocol` support PR-URL: https://github.com/nodejs/node/pull/23284 Reviewed-By: Refael Ackermann Reviewed-By: Gus Caplan Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat --- deps/nghttp2/lib/includes/nghttp2/nghttp2.h | 7 +++- .../nghttp2/lib/includes/nghttp2/nghttp2ver.h | 4 +- deps/nghttp2/lib/nghttp2_frame.c | 5 +++ deps/nghttp2/lib/nghttp2_hd.c | 20 +++++++--- deps/nghttp2/lib/nghttp2_hd.h | 1 + deps/nghttp2/lib/nghttp2_helper.c | 4 +- deps/nghttp2/lib/nghttp2_http.c | 39 ++++++++++++------- deps/nghttp2/lib/nghttp2_session.c | 35 +++++++++++++++++ deps/nghttp2/lib/nghttp2_session.h | 4 ++ deps/nghttp2/lib/nghttp2_stream.h | 3 +- 10 files changed, 96 insertions(+), 26 deletions(-) diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h index 8c54b9c8cc464d..e7198b3d27314d 100644 --- a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h +++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h @@ -680,7 +680,12 @@ typedef enum { /** * SETTINGS_MAX_HEADER_LIST_SIZE */ - NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 0x06 + NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 0x06, + /** + * SETTINGS_ENABLE_CONNECT_PROTOCOL + * (`RFC 8441 `_) + */ + NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL = 0x08 } nghttp2_settings_id; /* Note: If we add SETTINGS, update the capacity of NGHTTP2_INBOUND_NUM_IV as well */ diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h index 1f1d4808ca27c0..420adbd53dddce 100644 --- a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h +++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h @@ -29,7 +29,7 @@ * @macro * Version number of the nghttp2 library release */ -#define NGHTTP2_VERSION "1.33.0" +#define NGHTTP2_VERSION "1.34.0" /** * @macro @@ -37,6 +37,6 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define NGHTTP2_VERSION_NUM 0x012100 +#define NGHTTP2_VERSION_NUM 0x012200 #endif /* NGHTTP2VER_H */ diff --git a/deps/nghttp2/lib/nghttp2_frame.c b/deps/nghttp2/lib/nghttp2_frame.c index 6e33f3c247f5cb..4821de40885736 100644 --- a/deps/nghttp2/lib/nghttp2_frame.c +++ b/deps/nghttp2/lib/nghttp2_frame.c @@ -1050,6 +1050,11 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) { break; case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: break; + case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: + if (iv[i].value != 0 && iv[i].value != 1) { + return 0; + } + break; } } return 1; diff --git a/deps/nghttp2/lib/nghttp2_hd.c b/deps/nghttp2/lib/nghttp2_hd.c index 1eb3be33802c44..a61f0d47a6f79d 100644 --- a/deps/nghttp2/lib/nghttp2_hd.c +++ b/deps/nghttp2/lib/nghttp2_hd.c @@ -45,7 +45,7 @@ /* 3rd parameter is nghttp2_token value for header field name. We use first enum value if same header names are repeated (e.g., :status). */ -static nghttp2_hd_static_entry static_table[] = { +static const nghttp2_hd_static_entry static_table[] = { MAKE_STATIC_ENT(":authority", "", 0, 3153725150u), MAKE_STATIC_ENT(":method", "GET", 1, 695666056u), MAKE_STATIC_ENT(":method", "POST", 1, 695666056u), @@ -271,6 +271,15 @@ static int32_t lookup_token(const uint8_t *name, size_t namelen) { break; } break; + case 9: + switch (name[8]) { + case 'l': + if (memeq(":protoco", name, 8)) { + return NGHTTP2_TOKEN__PROTOCOL; + } + break; + } + break; case 10: switch (name[9]) { case 'e': @@ -1159,7 +1168,7 @@ static search_result search_static_table(const nghttp2_nv *nv, int32_t token, int name_only) { search_result res = {token, 0}; int i; - nghttp2_hd_static_entry *ent; + const nghttp2_hd_static_entry *ent; if (name_only) { return res; @@ -1184,7 +1193,7 @@ static search_result search_hd_table(nghttp2_hd_context *context, int indexing_mode, nghttp2_hd_map *map, uint32_t hash) { search_result res = {-1, 0}; - nghttp2_hd_entry *ent; + const nghttp2_hd_entry *ent; int exact_match; int name_only = indexing_mode == NGHTTP2_HD_NEVER_INDEXING; @@ -1289,8 +1298,9 @@ nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) { return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH) ->nv; } else { - nghttp2_hd_static_entry *ent = &static_table[idx]; - nghttp2_hd_nv nv = {&ent->name, &ent->value, ent->token, + const nghttp2_hd_static_entry *ent = &static_table[idx]; + nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name, + (nghttp2_rcbuf *)&ent->value, ent->token, NGHTTP2_NV_FLAG_NONE}; return nv; } diff --git a/deps/nghttp2/lib/nghttp2_hd.h b/deps/nghttp2/lib/nghttp2_hd.h index c64a1f2b9b406c..14ae98078957af 100644 --- a/deps/nghttp2/lib/nghttp2_hd.h +++ b/deps/nghttp2/lib/nghttp2_hd.h @@ -111,6 +111,7 @@ typedef enum { NGHTTP2_TOKEN_KEEP_ALIVE, NGHTTP2_TOKEN_PROXY_CONNECTION, NGHTTP2_TOKEN_UPGRADE, + NGHTTP2_TOKEN__PROTOCOL, } nghttp2_token; struct nghttp2_hd_entry; diff --git a/deps/nghttp2/lib/nghttp2_helper.c b/deps/nghttp2/lib/nghttp2_helper.c index 3b282c7301f95b..81a8a0cf99971a 100644 --- a/deps/nghttp2/lib/nghttp2_helper.c +++ b/deps/nghttp2/lib/nghttp2_helper.c @@ -340,7 +340,7 @@ const char *nghttp2_strerror(int error_code) { } /* Generated by gennmchartbl.py */ -static int VALID_HD_NAME_CHARS[] = { +static const int VALID_HD_NAME_CHARS[] = { 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */, @@ -428,7 +428,7 @@ int nghttp2_check_header_name(const uint8_t *name, size_t len) { } /* Generated by genvchartbl.py */ -static int VALID_HD_VALUE_CHARS[] = { +static const int VALID_HD_VALUE_CHARS[] = { 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */, diff --git a/deps/nghttp2/lib/nghttp2_http.c b/deps/nghttp2/lib/nghttp2_http.c index b08f8863f7ce16..6e8acfdcc141af 100644 --- a/deps/nghttp2/lib/nghttp2_http.c +++ b/deps/nghttp2/lib/nghttp2_http.c @@ -113,7 +113,7 @@ static int check_path(nghttp2_stream *stream) { } static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, - int trailer) { + int trailer, int connect_protocol) { if (nv->name->base[0] == ':') { if (trailer || (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) { @@ -146,10 +146,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, return NGHTTP2_ERR_HTTP_HEADER; } stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT; - if (stream->http_flags & - (NGHTTP2_HTTP_FLAG__PATH | NGHTTP2_HTTP_FLAG__SCHEME)) { - return NGHTTP2_ERR_HTTP_HEADER; - } } break; case 'S': @@ -162,9 +158,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, } break; case NGHTTP2_TOKEN__PATH: - if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) { - return NGHTTP2_ERR_HTTP_HEADER; - } if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) { return NGHTTP2_ERR_HTTP_HEADER; } @@ -175,9 +168,6 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, } break; case NGHTTP2_TOKEN__SCHEME: - if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) { - return NGHTTP2_ERR_HTTP_HEADER; - } if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) { return NGHTTP2_ERR_HTTP_HEADER; } @@ -186,6 +176,15 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP; } break; + case NGHTTP2_TOKEN__PROTOCOL: + if (!connect_protocol) { + return NGHTTP2_ERR_HTTP_HEADER; + } + + if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PROTOCOL)) { + return NGHTTP2_ERR_HTTP_HEADER; + } + break; case NGHTTP2_TOKEN_HOST: if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) { return NGHTTP2_ERR_HTTP_HEADER; @@ -265,7 +264,7 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv, return NGHTTP2_ERR_REMOVE_HTTP_HEADER; } if (stream->status_code / 100 == 1 || - (stream->status_code == 200 && + (stream->status_code / 100 == 2 && (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT))) { return NGHTTP2_ERR_HTTP_HEADER; } @@ -458,7 +457,9 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream, } if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) { - return http_request_on_header(stream, nv, trailer); + return http_request_on_header(stream, nv, trailer, + session->server && + session->pending_enable_connect_protocol); } return http_response_on_header(stream, nv, trailer); @@ -466,8 +467,11 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream, int nghttp2_http_on_request_headers(nghttp2_stream *stream, nghttp2_frame *frame) { - if (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) { - if ((stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) { + if (!(stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) && + (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) { + if ((stream->http_flags & + (NGHTTP2_HTTP_FLAG__SCHEME | NGHTTP2_HTTP_FLAG__PATH)) || + (stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) { return -1; } stream->content_length = -1; @@ -478,6 +482,11 @@ int nghttp2_http_on_request_headers(nghttp2_stream *stream, (NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) { return -1; } + if ((stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) && + ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) == 0 || + (stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0)) { + return -1; + } if (!check_path(stream)) { return -1; } diff --git a/deps/nghttp2/lib/nghttp2_session.c b/deps/nghttp2/lib/nghttp2_session.c index 418ad6663585f5..ef4932af4e4f58 100644 --- a/deps/nghttp2/lib/nghttp2_session.c +++ b/deps/nghttp2/lib/nghttp2_session.c @@ -4361,6 +4361,9 @@ int nghttp2_session_update_local_settings(nghttp2_session *session, case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: session->local_settings.max_header_list_size = iv[i].value; break; + case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: + session->local_settings.enable_connect_protocol = iv[i].value; + break; } } @@ -4499,6 +4502,26 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, session->remote_settings.max_header_list_size = entry->value; + break; + case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: + + if (entry->value != 0 && entry->value != 1) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "SETTINGS: invalid SETTINGS_ENABLE_CONNECT_PROTOCOL"); + } + + if (!session->server && + session->remote_settings.enable_connect_protocol && + entry->value == 0) { + return session_handle_invalid_connection( + session, frame, NGHTTP2_ERR_PROTO, + "SETTINGS: server attempted to disable " + "SETTINGS_ENABLE_CONNECT_PROTOCOL"); + } + + session->remote_settings.enable_connect_protocol = entry->value; + break; } } @@ -5250,6 +5273,7 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) { case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: + case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: break; default: DEBUGF("recv: unknown settings id=0x%02x\n", iv.settings_id); @@ -7052,6 +7076,13 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, } } + for (i = niv; i > 0; --i) { + if (iv[i - 1].settings_id == NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL) { + session->pending_enable_connect_protocol = (uint8_t)iv[i - 1].value; + break; + } + } + return 0; } @@ -7360,6 +7391,8 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session, return session->remote_settings.max_frame_size; case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: return session->remote_settings.max_header_list_size; + case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: + return session->remote_settings.enable_connect_protocol; } assert(0); @@ -7381,6 +7414,8 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session, return session->local_settings.max_frame_size; case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: return session->local_settings.max_header_list_size; + case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL: + return session->local_settings.enable_connect_protocol; } assert(0); diff --git a/deps/nghttp2/lib/nghttp2_session.h b/deps/nghttp2/lib/nghttp2_session.h index 5add50bc8bce16..40a8865a04b12f 100644 --- a/deps/nghttp2/lib/nghttp2_session.h +++ b/deps/nghttp2/lib/nghttp2_session.h @@ -164,6 +164,7 @@ typedef struct { uint32_t initial_window_size; uint32_t max_frame_size; uint32_t max_header_list_size; + uint32_t enable_connect_protocol; } nghttp2_settings_storage; typedef enum { @@ -321,6 +322,9 @@ struct nghttp2_session { /* Unacked local ENABLE_PUSH value. We use this to refuse PUSH_PROMISE before SETTINGS ACK is received. */ uint8_t pending_enable_push; + /* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to + accept :protocol header field before SETTINGS_ACK is received. */ + uint8_t pending_enable_connect_protocol; /* Nonzero if the session is server side. */ uint8_t server; /* Flags indicating GOAWAY is sent and/or received. The flags are diff --git a/deps/nghttp2/lib/nghttp2_stream.h b/deps/nghttp2/lib/nghttp2_stream.h index d1d5856d800e76..fb8dc14d67be6d 100644 --- a/deps/nghttp2/lib/nghttp2_stream.h +++ b/deps/nghttp2/lib/nghttp2_stream.h @@ -130,7 +130,8 @@ typedef enum { /* "http" or "https" scheme */ NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13, /* set if final response is expected */ - NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14 + NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14, + NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15, } nghttp2_http_flag; struct nghttp2_stream {