diff --git a/deps/nghttp2/lib/CMakeLists.txt b/deps/nghttp2/lib/CMakeLists.txt index fb24fa186f1114..7adba3a3ffa2da 100644 --- a/deps/nghttp2/lib/CMakeLists.txt +++ b/deps/nghttp2/lib/CMakeLists.txt @@ -24,7 +24,10 @@ set(NGHTTP2_SOURCES nghttp2_http.c nghttp2_rcbuf.c nghttp2_extpri.c + nghttp2_ratelim.c + nghttp2_time.c nghttp2_debug.c + sfparse.c ) set(NGHTTP2_RES "") diff --git a/deps/nghttp2/lib/Makefile.am b/deps/nghttp2/lib/Makefile.am index 9a985bf76b28a8..c3ace4029a69b8 100644 --- a/deps/nghttp2/lib/Makefile.am +++ b/deps/nghttp2/lib/Makefile.am @@ -51,7 +51,10 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \ nghttp2_http.c \ nghttp2_rcbuf.c \ nghttp2_extpri.c \ - nghttp2_debug.c + nghttp2_ratelim.c \ + nghttp2_time.c \ + nghttp2_debug.c \ + sfparse.c HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ nghttp2_frame.h \ @@ -68,7 +71,10 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ nghttp2_http.h \ nghttp2_rcbuf.h \ nghttp2_extpri.h \ - nghttp2_debug.h + nghttp2_ratelim.h \ + nghttp2_time.h \ + nghttp2_debug.h \ + sfparse.h libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS) libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \ diff --git a/deps/nghttp2/lib/Makefile.in b/deps/nghttp2/lib/Makefile.in index 8f7dc349d7cb15..0b95613bc21808 100644 --- a/deps/nghttp2/lib/Makefile.in +++ b/deps/nghttp2/lib/Makefile.in @@ -157,7 +157,8 @@ am__objects_2 = nghttp2_pq.lo nghttp2_map.lo nghttp2_queue.lo \ nghttp2_hd_huffman.lo nghttp2_hd_huffman_data.lo \ nghttp2_version.lo nghttp2_priority_spec.lo nghttp2_option.lo \ nghttp2_callbacks.lo nghttp2_mem.lo nghttp2_http.lo \ - nghttp2_rcbuf.lo nghttp2_extpri.lo nghttp2_debug.lo + nghttp2_rcbuf.lo nghttp2_extpri.lo nghttp2_ratelim.lo \ + nghttp2_time.lo nghttp2_debug.lo sfparse.lo am_libnghttp2_la_OBJECTS = $(am__objects_1) $(am__objects_2) libnghttp2_la_OBJECTS = $(am_libnghttp2_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) @@ -194,9 +195,11 @@ am__depfiles_remade = ./$(DEPDIR)/nghttp2_buf.Plo \ ./$(DEPDIR)/nghttp2_outbound_item.Plo \ ./$(DEPDIR)/nghttp2_pq.Plo \ ./$(DEPDIR)/nghttp2_priority_spec.Plo \ - ./$(DEPDIR)/nghttp2_queue.Plo ./$(DEPDIR)/nghttp2_rcbuf.Plo \ - ./$(DEPDIR)/nghttp2_session.Plo ./$(DEPDIR)/nghttp2_stream.Plo \ - ./$(DEPDIR)/nghttp2_submit.Plo ./$(DEPDIR)/nghttp2_version.Plo + ./$(DEPDIR)/nghttp2_queue.Plo ./$(DEPDIR)/nghttp2_ratelim.Plo \ + ./$(DEPDIR)/nghttp2_rcbuf.Plo ./$(DEPDIR)/nghttp2_session.Plo \ + ./$(DEPDIR)/nghttp2_stream.Plo ./$(DEPDIR)/nghttp2_submit.Plo \ + ./$(DEPDIR)/nghttp2_time.Plo ./$(DEPDIR)/nghttp2_version.Plo \ + ./$(DEPDIR)/sfparse.Plo am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) @@ -509,7 +512,10 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \ nghttp2_http.c \ nghttp2_rcbuf.c \ nghttp2_extpri.c \ - nghttp2_debug.c + nghttp2_ratelim.c \ + nghttp2_time.c \ + nghttp2_debug.c \ + sfparse.c HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ nghttp2_frame.h \ @@ -526,7 +532,10 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \ nghttp2_http.h \ nghttp2_rcbuf.h \ nghttp2_extpri.h \ - nghttp2_debug.h + nghttp2_ratelim.h \ + nghttp2_time.h \ + nghttp2_debug.h \ + sfparse.h libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS) libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \ @@ -630,11 +639,14 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_pq.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_priority_spec.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_queue.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_ratelim.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_rcbuf.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_session.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_stream.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_submit.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_time.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nghttp2_version.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sfparse.Plo@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @@ -912,11 +924,14 @@ distclean: distclean-recursive -rm -f ./$(DEPDIR)/nghttp2_pq.Plo -rm -f ./$(DEPDIR)/nghttp2_priority_spec.Plo -rm -f ./$(DEPDIR)/nghttp2_queue.Plo + -rm -f ./$(DEPDIR)/nghttp2_ratelim.Plo -rm -f ./$(DEPDIR)/nghttp2_rcbuf.Plo -rm -f ./$(DEPDIR)/nghttp2_session.Plo -rm -f ./$(DEPDIR)/nghttp2_stream.Plo -rm -f ./$(DEPDIR)/nghttp2_submit.Plo + -rm -f ./$(DEPDIR)/nghttp2_time.Plo -rm -f ./$(DEPDIR)/nghttp2_version.Plo + -rm -f ./$(DEPDIR)/sfparse.Plo -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -980,11 +995,14 @@ maintainer-clean: maintainer-clean-recursive -rm -f ./$(DEPDIR)/nghttp2_pq.Plo -rm -f ./$(DEPDIR)/nghttp2_priority_spec.Plo -rm -f ./$(DEPDIR)/nghttp2_queue.Plo + -rm -f ./$(DEPDIR)/nghttp2_ratelim.Plo -rm -f ./$(DEPDIR)/nghttp2_rcbuf.Plo -rm -f ./$(DEPDIR)/nghttp2_session.Plo -rm -f ./$(DEPDIR)/nghttp2_stream.Plo -rm -f ./$(DEPDIR)/nghttp2_submit.Plo + -rm -f ./$(DEPDIR)/nghttp2_time.Plo -rm -f ./$(DEPDIR)/nghttp2_version.Plo + -rm -f ./$(DEPDIR)/sfparse.Plo -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h index 65077dd51613c1..fa22081c517497 100644 --- a/deps/nghttp2/lib/includes/nghttp2/nghttp2.h +++ b/deps/nghttp2/lib/includes/nghttp2/nghttp2.h @@ -2756,6 +2756,23 @@ NGHTTP2_EXTERN void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation( nghttp2_option *option, int val); +/** + * @function + * + * This function sets the rate limit for the incoming stream reset + * (RST_STREAM frame). It is server use only. It is a token-bucket + * based rate limiter. |burst| specifies the number of tokens that is + * initially available. The maximum number of tokens is capped to + * this value. |rate| specifies the number of tokens that are + * regenerated per second. An incoming RST_STREAM consumes one token. + * If there is no token available, GOAWAY is sent to tear down the + * connection. |burst| and |rate| default to 1000 and 33 + * respectively. + */ +NGHTTP2_EXTERN void +nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, + uint64_t burst, uint64_t rate); + /** * @function * diff --git a/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/deps/nghttp2/lib/includes/nghttp2/nghttp2ver.h index 5dea3ffe100b40..f56954e7fded45 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.55.0" +#define NGHTTP2_VERSION "1.57.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 0x013700 +#define NGHTTP2_VERSION_NUM 0x013900 #endif /* NGHTTP2VER_H */ diff --git a/deps/nghttp2/lib/nghttp2_frame.c b/deps/nghttp2/lib/nghttp2_frame.c index 35072c15fc18e6..77cb463df5441f 100644 --- a/deps/nghttp2/lib/nghttp2_frame.c +++ b/deps/nghttp2/lib/nghttp2_frame.c @@ -418,8 +418,8 @@ void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec, nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive); } -int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, - const uint8_t *payload) { +void nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, + const uint8_t *payload) { if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload); } else { @@ -428,11 +428,9 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, frame->nva = NULL; frame->nvlen = 0; - - return 0; } -int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) { +void nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) { nghttp2_buf *buf; assert(bufs->head == bufs->cur); @@ -448,8 +446,6 @@ int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) { nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec); buf->last += NGHTTP2_PRIORITY_SPECLEN; - - return 0; } void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame, @@ -457,8 +453,8 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame, nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload); } -int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, - nghttp2_rst_stream *frame) { +void nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, + nghttp2_rst_stream *frame) { nghttp2_buf *buf; assert(bufs->head == bufs->cur); @@ -473,8 +469,6 @@ int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, nghttp2_put_uint32be(buf->last, frame->error_code); buf->last += 4; - - return 0; } void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame, @@ -592,16 +586,15 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs, return frame_pack_headers_shared(bufs, &frame->hd); } -int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, - const uint8_t *payload) { +void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, + const uint8_t *payload) { frame->promised_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; frame->nva = NULL; frame->nvlen = 0; - return 0; } -int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) { +void nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) { nghttp2_buf *buf; assert(bufs->head == bufs->cur); @@ -616,8 +609,6 @@ int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) { buf->last = nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data)); - - return 0; } void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame, @@ -697,8 +688,8 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame, return 0; } -int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, - nghttp2_window_update *frame) { +void nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, + nghttp2_window_update *frame) { nghttp2_buf *buf; assert(bufs->head == bufs->cur); @@ -713,8 +704,6 @@ int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, nghttp2_put_uint32be(buf->last, (uint32_t)frame->window_size_increment); buf->last += 4; - - return 0; } void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame, @@ -723,7 +712,7 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame, nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK; } -int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) { +void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) { int rv; nghttp2_buf *buf; nghttp2_ext_altsvc *altsvc; @@ -752,8 +741,6 @@ int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) { rv = nghttp2_bufs_add(bufs, altsvc->field_value, altsvc->field_value_len); assert(rv == 0); - - return 0; } void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, @@ -901,8 +888,8 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame, return 0; } -int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs, - nghttp2_extension *frame) { +void nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs, + nghttp2_extension *frame) { int rv; nghttp2_buf *buf; nghttp2_ext_priority_update *priority_update; @@ -927,8 +914,6 @@ int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs, priority_update->field_value_len); assert(rv == 0); - - return 0; } void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame, @@ -1186,14 +1171,14 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) { buf->last += trail_padlen; } -int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, - size_t padlen, int framehd_only) { +void nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, + size_t padlen, int framehd_only) { nghttp2_buf *buf; if (padlen == 0) { DEBUGF("send: padlen = 0, nothing to do\n"); - return 0; + return; } /* @@ -1226,6 +1211,4 @@ int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, hd->flags |= NGHTTP2_FLAG_PADDED; DEBUGF("send: final payloadlen=%zu, padlen=%zu\n", hd->length, padlen); - - return 0; } diff --git a/deps/nghttp2/lib/nghttp2_frame.h b/deps/nghttp2/lib/nghttp2_frame.h index 5f6152b74587ae..d58668806c432a 100644 --- a/deps/nghttp2/lib/nghttp2_frame.h +++ b/deps/nghttp2/lib/nghttp2_frame.h @@ -143,11 +143,9 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame, * Unpacks HEADERS frame byte sequence into |frame|. This function * only unapcks bytes that come before name/value header block and * after possible Pad Length field. - * - * This function always succeeds and returns 0. */ -int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, - const uint8_t *payload); +void nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, + const uint8_t *payload); /* * Packs PRIORITY frame |frame| in wire format and store it in @@ -155,10 +153,8 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, * * The caller must make sure that nghttp2_bufs_reset(bufs) is called * before calling this function. - * - * This function always succeeds and returns 0. */ -int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame); +void nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame); /* * Unpacks PRIORITY wire format into |frame|. @@ -172,11 +168,9 @@ void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame, * * The caller must make sure that nghttp2_bufs_reset(bufs) is called * before calling this function. - * - * This function always succeeds and returns 0. */ -int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, - nghttp2_rst_stream *frame); +void nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, + nghttp2_rst_stream *frame); /* * Unpacks RST_STREAM frame byte sequence into |frame|. @@ -265,15 +259,9 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs, * Unpacks PUSH_PROMISE frame byte sequence into |frame|. This * function only unapcks bytes that come before name/value header * block and after possible Pad Length field. - * - * This function returns 0 if it succeeds or one of the following - * negative error codes: - * - * NGHTTP2_ERR_PROTO - * TODO END_HEADERS flag is not set */ -int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, - const uint8_t *payload); +void nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, + const uint8_t *payload); /* * Packs PING frame |frame| in wire format and store it in @@ -281,10 +269,8 @@ int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, * * The caller must make sure that nghttp2_bufs_reset(bufs) is called * before calling this function. - * - * This function always succeeds and returns 0. */ -int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame); +void nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame); /* * Unpacks PING wire format into |frame|. @@ -343,11 +329,9 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame, * * The caller must make sure that nghttp2_bufs_reset(bufs) is called * before calling this function. - * - * This function always succeeds and returns 0. */ -int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, - nghttp2_window_update *frame); +void nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, + nghttp2_window_update *frame); /* * Unpacks WINDOW_UPDATE frame byte sequence into |frame|. @@ -361,17 +345,13 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame, * * The caller must make sure that nghttp2_bufs_reset(bufs) is called * before calling this function. - * - * This function always succeeds and returns 0. */ -int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext); +void nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext); /* * Unpacks ALTSVC wire format into |frame|. The |payload| of * |payloadlen| bytes contains frame payload. This function assumes * that frame->payload points to the nghttp2_ext_altsvc object. - * - * This function always succeeds and returns 0. */ void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, size_t origin_len, uint8_t *payload, @@ -431,19 +411,15 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame, * * The caller must make sure that nghttp2_bufs_reset(bufs) is called * before calling this function. - * - * This function always succeeds and returns 0. */ -int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs, - nghttp2_extension *ext); +void nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs, + nghttp2_extension *ext); /* * Unpacks PRIORITY_UPDATE wire format into |frame|. The |payload| of * |payloadlen| bytes contains frame payload. This function assumes * that frame->payload points to the nghttp2_ext_priority_update * object. - * - * This function always succeeds and returns 0. */ void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame, uint8_t *payload, @@ -654,16 +630,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); * |padlen| including Pad Length field. The |hd| is the frame header * for the serialized data. This function fills zeros padding region * unless framehd_only is nonzero. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_FRAME_SIZE_ERROR - * The length of the resulting frame is too large. */ -int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, - size_t padlen, int framehd_only); +void nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, + size_t padlen, int framehd_only); #endif /* NGHTTP2_FRAME_H */ diff --git a/deps/nghttp2/lib/nghttp2_http.c b/deps/nghttp2/lib/nghttp2_http.c index 83e5e6685f86d8..ecdeb21ddb694c 100644 --- a/deps/nghttp2/lib/nghttp2_http.c +++ b/deps/nghttp2/lib/nghttp2_http.c @@ -31,6 +31,7 @@ #include "nghttp2_hd.h" #include "nghttp2_helper.h" #include "nghttp2_extpri.h" +#include "sfparse.h" static uint8_t downcase(uint8_t c) { return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c; @@ -578,713 +579,52 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream, } } -/* Generated by genchartbl.py */ -static const int SF_KEY_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 */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */, - 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */, - 0 /* ( */, 0 /* ) */, 1 /* * */, 0 /* + */, 0 /* , */, - 1 /* - */, 1 /* . */, 0 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, - 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */, - 0 /* A */, 0 /* B */, 0 /* C */, 0 /* D */, 0 /* E */, - 0 /* F */, 0 /* G */, 0 /* H */, 0 /* I */, 0 /* J */, - 0 /* K */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */, - 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* T */, - 0 /* U */, 0 /* V */, 0 /* W */, 0 /* X */, 0 /* Y */, - 0 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */, - 1 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */, - 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static ssize_t sf_parse_key(const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - - if ((*p < 'a' || 'z' < *p) && *p != '*') { - return -1; - } - - for (; p != end && SF_KEY_CHARS[*p]; ++p) - ; - - return p - begin; -} - -static ssize_t sf_parse_integer_or_decimal(nghttp2_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - int sign = 1; - int64_t value = 0; - int type = NGHTTP2_SF_VALUE_TYPE_INTEGER; - size_t len = 0; - size_t fpos = 0; - size_t i; - - if (*p == '-') { - if (++p == end) { - return -1; - } - - sign = -1; - } - - if (*p < '0' || '9' < *p) { - return -1; - } - - for (; p != end; ++p) { - switch (*p) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - value *= 10; - value += *p - '0'; - - if (++len > 15) { - return -1; - } - - break; - case '.': - if (type != NGHTTP2_SF_VALUE_TYPE_INTEGER) { - goto fin; - } - - if (len > 12) { - return -1; - } - fpos = len; - type = NGHTTP2_SF_VALUE_TYPE_DECIMAL; - - break; - default: - goto fin; - }; - } - -fin: - switch (type) { - case NGHTTP2_SF_VALUE_TYPE_INTEGER: - if (dest) { - dest->type = (uint8_t)type; - dest->i = value * sign; - } - - return p - begin; - case NGHTTP2_SF_VALUE_TYPE_DECIMAL: - if (fpos == len || len - fpos > 3) { - return -1; - } - - if (dest) { - dest->type = (uint8_t)type; - dest->d = (double)value; - for (i = len - fpos; i > 0; --i) { - dest->d /= (double)10; - } - dest->d *= sign; - } - - return p - begin; - default: - assert(0); - abort(); - } -} - -/* Generated by genchartbl.py */ -static const int SF_DQUOTE_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 */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 1 /* SPC */, 1 /* ! */, 0 /* " */, - 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* , */, - 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, - 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* @ */, - 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */, - 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */, - 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */, - 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */, - 1 /* Z */, 1 /* [ */, 0 /* \ */, 1 /* ] */, 1 /* ^ */, - 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* | */, - 1 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static ssize_t sf_parse_string(nghttp2_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - - if (*p++ != '"') { - return -1; - } - - for (; p != end; ++p) { - switch (*p) { - case '\\': - if (++p == end) { - return -1; - } - - switch (*p) { - case '"': - case '\\': - break; - default: - return -1; - } - - break; - case '"': - if (dest) { - dest->type = NGHTTP2_SF_VALUE_TYPE_STRING; - dest->s.base = begin + 1; - dest->s.len = (size_t)(p - dest->s.base); - } - - ++p; - - return p - begin; - default: - if (!SF_DQUOTE_CHARS[*p]) { - return -1; - } - } - } - - return -1; -} - -/* Generated by genchartbl.py */ -static const int SF_TOKEN_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 */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 0 /* SPC */, 1 /* ! */, 0 /* " */, - 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* , */, - 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 0 /* ; */, - 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */, - 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */, - 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */, - 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */, - 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */, - 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */, - 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* | */, - 0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static ssize_t sf_parse_token(nghttp2_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - - if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') { - return -1; - } - - for (; p != end && SF_TOKEN_CHARS[*p]; ++p) - ; - - if (dest) { - dest->type = NGHTTP2_SF_VALUE_TYPE_TOKEN; - dest->s.base = begin; - dest->s.len = (size_t)(p - begin); - } - - return p - begin; -} - -/* Generated by genchartbl.py */ -static const int SF_BYTESEQ_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 */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */, - 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */, - 0 /* ( */, 0 /* ) */, 0 /* * */, 1 /* + */, 0 /* , */, - 0 /* - */, 0 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, - 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */, - 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */, - 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */, - 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */, - 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */, - 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */, - 0 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */, - 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static ssize_t sf_parse_byteseq(nghttp2_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - - if (*p++ != ':') { - return -1; - } - - for (; p != end; ++p) { - switch (*p) { - case ':': - if (dest) { - dest->type = NGHTTP2_SF_VALUE_TYPE_BYTESEQ; - dest->s.base = begin + 1; - dest->s.len = (size_t)(p - dest->s.base); - } - - ++p; - - return p - begin; - default: - if (!SF_BYTESEQ_CHARS[*p]) { - return -1; - } - } - } - - return -1; -} - -static ssize_t sf_parse_boolean(nghttp2_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - int b; - - if (*p++ != '?') { - return -1; - } - - if (p == end) { - return -1; - } - - switch (*p++) { - case '0': - b = 0; - break; - case '1': - b = 1; - break; - default: - return -1; - } - - if (dest) { - dest->type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN; - dest->b = b; - } - - return p - begin; -} - -static ssize_t sf_parse_bare_item(nghttp2_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - switch (*begin) { - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return sf_parse_integer_or_decimal(dest, begin, end); - case '"': - return sf_parse_string(dest, begin, end); - case '*': - return sf_parse_token(dest, begin, end); - case ':': - return sf_parse_byteseq(dest, begin, end); - case '?': - return sf_parse_boolean(dest, begin, end); - default: - if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) { - return sf_parse_token(dest, begin, end); - } - return -1; - } -} - -#define sf_discard_sp_end_err(BEGIN, END, ERR) \ - for (;; ++(BEGIN)) { \ - if ((BEGIN) == (END)) { \ - return (ERR); \ - } \ - if (*(BEGIN) != ' ') { \ - break; \ - } \ - } - -static ssize_t sf_parse_params(const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - ssize_t slen; - - for (; p != end && *p == ';';) { - ++p; - - sf_discard_sp_end_err(p, end, -1); - - slen = sf_parse_key(p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - if (p == end || *p != '=') { - /* Boolean true */ - } else if (++p == end) { - return -1; - } else { - slen = sf_parse_bare_item(NULL, p, end); - if (slen < 0) { - return -1; - } - - p += slen; - } - } - - return p - begin; -} - -static ssize_t sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - ssize_t slen; - - slen = sf_parse_bare_item(dest, p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - slen = sf_parse_params(p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - return p - begin; -} - -ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - return sf_parse_item(dest, begin, end); -} - -static ssize_t sf_parse_inner_list(nghttp2_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - ssize_t slen; - - if (*p++ != '(') { - return -1; - } - - for (;;) { - sf_discard_sp_end_err(p, end, -1); - - if (*p == ')') { - ++p; - - slen = sf_parse_params(p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - if (dest) { - dest->type = NGHTTP2_SF_VALUE_TYPE_INNER_LIST; - } - - return p - begin; - } - - slen = sf_parse_item(NULL, p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - if (p == end || (*p != ' ' && *p != ')')) { - return -1; - } - } -} - -ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest, - const uint8_t *begin, const uint8_t *end) { - return sf_parse_inner_list(dest, begin, end); -} - -static ssize_t sf_parse_item_or_inner_list(nghttp2_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - if (*begin == '(') { - return sf_parse_inner_list(dest, begin, end); - } - - return sf_parse_item(dest, begin, end); -} - -#define sf_discard_ows(BEGIN, END) \ - for (;; ++(BEGIN)) { \ - if ((BEGIN) == (END)) { \ - goto fin; \ - } \ - if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \ - break; \ - } \ - } - -#define sf_discard_ows_end_err(BEGIN, END, ERR) \ - for (;; ++(BEGIN)) { \ - if ((BEGIN) == (END)) { \ - return (ERR); \ - } \ - if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \ - break; \ - } \ - } - int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, size_t valuelen) { - const uint8_t *p = value, *end = value + valuelen; - ssize_t slen; - nghttp2_sf_value val; nghttp2_extpri pri = *dest; - const uint8_t *key; - size_t keylen; + sf_parser sfp; + sf_vec key; + sf_value val; + int rv; + + sf_parser_init(&sfp, value, valuelen); - for (; p != end && *p == ' '; ++p) - ; + for (;;) { + rv = sf_parser_dict(&sfp, &key, &val); + if (rv != 0) { + if (rv == SF_ERR_EOF) { + break; + } - for (; p != end;) { - slen = sf_parse_key(p, end); - if (slen < 0) { return NGHTTP2_ERR_INVALID_ARGUMENT; } - key = p; - keylen = (size_t)slen; - - p += slen; - - if (p == end || *p != '=') { - /* Boolean true */ - val.type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN; - val.b = 1; + if (key.len != 1) { + continue; + } - slen = sf_parse_params(p, end); - if (slen < 0) { + switch (key.base[0]) { + case 'i': + if (val.type != SF_TYPE_BOOLEAN) { return NGHTTP2_ERR_INVALID_ARGUMENT; } - } else if (++p == end) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } else { - slen = sf_parse_item_or_inner_list(&val, p, end); - if (slen < 0) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - } - - p += slen; - if (keylen == 1) { - switch (key[0]) { - case 'i': - if (val.type != NGHTTP2_SF_VALUE_TYPE_BOOLEAN) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - pri.inc = val.b; + pri.inc = val.boolean; - break; - case 'u': - if (val.type != NGHTTP2_SF_VALUE_TYPE_INTEGER || - val.i < NGHTTP2_EXTPRI_URGENCY_HIGH || - NGHTTP2_EXTPRI_URGENCY_LOW < val.i) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } - - pri.urgency = (uint32_t)val.i; - - break; + break; + case 'u': + if (val.type != SF_TYPE_INTEGER || + val.integer < NGHTTP2_EXTPRI_URGENCY_HIGH || + NGHTTP2_EXTPRI_URGENCY_LOW < val.integer) { + return NGHTTP2_ERR_INVALID_ARGUMENT; } - } - sf_discard_ows(p, end); + pri.urgency = (uint32_t)val.integer; - if (*p++ != ',') { - return NGHTTP2_ERR_INVALID_ARGUMENT; + break; } - - sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT); } -fin: *dest = pri; return 0; diff --git a/deps/nghttp2/lib/nghttp2_http.h b/deps/nghttp2/lib/nghttp2_http.h index 0c3a78eeefab79..d9992fe690830b 100644 --- a/deps/nghttp2/lib/nghttp2_http.h +++ b/deps/nghttp2/lib/nghttp2_http.h @@ -94,54 +94,6 @@ int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n); void nghttp2_http_record_request_method(nghttp2_stream *stream, nghttp2_frame *frame); -/* - * RFC 8941 Structured Field Values. - */ -typedef enum nghttp2_sf_value_type { - NGHTTP2_SF_VALUE_TYPE_BOOLEAN, - NGHTTP2_SF_VALUE_TYPE_INTEGER, - NGHTTP2_SF_VALUE_TYPE_DECIMAL, - NGHTTP2_SF_VALUE_TYPE_STRING, - NGHTTP2_SF_VALUE_TYPE_TOKEN, - NGHTTP2_SF_VALUE_TYPE_BYTESEQ, - NGHTTP2_SF_VALUE_TYPE_INNER_LIST, -} nghttp2_sf_value_type; - -/* - * nghttp2_sf_value stores Structured Field Values item. For Inner - * List, only type is set to NGHTTP2_SF_VALUE_TYPE_INNER_LIST. - */ -typedef struct nghttp2_sf_value { - uint8_t type; - union { - int b; - int64_t i; - double d; - struct { - const uint8_t *base; - size_t len; - } s; - }; -} nghttp2_sf_value; - -/* - * nghttp2_sf_parse_item parses the input sequence [|begin|, |end|) - * and stores the parsed an Item in |dest|. It returns the number of - * bytes consumed if it succeeds, or -1. This function is declared - * here for unit tests. - */ -ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin, - const uint8_t *end); - -/* - * nghttp2_sf_parse_inner_list parses the input sequence [|begin|, |end|) - * and stores the parsed an Inner List in |dest|. It returns the number of - * bytes consumed if it succeeds, or -1. This function is declared - * here for unit tests. - */ -ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest, - const uint8_t *begin, const uint8_t *end); - int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value, size_t valuelen); diff --git a/deps/nghttp2/lib/nghttp2_map.c b/deps/nghttp2/lib/nghttp2_map.c index e5db168ca2bc3b..5f63fc2bb87e99 100644 --- a/deps/nghttp2/lib/nghttp2_map.c +++ b/deps/nghttp2/lib/nghttp2_map.c @@ -31,21 +31,14 @@ #include "nghttp2_helper.h" -#define NGHTTP2_INITIAL_TABLE_LENBITS 8 +#define NGHTTP2_INITIAL_TABLE_LENBITS 4 -int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) { +void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) { map->mem = mem; - map->tablelen = 1 << NGHTTP2_INITIAL_TABLE_LENBITS; - map->tablelenbits = NGHTTP2_INITIAL_TABLE_LENBITS; - map->table = - nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_bucket)); - if (map->table == NULL) { - return NGHTTP2_ERR_NOMEM; - } - + map->tablelen = 0; + map->tablelenbits = 0; + map->table = NULL; map->size = 0; - - return 0; } void nghttp2_map_free(nghttp2_map *map) { @@ -78,6 +71,10 @@ int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr), uint32_t i; nghttp2_map_bucket *bkt; + if (map->size == 0) { + return 0; + } + for (i = 0; i < map->tablelen; ++i) { bkt = &map->table[i]; @@ -223,9 +220,17 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) { /* Load factor is 0.75 */ if ((map->size + 1) * 4 > map->tablelen * 3) { - rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1); - if (rv != 0) { - return rv; + if (map->tablelen) { + rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1); + if (rv != 0) { + return rv; + } + } else { + rv = map_resize(map, 1 << NGHTTP2_INITIAL_TABLE_LENBITS, + NGHTTP2_INITIAL_TABLE_LENBITS); + if (rv != 0) { + return rv; + } } } @@ -239,11 +244,18 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) { } void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) { - uint32_t h = hash(key); - size_t idx = h2idx(h, map->tablelenbits); + uint32_t h; + size_t idx; nghttp2_map_bucket *bkt; size_t d = 0; + if (map->size == 0) { + return NULL; + } + + h = hash(key); + idx = h2idx(h, map->tablelenbits); + for (;;) { bkt = &map->table[idx]; @@ -262,11 +274,18 @@ void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) { } int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) { - uint32_t h = hash(key); - size_t idx = h2idx(h, map->tablelenbits), didx; + uint32_t h; + size_t idx, didx; nghttp2_map_bucket *bkt; size_t d = 0; + if (map->size == 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + + h = hash(key); + idx = h2idx(h, map->tablelenbits); + for (;;) { bkt = &map->table[idx]; @@ -306,6 +325,10 @@ int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) { } void nghttp2_map_clear(nghttp2_map *map) { + if (map->tablelen == 0) { + return; + } + memset(map->table, 0, sizeof(*map->table) * map->tablelen); map->size = 0; } diff --git a/deps/nghttp2/lib/nghttp2_map.h b/deps/nghttp2/lib/nghttp2_map.h index 1419a09a35b10e..d90245aab74c97 100644 --- a/deps/nghttp2/lib/nghttp2_map.h +++ b/deps/nghttp2/lib/nghttp2_map.h @@ -54,14 +54,8 @@ typedef struct nghttp2_map { /* * Initializes the map |map|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory */ -int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem); +void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem); /* * Deallocates any resources allocated for |map|. The stored entries diff --git a/deps/nghttp2/lib/nghttp2_option.c b/deps/nghttp2/lib/nghttp2_option.c index ee0cd0f0226db9..43d4e952291ba4 100644 --- a/deps/nghttp2/lib/nghttp2_option.c +++ b/deps/nghttp2/lib/nghttp2_option.c @@ -143,3 +143,10 @@ void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation( NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION; option->no_rfc9113_leading_and_trailing_ws_validation = val; } + +void nghttp2_option_set_stream_reset_rate_limit(nghttp2_option *option, + uint64_t burst, uint64_t rate) { + option->opt_set_mask |= NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT; + option->stream_reset_burst = burst; + option->stream_reset_rate = rate; +} diff --git a/deps/nghttp2/lib/nghttp2_option.h b/deps/nghttp2/lib/nghttp2_option.h index b228a0754c989e..2259e1849d810f 100644 --- a/deps/nghttp2/lib/nghttp2_option.h +++ b/deps/nghttp2/lib/nghttp2_option.h @@ -70,12 +70,18 @@ typedef enum { NGHTTP2_OPT_MAX_SETTINGS = 1 << 12, NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13, NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14, + NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15, } nghttp2_option_flag; /** * Struct to store option values for nghttp2_session. */ struct nghttp2_option { + /** + * NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT + */ + uint64_t stream_reset_burst; + uint64_t stream_reset_rate; /** * NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH */ diff --git a/deps/nghttp2/lib/nghttp2_ratelim.c b/deps/nghttp2/lib/nghttp2_ratelim.c new file mode 100644 index 00000000000000..7011655b006f7c --- /dev/null +++ b/deps/nghttp2/lib/nghttp2_ratelim.c @@ -0,0 +1,75 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2023 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "nghttp2_ratelim.h" +#include "nghttp2_helper.h" + +void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate) { + rl->val = rl->burst = burst; + rl->rate = rate; + rl->tstamp = 0; +} + +void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp) { + uint64_t d, gain; + + if (tstamp == rl->tstamp) { + return; + } + + if (tstamp > rl->tstamp) { + d = tstamp - rl->tstamp; + } else { + d = 1; + } + + rl->tstamp = tstamp; + + if (UINT64_MAX / d < rl->rate) { + rl->val = rl->burst; + + return; + } + + gain = rl->rate * d; + + if (UINT64_MAX - gain < rl->val) { + rl->val = rl->burst; + + return; + } + + rl->val += gain; + rl->val = nghttp2_min(rl->val, rl->burst); +} + +int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n) { + if (rl->val < n) { + return -1; + } + + rl->val -= n; + + return 0; +} diff --git a/deps/nghttp2/lib/nghttp2_ratelim.h b/deps/nghttp2/lib/nghttp2_ratelim.h new file mode 100644 index 00000000000000..866ed3f00aed4c --- /dev/null +++ b/deps/nghttp2/lib/nghttp2_ratelim.h @@ -0,0 +1,57 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2023 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGHTTP2_RATELIM_H +#define NGHTTP2_RATELIM_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +typedef struct nghttp2_ratelim { + /* burst is the maximum value of val. */ + uint64_t burst; + /* rate is the amount of value that is regenerated per 1 tstamp. */ + uint64_t rate; + /* val is the amount of value available to drain. */ + uint64_t val; + /* tstamp is the last timestamp in second resolution that is known + to this object. */ + uint64_t tstamp; +} nghttp2_ratelim; + +/* nghttp2_ratelim_init initializes |rl| with the given parameters. */ +void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate); + +/* nghttp2_ratelim_update updates rl->val with the current |tstamp| + given in second resolution. */ +void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp); + +/* nghttp2_ratelim_drain drains |n| from rl->val. It returns 0 if it + succeeds, or -1. */ +int nghttp2_ratelim_drain(nghttp2_ratelim *rl, uint64_t n); + +#endif /* NGHTTP2_RATELIM_H */ diff --git a/deps/nghttp2/lib/nghttp2_session.c b/deps/nghttp2/lib/nghttp2_session.c index 93f3f07cf782b3..ec5024d0f2168e 100644 --- a/deps/nghttp2/lib/nghttp2_session.c +++ b/deps/nghttp2/lib/nghttp2_session.c @@ -37,6 +37,7 @@ #include "nghttp2_http.h" #include "nghttp2_pq.h" #include "nghttp2_extpri.h" +#include "nghttp2_time.h" #include "nghttp2_debug.h" /* @@ -475,6 +476,10 @@ static int session_new(nghttp2_session **session_ptr, (*session_ptr)->pending_enable_push = 1; (*session_ptr)->pending_no_rfc7540_priorities = UINT8_MAX; + nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim, + NGHTTP2_DEFAULT_STREAM_RESET_BURST, + NGHTTP2_DEFAULT_STREAM_RESET_RATE); + if (server) { (*session_ptr)->server = 1; } @@ -573,6 +578,12 @@ static int session_new(nghttp2_session **session_ptr, (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION; } + + if (option->opt_set_mask & NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT) { + nghttp2_ratelim_init(&(*session_ptr)->stream_reset_ratelim, + option->stream_reset_burst, + option->stream_reset_rate); + } } rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater, @@ -584,10 +595,6 @@ static int session_new(nghttp2_session **session_ptr, if (rv != 0) { goto fail_hd_inflater; } - rv = nghttp2_map_init(&(*session_ptr)->streams, mem); - if (rv != 0) { - goto fail_map; - } nbuffer = ((*session_ptr)->max_send_header_block_length + NGHTTP2_FRAMEBUF_CHUNKLEN - 1) / @@ -605,6 +612,8 @@ static int session_new(nghttp2_session **session_ptr, goto fail_aob_framebuf; } + nghttp2_map_init(&(*session_ptr)->streams, mem); + active_outbound_item_reset(&(*session_ptr)->aob, mem); (*session_ptr)->callbacks = *callbacks; @@ -637,8 +646,6 @@ static int session_new(nghttp2_session **session_ptr, return 0; fail_aob_framebuf: - nghttp2_map_free(&(*session_ptr)->streams); -fail_map: nghttp2_hd_inflate_free(&(*session_ptr)->hd_inflater); fail_hd_inflater: nghttp2_hd_deflate_free(&(*session_ptr)->hd_deflater); @@ -941,8 +948,8 @@ static int session_ob_data_push(nghttp2_session *session, return 0; } -static int session_ob_data_remove(nghttp2_session *session, - nghttp2_stream *stream) { +static void session_ob_data_remove(nghttp2_session *session, + nghttp2_stream *stream) { uint32_t urgency; assert(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES); @@ -955,8 +962,6 @@ static int session_ob_data_remove(nghttp2_session *session, nghttp2_pq_remove(&session->sched[urgency].ob_data, &stream->pq_entry); stream->queued = 0; - - return 0; } static int session_attach_stream_item(nghttp2_session *session, @@ -976,38 +981,28 @@ static int session_attach_stream_item(nghttp2_session *session, return session_ob_data_push(session, stream); } -static int session_detach_stream_item(nghttp2_session *session, - nghttp2_stream *stream) { - int rv; - - rv = nghttp2_stream_detach_item(stream); - if (rv != 0) { - return rv; - } +static void session_detach_stream_item(nghttp2_session *session, + nghttp2_stream *stream) { + nghttp2_stream_detach_item(stream); if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || !stream->queued) { - return 0; + return; } - return session_ob_data_remove(session, stream); + session_ob_data_remove(session, stream); } -static int session_defer_stream_item(nghttp2_session *session, - nghttp2_stream *stream, uint8_t flags) { - int rv; - - rv = nghttp2_stream_defer_item(stream, flags); - if (rv != 0) { - return rv; - } +static void session_defer_stream_item(nghttp2_session *session, + nghttp2_stream *stream, uint8_t flags) { + nghttp2_stream_defer_item(stream, flags); if (!(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) || !stream->queued) { - return 0; + return; } - return session_ob_data_remove(session, stream); + session_ob_data_remove(session, stream); } static int session_resume_deferred_stream_item(nghttp2_session *session, @@ -1480,11 +1475,7 @@ int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id, item = stream->item; - rv = session_detach_stream_item(session, stream); - - if (rv != 0) { - return rv; - } + session_detach_stream_item(session, stream); /* If item is queued, it will be deleted when it is popped (nghttp2_session_prep_frame() will fail). If session->aob.item @@ -2225,7 +2216,6 @@ static ssize_t session_call_select_padding(nghttp2_session *session, frame->push_promise has also padlen in the same position. */ static int session_headers_add_pad(nghttp2_session *session, nghttp2_frame *frame) { - int rv; ssize_t padded_payloadlen; nghttp2_active_outbound_item *aob; nghttp2_bufs *framebufs; @@ -2250,11 +2240,7 @@ static int session_headers_add_pad(nghttp2_session *session, DEBUGF("send: padding selected: payloadlen=%zd, padlen=%zu\n", padded_payloadlen, padlen); - rv = nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0); - - if (rv != 0) { - return rv; - } + nghttp2_frame_add_pad(framebufs, &frame->hd, padlen, 0); frame->headers.padlen = padlen; @@ -2337,13 +2323,7 @@ static int session_prep_frame(nghttp2_session *session, // Search stream including closed again. stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id); if (stream) { - int rv2; - - rv2 = session_detach_stream_item(session, stream); - - if (nghttp2_is_fatal(rv2)) { - return rv2; - } + session_detach_stream_item(session, stream); } return rv; @@ -2358,12 +2338,8 @@ static int session_prep_frame(nghttp2_session *session, queue when session->remote_window_size > 0 */ assert(session->remote_window_size > 0); - rv = session_defer_stream_item(session, stream, - NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); - - if (nghttp2_is_fatal(rv)) { - return rv; - } + session_defer_stream_item(session, stream, + NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL); session->aob.item = NULL; active_outbound_item_reset(&session->aob, mem); @@ -2377,23 +2353,15 @@ static int session_prep_frame(nghttp2_session *session, return rv; } if (rv == NGHTTP2_ERR_DEFERRED) { - rv = session_defer_stream_item(session, stream, - NGHTTP2_STREAM_FLAG_DEFERRED_USER); - - if (nghttp2_is_fatal(rv)) { - return rv; - } + session_defer_stream_item(session, stream, + NGHTTP2_STREAM_FLAG_DEFERRED_USER); session->aob.item = NULL; active_outbound_item_reset(&session->aob, mem); return NGHTTP2_ERR_DEFERRED; } if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - rv = session_detach_stream_item(session, stream); - - if (nghttp2_is_fatal(rv)) { - return rv; - } + session_detach_stream_item(session, stream); rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id, NGHTTP2_INTERNAL_ERROR); @@ -2403,13 +2371,7 @@ static int session_prep_frame(nghttp2_session *session, return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } if (rv != 0) { - int rv2; - - rv2 = session_detach_stream_item(session, stream); - - if (nghttp2_is_fatal(rv2)) { - return rv2; - } + session_detach_stream_item(session, stream); return rv; } @@ -2911,10 +2873,7 @@ static int session_after_frame_sent1(nghttp2_session *session) { } if (stream && aux_data->eof) { - rv = session_detach_stream_item(session, stream); - if (nghttp2_is_fatal(rv)) { - return rv; - } + session_detach_stream_item(session, stream); /* Call on_frame_send_callback after nghttp2_stream_detach_item(), so that application can issue @@ -3147,17 +3106,8 @@ static int session_after_frame_sent1(nghttp2_session *session) { /* * Called after a frame is sent and session_after_frame_sent1. This * function is responsible to reset session->aob. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory. - * NGHTTP2_ERR_CALLBACK_FAILURE - * The callback function failed. */ -static int session_after_frame_sent2(nghttp2_session *session) { - int rv; +static void session_after_frame_sent2(nghttp2_session *session) { nghttp2_active_outbound_item *aob = &session->aob; nghttp2_outbound_item *item = aob->item; nghttp2_bufs *framebufs = &aob->framebufs; @@ -3180,13 +3130,13 @@ static int session_after_frame_sent2(nghttp2_session *session) { DEBUGF("send: next CONTINUATION frame, %zu bytes\n", nghttp2_buf_len(&framebufs->cur->buf)); - return 0; + return; } } active_outbound_item_reset(&session->aob, mem); - return 0; + return; } /* DATA frame */ @@ -3200,7 +3150,7 @@ static int session_after_frame_sent2(nghttp2_session *session) { if (aux_data->eof) { active_outbound_item_reset(aob, mem); - return 0; + return; } /* Reset no_copy here because next write may not use this. */ @@ -3212,22 +3162,18 @@ static int session_after_frame_sent2(nghttp2_session *session) { further data. */ if (nghttp2_session_predicate_data_send(session, stream) != 0) { if (stream) { - rv = session_detach_stream_item(session, stream); - - if (nghttp2_is_fatal(rv)) { - return rv; - } + session_detach_stream_item(session, stream); } active_outbound_item_reset(aob, mem); - return 0; + return; } aob->item = NULL; active_outbound_item_reset(&session->aob, mem); - return 0; + return; } static int session_call_send_data(nghttp2_session *session, @@ -3300,6 +3246,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, if (rv < 0) { int32_t opened_stream_id = 0; uint32_t error_code = NGHTTP2_INTERNAL_ERROR; + int rv2 = 0; DEBUGF("send: frame preparation failed with %s\n", nghttp2_strerror(rv)); @@ -3342,19 +3289,18 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, } if (opened_stream_id) { /* careful not to override rv */ - int rv2; rv2 = nghttp2_session_close_stream(session, opened_stream_id, error_code); - - if (nghttp2_is_fatal(rv2)) { - return rv2; - } } nghttp2_outbound_item_free(item, mem); nghttp2_mem_free(mem, item); active_outbound_item_reset(aob, mem); + if (nghttp2_is_fatal(rv2)) { + return rv2; + } + if (rv == NGHTTP2_ERR_HEADER_COMP) { /* If header compression error occurred, should terminiate connection. */ @@ -3458,7 +3404,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, /* Frame has completely sent */ if (fast_cb) { - rv = session_after_frame_sent2(session); + session_after_frame_sent2(session); } else { rv = session_after_frame_sent1(session); if (rv < 0) { @@ -3466,12 +3412,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, assert(nghttp2_is_fatal(rv)); return rv; } - rv = session_after_frame_sent2(session); - } - if (rv < 0) { - /* FATAL */ - assert(nghttp2_is_fatal(rv)); - return rv; + session_after_frame_sent2(session); } /* We have already adjusted the next state */ break; @@ -3510,11 +3451,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, } if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - rv = session_detach_stream_item(session, stream); - - if (nghttp2_is_fatal(rv)) { - return rv; - } + session_detach_stream_item(session, stream); rv = nghttp2_session_add_rst_stream(session, frame->hd.stream_id, NGHTTP2_INTERNAL_ERROR); @@ -3538,11 +3475,7 @@ static ssize_t nghttp2_session_mem_send_internal(nghttp2_session *session, assert(nghttp2_is_fatal(rv)); return rv; } - rv = session_after_frame_sent2(session); - if (rv < 0) { - assert(nghttp2_is_fatal(rv)); - return rv; - } + session_after_frame_sent2(session); /* We have already adjusted the next state */ @@ -4428,17 +4361,12 @@ int nghttp2_session_on_headers_received(nghttp2_session *session, } static int session_process_headers_frame(nghttp2_session *session) { - int rv; nghttp2_inbound_frame *iframe = &session->iframe; nghttp2_frame *frame = &iframe->frame; nghttp2_stream *stream; - rv = nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos); + nghttp2_frame_unpack_headers_payload(&frame->headers, iframe->sbuf.pos); - if (rv != 0) { - return nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, "HEADERS: could not unpack"); - } stream = nghttp2_session_get_stream(session, frame->hd.stream_id); if (!stream) { frame->headers.cat = NGHTTP2_HCAT_REQUEST; @@ -4532,6 +4460,23 @@ static int session_process_priority_frame(nghttp2_session *session) { return nghttp2_session_on_priority_received(session, frame); } +static int session_update_stream_reset_ratelim(nghttp2_session *session) { + if (!session->server || (session->goaway_flags & NGHTTP2_GOAWAY_SUBMITTED)) { + return 0; + } + + nghttp2_ratelim_update(&session->stream_reset_ratelim, + nghttp2_time_now_sec()); + + if (nghttp2_ratelim_drain(&session->stream_reset_ratelim, 1) == 0) { + return 0; + } + + return nghttp2_session_add_goaway(session, session->last_recv_stream_id, + NGHTTP2_INTERNAL_ERROR, NULL, 0, + NGHTTP2_GOAWAY_AUX_NONE); +} + int nghttp2_session_on_rst_stream_received(nghttp2_session *session, nghttp2_frame *frame) { int rv; @@ -4561,7 +4506,8 @@ int nghttp2_session_on_rst_stream_received(nghttp2_session *session, if (nghttp2_is_fatal(rv)) { return rv; } - return 0; + + return session_update_stream_reset_ratelim(session); } static int session_process_rst_stream_frame(nghttp2_session *session) { @@ -5101,17 +5047,11 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, } static int session_process_push_promise_frame(nghttp2_session *session) { - int rv; nghttp2_inbound_frame *iframe = &session->iframe; nghttp2_frame *frame = &iframe->frame; - rv = nghttp2_frame_unpack_push_promise_payload(&frame->push_promise, - iframe->sbuf.pos); - - if (rv != 0) { - return nghttp2_session_terminate_session_with_reason( - session, NGHTTP2_PROTOCOL_ERROR, "PUSH_PROMISE: could not unpack"); - } + nghttp2_frame_unpack_push_promise_payload(&frame->push_promise, + iframe->sbuf.pos); return nghttp2_session_on_push_promise_received(session, frame); } @@ -5931,7 +5871,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, in += readlen; if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return in - first; + return (ssize_t)(in - first); } if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS || @@ -5968,7 +5908,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, in += readlen; if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return in - first; + return (ssize_t)(in - first); } nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->sbuf.pos); @@ -6468,7 +6408,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return in - first; + return (ssize_t)(in - first); } switch (iframe->frame.hd.type) { @@ -6772,7 +6712,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, in += hd_proclen; iframe->payloadleft -= hd_proclen; - return in - first; + return (ssize_t)(in - first); } if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { @@ -6963,7 +6903,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, in += readlen; if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return in - first; + return (ssize_t)(in - first); } nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->sbuf.pos); @@ -7021,7 +6961,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf)); if (nghttp2_buf_mark_avail(&iframe->sbuf)) { - return in - first; + return (ssize_t)(in - first); } /* Pad Length field is subject to flow control */ @@ -7171,7 +7111,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, session, iframe->frame.hd.flags, iframe->frame.hd.stream_id, in - readlen, (size_t)data_readlen, session->user_data); if (rv == NGHTTP2_ERR_PAUSE) { - return in - first; + return (ssize_t)(in - first); } if (nghttp2_is_fatal(rv)) { @@ -7351,7 +7291,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, assert(in == last); - return in - first; + return (ssize_t)(in - first); } int nghttp2_session_recv(nghttp2_session *session) { @@ -7523,6 +7463,9 @@ int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id, nghttp2_mem_free(mem, item); return rv; } + + session->goaway_flags |= NGHTTP2_GOAWAY_SUBMITTED; + return 0; } @@ -7812,11 +7755,8 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs, nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); - rv = nghttp2_frame_add_pad(bufs, &frame->hd, frame->data.padlen, - aux_data->no_copy); - if (rv != 0) { - return rv; - } + nghttp2_frame_add_pad(bufs, &frame->hd, frame->data.padlen, + aux_data->no_copy); session_reschedule_stream(session, stream); diff --git a/deps/nghttp2/lib/nghttp2_session.h b/deps/nghttp2/lib/nghttp2_session.h index 34d2d58528a796..b119329a04da45 100644 --- a/deps/nghttp2/lib/nghttp2_session.h +++ b/deps/nghttp2/lib/nghttp2_session.h @@ -39,6 +39,7 @@ #include "nghttp2_buf.h" #include "nghttp2_callbacks.h" #include "nghttp2_mem.h" +#include "nghttp2_ratelim.h" /* The global variable for tests where we want to disable strict preface handling. */ @@ -105,6 +106,10 @@ typedef struct { /* The default value of maximum number of concurrent streams. */ #define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu +/* The default values for stream reset rate limiter. */ +#define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000 +#define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33 + /* Internal state when receiving incoming frame */ typedef enum { /* Receiving frame header */ @@ -178,7 +183,9 @@ typedef enum { /* Flag means GOAWAY was sent */ NGHTTP2_GOAWAY_SENT = 0x4, /* Flag means GOAWAY was received */ - NGHTTP2_GOAWAY_RECV = 0x8 + NGHTTP2_GOAWAY_RECV = 0x8, + /* Flag means GOAWAY has been submitted at least once */ + NGHTTP2_GOAWAY_SUBMITTED = 0x10 } nghttp2_goaway_flag; /* nghttp2_inflight_settings stores the SETTINGS entries which local @@ -235,6 +242,9 @@ struct nghttp2_session { /* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not considered as in-flight. */ nghttp2_inflight_settings *inflight_settings_head; + /* Stream reset rate limiter. If receiving excessive amount of + stream resets, GOAWAY will be sent. */ + nghttp2_ratelim stream_reset_ratelim; /* Sequential number across all streams to process streams in FIFO. */ uint64_t stream_seq; diff --git a/deps/nghttp2/lib/nghttp2_stream.c b/deps/nghttp2/lib/nghttp2_stream.c index b3614a0b02761e..f1951f879d7927 100644 --- a/deps/nghttp2/lib/nghttp2_stream.c +++ b/deps/nghttp2/lib/nghttp2_stream.c @@ -465,14 +465,12 @@ static int stream_update_dep_on_attach_item(nghttp2_stream *stream) { return 0; } -static int stream_update_dep_on_detach_item(nghttp2_stream *stream) { +static void stream_update_dep_on_detach_item(nghttp2_stream *stream) { if (nghttp2_pq_empty(&stream->obq)) { stream_obq_remove(stream); } validate_tree(stream); - - return 0; } int nghttp2_stream_attach_item(nghttp2_stream *stream, @@ -503,20 +501,20 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream, return 0; } -int nghttp2_stream_detach_item(nghttp2_stream *stream) { +void nghttp2_stream_detach_item(nghttp2_stream *stream) { DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item); stream->item = NULL; stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL); if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return 0; + return; } - return stream_update_dep_on_detach_item(stream); + stream_update_dep_on_detach_item(stream); } -int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { +void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { assert(stream->item); DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id, @@ -525,10 +523,10 @@ int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) { stream->flags |= flags; if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) { - return 0; + return; } - return stream_update_dep_on_detach_item(stream); + stream_update_dep_on_detach_item(stream); } int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) { diff --git a/deps/nghttp2/lib/nghttp2_stream.h b/deps/nghttp2/lib/nghttp2_stream.h index 7a8e4c6c1ddb08..71b9fb1140c932 100644 --- a/deps/nghttp2/lib/nghttp2_stream.h +++ b/deps/nghttp2/lib/nghttp2_stream.h @@ -258,14 +258,8 @@ void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag); * more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates * the reason of this action. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory */ -int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags); +void nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags); /* * Put back deferred data in this stream to active state. The |flags| @@ -379,14 +373,8 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream, /* * Detaches |stream->item|. This function does not free * |stream->item|. The caller must free it. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP2_ERR_NOMEM - * Out of memory */ -int nghttp2_stream_detach_item(nghttp2_stream *stream); +void nghttp2_stream_detach_item(nghttp2_stream *stream); /* * Makes the |stream| depend on the |dep_stream|. This dependency is diff --git a/deps/nghttp2/lib/nghttp2_time.c b/deps/nghttp2/lib/nghttp2_time.c new file mode 100644 index 00000000000000..2a5f1a6ff524df --- /dev/null +++ b/deps/nghttp2/lib/nghttp2_time.c @@ -0,0 +1,62 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2023 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "nghttp2_time.h" + +#ifdef HAVE_TIME_H +# include +#endif /* HAVE_TIME_H */ + +#ifdef HAVE_SYSINFOAPI_H +# include +#endif /* HAVE_SYSINFOAPI_H */ + +#ifndef HAVE_GETTICKCOUNT64 +static uint64_t time_now_sec(void) { + time_t t = time(NULL); + + if (t == -1) { + return 0; + } + + return (uint64_t)t; +} +#endif /* HAVE_GETTICKCOUNT64 */ + +#ifdef HAVE_CLOCK_GETTIME +uint64_t nghttp2_time_now_sec(void) { + struct timespec tp; + int rv = clock_gettime(CLOCK_MONOTONIC, &tp); + + if (rv == -1) { + return time_now_sec(); + } + + return (uint64_t)tp.tv_sec; +} +#elif defined(HAVE_GETTICKCOUNT64) +uint64_t nghttp2_time_now_sec(void) { return GetTickCount64() / 1000; } +#else /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */ +uint64_t nghttp2_time_now_sec(void) { return time_now_sec(); } +#endif /* !HAVE_CLOCK_GETTIME && !HAVE_GETTICKCOUNT64 */ diff --git a/deps/nghttp2/lib/nghttp2_time.h b/deps/nghttp2/lib/nghttp2_time.h new file mode 100644 index 00000000000000..03c0bbe944ee3b --- /dev/null +++ b/deps/nghttp2/lib/nghttp2_time.h @@ -0,0 +1,38 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2023 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef NGHTTP2_TIME_H +#define NGHTTP2_TIME_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +/* nghttp2_time_now_sec returns seconds from implementation-specific + timepoint. If it is unable to get seconds, it returns 0. */ +uint64_t nghttp2_time_now_sec(void); + +#endif /* NGHTTP2_TIME_H */ diff --git a/deps/nghttp2/lib/sfparse.c b/deps/nghttp2/lib/sfparse.c new file mode 100644 index 00000000000000..efa2850c9d661d --- /dev/null +++ b/deps/nghttp2/lib/sfparse.c @@ -0,0 +1,1146 @@ +/* + * sfparse + * + * Copyright (c) 2023 sfparse contributors + * Copyright (c) 2019 nghttp3 contributors + * Copyright (c) 2015 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "sfparse.h" + +#include +#include +#include + +#define SF_STATE_DICT 0x08u +#define SF_STATE_LIST 0x10u +#define SF_STATE_ITEM 0x18u + +#define SF_STATE_INNER_LIST 0x04u + +#define SF_STATE_BEFORE 0x00u +#define SF_STATE_BEFORE_PARAMS 0x01u +#define SF_STATE_PARAMS 0x02u +#define SF_STATE_AFTER 0x03u + +#define SF_STATE_OP_MASK 0x03u + +#define SF_SET_STATE_AFTER(NAME) (SF_STATE_##NAME | SF_STATE_AFTER) +#define SF_SET_STATE_BEFORE_PARAMS(NAME) \ + (SF_STATE_##NAME | SF_STATE_BEFORE_PARAMS) +#define SF_SET_STATE_INNER_LIST_BEFORE(NAME) \ + (SF_STATE_##NAME | SF_STATE_INNER_LIST | SF_STATE_BEFORE) + +#define SF_STATE_DICT_AFTER SF_SET_STATE_AFTER(DICT) +#define SF_STATE_DICT_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(DICT) +#define SF_STATE_DICT_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(DICT) + +#define SF_STATE_LIST_AFTER SF_SET_STATE_AFTER(LIST) +#define SF_STATE_LIST_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(LIST) +#define SF_STATE_LIST_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(LIST) + +#define SF_STATE_ITEM_AFTER SF_SET_STATE_AFTER(ITEM) +#define SF_STATE_ITEM_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(ITEM) +#define SF_STATE_ITEM_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(ITEM) + +#define SF_STATE_INITIAL 0x00u + +#define DIGIT_CASES \ + case '0': \ + case '1': \ + case '2': \ + case '3': \ + case '4': \ + case '5': \ + case '6': \ + case '7': \ + case '8': \ + case '9' + +#define LCALPHA_CASES \ + case 'a': \ + case 'b': \ + case 'c': \ + case 'd': \ + case 'e': \ + case 'f': \ + case 'g': \ + case 'h': \ + case 'i': \ + case 'j': \ + case 'k': \ + case 'l': \ + case 'm': \ + case 'n': \ + case 'o': \ + case 'p': \ + case 'q': \ + case 'r': \ + case 's': \ + case 't': \ + case 'u': \ + case 'v': \ + case 'w': \ + case 'x': \ + case 'y': \ + case 'z' + +#define UCALPHA_CASES \ + case 'A': \ + case 'B': \ + case 'C': \ + case 'D': \ + case 'E': \ + case 'F': \ + case 'G': \ + case 'H': \ + case 'I': \ + case 'J': \ + case 'K': \ + case 'L': \ + case 'M': \ + case 'N': \ + case 'O': \ + case 'P': \ + case 'Q': \ + case 'R': \ + case 'S': \ + case 'T': \ + case 'U': \ + case 'V': \ + case 'W': \ + case 'X': \ + case 'Y': \ + case 'Z' + +#define ALPHA_CASES \ + UCALPHA_CASES: \ + LCALPHA_CASES + +#define X20_21_CASES \ + case ' ': \ + case '!' + +#define X23_5B_CASES \ + case '#': \ + case '$': \ + case '%': \ + case '&': \ + case '\'': \ + case '(': \ + case ')': \ + case '*': \ + case '+': \ + case ',': \ + case '-': \ + case '.': \ + case '/': \ + DIGIT_CASES: \ + case ':': \ + case ';': \ + case '<': \ + case '=': \ + case '>': \ + case '?': \ + case '@': \ + UCALPHA_CASES: \ + case '[' + +#define X5D_7E_CASES \ + case ']': \ + case '^': \ + case '_': \ + case '`': \ + LCALPHA_CASES: \ + case '{': \ + case '|': \ + case '}': \ + case '~' + +static int is_ws(uint8_t c) { + switch (c) { + case ' ': + case '\t': + return 1; + default: + return 0; + } +} + +static int parser_eof(sf_parser *sfp) { return sfp->pos == sfp->end; } + +static void parser_discard_ows(sf_parser *sfp) { + for (; !parser_eof(sfp) && is_ws(*sfp->pos); ++sfp->pos) + ; +} + +static void parser_discard_sp(sf_parser *sfp) { + for (; !parser_eof(sfp) && *sfp->pos == ' '; ++sfp->pos) + ; +} + +static void parser_set_op_state(sf_parser *sfp, uint32_t op) { + sfp->state &= ~SF_STATE_OP_MASK; + sfp->state |= op; +} + +static void parser_unset_inner_list_state(sf_parser *sfp) { + sfp->state &= ~SF_STATE_INNER_LIST; +} + +static int parser_key(sf_parser *sfp, sf_vec *dest) { + const uint8_t *base; + + switch (*sfp->pos) { + case '*': + LCALPHA_CASES: + break; + default: + return SF_ERR_PARSE_ERROR; + } + + base = sfp->pos++; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + case '_': + case '-': + case '.': + case '*': + DIGIT_CASES: + LCALPHA_CASES: + continue; + } + + break; + } + + if (dest) { + dest->base = (uint8_t *)base; + dest->len = (size_t)(sfp->pos - dest->base); + } + + return 0; +} + +static int parser_number(sf_parser *sfp, sf_value *dest) { + int sign = 1; + int64_t value = 0; + size_t len = 0; + size_t fpos = 0; + + if (*sfp->pos == '-') { + ++sfp->pos; + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + sign = -1; + } + + assert(!parser_eof(sfp)); + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + DIGIT_CASES: + if (++len > 15) { + return SF_ERR_PARSE_ERROR; + } + + value *= 10; + value += *sfp->pos - '0'; + + continue; + } + + break; + } + + if (len == 0) { + return SF_ERR_PARSE_ERROR; + } + + if (parser_eof(sfp) || *sfp->pos != '.') { + if (dest) { + dest->type = SF_TYPE_INTEGER; + dest->flags = SF_VALUE_FLAG_NONE; + dest->integer = value * sign; + } + + return 0; + } + + /* decimal */ + + if (len > 12) { + return SF_ERR_PARSE_ERROR; + } + + fpos = len; + + ++sfp->pos; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + DIGIT_CASES: + if (++len > 15) { + return SF_ERR_PARSE_ERROR; + } + + value *= 10; + value += *sfp->pos - '0'; + + continue; + } + + break; + } + + if (fpos == len || len - fpos > 3) { + return SF_ERR_PARSE_ERROR; + } + + if (dest) { + dest->type = SF_TYPE_DECIMAL; + dest->flags = SF_VALUE_FLAG_NONE; + dest->decimal.numer = value * sign; + + switch (len - fpos) { + case 1: + dest->decimal.denom = 10; + + break; + case 2: + dest->decimal.denom = 100; + + break; + case 3: + dest->decimal.denom = 1000; + + break; + } + } + + return 0; +} + +static int parser_date(sf_parser *sfp, sf_value *dest) { + int rv; + sf_value val; + + /* The first byte has already been validated by the caller. */ + assert('@' == *sfp->pos); + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + rv = parser_number(sfp, &val); + if (rv != 0) { + return rv; + } + + if (val.type != SF_TYPE_INTEGER) { + return SF_ERR_PARSE_ERROR; + } + + if (dest) { + *dest = val; + dest->type = SF_TYPE_DATE; + } + + return 0; +} + +static int parser_string(sf_parser *sfp, sf_value *dest) { + const uint8_t *base; + uint32_t flags = SF_VALUE_FLAG_NONE; + + /* The first byte has already been validated by the caller. */ + assert('"' == *sfp->pos); + + base = ++sfp->pos; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + X20_21_CASES: + X23_5B_CASES: + X5D_7E_CASES: + break; + case '\\': + ++sfp->pos; + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + switch (*sfp->pos) { + case '"': + case '\\': + flags = SF_VALUE_FLAG_ESCAPED_STRING; + + break; + default: + return SF_ERR_PARSE_ERROR; + } + + break; + case '"': + if (dest) { + dest->type = SF_TYPE_STRING; + dest->flags = flags; + dest->vec.len = (size_t)(sfp->pos - base); + dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; + } + + ++sfp->pos; + + return 0; + default: + return SF_ERR_PARSE_ERROR; + } + } + + return SF_ERR_PARSE_ERROR; +} + +static int parser_token(sf_parser *sfp, sf_value *dest) { + const uint8_t *base; + + /* The first byte has already been validated by the caller. */ + base = sfp->pos++; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + case '!': + case '#': + case '$': + case '%': + case '&': + case '\'': + case '*': + case '+': + case '-': + case '.': + case '^': + case '_': + case '`': + case '|': + case '~': + case ':': + case '/': + DIGIT_CASES: + ALPHA_CASES: + continue; + } + + break; + } + + if (dest) { + dest->type = SF_TYPE_TOKEN; + dest->flags = SF_VALUE_FLAG_NONE; + dest->vec.base = (uint8_t *)base; + dest->vec.len = (size_t)(sfp->pos - base); + } + + return 0; +} + +static int parser_byteseq(sf_parser *sfp, sf_value *dest) { + const uint8_t *base; + + /* The first byte has already been validated by the caller. */ + assert(':' == *sfp->pos); + + base = ++sfp->pos; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + case '+': + case '/': + DIGIT_CASES: + ALPHA_CASES: + continue; + case '=': + switch ((sfp->pos - base) & 0x3) { + case 0: + case 1: + return SF_ERR_PARSE_ERROR; + case 2: + switch (*(sfp->pos - 1)) { + case 'A': + case 'Q': + case 'g': + case 'w': + break; + default: + return SF_ERR_PARSE_ERROR; + } + + ++sfp->pos; + + if (parser_eof(sfp) || *sfp->pos != '=') { + return SF_ERR_PARSE_ERROR; + } + + break; + case 3: + switch (*(sfp->pos - 1)) { + case 'A': + case 'E': + case 'I': + case 'M': + case 'Q': + case 'U': + case 'Y': + case 'c': + case 'g': + case 'k': + case 'o': + case 's': + case 'w': + case '0': + case '4': + case '8': + break; + default: + return SF_ERR_PARSE_ERROR; + } + + break; + } + + ++sfp->pos; + + if (parser_eof(sfp) || *sfp->pos != ':') { + return SF_ERR_PARSE_ERROR; + } + + goto fin; + case ':': + if ((sfp->pos - base) & 0x3) { + return SF_ERR_PARSE_ERROR; + } + + goto fin; + default: + return SF_ERR_PARSE_ERROR; + } + } + + return SF_ERR_PARSE_ERROR; + +fin: + if (dest) { + dest->type = SF_TYPE_BYTESEQ; + dest->flags = SF_VALUE_FLAG_NONE; + dest->vec.len = (size_t)(sfp->pos - base); + dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; + } + + ++sfp->pos; + + return 0; +} + +static int parser_boolean(sf_parser *sfp, sf_value *dest) { + int b; + + /* The first byte has already been validated by the caller. */ + assert('?' == *sfp->pos); + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + switch (*sfp->pos) { + case '0': + b = 0; + + break; + case '1': + b = 1; + + break; + default: + return SF_ERR_PARSE_ERROR; + } + + ++sfp->pos; + + if (dest) { + dest->type = SF_TYPE_BOOLEAN; + dest->flags = SF_VALUE_FLAG_NONE; + dest->boolean = b; + } + + return 0; +} + +static int parser_bare_item(sf_parser *sfp, sf_value *dest) { + switch (*sfp->pos) { + case '"': + return parser_string(sfp, dest); + case '-': + DIGIT_CASES: + return parser_number(sfp, dest); + case '@': + return parser_date(sfp, dest); + case ':': + return parser_byteseq(sfp, dest); + case '?': + return parser_boolean(sfp, dest); + case '*': + ALPHA_CASES: + return parser_token(sfp, dest); + default: + return SF_ERR_PARSE_ERROR; + } +} + +static int parser_skip_inner_list(sf_parser *sfp); + +int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { + int rv; + + switch (sfp->state & SF_STATE_OP_MASK) { + case SF_STATE_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_BEFORE_PARAMS: + parser_set_op_state(sfp, SF_STATE_PARAMS); + + break; + case SF_STATE_PARAMS: + break; + default: + assert(0); + abort(); + } + + if (parser_eof(sfp) || *sfp->pos != ';') { + parser_set_op_state(sfp, SF_STATE_AFTER); + + return SF_ERR_EOF; + } + + ++sfp->pos; + + parser_discard_sp(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + rv = parser_key(sfp, dest_key); + if (rv != 0) { + return rv; + } + + if (parser_eof(sfp) || *sfp->pos != '=') { + if (dest_value) { + dest_value->type = SF_TYPE_BOOLEAN; + dest_value->flags = SF_VALUE_FLAG_NONE; + dest_value->boolean = 1; + } + + return 0; + } + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + return parser_bare_item(sfp, dest_value); +} + +static int parser_skip_params(sf_parser *sfp) { + int rv; + + for (;;) { + rv = sf_parser_param(sfp, NULL, NULL); + switch (rv) { + case 0: + break; + case SF_ERR_EOF: + return 0; + case SF_ERR_PARSE_ERROR: + return rv; + default: + assert(0); + abort(); + } + } +} + +int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { + int rv; + + switch (sfp->state & SF_STATE_OP_MASK) { + case SF_STATE_BEFORE: + parser_discard_sp(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + break; + case SF_STATE_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* Technically, we are entering SF_STATE_AFTER, but we will set + another state without reading the state. */ + /* parser_set_op_state(sfp, SF_STATE_AFTER); */ + + /* fall through */ + case SF_STATE_AFTER: + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + switch (*sfp->pos) { + case ' ': + parser_discard_sp(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + break; + case ')': + break; + default: + return SF_ERR_PARSE_ERROR; + } + + break; + default: + assert(0); + abort(); + } + + if (*sfp->pos == ')') { + ++sfp->pos; + + parser_unset_inner_list_state(sfp); + parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + + return SF_ERR_EOF; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + + return 0; +} + +static int parser_skip_inner_list(sf_parser *sfp) { + int rv; + + for (;;) { + rv = sf_parser_inner_list(sfp, NULL); + switch (rv) { + case 0: + break; + case SF_ERR_EOF: + return 0; + case SF_ERR_PARSE_ERROR: + return rv; + default: + assert(0); + abort(); + } + } +} + +static int parser_next_key_or_item(sf_parser *sfp) { + parser_discard_ows(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_EOF; + } + + if (*sfp->pos != ',') { + return SF_ERR_PARSE_ERROR; + } + + ++sfp->pos; + + parser_discard_ows(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + return 0; +} + +static int parser_dict_value(sf_parser *sfp, sf_value *dest) { + int rv; + + if (parser_eof(sfp) || *(sfp->pos) != '=') { + /* Boolean true */ + if (dest) { + dest->type = SF_TYPE_BOOLEAN; + dest->flags = SF_VALUE_FLAG_NONE; + dest->boolean = 1; + } + + sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + + return 0; + } + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + if (*sfp->pos == '(') { + if (dest) { + dest->type = SF_TYPE_INNER_LIST; + dest->flags = SF_VALUE_FLAG_NONE; + } + + ++sfp->pos; + + sfp->state = SF_STATE_DICT_INNER_LIST_BEFORE; + + return 0; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + + return 0; +} + +int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { + int rv; + + switch (sfp->state) { + case SF_STATE_DICT_INNER_LIST_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_DICT_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_DICT_AFTER: + rv = parser_next_key_or_item(sfp); + if (rv != 0) { + return rv; + } + + break; + case SF_STATE_INITIAL: + parser_discard_sp(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_EOF; + } + + break; + default: + assert(0); + abort(); + } + + rv = parser_key(sfp, dest_key); + if (rv != 0) { + return rv; + } + + return parser_dict_value(sfp, dest_value); +} + +int sf_parser_list(sf_parser *sfp, sf_value *dest) { + int rv; + + switch (sfp->state) { + case SF_STATE_LIST_INNER_LIST_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_LIST_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_LIST_AFTER: + rv = parser_next_key_or_item(sfp); + if (rv != 0) { + return rv; + } + + break; + case SF_STATE_INITIAL: + parser_discard_sp(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_EOF; + } + + break; + default: + assert(0); + abort(); + } + + if (*sfp->pos == '(') { + if (dest) { + dest->type = SF_TYPE_INNER_LIST; + dest->flags = SF_VALUE_FLAG_NONE; + } + + ++sfp->pos; + + sfp->state = SF_STATE_LIST_INNER_LIST_BEFORE; + + return 0; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + sfp->state = SF_STATE_LIST_BEFORE_PARAMS; + + return 0; +} + +int sf_parser_item(sf_parser *sfp, sf_value *dest) { + int rv; + + switch (sfp->state) { + case SF_STATE_INITIAL: + parser_discard_sp(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + break; + case SF_STATE_ITEM_INNER_LIST_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_ITEM_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_ITEM_AFTER: + parser_discard_sp(sfp); + + if (!parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + return SF_ERR_EOF; + default: + assert(0); + abort(); + } + + if (*sfp->pos == '(') { + if (dest) { + dest->type = SF_TYPE_INNER_LIST; + dest->flags = SF_VALUE_FLAG_NONE; + } + + ++sfp->pos; + + sfp->state = SF_STATE_ITEM_INNER_LIST_BEFORE; + + return 0; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + sfp->state = SF_STATE_ITEM_BEFORE_PARAMS; + + return 0; +} + +void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { + if (datalen == 0) { + sfp->pos = sfp->end = NULL; + } else { + sfp->pos = data; + sfp->end = data + datalen; + } + + sfp->state = SF_STATE_INITIAL; +} + +void sf_unescape(sf_vec *dest, const sf_vec *src) { + const uint8_t *p, *q; + uint8_t *o; + size_t len, slen; + + if (src->len == 0) { + *dest = *src; + + return; + } + + o = dest->base; + p = src->base; + len = src->len; + + for (;;) { + q = memchr(p, '\\', len); + if (q == NULL) { + if (len == src->len) { + *dest = *src; + + return; + } + + memcpy(o, p, len); + o += len; + + break; + } + + slen = (size_t)(q - p); + memcpy(o, p, slen); + o += slen; + + p = q + 1; + *o++ = *p++; + len -= slen + 2; + } + + dest->len = (size_t)(o - dest->base); +} + +void sf_base64decode(sf_vec *dest, const sf_vec *src) { + static const int index_tbl[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; + uint8_t *o; + const uint8_t *p, *end; + uint32_t n; + size_t i; + int idx; + + assert((src->len & 0x3) == 0); + + if (src->len == 0) { + *dest = *src; + + return; + } + + o = dest->base; + p = src->base; + end = src->base + src->len; + + for (; p != end;) { + n = 0; + + for (i = 1; i <= 4; ++i, ++p) { + idx = index_tbl[*p]; + + if (idx == -1) { + assert(i > 2); + + if (i == 3) { + assert(*p == '=' && *(p + 1) == '=' && p + 2 == end); + + *o++ = (uint8_t)(n >> 16); + + goto fin; + } + + assert(*p == '=' && p + 1 == end); + + *o++ = (uint8_t)(n >> 16); + *o++ = (n >> 8) & 0xffu; + + goto fin; + } + + n += (uint32_t)(idx << (24 - i * 6)); + } + + *o++ = (uint8_t)(n >> 16); + *o++ = (n >> 8) & 0xffu; + *o++ = n & 0xffu; + } + +fin: + dest->len = (size_t)(o - dest->base); +} diff --git a/deps/nghttp2/lib/sfparse.h b/deps/nghttp2/lib/sfparse.h new file mode 100644 index 00000000000000..1474db1429acea --- /dev/null +++ b/deps/nghttp2/lib/sfparse.h @@ -0,0 +1,409 @@ +/* + * sfparse + * + * Copyright (c) 2023 sfparse contributors + * Copyright (c) 2019 nghttp3 contributors + * Copyright (c) 2015 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef SFPARSE_H +#define SFPARSE_H + +/* Define WIN32 when build target is Win32 API (borrowed from + libcurl) */ +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1800) +/* MSVC < 2013 does not have inttypes.h because it is not C99 + compliant. See compiler macros and version number in + https://sourceforge.net/p/predef/wiki/Compilers/ */ +# include +#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +# include +#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +#include +#include + +/** + * @enum + * + * :type:`sf_type` defines value type. + */ +typedef enum sf_type { + /** + * :enum:`SF_TYPE_BOOLEAN` indicates boolean type. + */ + SF_TYPE_BOOLEAN, + /** + * :enum:`SF_TYPE_INTEGER` indicates integer type. + */ + SF_TYPE_INTEGER, + /** + * :enum:`SF_TYPE_DECIMAL` indicates decimal type. + */ + SF_TYPE_DECIMAL, + /** + * :enum:`SF_TYPE_STRING` indicates string type. + */ + SF_TYPE_STRING, + /** + * :enum:`SF_TYPE_TOKEN` indicates token type. + */ + SF_TYPE_TOKEN, + /** + * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type. + */ + SF_TYPE_BYTESEQ, + /** + * :enum:`SF_TYPE_INNER_LIST` indicates inner list type. + */ + SF_TYPE_INNER_LIST, + /** + * :enum:`SF_TYPE_DATE` indicates date type. + */ + SF_TYPE_DATE +} sf_type; + +/** + * @macro + * + * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has + * occurred, and it is not possible to continue the processing. + */ +#define SF_ERR_PARSE_ERROR -1 + +/** + * @macro + * + * :macro:`SF_ERR_EOF` indicates that there is nothing left to read. + * The context of this error varies depending on the function that + * returns this error code. + */ +#define SF_ERR_EOF -2 + +/** + * @struct + * + * :type:`sf_vec` stores sequence of bytes. + */ +typedef struct sf_vec { + /** + * :member:`base` points to the beginning of the sequence of bytes. + */ + uint8_t *base; + /** + * :member:`len` is the number of bytes contained in this sequence. + */ + size_t len; +} sf_vec; + +/** + * @macro + * + * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set. + */ +#define SF_VALUE_FLAG_NONE 0x0u + +/** + * @macro + * + * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string + * contains escaped character(s). + */ +#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u + +/** + * @struct + * + * :type:`sf_decimal` contains decimal value. + */ +typedef struct sf_decimal { + /** + * :member:`numer` contains numerator of the decimal value. + */ + int64_t numer; + /** + * :member:`denom` contains denominator of the decimal value. + */ + int64_t denom; +} sf_decimal; + +/** + * @struct + * + * :type:`sf_value` stores a Structured Field item. For Inner List, + * only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order + * to read the items contained in an inner list, call + * `sf_parser_inner_list`. + */ +typedef struct sf_value { + /** + * :member:`type` is the type of the value contained in this + * particular object. + */ + sf_type type; + /** + * :member:`flags` is bitwise OR of one or more of + * :macro:`SF_VALUE_FLAG_* `. + */ + uint32_t flags; + /** + * @anonunion_start + * + * @sf_value_value + */ + union { + /** + * :member:`boolean` contains boolean value if :member:`type` == + * :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0 + * indicates false. + */ + int boolean; + /** + * :member:`integer` contains integer value if :member:`type` is + * either :enum:`sf_type.SF_TYPE_INTEGER` or + * :enum:`sf_type.SF_TYPE_DATE`. + */ + int64_t integer; + /** + * :member:`decimal` contains decimal value if :member:`type` == + * :enum:`sf_type.SF_TYPE_DECIMAL`. + */ + sf_decimal decimal; + /** + * :member:`vec` contains sequence of bytes if :member:`type` is + * either :enum:`sf_type.SF_TYPE_STRING`, + * :enum:`sf_type.SF_TYPE_TOKEN`, or + * :enum:`sf_type.SF_TYPE_BYTESEQ`. + * + * For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or + * more escaped characters if :member:`flags` has + * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the + * string, use `sf_unescape`. + * + * For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64 + * encoded string. To decode this byte string, use + * `sf_base64decode`. + * + * If :member:`vec.len ` == 0, :member:`vec.base + * ` is guaranteed to be NULL. + */ + sf_vec vec; + /** + * @anonunion_end + */ + }; +} sf_value; + +/** + * @struct + * + * :type:`sf_parser` is the Structured Field Values parser. Use + * `sf_parser_init` to initialize it. + */ +typedef struct sf_parser { + /* all fields are private */ + const uint8_t *pos; + const uint8_t *end; + uint32_t state; +} sf_parser; + +/** + * @function + * + * `sf_parser_init` initializes |sfp| with the given buffer pointed by + * |data| of length |datalen|. + */ +void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen); + +/** + * @function + * + * `sf_parser_param` reads a parameter. If this function returns 0, + * it stores parameter key and value in |dest_key| and |dest_value| + * respectively, if they are not NULL. + * + * This function does no effort to find duplicated keys. Same key may + * be reported more than once. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all parameters have + * read, and caller can continue to read rest of the values. If it + * returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error + * while parsing field value. + */ +int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); + +/** + * @function + * + * `sf_parser_dict` reads the next dictionary key and value pair. If + * this function returns 0, it stores the key and value in |dest_key| + * and |dest_value| respectively, if they are not NULL. + * + * Caller can optionally read parameters attached to the pair by + * calling `sf_parser_param`. + * + * This function does no effort to find duplicated keys. Same key may + * be reported more than once. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all key and value + * pairs have been read, and there is nothing left to read. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * All values in the dictionary have read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); + +/** + * @function + * + * `sf_parser_list` reads the next list item. If this function + * returns 0, it stores the item in |dest| if it is not NULL. + * + * Caller can optionally read parameters attached to the item by + * calling `sf_parser_param`. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all values in the + * list have been read, and there is nothing left to read. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * All values in the list have read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_list(sf_parser *sfp, sf_value *dest); + +/** + * @function + * + * `sf_parser_item` reads a single item. If this function returns 0, + * it stores the item in |dest| if it is not NULL. + * + * This function is only used for the field value that consists of a + * single item. + * + * Caller can optionally read parameters attached to the item by + * calling `sf_parser_param`. + * + * Caller should call this function again to make sure that there is + * nothing left to read. If this 2nd function call returns + * :macro:`SF_ERR_EOF`, all data have been processed successfully. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * There is nothing left to read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_item(sf_parser *sfp, sf_value *dest); + +/** + * @function + * + * `sf_parser_inner_list` reads the next inner list item. If this + * function returns 0, it stores the item in |dest| if it is not NULL. + * + * Caller can optionally read parameters attached to the item by + * calling `sf_parser_param`. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all values in this + * inner list have been read, and caller can optionally read + * parameters attached to this inner list by calling + * `sf_parser_param`. Then caller can continue to read rest of the + * values. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * All values in the inner list have read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_inner_list(sf_parser *sfp, sf_value *dest); + +/** + * @function + * + * `sf_unescape` copies |src| to |dest| by removing escapes (``\``). + * |src| should be the pointer to :member:`sf_value.vec` of type + * :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`, + * `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or + * `sf_parser_param`, otherwise the behavior is undefined. + * + * :member:`dest->base ` must point to the buffer that + * has sufficient space to store the unescaped string. + * + * If there is no escape character in |src|, |*src| is assigned to + * |*dest|. This includes the case that :member:`src->len + * ` == 0. + * + * This function sets the length of unescaped string to + * :member:`dest->len `. + */ +void sf_unescape(sf_vec *dest, const sf_vec *src); + +/** + * @function + * + * `sf_base64decode` decodes Base64 encoded string |src| and writes + * the result into |dest|. |src| should be the pointer to + * :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ` + * produced by either `sf_parser_dict`, `sf_parser_list`, + * `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`, + * otherwise the behavior is undefined. + * + * :member:`dest->base ` must point to the buffer that + * has sufficient space to store the decoded byte string. + * + * If :member:`src->len ` == 0, |*src| is assigned to + * |*dest|. + * + * This function sets the length of decoded byte string to + * :member:`dest->len `. + */ +void sf_base64decode(sf_vec *dest, const sf_vec *src); + +#ifdef __cplusplus +} +#endif + +#endif /* SFPARSE_H */ diff --git a/deps/nghttp2/nghttp2.gyp b/deps/nghttp2/nghttp2.gyp index c4a18650efe789..87909c5f296a2c 100644 --- a/deps/nghttp2/nghttp2.gyp +++ b/deps/nghttp2/nghttp2.gyp @@ -1,4 +1,34 @@ { + 'variables': { + 'nghttp2_sources': [ + 'lib/nghttp2_buf.c', + 'lib/nghttp2_callbacks.c', + 'lib/nghttp2_debug.c', + 'lib/nghttp2_extpri.c', + 'lib/nghttp2_frame.c', + 'lib/nghttp2_hd.c', + 'lib/nghttp2_hd_huffman.c', + 'lib/nghttp2_hd_huffman_data.c', + 'lib/nghttp2_helper.c', + 'lib/nghttp2_http.c', + 'lib/nghttp2_map.c', + 'lib/nghttp2_mem.c', + 'lib/nghttp2_npn.c', + 'lib/nghttp2_option.c', + 'lib/nghttp2_outbound_item.c', + 'lib/nghttp2_pq.c', + 'lib/nghttp2_priority_spec.c', + 'lib/nghttp2_queue.c', + 'lib/nghttp2_ratelim.c', + 'lib/nghttp2_rcbuf.c', + 'lib/nghttp2_session.c', + 'lib/nghttp2_stream.c', + 'lib/nghttp2_submit.c', + 'lib/nghttp2_time.c', + 'lib/nghttp2_version.c', + 'lib/sfparse.c', + ] + }, 'target_defaults': { 'defines': [ '_U_=' @@ -35,29 +65,7 @@ 'include_dirs': [ 'lib/includes' ] }, 'sources': [ - 'lib/nghttp2_buf.c', - 'lib/nghttp2_callbacks.c', - 'lib/nghttp2_debug.c', - 'lib/nghttp2_extpri.c', - 'lib/nghttp2_frame.c', - 'lib/nghttp2_hd.c', - 'lib/nghttp2_hd_huffman.c', - 'lib/nghttp2_hd_huffman_data.c', - 'lib/nghttp2_helper.c', - 'lib/nghttp2_http.c', - 'lib/nghttp2_map.c', - 'lib/nghttp2_mem.c', - 'lib/nghttp2_npn.c', - 'lib/nghttp2_option.c', - 'lib/nghttp2_outbound_item.c', - 'lib/nghttp2_pq.c', - 'lib/nghttp2_priority_spec.c', - 'lib/nghttp2_queue.c', - 'lib/nghttp2_rcbuf.c', - 'lib/nghttp2_session.c', - 'lib/nghttp2_stream.c', - 'lib/nghttp2_submit.c', - 'lib/nghttp2_version.c' + '<@(nghttp2_sources)', ] } ]