From 7bf009c6e3114d99c6454493c24578e7df3b05bc Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 20 Aug 2017 23:48:15 +0200 Subject: [PATCH] deps: update nghttp2 to v1.25.0 PR-URL: https://github.com/nodejs/node/pull/14955 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig --- deps/nghttp2/lib/Makefile.msvc | 12 +- deps/nghttp2/lib/includes/nghttp2/nghttp2.h | 32 ++-- .../nghttp2/lib/includes/nghttp2/nghttp2ver.h | 4 +- deps/nghttp2/lib/nghttp2_frame.c | 3 + deps/nghttp2/lib/nghttp2_hd.c | 6 +- deps/nghttp2/lib/nghttp2_pq.h | 2 +- deps/nghttp2/lib/nghttp2_session.c | 177 ++++++++++-------- deps/nghttp2/lib/nghttp2_session.h | 2 +- 8 files changed, 135 insertions(+), 103 deletions(-) diff --git a/deps/nghttp2/lib/Makefile.msvc b/deps/nghttp2/lib/Makefile.msvc index cef359ee256cbb..0077dc4e5170a1 100644 --- a/deps/nghttp2/lib/Makefile.msvc +++ b/deps/nghttp2/lib/Makefile.msvc @@ -50,7 +50,7 @@ IMP_D := $(OBJ_DIR)/nghttp2d.lib TARGETS := $(LIB_R) $(DLL_R) $(IMP_R) \ $(LIB_D) $(DLL_D) $(IMP_D) -EXT_LIBS = +EXT_LIBS = NGHTTP2_PDB_R := $(OBJ_DIR)/nghttp2.pdb NGHTTP2_PDB_D := $(OBJ_DIR)/nghttp2d.pdb @@ -121,7 +121,7 @@ $(OBJ_DIR): install: includes/nghttp2/nghttp2.h includes/nghttp2/nghttp2ver.h \ $(TARGETS) \ - copy_headers_and_libs install_nghttp2_pyd_$(USE_CYTHON) + copy_headers_and_libs install_nghttp2_pyd_$(USE_CYTHON) # # This MUST be done before using the 'install_nghttp2_pyd_1' rule. @@ -144,14 +144,14 @@ $(LIB_D): $(NGHTTP2_OBJ_D) $(IMP_R): $(DLL_R) -$(DLL_R): $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res +$(DLL_R): $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res $(LD) $(LDFLAGS) -dll -out:$@ -implib:$(IMP_R) $(NGHTTP2_OBJ_R) -PDB:$(NGHTTP2_PDB_R) $(OBJ_DIR)/r_nghttp2.res $(EXT_LIBS) mt -nologo -manifest $@.manifest -outputresource:$@\;2 @echo $(IMP_D): $(DLL_D) - -$(DLL_D): $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res + +$(DLL_D): $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res $(LD) $(LDFLAGS) -dll -out:$@ -implib:$(IMP_D) $(NGHTTP2_OBJ_D) -PDB:$(NGHTTP2_PDB_D) $(OBJ_DIR)/d_nghttp2.res $(EXT_LIBS) mt -nologo -manifest $@.manifest -outputresource:$@\;2 @echo @@ -174,7 +174,7 @@ build_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx) python setup.py build_ext -i -f bdist_wininst install_nghttp2_pyd_0: ; - + install_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx) cd ../python ; \ pip install . diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h index 848ef066be4405..5696a2ef633653 100644 --- a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h +++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h @@ -472,9 +472,9 @@ NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf); /** * @function * - * Returns 1 if the underlying buffer is statically allocated, - * and 0 otherwise. This can be useful for language bindings that wish to avoid - * creating duplicate strings for these buffers. + * Returns nonzero if the underlying buffer is statically allocated, + * and 0 otherwise. This can be useful for language bindings that wish + * to avoid creating duplicate strings for these buffers. */ NGHTTP2_EXTERN int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf); @@ -1750,11 +1750,12 @@ typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session, * The parameter and behaviour are similar to * :type:`nghttp2_on_header_callback`. The difference is that this * callback is only invoked when a invalid header name/value pair is - * received which is silently ignored if this callback is not set. - * Only invalid regular header field are passed to this callback. In - * other words, invalid pseudo header field is not passed to this - * callback. Also header fields which includes upper cased latter are - * also treated as error without passing them to this callback. + * received which is treated as stream error if this callback is not + * set. Only invalid regular header field are passed to this + * callback. In other words, invalid pseudo header field is not + * passed to this callback. Also header fields which includes upper + * cased latter are also treated as error without passing them to this + * callback. * * This callback is only considered if HTTP messaging validation is * turned on (which is on by default, see @@ -1763,10 +1764,13 @@ typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session, * With this callback, application inspects the incoming invalid * field, and it also can reset stream from this callback by returning * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. By default, the - * error code is :enum:`NGHTTP2_INTERNAL_ERROR`. To change the error + * error code is :enum:`NGHTTP2_PROTOCOL_ERROR`. To change the error * code, call `nghttp2_submit_rst_stream()` with the error code of * choice in addition to returning * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`. + * + * If 0 is returned, the header field is ignored, and the stream is + * not reset. */ typedef int (*nghttp2_on_invalid_header_callback)( nghttp2_session *session, const nghttp2_frame *frame, const uint8_t *name, @@ -2457,7 +2461,10 @@ nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val); * `_. See * :ref:`http-messaging` section for details. For those applications * who use nghttp2 library as non-HTTP use, give nonzero to |val| to - * disable this enforcement. + * disable this enforcement. Please note that disabling this feature + * does not change the fundamental client and server model of HTTP. + * That is, even if the validation is disabled, only client can send + * requests. */ NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val); @@ -3811,9 +3818,8 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id, * Submits trailer fields HEADERS against the stream |stream_id|. * * The |nva| is an array of name/value pair :type:`nghttp2_nv` with - * |nvlen| elements. The application is responsible not to include - * pseudo-header fields (header field whose name starts with ":") in - * |nva|. + * |nvlen| elements. The application must not include pseudo-header + * fields (headers whose names starts with ":") in |nva|. * * This function creates copies of all name/value pairs in |nva|. It * also lower-cases all names in |nva|. The order of elements in diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h index dd0587d1642c38..c4024e1684871d 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.22.0" +#define NGHTTP2_VERSION "1.21.0-DEV" /** * @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 0x011600 +#define NGHTTP2_VERSION_NUM 0x011500 #endif /* NGHTTP2VER_H */ diff --git a/deps/nghttp2/lib/nghttp2_frame.c b/deps/nghttp2/lib/nghttp2_frame.c index 90efaff5317161..210df0584443df 100644 --- a/deps/nghttp2/lib/nghttp2_frame.c +++ b/deps/nghttp2/lib/nghttp2_frame.c @@ -672,6 +672,9 @@ int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) { nghttp2_buf *buf; nghttp2_ext_altsvc *altsvc; + /* This is required with --disable-assert. */ + (void)rv; + altsvc = frame->payload; buf = &bufs->head->buf; diff --git a/deps/nghttp2/lib/nghttp2_hd.c b/deps/nghttp2/lib/nghttp2_hd.c index e9a109dcc1da94..1eb3be33802c44 100644 --- a/deps/nghttp2/lib/nghttp2_hd.c +++ b/deps/nghttp2/lib/nghttp2_hd.c @@ -662,9 +662,9 @@ static int hd_context_init(nghttp2_hd_context *context, nghttp2_mem *mem) { context->mem = mem; context->bad = 0; context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; - rv = hd_ringbuf_init(&context->hd_table, context->hd_table_bufsize_max / - NGHTTP2_HD_ENTRY_OVERHEAD, - mem); + rv = hd_ringbuf_init( + &context->hd_table, + context->hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD, mem); if (rv != 0) { return rv; } diff --git a/deps/nghttp2/lib/nghttp2_pq.h b/deps/nghttp2/lib/nghttp2_pq.h index 6b0ecfb4763494..1426bef760132c 100644 --- a/deps/nghttp2/lib/nghttp2_pq.h +++ b/deps/nghttp2/lib/nghttp2_pq.h @@ -42,7 +42,7 @@ typedef struct { nghttp2_pq_entry **q; /* Memory allocator */ nghttp2_mem *mem; - /* The number of items sotred */ + /* The number of items stored */ size_t length; /* The maximum number of items this pq can store. This is automatically extended when length is reached to this value. */ diff --git a/deps/nghttp2/lib/nghttp2_session.c b/deps/nghttp2/lib/nghttp2_session.c index 1c060f1b10e612..4bc94cbb1982ad 100644 --- a/deps/nghttp2/lib/nghttp2_session.c +++ b/deps/nghttp2/lib/nghttp2_session.c @@ -1524,13 +1524,14 @@ static int session_predicate_response_headers_send(nghttp2_session *session, if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { return NGHTTP2_ERR_INVALID_STREAM_ID; } - if (stream->state == NGHTTP2_STREAM_OPENING) { + switch (stream->state) { + case NGHTTP2_STREAM_OPENING: return 0; - } - if (stream->state == NGHTTP2_STREAM_CLOSING) { + case NGHTTP2_STREAM_CLOSING: return NGHTTP2_ERR_STREAM_CLOSING; + default: + return NGHTTP2_ERR_INVALID_STREAM_STATE; } - return NGHTTP2_ERR_INVALID_STREAM_STATE; } /* @@ -1573,9 +1574,6 @@ session_predicate_push_response_headers_send(nghttp2_session *session, if (stream->state != NGHTTP2_STREAM_RESERVED) { return NGHTTP2_ERR_PROTO; } - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_STREAM_CLOSING; - } if (session->goaway_flags & NGHTTP2_GOAWAY_RECV) { return NGHTTP2_ERR_START_STREAM_NOT_ALLOWED; } @@ -1610,19 +1608,18 @@ static int session_predicate_headers_send(nghttp2_session *session, return rv; } assert(stream); - if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { - if (stream->state == NGHTTP2_STREAM_CLOSING) { - return NGHTTP2_ERR_STREAM_CLOSING; - } - return 0; - } - if (stream->state == NGHTTP2_STREAM_OPENED) { + + switch (stream->state) { + case NGHTTP2_STREAM_OPENED: return 0; - } - if (stream->state == NGHTTP2_STREAM_CLOSING) { + case NGHTTP2_STREAM_CLOSING: return NGHTTP2_ERR_STREAM_CLOSING; + default: + if (nghttp2_session_is_my_stream_id(session, stream->stream_id)) { + return 0; + } + return NGHTTP2_ERR_INVALID_STREAM_STATE; } - return NGHTTP2_ERR_INVALID_STREAM_STATE; } /* @@ -2068,14 +2065,6 @@ static int session_prep_frame(nghttp2_session *session, /* We don't call nghttp2_session_adjust_closed_stream() here, since we don't keep closed stream in client side */ - estimated_payloadlen = session_estimate_headers_payload( - session, frame->headers.nva, frame->headers.nvlen, - NGHTTP2_PRIORITY_SPECLEN); - - if (estimated_payloadlen > session->max_send_header_block_length) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - rv = session_predicate_request_headers_send(session, item); if (rv != 0) { return rv; @@ -2087,14 +2076,6 @@ static int session_prep_frame(nghttp2_session *session, } else { nghttp2_stream *stream; - estimated_payloadlen = session_estimate_headers_payload( - session, frame->headers.nva, frame->headers.nvlen, - NGHTTP2_PRIORITY_SPECLEN); - - if (estimated_payloadlen > session->max_send_header_block_length) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); if (stream && stream->state == NGHTTP2_STREAM_RESERVED) { @@ -2121,6 +2102,14 @@ static int session_prep_frame(nghttp2_session *session, } } + estimated_payloadlen = session_estimate_headers_payload( + session, frame->headers.nva, frame->headers.nvlen, + NGHTTP2_PRIORITY_SPECLEN); + + if (estimated_payloadlen > session->max_send_header_block_length) { + return NGHTTP2_ERR_FRAME_SIZE_ERROR; + } + rv = nghttp2_frame_pack_headers(&session->aob.framebufs, &frame->headers, &session->hd_deflater); @@ -2190,13 +2179,6 @@ static int session_prep_frame(nghttp2_session *session, nghttp2_stream *stream; size_t estimated_payloadlen; - estimated_payloadlen = session_estimate_headers_payload( - session, frame->push_promise.nva, frame->push_promise.nvlen, 0); - - if (estimated_payloadlen > session->max_send_header_block_length) { - return NGHTTP2_ERR_FRAME_SIZE_ERROR; - } - /* stream could be NULL if associated stream was already closed. */ stream = nghttp2_session_get_stream(session, frame->hd.stream_id); @@ -2209,6 +2191,13 @@ static int session_prep_frame(nghttp2_session *session, assert(stream); + estimated_payloadlen = session_estimate_headers_payload( + session, frame->push_promise.nva, frame->push_promise.nvlen, 0); + + if (estimated_payloadlen > session->max_send_header_block_length) { + return NGHTTP2_ERR_FRAME_SIZE_ERROR; + } + rv = nghttp2_frame_pack_push_promise( &session->aob.framebufs, &frame->push_promise, &session->hd_deflater); if (rv != 0) { @@ -3332,7 +3321,7 @@ static int session_call_on_invalid_header(nghttp2_session *session, session, frame, nv->name->base, nv->name->len, nv->value->base, nv->value->len, nv->flags, session->user_data); } else { - return 0; + return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { @@ -3422,6 +3411,27 @@ static uint32_t get_error_code_from_lib_error_code(int lib_error_code) { } } +/* + * Calls on_invalid_frame_recv_callback if it is set to |session|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_CALLBACK_FAILURE + * User defined callback function fails. + */ +static int session_call_on_invalid_frame_recv_callback(nghttp2_session *session, + nghttp2_frame *frame, + int lib_error_code) { + if (session->callbacks.on_invalid_frame_recv_callback) { + if (session->callbacks.on_invalid_frame_recv_callback( + session, frame, lib_error_code, session->user_data) != 0) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + } + return 0; +} + static int session_handle_invalid_stream2(nghttp2_session *session, int32_t stream_id, nghttp2_frame *frame, @@ -3579,6 +3589,37 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, if (subject_stream && session_enforce_http_messaging(session)) { rv = nghttp2_http_on_header(session, subject_stream, frame, &nv, trailer); + + if (rv == NGHTTP2_ERR_IGN_HTTP_HEADER) { + /* Don't overwrite rv here */ + int rv2; + + rv2 = session_call_on_invalid_header(session, frame, &nv); + if (rv2 == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + rv = NGHTTP2_ERR_HTTP_HEADER; + } else { + if (rv2 != 0) { + return rv2; + } + + /* header is ignored */ + DEBUGF("recv: HTTP ignored: type=%u, id=%d, header %.*s: %.*s\n", + frame->hd.type, frame->hd.stream_id, (int)nv.name->len, + nv.name->base, (int)nv.value->len, nv.value->base); + + rv2 = session_call_error_callback( + session, + "Ignoring received invalid HTTP header field: frame type: " + "%u, stream: %d, name: [%.*s], value: [%.*s]", + frame->hd.type, frame->hd.stream_id, (int)nv.name->len, + nv.name->base, (int)nv.value->len, nv.value->base); + + if (nghttp2_is_fatal(rv2)) { + return rv2; + } + } + } + if (rv == NGHTTP2_ERR_HTTP_HEADER) { DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n", frame->hd.type, frame->hd.stream_id, (int)nv.name->len, @@ -3602,34 +3643,6 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame, } return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } - - if (rv == NGHTTP2_ERR_IGN_HTTP_HEADER) { - /* Don't overwrite rv here */ - int rv2; - - rv2 = session_call_on_invalid_header(session, frame, &nv); - /* This handles NGHTTP2_ERR_PAUSE and - NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE as well */ - if (rv2 != 0) { - return rv2; - } - - /* header is ignored */ - DEBUGF("recv: HTTP ignored: type=%u, id=%d, header %.*s: %.*s\n", - frame->hd.type, frame->hd.stream_id, (int)nv.name->len, - nv.name->base, (int)nv.value->len, nv.value->base); - - rv2 = session_call_error_callback( - session, - "Ignoring received invalid HTTP header field: frame type: " - "%u, stream: %d, name: [%.*s], value: [%.*s]", - frame->hd.type, frame->hd.stream_id, (int)nv.name->len, - nv.name->base, (int)nv.value->len, nv.value->base); - - if (nghttp2_is_fatal(rv2)) { - return rv2; - } - } } if (rv == 0) { rv = session_call_on_header(session, frame, &nv); @@ -4772,11 +4785,13 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session, if (frame->hd.stream_id == 0) { if (altsvc->origin_len == 0) { - return 0; + return session_call_on_invalid_frame_recv_callback(session, frame, + NGHTTP2_ERR_PROTO); } } else { if (altsvc->origin_len > 0) { - return 0; + return session_call_on_invalid_frame_recv_callback(session, frame, + NGHTTP2_ERR_PROTO); } stream = nghttp2_session_get_stream(session, frame->hd.stream_id); @@ -4789,6 +4804,11 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session, } } + if (altsvc->field_value_len == 0) { + return session_call_on_invalid_frame_recv_callback(session, frame, + NGHTTP2_ERR_PROTO); + } + return session_call_on_frame_received(session, frame); } @@ -5573,8 +5593,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, iframe->max_niv = iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1; - iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) * - iframe->max_niv); + iframe->iv = nghttp2_mem_malloc( + mem, sizeof(nghttp2_settings_entry) * iframe->max_niv); if (!iframe->iv) { return NGHTTP2_ERR_NOMEM; @@ -5951,7 +5971,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, DEBUGF("recv: origin_len=%zu\n", origin_len); - if (2 + origin_len > iframe->payloadleft) { + if (origin_len > iframe->payloadleft) { busy = 1; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; break; @@ -6037,9 +6057,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, /* Use promised stream ID for PUSH_PROMISE */ rv = nghttp2_session_add_rst_stream( - session, iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE - ? iframe->frame.push_promise.promised_stream_id - : iframe->frame.hd.stream_id, + session, + iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE + ? iframe->frame.push_promise.promised_stream_id + : iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR); if (nghttp2_is_fatal(rv)) { return rv; @@ -7129,6 +7150,7 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session, } assert(0); + abort(); /* if NDEBUG is set */ } uint32_t nghttp2_session_get_local_settings(nghttp2_session *session, @@ -7149,6 +7171,7 @@ uint32_t nghttp2_session_get_local_settings(nghttp2_session *session, } assert(0); + abort(); /* if NDEBUG is set */ } static int nghttp2_session_upgrade_internal(nghttp2_session *session, diff --git a/deps/nghttp2/lib/nghttp2_session.h b/deps/nghttp2/lib/nghttp2_session.h index 3e4c1440a5ab73..3e1467f6a356d7 100644 --- a/deps/nghttp2/lib/nghttp2_session.h +++ b/deps/nghttp2/lib/nghttp2_session.h @@ -311,7 +311,7 @@ struct nghttp2_session { /* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this to refuse the incoming stream if it exceeds this value. */ uint32_t pending_local_max_concurrent_stream; - /* The bitwose OR of zero or more of nghttp2_typemask to indicate + /* The bitwise OR of zero or more of nghttp2_typemask to indicate that the default handling of extension frame is enabled. */ uint32_t builtin_recv_ext_types; /* Unacked local ENABLE_PUSH value. We use this to refuse