diff --git a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h index 6cf947487bf899..83820fc983bd84 100644 --- a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h +++ b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h @@ -1116,11 +1116,43 @@ typedef struct nghttp3_qpack_encoder nghttp3_qpack_encoder; * * :macro:`NGHTTP3_ERR_NOMEM` * Out of memory. + * + * See also `nghttp3_qpack_encoder_new2`. This function calls + * `nghttp3_qpack_encoder_new2` with the given parameters and 0 as + * seed. */ NGHTTP3_EXTERN int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder, size_t hard_max_dtable_capacity, const nghttp3_mem *mem); +/** + * @function + * + * `nghttp3_qpack_encoder_new2` initializes QPACK encoder. |pencoder| + * must be non-NULL pointer. |hard_max_dtable_capacity| is the upper + * bound of the dynamic table capacity. |seed| must be unpredictable + * value, and is used to seed the internal data structure. |mem| is a + * memory allocator. This function allocates memory for + * :type:`nghttp3_qpack_encoder` itself, and assigns its pointer to + * |*pencoder| if it succeeds. + * + * The maximum dynamic table capacity is still 0. In order to change + * the maximum dynamic table capacity, call + * `nghttp3_qpack_encoder_set_max_dtable_capacity`. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. + * + * This function is available since v1.11.0. + */ +NGHTTP3_EXTERN int nghttp3_qpack_encoder_new2(nghttp3_qpack_encoder **pencoder, + size_t hard_max_dtable_capacity, + uint64_t seed, + const nghttp3_mem *mem); + /** * @function * @@ -1605,7 +1637,8 @@ NGHTTP3_EXTERN void nghttp3_set_debug_vprintf_callback( typedef struct nghttp3_conn nghttp3_conn; #define NGHTTP3_SETTINGS_V1 1 -#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_V1 +#define NGHTTP3_SETTINGS_V2 2 +#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_V2 /** * @struct @@ -1652,6 +1685,21 @@ typedef struct nghttp3_settings { * Datagrams (see :rfc:`9297`). */ uint8_t h3_datagram; + /* The following fields have been added since NGHTTP3_SETTINGS_V2. */ + /** + * :member:`origin_list`, if set, must contain a serialized HTTP/3 + * ORIGIN frame (see :rfc:`9412`) payload. The ORIGIN frame payload + * is a sequence of zero or more of a length prefixed byte string. + * The length is encoded in 2 bytes in network byte order. If + * :member:`origin_list->len ` is zero, an empty + * ORIGIN frame is sent. An application must keep the buffer + * pointed by :member:`origin_list->base ` alive + * until the :type:`nghttp3_conn` to which this field was passed is + * freed by `nghttp3_conn_del`. The object pointed to by this field + * is copied internally, and does not need to be kept alive. Only + * server uses this field. This field is available since v1.11.0. + */ + const nghttp3_vec *origin_list; } nghttp3_settings; /** @@ -1891,8 +1939,47 @@ typedef int (*nghttp3_recv_settings)(nghttp3_conn *conn, const nghttp3_settings *settings, void *conn_user_data); +/** + * @functypedef + * + * :type:`nghttp3_recv_origin` is a callback function which is invoked + * when a single origin in ORIGIN frame is received. |origin| is a + * received origin of length |originlen|. |originlen| never be 0. + * + * The implementation of this callback must return 0 if it succeeds. + * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the + * caller immediately. Any values other than 0 is treated as + * :macro:`NGHTTP3_ERR_CALLBACK_FAILURE`. + */ +typedef int (*nghttp3_recv_origin)(nghttp3_conn *conn, const uint8_t *origin, + size_t originlen, void *conn_user_data); + +/** + * @functypedef + * + * :type:`nghttp3_end_origin` is a callback function which is invoked + * when an ORIGIN frame has been completely processed. + * + * The implementation of this callback must return 0 if it succeeds. + * Returning :macro:`NGHTTP3_ERR_CALLBACK_FAILURE` will return to the + * caller immediately. Any values other than 0 is treated as + * :macro:`NGHTTP3_ERR_CALLBACK_FAILURE`. + */ +typedef int (*nghttp3_end_origin)(nghttp3_conn *conn, void *conn_user_data); + +/** + * @functypedef + * + * :type:`nghttp3_rand` is a callback function which is invoked when + * unpredictable data of |destlen| bytes are needed. The + * implementation must write unpredictable data of |destlen| bytes + * into the buffer pointed by |dest|. + */ +typedef void (*nghttp3_rand)(uint8_t *dest, size_t destlen); + #define NGHTTP3_CALLBACKS_V1 1 -#define NGHTTP3_CALLBACKS_VERSION NGHTTP3_CALLBACKS_V1 +#define NGHTTP3_CALLBACKS_V2 2 +#define NGHTTP3_CALLBACKS_VERSION NGHTTP3_CALLBACKS_V2 /** * @struct @@ -1986,6 +2073,28 @@ typedef struct nghttp3_callbacks { * when SETTINGS frame is received. */ nghttp3_recv_settings recv_settings; + /* The following fields have been added since NGHTTP3_CALLBACKS_V2. */ + /** + * :member:`recv_origin` is a callback function which is invoked + * when a single origin in an ORIGIN frame is received. This field + * is available since v1.11.0. + */ + nghttp3_recv_origin recv_origin; + /** + * :member:`end_origin` is a callback function which is invoked when + * an ORIGIN frame has been completely processed. This field is + * available since v1.11.0. + */ + nghttp3_end_origin end_origin; + /** + * :member:`rand` is a callback function which is invoked when + * unpredictable data are needed. Although this field is optional + * due to the backward compatibility, it is recommended to specify + * this field to harden the runtime behavior against suspicious + * activities of a remote endpoint. This field is available since + * v1.11.0. + */ + nghttp3_rand rand; } nghttp3_callbacks; /** @@ -2106,7 +2215,7 @@ NGHTTP3_EXTERN int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn, * control credit (both stream and connection) of underlying QUIC * connection by that amount. It does not include the amount of data * carried by DATA frame which contains application data (excluding - * any control or QPACK unidirectional streams) . See + * any control or QPACK unidirectional streams). See * :type:`nghttp3_recv_data` to handle those bytes. If |fin| is * nonzero, this is the last data from remote endpoint in this stream. * @@ -2480,8 +2589,6 @@ typedef struct nghttp3_data_reader { * This function returns 0 if it succeeds, or one of the following * negative error codes: * - * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` - * |stream_id| identifies unidirectional stream. * :macro:`NGHTTP3_ERR_CONN_CLOSING` * Connection is shutting down, and no new stream is allowed. * :macro:`NGHTTP3_ERR_STREAM_IN_USE` diff --git a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h index 7f6cb8acffe672..bd442b8be636ee 100644 --- a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h +++ b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h @@ -31,7 +31,7 @@ * * Version number of the nghttp3 library release. */ -#define NGHTTP3_VERSION "1.6.0" +#define NGHTTP3_VERSION "1.11.0" /** * @macro @@ -41,6 +41,6 @@ * number, 8 bits for minor and 8 bits for patch. Version 1.2.3 * becomes 0x010203. */ -#define NGHTTP3_VERSION_NUM 0x010600 +#define NGHTTP3_VERSION_NUM 0x010b00 #endif /* !defined(NGHTTP3_VERSION_H) */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_buf.c b/deps/ngtcp2/nghttp3/lib/nghttp3_buf.c index aae075a73cc4be..57cf744680e0a2 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_buf.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_buf.c @@ -50,6 +50,10 @@ size_t nghttp3_buf_cap(const nghttp3_buf *buf) { return (size_t)(buf->end - buf->begin); } +size_t nghttp3_buf_offset(const nghttp3_buf *buf) { + return (size_t)(buf->pos - buf->begin); +} + void nghttp3_buf_reset(nghttp3_buf *buf) { buf->pos = buf->last = buf->begin; } int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem) { @@ -87,4 +91,12 @@ void nghttp3_typed_buf_init(nghttp3_typed_buf *tbuf, const nghttp3_buf *buf, nghttp3_buf_type type) { tbuf->buf = *buf; tbuf->type = type; + tbuf->buf.begin = tbuf->buf.pos; +} + +void nghttp3_typed_buf_shared_init(nghttp3_typed_buf *tbuf, + const nghttp3_buf *chunk) { + tbuf->buf = *chunk; + tbuf->type = NGHTTP3_BUF_TYPE_SHARED; + tbuf->buf.begin = tbuf->buf.pos = tbuf->buf.last; } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_buf.h b/deps/ngtcp2/nghttp3/lib/nghttp3_buf.h index 9fa067de91b949..abc59b92a97a73 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_buf.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_buf.h @@ -42,6 +42,12 @@ void nghttp3_buf_wrap_init(nghttp3_buf *buf, uint8_t *src, size_t len); */ size_t nghttp3_buf_cap(const nghttp3_buf *buf); +/* + * nghttp3_buf_offset returns the distance from tbuf->begin to + * tbuf->pos. In other words, it returns buf->pos - buf->begin. + */ +size_t nghttp3_buf_offset(const nghttp3_buf *buf); + int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem); /* @@ -57,8 +63,12 @@ typedef enum nghttp3_buf_type { memory. */ NGHTTP3_BUF_TYPE_SHARED, /* NGHTTP3_BUF_TYPE_ALIEN indicates that the buffer points to a - memory which comes from outside of the library. */ + memory which comes from outside of the library. When + acknowledged, acked_data callback is called. */ NGHTTP3_BUF_TYPE_ALIEN, + /* NGHTTP3_BUF_TYPE_ALIEN_NO_ACK is like NGHTTP3_BUF_TYPE_ALIEN, but + acked_data callback is not called. */ + NGHTTP3_BUF_TYPE_ALIEN_NO_ACK, } nghttp3_buf_type; typedef struct nghttp3_typed_buf { @@ -69,6 +79,13 @@ typedef struct nghttp3_typed_buf { void nghttp3_typed_buf_init(nghttp3_typed_buf *tbuf, const nghttp3_buf *buf, nghttp3_buf_type type); +/* + * nghttp3_typed_buf_shared_init initializes |tbuf| of type + * NGHTTP3_BUF_TYPE_SHARED. + */ +void nghttp3_typed_buf_shared_init(nghttp3_typed_buf *tbuf, + const nghttp3_buf *chunk); + void nghttp3_typed_buf_free(nghttp3_typed_buf *tbuf); #endif /* !defined(NGHTTP3_BUF_H) */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_callbacks.c b/deps/ngtcp2/nghttp3/lib/nghttp3_callbacks.c new file mode 100644 index 00000000000000..5db8376ad229dd --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_callbacks.c @@ -0,0 +1,75 @@ +/* + * nghttp3 + * + * Copyright (c) 2025 nghttp3 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 "nghttp3_callbacks.h" + +#include +#include + +#include "nghttp3_unreachable.h" + +static void callbacks_copy(nghttp3_callbacks *dest, + const nghttp3_callbacks *src, + int callbacks_version) { + assert(callbacks_version != NGHTTP3_CALLBACKS_VERSION); + + memcpy(dest, src, nghttp3_callbackslen_version(callbacks_version)); +} + +const nghttp3_callbacks * +nghttp3_callbacks_convert_to_latest(nghttp3_callbacks *dest, + int callbacks_version, + const nghttp3_callbacks *src) { + if (callbacks_version == NGHTTP3_CALLBACKS_VERSION) { + return src; + } + + memset(dest, 0, sizeof(*dest)); + + callbacks_copy(dest, src, callbacks_version); + + return dest; +} + +void nghttp3_callbacks_convert_to_old(int callbacks_version, + nghttp3_callbacks *dest, + const nghttp3_callbacks *src) { + assert(callbacks_version != NGHTTP3_CALLBACKS_VERSION); + + callbacks_copy(dest, src, callbacks_version); +} + +size_t nghttp3_callbackslen_version(int callbacks_version) { + nghttp3_callbacks callbacks; + + switch (callbacks_version) { + case NGHTTP3_CALLBACKS_VERSION: + return sizeof(callbacks); + case NGHTTP3_CALLBACKS_V1: + return offsetof(nghttp3_callbacks, recv_settings) + + sizeof(callbacks.recv_settings); + default: + nghttp3_unreachable(); + } +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_callbacks.h b/deps/ngtcp2/nghttp3/lib/nghttp3_callbacks.h new file mode 100644 index 00000000000000..6bebb3a98dd8ca --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_callbacks.h @@ -0,0 +1,74 @@ +/* + * nghttp3 + * + * Copyright (c) 2025 nghttp3 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 NGHTTP3_CALLBACKS_H +#define NGHTTP3_CALLBACKS_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* defined(HAVE_CONFIG_H) */ + +#include + +/* + * nghttp3_callbacks_convert_to_latest converts |src| of version + * |callbacks_version| to the latest version + * NGHTTP3_CALLBACKS_VERSION. + * + * |dest| must point to the latest version. |src| may be the older + * version, and if so, it may have fewer fields. Accessing those + * fields causes undefined behavior. + * + * If |callbacks_version| == NGHTTP3_CALLBACKS_VERSION, no conversion + * is made, and |src| is returned. Otherwise, first |dest| is + * zero-initialized, and then all valid fields in |src| are copied + * into |dest|. Finally, |dest| is returned. + */ +const nghttp3_callbacks *nghttp3_callbacks_convert_to_latest( + nghttp3_callbacks *dest, int callbacks_version, const nghttp3_callbacks *src); + +/* + * nghttp3_callbacks_convert_to_old converts |src| of the latest + * version to |dest| of version |callbacks_version|. + * + * |callbacks_version| must not be the latest version + * NGHTTP3_CALLBACKS_VERSION. + * + * |dest| points to the older version, and it may have fewer fields. + * Accessing those fields causes undefined behavior. + * + * This function copies all valid fields in version + * |callbacks_version| from |src| to |dest|. + */ +void nghttp3_callbacks_convert_to_old(int callbacks_version, + nghttp3_callbacks *dest, + const nghttp3_callbacks *src); + +/* + * nghttp3_callbackslen_version returns the effective length of + * nghttp3_callbacks at the version |callbacks_version|. + */ +size_t nghttp3_callbackslen_version(int callbacks_version); + +#endif /* !defined(NGHTTP3_CALLBACKS_H) */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c index f70b4f5472de64..8c0e94dc768a29 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c @@ -34,12 +34,10 @@ #include "nghttp3_conv.h" #include "nghttp3_http.h" #include "nghttp3_unreachable.h" +#include "nghttp3_settings.h" +#include "nghttp3_callbacks.h" -/* NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY is the upper bound of the - dynamic table capacity that QPACK encoder is willing to use. */ -#define NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY 4096 - -nghttp3_objalloc_def(chunk, nghttp3_chunk, oplent); +nghttp3_objalloc_def(chunk, nghttp3_chunk, oplent) /* * conn_remote_stream_uni returns nonzero if |stream_id| is remote @@ -207,6 +205,32 @@ static int conn_call_recv_settings(nghttp3_conn *conn) { return 0; } +static int conn_call_recv_origin(nghttp3_conn *conn, const uint8_t *origin, + size_t originlen) { + if (!conn->callbacks.recv_origin) { + return 0; + } + + if (conn->callbacks.recv_origin(conn, origin, originlen, conn->user_data) != + 0) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + + return 0; +} + +static int conn_call_end_origin(nghttp3_conn *conn) { + if (!conn->callbacks.end_origin) { + return 0; + } + + if (conn->callbacks.end_origin(conn, conn->user_data) != 0) { + return NGHTTP3_ERR_CALLBACK_FAILURE; + } + + return 0; +} + static int ricnt_less(const nghttp3_pq_entry *lhsx, const nghttp3_pq_entry *rhsx) { nghttp3_stream *lhs = @@ -233,11 +257,22 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version, const nghttp3_callbacks *callbacks, int settings_version, const nghttp3_settings *settings, const nghttp3_mem *mem, void *user_data) { - int rv; nghttp3_conn *conn; + nghttp3_settings settings_latest; + nghttp3_callbacks callbacks_latest; + uint64_t map_seed; size_t i; (void)callbacks_version; - (void)settings_version; + + settings = nghttp3_settings_convert_to_latest(&settings_latest, + settings_version, settings); + callbacks = nghttp3_callbacks_convert_to_latest(&callbacks_latest, + callbacks_version, callbacks); + + assert(settings->max_field_section_size <= NGHTTP3_VARINT_MAX); + assert(settings->qpack_max_dtable_capacity <= NGHTTP3_VARINT_MAX); + assert(settings->qpack_encoder_max_dtable_capacity <= NGHTTP3_VARINT_MAX); + assert(settings->qpack_blocked_streams <= NGHTTP3_VARINT_MAX); if (mem == NULL) { mem = nghttp3_mem_default(); @@ -252,20 +287,19 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version, NGHTTP3_STREAM_MIN_CHUNK_SIZE * 16, mem); nghttp3_objalloc_stream_init(&conn->stream_objalloc, 8, mem); - nghttp3_map_init(&conn->streams, mem); - - rv = - nghttp3_qpack_decoder_init(&conn->qdec, settings->qpack_max_dtable_capacity, - settings->qpack_blocked_streams, mem); - if (rv != 0) { - goto qdec_init_fail; + if (callbacks->rand) { + callbacks->rand((uint8_t *)&map_seed, sizeof(map_seed)); + } else { + map_seed = 0; } - rv = nghttp3_qpack_encoder_init( - &conn->qenc, settings->qpack_encoder_max_dtable_capacity, mem); - if (rv != 0) { - goto qenc_init_fail; - } + nghttp3_map_init(&conn->streams, map_seed, mem); + + nghttp3_qpack_decoder_init(&conn->qdec, settings->qpack_max_dtable_capacity, + settings->qpack_blocked_streams, mem); + + nghttp3_qpack_encoder_init( + &conn->qenc, settings->qpack_encoder_max_dtable_capacity, ++map_seed, mem); nghttp3_pq_init(&conn->qpack_blocked_streams, ricnt_less, mem); @@ -277,8 +311,14 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version, conn->callbacks = *callbacks; conn->local.settings = *settings; - if (!server) { + if (server) { + if (settings->origin_list) { + conn->local.settings.origin_list = &conn->local.origin_list; + conn->local.origin_list = *settings->origin_list; + } + } else { conn->local.settings.enable_connect_protocol = 0; + conn->local.settings.origin_list = NULL; } nghttp3_settings_default(&conn->remote.settings); conn->mem = mem; @@ -291,16 +331,6 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version, *pconn = conn; return 0; - -qenc_init_fail: - nghttp3_qpack_decoder_free(&conn->qdec); -qdec_init_fail: - nghttp3_map_free(&conn->streams); - nghttp3_objalloc_free(&conn->stream_objalloc); - nghttp3_objalloc_free(&conn->out_chunk_objalloc); - nghttp3_mem_free(mem, conn); - - return rv; } int nghttp3_conn_client_new_versioned(nghttp3_conn **pconn, @@ -374,6 +404,8 @@ void nghttp3_conn_del(nghttp3_conn *conn) { nghttp3_objalloc_free(&conn->stream_objalloc); nghttp3_objalloc_free(&conn->out_chunk_objalloc); + nghttp3_mem_free(conn->mem, conn->rx.originbuf); + nghttp3_mem_free(conn->mem, conn); } @@ -399,6 +431,9 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id, size_t bidi_nproc; int rv; + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); + stream = nghttp3_conn_find_stream(conn, stream_id); if (stream == NULL) { /* TODO Assert idtr */ @@ -434,6 +469,10 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id, return rv; } } + } else if (!nghttp3_client_stream_uni(stream_id)) { + /* server does not expect to receive new server initiated + bidirectional or unidirectional stream from client. */ + return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR; } else { /* unidirectional stream */ if (srclen == 0 && fin) { @@ -448,7 +487,7 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id, stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; - } else if (nghttp3_stream_uni(stream_id)) { + } else if (nghttp3_server_stream_uni(stream_id)) { if (srclen == 0 && fin) { return 0; } @@ -461,17 +500,16 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id, stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL; stream->tx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL; } else { - /* client doesn't expect to receive new bidirectional stream - from server. */ + /* client doesn't expect to receive new bidirectional stream or + client initiated unidirectional stream from server. */ return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR; } } else if (conn->server) { - if (nghttp3_client_stream_bidi(stream_id)) { - if (stream->rx.hstate == NGHTTP3_HTTP_STATE_NONE) { - stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; - stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; - } - } + assert(nghttp3_client_stream_bidi(stream_id) || + nghttp3_client_stream_uni(stream_id)); + } else { + assert(nghttp3_client_stream_bidi(stream_id) || + nghttp3_server_stream_uni(stream_id)); } if (srclen == 0 && !fin) { @@ -608,6 +646,9 @@ nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream, break; case NGHTTP3_STREAM_TYPE_UNKNOWN: nconsumed = (nghttp3_ssize)srclen; + if (fin) { + break; + } rv = conn_call_stop_sending(conn, stream, NGHTTP3_H3_STREAM_CREATION_ERROR); if (rv != 0) { @@ -625,6 +666,11 @@ nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream, return nread + nconsumed; } +static void conn_reset_rx_originlen(nghttp3_conn *conn) { + conn->rx.originlen_offset = 0; + conn->rx.originlen = 0; +} + static int frame_fin(nghttp3_stream_read_state *rstate, size_t len) { return (int64_t)len >= rstate->left; } @@ -661,11 +707,11 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, return (nghttp3_ssize)nconsumed; } - rstate->fr.hd.type = rvint->acc; + rstate->fr.type = rvint->acc; nghttp3_varint_read_state_reset(rvint); rstate->state = NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH; if (p == end) { - break; + return (nghttp3_ssize)nconsumed; } /* Fall through */ case NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH: @@ -681,19 +727,19 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, return (nghttp3_ssize)nconsumed; } - rstate->left = rstate->fr.hd.length = rvint->acc; + rstate->left = rvint->acc; nghttp3_varint_read_state_reset(rvint); if (!(conn->flags & NGHTTP3_CONN_FLAG_SETTINGS_RECVED)) { - if (rstate->fr.hd.type != NGHTTP3_FRAME_SETTINGS) { + if (rstate->fr.type != NGHTTP3_FRAME_SETTINGS) { return NGHTTP3_ERR_H3_MISSING_SETTINGS; } conn->flags |= NGHTTP3_CONN_FLAG_SETTINGS_RECVED; - } else if (rstate->fr.hd.type == NGHTTP3_FRAME_SETTINGS) { + } else if (rstate->fr.type == NGHTTP3_FRAME_SETTINGS) { return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; } - switch (rstate->fr.hd.type) { + switch (rstate->fr.type) { case NGHTTP3_FRAME_SETTINGS: /* SETTINGS frame might be empty. */ if (rstate->left == 0) { @@ -734,6 +780,31 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, case NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID: /* We do not support push */ return NGHTTP3_ERR_H3_ID_ERROR; + case NGHTTP3_FRAME_ORIGIN: + if (conn->server || + (!conn->callbacks.recv_origin && !conn->callbacks.end_origin)) { + busy = 1; + rstate->state = NGHTTP3_CTRL_STREAM_STATE_IGN_FRAME; + break; + } + + /* ORIGIN frame might be empty */ + if (rstate->left == 0) { + rv = conn_call_end_origin(conn); + if (rv != 0) { + return rv; + } + + nghttp3_stream_read_state_reset(rstate); + + break; + } + + conn_reset_rx_originlen(conn); + + rstate->state = NGHTTP3_CTRL_STREAM_STATE_ORIGIN_ORIGIN_LEN; + + break; case NGHTTP3_FRAME_CANCEL_PUSH: /* We do not support push */ case NGHTTP3_FRAME_DATA: case NGHTTP3_FRAME_HEADERS: @@ -971,8 +1042,14 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, break; } + conn->rx.pri_fieldbuflen = 0; + rstate->state = NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE; + if (p == end) { + return (nghttp3_ssize)nconsumed; + } + /* Fall through */ case NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE: /* We need to buffer Priority Field Value because it might be @@ -1027,9 +1104,134 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, return rv; } - conn->rx.pri_fieldbuflen = 0; + nghttp3_stream_read_state_reset(rstate); + break; + case NGHTTP3_CTRL_STREAM_STATE_ORIGIN_ORIGIN_LEN: + /* client side only */ + len = (size_t)nghttp3_min_int64(rstate->left, (int64_t)(end - p)); + + assert(len > 0); + + for (;;) { + nread = 0; + + for (; conn->rx.originlen_offset < sizeof(conn->rx.originlen) && + (size_t)nread < len; + ++conn->rx.originlen_offset, ++nread) { + conn->rx.originlen <<= 8; + conn->rx.originlen += *p++; + } + + nconsumed += (size_t)nread; + rstate->left -= nread; + len -= (size_t)nread; + + if (conn->rx.originlen_offset < sizeof(conn->rx.originlen)) { + /* Needs another byte to parse Origin-Len */ + if (rstate->left == 0) { + return NGHTTP3_ERR_H3_FRAME_ERROR; + } + + return (nghttp3_ssize)nconsumed; + } + + if (conn->rx.originlen == 0 || rstate->left < conn->rx.originlen) { + /* While this seems OK in very loose RFC, allowing this + sounds like an atack vector. */ + return NGHTTP3_ERR_H3_FRAME_ERROR; + } + + if (len < conn->rx.originlen) { + /* ASCII-Origin does not fit into this buffer. Needs + buffering. */ + if (conn->rx.originbuf == NULL) { + conn->rx.originbuf = nghttp3_mem_malloc(conn->mem, UINT16_MAX); + if (conn->rx.originbuf == NULL) { + return NGHTTP3_ERR_NOMEM; + } + } + + memcpy(conn->rx.originbuf, p, len); + + /* No need to update p because we will return very soon. */ + nconsumed += len; + rstate->left -= (int64_t)len; + + conn->rx.originbuflen = len; + + rstate->state = NGHTTP3_CTRL_STREAM_STATE_ORIGIN_ASCII_ORIGIN; + + return (nghttp3_ssize)nconsumed; + } + + rv = conn_call_recv_origin(conn, p, conn->rx.originlen); + if (rv != 0) { + return rv; + } + + p += conn->rx.originlen; + nconsumed += conn->rx.originlen; + rstate->left -= conn->rx.originlen; + + if (rstate->left == 0) { + rv = conn_call_end_origin(conn); + if (rv != 0) { + return rv; + } + + nghttp3_stream_read_state_reset(rstate); + + break; + } + + len -= conn->rx.originlen; + + conn_reset_rx_originlen(conn); + + if (p == end) { + return (nghttp3_ssize)nconsumed; + } + } + + break; + case NGHTTP3_CTRL_STREAM_STATE_ORIGIN_ASCII_ORIGIN: + /* client side only */ + len = nghttp3_min_size(conn->rx.originlen - conn->rx.originbuflen, + (size_t)(end - p)); + + assert(len > 0); + + memcpy(conn->rx.originbuf + conn->rx.originbuflen, p, len); + + conn->rx.originbuflen += len; + p += len; + nconsumed += len; + rstate->left -= (int64_t)len; + + if (conn->rx.originbuflen < conn->rx.originlen) { + return (nghttp3_ssize)nconsumed; + } + + rv = conn_call_recv_origin(conn, conn->rx.originbuf, conn->rx.originlen); + if (rv != 0) { + return rv; + } + + if (rstate->left) { + conn_reset_rx_originlen(conn); + + rstate->state = NGHTTP3_CTRL_STREAM_STATE_ORIGIN_ORIGIN_LEN; + + break; + } + + rv = conn_call_end_origin(conn); + if (rv != 0) { + return rv; + } nghttp3_stream_read_state_reset(rstate); + break; case NGHTTP3_CTRL_STREAM_STATE_IGN_FRAME: len = (size_t)nghttp3_min_int64(rstate->left, (int64_t)(end - p)); @@ -1251,7 +1453,7 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, goto almost_done; } - rstate->fr.hd.type = rvint->acc; + rstate->fr.type = rvint->acc; nghttp3_varint_read_state_reset(rvint); rstate->state = NGHTTP3_REQ_STREAM_STATE_FRAME_LENGTH; if (p == end) { @@ -1271,10 +1473,10 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, goto almost_done; } - rstate->left = rstate->fr.hd.length = rvint->acc; + rstate->left = rvint->acc; nghttp3_varint_read_state_reset(rvint); - switch (rstate->fr.hd.type) { + switch (rstate->fr.type) { case NGHTTP3_FRAME_DATA: rv = nghttp3_stream_transit_rx_http_state( stream, NGHTTP3_HTTP_EVENT_DATA_BEGIN); @@ -1374,10 +1576,6 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, nread = nghttp3_conn_on_headers(conn, stream, p, len, (int64_t)len == rstate->left); if (nread < 0) { - if (nread == NGHTTP3_ERR_MALFORMED_HTTP_HEADER) { - goto http_header_error; - } - return nread; } @@ -1416,10 +1614,6 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, } if (rv != 0) { - if (rv == NGHTTP3_ERR_MALFORMED_HTTP_HEADER) { - goto http_header_error; - } - return rv; } @@ -1458,24 +1652,6 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, nghttp3_stream_read_state_reset(rstate); - break; - - http_header_error: - stream->flags |= NGHTTP3_STREAM_FLAG_HTTP_ERROR; - - busy = 1; - rstate->state = NGHTTP3_REQ_STREAM_STATE_IGN_REST; - - rv = conn_call_stop_sending(conn, stream, NGHTTP3_H3_MESSAGE_ERROR); - if (rv != 0) { - return rv; - } - - rv = conn_call_reset_stream(conn, stream, NGHTTP3_H3_MESSAGE_ERROR); - if (rv != 0) { - return rv; - } - break; case NGHTTP3_REQ_STREAM_STATE_IGN_FRAME: len = (size_t)nghttp3_min_int64(rstate->left, (int64_t)(end - p)); @@ -1792,6 +1968,8 @@ conn_on_priority_update_stream(nghttp3_conn *conn, stream->node.pri = fr->pri; stream->flags |= NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED; + stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; + stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; return 0; } @@ -1808,7 +1986,7 @@ conn_on_priority_update_stream(nghttp3_conn *conn, int nghttp3_conn_on_priority_update(nghttp3_conn *conn, const nghttp3_frame_priority_update *fr) { assert(conn->server); - assert(fr->hd.type == NGHTTP3_FRAME_PRIORITY_UPDATE); + assert(fr->type == NGHTTP3_FRAME_PRIORITY_UPDATE); return conn_on_priority_update_stream(conn, fr); } @@ -1836,7 +2014,7 @@ int nghttp3_conn_create_stream(nghttp3_conn *conn, nghttp3_stream **pstream, nghttp3_stream *stream; int rv; nghttp3_stream_callbacks callbacks = { - conn_stream_acked_data, + .acked_data = conn_stream_acked_data, }; rv = nghttp3_stream_new(&stream, stream_id, &callbacks, @@ -1874,6 +2052,8 @@ int nghttp3_conn_bind_control_stream(nghttp3_conn *conn, int64_t stream_id) { nghttp3_frame_entry frent; int rv; + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); assert(!conn->server || nghttp3_server_stream_uni(stream_id)); assert(conn->server || nghttp3_client_stream_uni(stream_id)); @@ -1895,10 +2075,27 @@ int nghttp3_conn_bind_control_stream(nghttp3_conn *conn, int64_t stream_id) { return rv; } - frent.fr.hd.type = NGHTTP3_FRAME_SETTINGS; + frent.fr.type = NGHTTP3_FRAME_SETTINGS; frent.aux.settings.local_settings = &conn->local.settings; - return nghttp3_stream_frq_add(stream, &frent); + rv = nghttp3_stream_frq_add(stream, &frent); + if (rv != 0) { + return rv; + } + + if (conn->local.settings.origin_list) { + assert(conn->server); + + frent.fr.origin.type = NGHTTP3_FRAME_ORIGIN; + frent.fr.origin.origin_list = *conn->local.settings.origin_list; + + rv = nghttp3_stream_frq_add(stream, &frent); + if (rv != 0) { + return rv; + } + } + + return 0; } int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn, int64_t qenc_stream_id, @@ -1906,6 +2103,10 @@ int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn, int64_t qenc_stream_id, nghttp3_stream *stream; int rv; + assert(qenc_stream_id >= 0); + assert(qenc_stream_id <= (int64_t)NGHTTP3_MAX_VARINT); + assert(qdec_stream_id >= 0); + assert(qdec_stream_id <= (int64_t)NGHTTP3_MAX_VARINT); assert(!conn->server || nghttp3_server_stream_uni(qenc_stream_id)); assert(!conn->server || nghttp3_server_stream_uni(qdec_stream_id)); assert(conn->server || nghttp3_client_stream_uni(qenc_stream_id)); @@ -2118,14 +2319,14 @@ static int conn_submit_headers_data(nghttp3_conn *conn, nghttp3_stream *stream, const nghttp3_data_reader *dr) { int rv; nghttp3_nv *nnva; - nghttp3_frame_entry frent = {0}; + nghttp3_frame_entry frent; rv = nghttp3_nva_copy(&nnva, nva, nvlen, conn->mem); if (rv != 0) { return rv; } - frent.fr.hd.type = NGHTTP3_FRAME_HEADERS; + frent.fr.type = NGHTTP3_FRAME_HEADERS; frent.fr.headers.nva = nnva; frent.fr.headers.nvlen = nvlen; @@ -2136,7 +2337,7 @@ static int conn_submit_headers_data(nghttp3_conn *conn, nghttp3_stream *stream, } if (dr) { - frent.fr.hd.type = NGHTTP3_FRAME_DATA; + frent.fr.type = NGHTTP3_FRAME_DATA; frent.aux.data.dr = *dr; rv = nghttp3_stream_frq_add(stream, &frent); @@ -2194,13 +2395,11 @@ int nghttp3_conn_submit_request(nghttp3_conn *conn, int64_t stream_id, assert(!conn->server); assert(conn->tx.qenc); + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); assert(nghttp3_client_stream_bidi(stream_id)); - /* TODO Should we check that stream_id is client stream_id? */ /* TODO Check GOAWAY last stream ID */ - if (nghttp3_stream_uni(stream_id)) { - return NGHTTP3_ERR_INVALID_ARGUMENT; - } if (conn->flags & NGHTTP3_CONN_FLAG_GOAWAY_RECVED) { return NGHTTP3_ERR_CONN_CLOSING; @@ -2288,12 +2487,12 @@ int nghttp3_conn_submit_trailers(nghttp3_conn *conn, int64_t stream_id, } int nghttp3_conn_submit_shutdown_notice(nghttp3_conn *conn) { - nghttp3_frame_entry frent = {0}; + nghttp3_frame_entry frent; int rv; assert(conn->tx.ctrl); - frent.fr.hd.type = NGHTTP3_FRAME_GOAWAY; + frent.fr.type = NGHTTP3_FRAME_GOAWAY; frent.fr.goaway.id = conn->server ? NGHTTP3_SHUTDOWN_NOTICE_STREAM_ID : NGHTTP3_SHUTDOWN_NOTICE_PUSH_ID; @@ -2311,12 +2510,12 @@ int nghttp3_conn_submit_shutdown_notice(nghttp3_conn *conn) { } int nghttp3_conn_shutdown(nghttp3_conn *conn) { - nghttp3_frame_entry frent = {0}; + nghttp3_frame_entry frent; int rv; assert(conn->tx.ctrl); - frent.fr.hd.type = NGHTTP3_FRAME_GOAWAY; + frent.fr.type = NGHTTP3_FRAME_GOAWAY; if (conn->server) { frent.fr.goaway.id = nghttp3_min_int64((1ll << 62) - 4, conn->rx.max_stream_id_bidi + 4); @@ -2454,6 +2653,9 @@ int nghttp3_conn_close_stream(nghttp3_conn *conn, int64_t stream_id, int nghttp3_conn_shutdown_stream_read(nghttp3_conn *conn, int64_t stream_id) { nghttp3_stream *stream; + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); + if (!nghttp3_client_stream_bidi(stream_id)) { return 0; } @@ -2515,6 +2717,9 @@ uint64_t nghttp3_conn_get_frame_payload_left(nghttp3_conn *conn, nghttp3_stream *stream; int uni = 0; + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); + if (!nghttp3_client_stream_bidi(stream_id)) { uni = conn_remote_stream_uni(conn, stream_id); if (!uni) { @@ -2542,6 +2747,8 @@ int nghttp3_conn_get_stream_priority_versioned(nghttp3_conn *conn, (void)pri_version; assert(conn->server); + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); if (!nghttp3_client_stream_bidi(stream_id)) { return NGHTTP3_ERR_INVALID_ARGUMENT; @@ -2562,10 +2769,12 @@ int nghttp3_conn_set_client_stream_priority(nghttp3_conn *conn, const uint8_t *data, size_t datalen) { nghttp3_stream *stream; - nghttp3_frame_entry frent = {0}; + nghttp3_frame_entry frent; uint8_t *buf = NULL; assert(!conn->server); + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); if (!nghttp3_client_stream_bidi(stream_id)) { return NGHTTP3_ERR_INVALID_ARGUMENT; @@ -2585,7 +2794,7 @@ int nghttp3_conn_set_client_stream_priority(nghttp3_conn *conn, memcpy(buf, data, datalen); } - frent.fr.hd.type = NGHTTP3_FRAME_PRIORITY_UPDATE; + frent.fr.type = NGHTTP3_FRAME_PRIORITY_UPDATE; frent.fr.priority_update.pri_elem_id = stream_id; frent.fr.priority_update.data = buf; frent.fr.priority_update.datalen = datalen; @@ -2603,6 +2812,8 @@ int nghttp3_conn_set_server_stream_priority_versioned(nghttp3_conn *conn, assert(conn->server); assert(pri->urgency < NGHTTP3_URGENCY_LEVELS); assert(pri->inc == 0 || pri->inc == 1); + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); if (!nghttp3_client_stream_bidi(stream_id)) { return NGHTTP3_ERR_INVALID_ARGUMENT; @@ -2626,13 +2837,3 @@ int nghttp3_conn_is_drained(nghttp3_conn *conn) { nghttp3_stream_outq_write_done(conn->tx.ctrl) && nghttp3_ringbuf_len(&conn->tx.ctrl->frq) == 0; } - -void nghttp3_settings_default_versioned(int settings_version, - nghttp3_settings *settings) { - (void)settings_version; - - memset(settings, 0, sizeof(nghttp3_settings)); - settings->max_field_section_size = NGHTTP3_VARINT_MAX; - settings->qpack_encoder_max_dtable_capacity = - NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY; -} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h index 1218ba508ba46a..80c26f80322c60 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h @@ -38,8 +38,6 @@ #include "nghttp3_idtr.h" #include "nghttp3_gaptr.h" -#define NGHTTP3_VARINT_MAX ((1ull << 62) - 1) - /* NGHTTP3_QPACK_ENCODER_MAX_TABLE_CAPACITY is the maximum dynamic table size for QPACK encoder. */ #define NGHTTP3_QPACK_ENCODER_MAX_TABLE_CAPACITY 16384 @@ -76,7 +74,7 @@ typedef struct nghttp3_chunk { nghttp3_opl_entry oplent; } nghttp3_chunk; -nghttp3_objalloc_decl(chunk, nghttp3_chunk, oplent); +nghttp3_objalloc_decl(chunk, nghttp3_chunk, oplent) struct nghttp3_conn { nghttp3_objalloc out_chunk_objalloc; @@ -95,6 +93,11 @@ struct nghttp3_conn { uint16_t flags; struct { + /* origin_list contains the shallow copy of + nghttp3_settings.origin_list passed from an application if this + object is initialized as server. settings.origin_list may + point to the address of this field. */ + nghttp3_vec origin_list; nghttp3_settings settings; struct { /* max_pushes is the number of push IDs that local endpoint can @@ -125,12 +128,36 @@ struct nghttp3_conn { int64_t max_stream_id_bidi; - /* pri_fieldbuf is a buffer to store incoming Priority Field Value - in PRIORITY_UPDATE frame. */ - uint8_t pri_fieldbuf[8]; - /* pri_fieldlen is the number of bytes written into - pri_fieldbuf. */ - size_t pri_fieldbuflen; + union { + struct { + /* pri_fieldbuf is a buffer to store incoming Priority Field Value + in PRIORITY_UPDATE frame. */ + uint8_t pri_fieldbuf[8]; + /* pri_fieldlen is the number of bytes written into + pri_fieldbuf. */ + size_t pri_fieldbuflen; + }; + /* ORIGIN frame */ + struct { + /* originlen_offset is the offset to Origin-Len that is going + to be added to originlen. If this value equals + sizeof(originlen), Origin-Len is fully read, and the length + of ASCII-Origin is determined. */ + size_t originlen_offset; + /* originlen is Origin-Len of ASCII-Origin currently read. */ + uint16_t originlen; + }; + }; + + /* originbuf points to the buffer that contains ASCII-Origin that + is not fully available in a single input buffer. If it is + fully available in the input buffer, it is emitted to an + application without using this field. Otherwise, partial + ASCII-Origin is copied to this field, and the complete + ASCII-Origin is emitted when the assembly finishes. */ + uint8_t *originbuf; + /* originbuflen is the length of bytes written to originbuf. */ + size_t originbuflen; } rx; struct { diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c index 6439a6d782960c..9b32ca3f405b9f 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c @@ -66,8 +66,6 @@ const uint8_t *nghttp3_get_varint(int64_t *dest, const uint8_t *p) { } } -int64_t nghttp3_get_varint_fb(const uint8_t *p) { return *p & 0x3f; } - size_t nghttp3_get_varintlen(const uint8_t *p) { return (size_t)(1u << (*p >> 6)); } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h index 40f5d4de782883..8895fe8d3415d6 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h @@ -56,6 +56,8 @@ #include +#define NGHTTP3_VARINT_MAX ((1ull << 62) - 1) + #if HAVE_DECL_BE64TOH # define nghttp3_ntohl64(N) be64toh(N) # define nghttp3_htonl64(N) htobe64(N) @@ -135,12 +137,6 @@ STIN uint16_t ntohs(uint16_t netshort) { */ const uint8_t *nghttp3_get_varint(int64_t *dest, const uint8_t *p); -/* - * nghttp3_get_varint_fb reads first byte of encoded variable-length - * integer from |p|. - */ -int64_t nghttp3_get_varint_fb(const uint8_t *p); - /* * nghttp3_get_varintlen returns the required number of bytes to read * variable-length integer starting at |p|. diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c index 1d87e448d887cf..da88b54f96de65 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c @@ -31,21 +31,22 @@ #include "nghttp3_conv.h" #include "nghttp3_str.h" -uint8_t *nghttp3_frame_write_hd(uint8_t *p, const nghttp3_frame_hd *hd) { - p = nghttp3_put_varint(p, hd->type); - p = nghttp3_put_varint(p, hd->length); +uint8_t *nghttp3_frame_write_hd(uint8_t *p, int64_t type, int64_t payloadlen) { + p = nghttp3_put_varint(p, type); + p = nghttp3_put_varint(p, payloadlen); return p; } -size_t nghttp3_frame_write_hd_len(const nghttp3_frame_hd *hd) { - return nghttp3_put_varintlen(hd->type) + nghttp3_put_varintlen(hd->length); +size_t nghttp3_frame_write_hd_len(int64_t type, int64_t payloadlen) { + return nghttp3_put_varintlen(type) + nghttp3_put_varintlen(payloadlen); } uint8_t *nghttp3_frame_write_settings(uint8_t *p, - const nghttp3_frame_settings *fr) { + const nghttp3_frame_settings *fr, + int64_t payloadlen) { size_t i; - p = nghttp3_frame_write_hd(p, &fr->hd); + p = nghttp3_frame_write_hd(p, fr->type, payloadlen); for (i = 0; i < fr->niv; ++i) { p = nghttp3_put_varint(p, (int64_t)fr->iv[i].id); @@ -71,9 +72,9 @@ size_t nghttp3_frame_write_settings_len(int64_t *ppayloadlen, nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; } -uint8_t *nghttp3_frame_write_goaway(uint8_t *p, - const nghttp3_frame_goaway *fr) { - p = nghttp3_frame_write_hd(p, &fr->hd); +uint8_t *nghttp3_frame_write_goaway(uint8_t *p, const nghttp3_frame_goaway *fr, + int64_t payloadlen) { + p = nghttp3_frame_write_hd(p, fr->type, payloadlen); p = nghttp3_put_varint(p, fr->id); return p; @@ -89,10 +90,9 @@ size_t nghttp3_frame_write_goaway_len(int64_t *ppayloadlen, nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; } -uint8_t * -nghttp3_frame_write_priority_update(uint8_t *p, - const nghttp3_frame_priority_update *fr) { - p = nghttp3_frame_write_hd(p, &fr->hd); +uint8_t *nghttp3_frame_write_priority_update( + uint8_t *p, const nghttp3_frame_priority_update *fr, int64_t payloadlen) { + p = nghttp3_frame_write_hd(p, fr->type, payloadlen); p = nghttp3_put_varint(p, fr->pri_elem_id); if (fr->datalen) { p = nghttp3_cpymem(p, fr->data, fr->datalen); @@ -107,7 +107,27 @@ size_t nghttp3_frame_write_priority_update_len( *ppayloadlen = (int64_t)payloadlen; - return nghttp3_put_varintlen(fr->hd.type) + + return nghttp3_put_varintlen(fr->type) + + nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; +} + +uint8_t *nghttp3_frame_write_origin(uint8_t *p, const nghttp3_frame_origin *fr, + int64_t payloadlen) { + p = nghttp3_frame_write_hd(p, fr->type, payloadlen); + if (fr->origin_list.len) { + p = nghttp3_cpymem(p, fr->origin_list.base, fr->origin_list.len); + } + + return p; +} + +size_t nghttp3_frame_write_origin_len(int64_t *ppayloadlen, + const nghttp3_frame_origin *fr) { + size_t payloadlen = fr->origin_list.len; + + *ppayloadlen = (int64_t)payloadlen; + + return nghttp3_put_varintlen(fr->type) + nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h index e216967d740b86..cca7ed0d6c95c7 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h @@ -44,6 +44,8 @@ /* PRIORITY_UPDATE: https://datatracker.ietf.org/doc/html/rfc9218 */ #define NGHTTP3_FRAME_PRIORITY_UPDATE 0x0f0700 #define NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID 0x0f0701 +/* ORIGIN: https://datatracker.ietf.org/doc/html/rfc9412 */ +#define NGHTTP3_FRAME_ORIGIN 0x0c /* Frame types that are reserved for HTTP/2, and must not be used in HTTP/3. */ @@ -52,17 +54,12 @@ #define NGHTTP3_H2_FRAME_WINDOW_UPDATE 0x08 #define NGHTTP3_H2_FRAME_CONTINUATION 0x9 -typedef struct nghttp3_frame_hd { - int64_t type; - int64_t length; -} nghttp3_frame_hd; - typedef struct nghttp3_frame_data { - nghttp3_frame_hd hd; + int64_t type; } nghttp3_frame_data; typedef struct nghttp3_frame_headers { - nghttp3_frame_hd hd; + int64_t type; nghttp3_nv *nva; size_t nvlen; } nghttp3_frame_headers; @@ -84,20 +81,20 @@ typedef struct nghttp3_settings_entry { } nghttp3_settings_entry; typedef struct nghttp3_frame_settings { - nghttp3_frame_hd hd; + int64_t type; size_t niv; nghttp3_settings_entry iv[1]; } nghttp3_frame_settings; typedef struct nghttp3_frame_goaway { - nghttp3_frame_hd hd; + int64_t type; int64_t id; } nghttp3_frame_goaway; typedef struct nghttp3_frame_priority_update { - nghttp3_frame_hd hd; - /* pri_elem_id is stream ID if hd.type == - NGHTTP3_FRAME_PRIORITY_UPDATE. It is push ID if hd.type == + int64_t type; + /* pri_elem_id is stream ID if type == + NGHTTP3_FRAME_PRIORITY_UPDATE. It is push ID if type == NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID. It is undefined otherwise. */ int64_t pri_elem_id; @@ -114,42 +111,54 @@ typedef struct nghttp3_frame_priority_update { }; } nghttp3_frame_priority_update; +typedef struct nghttp3_frame_origin { + int64_t type; + /* These fields are only used by server to send ORIGIN frame. + Client never use them. */ + nghttp3_vec origin_list; +} nghttp3_frame_origin; + typedef union nghttp3_frame { - nghttp3_frame_hd hd; + int64_t type; nghttp3_frame_data data; nghttp3_frame_headers headers; nghttp3_frame_settings settings; nghttp3_frame_goaway goaway; nghttp3_frame_priority_update priority_update; + nghttp3_frame_origin origin; } nghttp3_frame; /* - * nghttp3_frame_write_hd writes frame header |hd| to |dest|. This - * function assumes that |dest| has enough space to write |hd|. + * nghttp3_frame_write_hd writes frame header consisting of |type| and + * |payloadlen| to |dest|. This function assumes that |dest| has + * enough space to write the frame header. * * This function returns |dest| plus the number of bytes written. */ -uint8_t *nghttp3_frame_write_hd(uint8_t *dest, const nghttp3_frame_hd *hd); +uint8_t *nghttp3_frame_write_hd(uint8_t *dest, int64_t type, + int64_t payloadlen); /* * nghttp3_frame_write_hd_len returns the number of bytes required to - * write |hd|. hd->length must be set. + * write a frame header consisting of |type| and |payloadlen|. */ -size_t nghttp3_frame_write_hd_len(const nghttp3_frame_hd *hd); +size_t nghttp3_frame_write_hd_len(int64_t type, int64_t payloadlen); /* * nghttp3_frame_write_settings writes SETTINGS frame |fr| to |dest|. * This function assumes that |dest| has enough space to write |fr|. + * |payloadlen| is the length of the frame payload. * * This function returns |dest| plus the number of bytes written. */ uint8_t *nghttp3_frame_write_settings(uint8_t *dest, - const nghttp3_frame_settings *fr); + const nghttp3_frame_settings *fr, + int64_t payloadlen); /* * nghttp3_frame_write_settings_len returns the number of bytes - * required to write |fr|. fr->hd.length is ignored. This function - * stores payload length in |*ppayloadlen|. + * required to write |fr|. This function stores the frame payload + * length in |*ppayloadlen|. */ size_t nghttp3_frame_write_settings_len(int64_t *pppayloadlen, const nghttp3_frame_settings *fr); @@ -157,16 +166,18 @@ size_t nghttp3_frame_write_settings_len(int64_t *pppayloadlen, /* * nghttp3_frame_write_goaway writes GOAWAY frame |fr| to |dest|. * This function assumes that |dest| has enough space to write |fr|. + * |payloadlen| is the length of the frame payload. * * This function returns |dest| plus the number of bytes written. */ uint8_t *nghttp3_frame_write_goaway(uint8_t *dest, - const nghttp3_frame_goaway *fr); + const nghttp3_frame_goaway *fr, + int64_t payloadlen); /* * nghttp3_frame_write_goaway_len returns the number of bytes required - * to write |fr|. fr->hd.length is ignored. This function stores - * payload length in |*ppayloadlen|. + * to write |fr|. This function stores the frame payload length in + * |*ppayloadlen|. */ size_t nghttp3_frame_write_goaway_len(int64_t *ppayloadlen, const nghttp3_frame_goaway *fr); @@ -174,22 +185,40 @@ size_t nghttp3_frame_write_goaway_len(int64_t *ppayloadlen, /* * nghttp3_frame_write_priority_update writes PRIORITY_UPDATE frame * |fr| to |dest|. This function assumes that |dest| has enough space - * to write |fr|. + * to write |fr|. |payloadlen| is the length of the frame payload. * * This function returns |dest| plus the number of bytes written; */ -uint8_t * -nghttp3_frame_write_priority_update(uint8_t *dest, - const nghttp3_frame_priority_update *fr); +uint8_t *nghttp3_frame_write_priority_update( + uint8_t *dest, const nghttp3_frame_priority_update *fr, int64_t payloadlen); /* * nghttp3_frame_write_priority_update_len returns the number of bytes - * required to write |fr|. fr->hd.length is ignored. This function - * stores payload length in |*ppayloadlen|. + * required to write |fr|. This function stores the frame payload + * length in |*ppayloadlen|. */ size_t nghttp3_frame_write_priority_update_len( int64_t *ppayloadlen, const nghttp3_frame_priority_update *fr); +/* + * nghttp3_frame_write_origin writes ORIGIN frame |fr| to |dest|. + * This function assumes that |dest| has enough space to write |fr|. + * |payloadlen| is the length of the frame payload. + * + * This function returns |dest| plus the number of bytes written; + */ +uint8_t *nghttp3_frame_write_origin(uint8_t *dest, + const nghttp3_frame_origin *fr, + int64_t payloadlen); + +/* + * nghttp3_frame_write_origin_len returns the number of bytes required + * to write |fr|. This function stores the frame payload length in + * |*ppayloadlen|. + */ +size_t nghttp3_frame_write_origin_len(int64_t *ppayloadlen, + const nghttp3_frame_origin *fr); + /* * nghttp3_nva_copy copies name/value pairs from |nva|, which contains * |nvlen| pairs, to |*nva_ptr|, which is dynamically allocated so diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_gaptr.c b/deps/ngtcp2/nghttp3/lib/nghttp3_gaptr.c index 20eed5faa2bcba..e8ab509c8f9a11 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_gaptr.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_gaptr.c @@ -29,14 +29,16 @@ #include void nghttp3_gaptr_init(nghttp3_gaptr *gaptr, const nghttp3_mem *mem) { - nghttp3_ksl_init(&gaptr->gap, nghttp3_ksl_range_compar, sizeof(nghttp3_range), - mem); + nghttp3_ksl_init(&gaptr->gap, nghttp3_ksl_range_compar, + nghttp3_ksl_range_search, sizeof(nghttp3_range), mem); gaptr->mem = mem; } static int gaptr_gap_init(nghttp3_gaptr *gaptr) { - nghttp3_range range = {0, UINT64_MAX}; + nghttp3_range range = { + .end = UINT64_MAX, + }; return nghttp3_ksl_insert(&gaptr->gap, NULL, &range, NULL); } @@ -52,7 +54,11 @@ void nghttp3_gaptr_free(nghttp3_gaptr *gaptr) { int nghttp3_gaptr_push(nghttp3_gaptr *gaptr, uint64_t offset, uint64_t datalen) { int rv; - nghttp3_range k, m, l, r, q = {offset, offset + datalen}; + nghttp3_range k, m, l, r; + nghttp3_range q = { + .begin = offset, + .end = offset + datalen, + }; nghttp3_ksl_it it; if (nghttp3_ksl_len(&gaptr->gap) == 0) { @@ -62,8 +68,8 @@ int nghttp3_gaptr_push(nghttp3_gaptr *gaptr, uint64_t offset, } } - it = nghttp3_ksl_lower_bound_compar(&gaptr->gap, &q, - nghttp3_ksl_range_exclusive_compar); + it = nghttp3_ksl_lower_bound_search(&gaptr->gap, &q, + nghttp3_ksl_range_exclusive_search); for (; !nghttp3_ksl_it_end(&it);) { k = *(nghttp3_range *)nghttp3_ksl_it_key(&it); @@ -112,7 +118,10 @@ uint64_t nghttp3_gaptr_first_gap_offset(nghttp3_gaptr *gaptr) { nghttp3_range nghttp3_gaptr_get_first_gap_after(nghttp3_gaptr *gaptr, uint64_t offset) { - nghttp3_range q = {offset, offset + 1}; + nghttp3_range q = { + .begin = offset, + .end = offset + 1, + }; nghttp3_ksl_it it; if (nghttp3_ksl_len(&gaptr->gap) == 0) { @@ -120,8 +129,8 @@ nghttp3_range nghttp3_gaptr_get_first_gap_after(nghttp3_gaptr *gaptr, return r; } - it = nghttp3_ksl_lower_bound_compar(&gaptr->gap, &q, - nghttp3_ksl_range_exclusive_compar); + it = nghttp3_ksl_lower_bound_search(&gaptr->gap, &q, + nghttp3_ksl_range_exclusive_search); assert(!nghttp3_ksl_it_end(&it)); @@ -130,7 +139,10 @@ nghttp3_range nghttp3_gaptr_get_first_gap_after(nghttp3_gaptr *gaptr, int nghttp3_gaptr_is_pushed(nghttp3_gaptr *gaptr, uint64_t offset, uint64_t datalen) { - nghttp3_range q = {offset, offset + datalen}; + nghttp3_range q = { + .begin = offset, + .end = offset + datalen, + }; nghttp3_ksl_it it; nghttp3_range m; @@ -138,8 +150,11 @@ int nghttp3_gaptr_is_pushed(nghttp3_gaptr *gaptr, uint64_t offset, return 0; } - it = nghttp3_ksl_lower_bound_compar(&gaptr->gap, &q, - nghttp3_ksl_range_exclusive_compar); + it = nghttp3_ksl_lower_bound_search(&gaptr->gap, &q, + nghttp3_ksl_range_exclusive_search); + + assert(!nghttp3_ksl_it_end(&it)); + m = nghttp3_range_intersect(&q, (nghttp3_range *)nghttp3_ksl_it_key(&it)); return nghttp3_range_len(&m) == 0; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_http.c b/deps/ngtcp2/nghttp3/lib/nghttp3_http.c index 38092cfb7c322c..9a8f06ea11da9b 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_http.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_http.c @@ -69,11 +69,11 @@ static int64_t parse_uint(const uint8_t *s, size_t len) { } for (i = 0; i < len; ++i) { if ('0' <= s[i] && s[i] <= '9') { - if (n > INT64_MAX / 10) { + if (n > (int64_t)NGHTTP3_MAX_VARINT / 10) { return -1; } n *= 10; - if (n > INT64_MAX - (s[i] - '0')) { + if (n > (int64_t)NGHTTP3_MAX_VARINT - (s[i] - '0')) { return -1; } n += s[i] - '0'; @@ -124,17 +124,17 @@ static int is_ws(uint8_t c) { int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value, size_t valuelen) { nghttp3_pri pri = *dest; - sf_parser sfp; - sf_vec key; - sf_value val; + sfparse_parser sfp; + sfparse_vec key; + sfparse_value val; int rv; - sf_parser_init(&sfp, value, valuelen); + sfparse_parser_init(&sfp, value, valuelen); for (;;) { - rv = sf_parser_dict(&sfp, &key, &val); + rv = sfparse_parser_dict(&sfp, &key, &val); if (rv != 0) { - if (rv == SF_ERR_EOF) { + if (rv == SFPARSE_ERR_EOF) { break; } @@ -147,7 +147,7 @@ int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value, switch (key.base[0]) { case 'i': - if (val.type != SF_TYPE_BOOLEAN) { + if (val.type != SFPARSE_TYPE_BOOLEAN) { return NGHTTP3_ERR_INVALID_ARGUMENT; } @@ -155,7 +155,8 @@ int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value, break; case 'u': - if (val.type != SF_TYPE_INTEGER || val.integer < NGHTTP3_URGENCY_HIGH || + if (val.type != SFPARSE_TYPE_INTEGER || + val.integer < NGHTTP3_URGENCY_HIGH || NGHTTP3_URGENCY_LOW < val.integer) { return NGHTTP3_ERR_INVALID_ARGUMENT; } @@ -197,7 +198,7 @@ static char VALID_AUTHORITY_CHARS[] = { 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, - 1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, + 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 */, @@ -548,6 +549,9 @@ static int http_request_on_header(nghttp3_http_state *http, break; case NGHTTP3_QPACK_TOKEN_PRIORITY: if (!nghttp3_check_header_value(nv->value->base, nv->value->len)) { + http->flags &= ~NGHTTP3_HTTP_FLAG_PRIORITY; + http->flags |= NGHTTP3_HTTP_FLAG_BAD_PRIORITY; + return NGHTTP3_ERR_REMOVE_HTTP_HEADER; } @@ -991,7 +995,11 @@ int nghttp3_check_header_value(const uint8_t *value, size_t len) { case 0: return 1; case 1: - return !is_ws(*value); + if (is_ws(*value)) { + return 0; + } + + break; default: if (is_ws(*value) || is_ws(*(value + len - 1))) { return 0; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c b/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c index a3b5fbcb05f4f3..33dec06388a70a 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.c @@ -34,9 +34,9 @@ #include "nghttp3_mem.h" #include "nghttp3_range.h" -static nghttp3_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}}; +static nghttp3_ksl_blk null_blk; -nghttp3_objalloc_def(ksl_blk, nghttp3_ksl_blk, oplent); +nghttp3_objalloc_def(ksl_blk, nghttp3_ksl_blk, oplent) static size_t ksl_nodelen(size_t keylen) { assert(keylen >= sizeof(uint64_t)); @@ -59,7 +59,8 @@ static void ksl_node_set_key(nghttp3_ksl *ksl, nghttp3_ksl_node *node, } void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar, - size_t keylen, const nghttp3_mem *mem) { + nghttp3_ksl_search search, size_t keylen, + const nghttp3_mem *mem) { size_t nodelen = ksl_nodelen(keylen); nghttp3_objalloc_init(&ksl->blkalloc, @@ -68,6 +69,7 @@ void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar, ksl->head = NULL; ksl->front = ksl->back = NULL; ksl->compar = compar; + ksl->search = search; ksl->n = 0; ksl->keylen = keylen; ksl->nodelen = nodelen; @@ -274,20 +276,6 @@ static void ksl_insert_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i, ++blk->n; } -static size_t ksl_search(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, - const nghttp3_ksl_key *key, - nghttp3_ksl_compar compar) { - size_t i; - nghttp3_ksl_node *node; - - for (i = 0, node = (nghttp3_ksl_node *)(void *)blk->nodes; - i < blk->n && compar((nghttp3_ksl_key *)node->key, key); - ++i, node = (nghttp3_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen)) - ; - - return i; -} - int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it, const nghttp3_ksl_key *key, void *data) { nghttp3_ksl_blk *blk; @@ -312,7 +300,7 @@ int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it, blk = ksl->head; for (;;) { - i = ksl_search(ksl, blk, key, ksl->compar); + i = ksl->search(ksl, blk, key); if (blk->leaf) { if (i < blk->n && @@ -571,7 +559,7 @@ int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it, } for (;;) { - i = ksl_search(ksl, blk, key, ksl->compar); + i = ksl->search(ksl, blk, key); if (i == blk->n) { if (it) { @@ -642,12 +630,12 @@ int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it, nghttp3_ksl_it nghttp3_ksl_lower_bound(const nghttp3_ksl *ksl, const nghttp3_ksl_key *key) { - return nghttp3_ksl_lower_bound_compar(ksl, key, ksl->compar); + return nghttp3_ksl_lower_bound_search(ksl, key, ksl->search); } -nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(const nghttp3_ksl *ksl, +nghttp3_ksl_it nghttp3_ksl_lower_bound_search(const nghttp3_ksl *ksl, const nghttp3_ksl_key *key, - nghttp3_ksl_compar compar) { + nghttp3_ksl_search search) { nghttp3_ksl_blk *blk = ksl->head; nghttp3_ksl_it it; size_t i; @@ -658,7 +646,7 @@ nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(const nghttp3_ksl *ksl, } for (;;) { - i = ksl_search(ksl, blk, key, compar); + i = search(ksl, blk, key); if (blk->leaf) { if (i == blk->n && blk->next) { @@ -702,7 +690,7 @@ void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key, assert(ksl->head); for (;;) { - i = ksl_search(ksl, blk, old_key, ksl->compar); + i = ksl->search(ksl, blk, old_key); assert(i < blk->n); node = nghttp3_ksl_nth_node(ksl, blk, i); @@ -825,9 +813,50 @@ int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs, return a->begin < b->begin; } +nghttp3_ksl_search_def(range, nghttp3_ksl_range_compar) + +size_t nghttp3_ksl_range_search(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, + const nghttp3_ksl_key *key) { + return ksl_range_search(ksl, blk, key); +} + int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs, const nghttp3_ksl_key *rhs) { const nghttp3_range *a = lhs, *b = rhs; return a->begin < b->begin && !(nghttp3_max_uint64(a->begin, b->begin) < nghttp3_min_uint64(a->end, b->end)); } + +nghttp3_ksl_search_def(range_exclusive, nghttp3_ksl_range_exclusive_compar) + +size_t nghttp3_ksl_range_exclusive_search(const nghttp3_ksl *ksl, + nghttp3_ksl_blk *blk, + const nghttp3_ksl_key *key) { + return ksl_range_exclusive_search(ksl, blk, key); +} + +int nghttp3_ksl_uint64_less(const nghttp3_ksl_key *lhs, + const nghttp3_ksl_key *rhs) { + return *(uint64_t *)lhs < *(uint64_t *)rhs; +} + +nghttp3_ksl_search_def(uint64_less, nghttp3_ksl_uint64_less) + +size_t nghttp3_ksl_uint64_less_search(const nghttp3_ksl *ksl, + nghttp3_ksl_blk *blk, + const nghttp3_ksl_key *key) { + return ksl_uint64_less_search(ksl, blk, key); +} + +int nghttp3_ksl_int64_greater(const nghttp3_ksl_key *lhs, + const nghttp3_ksl_key *rhs) { + return *(int64_t *)lhs > *(int64_t *)rhs; +} + +nghttp3_ksl_search_def(int64_greater, nghttp3_ksl_int64_greater) + +size_t nghttp3_ksl_int64_greater_search(const nghttp3_ksl *ksl, + nghttp3_ksl_blk *blk, + const nghttp3_ksl_key *key) { + return ksl_int64_greater_search(ksl, blk, key); +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h b/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h index e15e227ce50fb0..be7469baa99c44 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_ksl.h @@ -104,7 +104,7 @@ struct nghttp3_ksl_blk { }; }; -nghttp3_objalloc_decl(ksl_blk, nghttp3_ksl_blk, oplent); +nghttp3_objalloc_decl(ksl_blk, nghttp3_ksl_blk, oplent) /* * nghttp3_ksl_compar is a function type which returns nonzero if key @@ -115,6 +115,35 @@ typedef int (*nghttp3_ksl_compar)(const nghttp3_ksl_key *lhs, typedef struct nghttp3_ksl nghttp3_ksl; +/* + * nghttp3_ksl_search is a function to search for the first element in + * |blk|->nodes which is not ordered before |key|. It returns the + * index of such element. It returns |blk|->n if there is no such + * element. + */ +typedef size_t (*nghttp3_ksl_search)(const nghttp3_ksl *ksl, + nghttp3_ksl_blk *blk, + const nghttp3_ksl_key *key); + +/* + * nghttp3_ksl_search_def is a macro to implement nghttp3_ksl_search + * with COMPAR which is supposed to be nghttp3_ksl_compar. + */ +#define nghttp3_ksl_search_def(NAME, COMPAR) \ + static size_t ksl_##NAME##_search(const nghttp3_ksl *ksl, \ + nghttp3_ksl_blk *blk, \ + const nghttp3_ksl_key *key) { \ + size_t i; \ + nghttp3_ksl_node *node; \ + \ + for (i = 0, node = (nghttp3_ksl_node *)(void *)blk->nodes; \ + i < blk->n && COMPAR((nghttp3_ksl_key *)node->key, key); ++i, \ + node = (nghttp3_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen)) \ + ; \ + \ + return i; \ + } + typedef struct nghttp3_ksl_it nghttp3_ksl_it; /* @@ -138,6 +167,7 @@ struct nghttp3_ksl { /* back points to the last leaf block. */ nghttp3_ksl_blk *back; nghttp3_ksl_compar compar; + nghttp3_ksl_search search; /* n is the number of elements stored. */ size_t n; /* keylen is the size of key */ @@ -149,11 +179,13 @@ struct nghttp3_ksl { /* * nghttp3_ksl_init initializes |ksl|. |compar| specifies compare - * function. |keylen| is the length of key and must be at least + * function. |search| is a search function which must use |compar|. + * |keylen| is the length of key and must be at least * sizeof(uint64_t). */ void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar, - size_t keylen, const nghttp3_mem *mem); + nghttp3_ksl_search search, size_t keylen, + const nghttp3_mem *mem); /* * nghttp3_ksl_free frees resources allocated for |ksl|. If |ksl| is @@ -218,12 +250,12 @@ nghttp3_ksl_it nghttp3_ksl_lower_bound(const nghttp3_ksl *ksl, const nghttp3_ksl_key *key); /* - * nghttp3_ksl_lower_bound_compar works like nghttp3_ksl_lower_bound, - * but it takes custom function |compar| to do lower bound search. + * nghttp3_ksl_lower_bound_search works like nghttp3_ksl_lower_bound, + * but it takes custom function |search| to do lower bound search. */ -nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(const nghttp3_ksl *ksl, +nghttp3_ksl_it nghttp3_ksl_lower_bound_search(const nghttp3_ksl *ksl, const nghttp3_ksl_key *key, - nghttp3_ksl_compar compar); + nghttp3_ksl_search search); /* * nghttp3_ksl_update_key replaces the key of nodes which has @@ -263,8 +295,11 @@ void nghttp3_ksl_clear(nghttp3_ksl *ksl); /* * nghttp3_ksl_nth_node returns the |n|th node under |blk|. */ -#define nghttp3_ksl_nth_node(KSL, BLK, N) \ - ((nghttp3_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N))) +static inline nghttp3_ksl_node *nghttp3_ksl_nth_node(const nghttp3_ksl *ksl, + const nghttp3_ksl_blk *blk, + size_t n) { + return (nghttp3_ksl_node *)(void *)(blk->nodes + ksl->nodelen * n); +} #ifndef WIN32 /* @@ -286,18 +321,21 @@ void nghttp3_ksl_it_init(nghttp3_ksl_it *it, const nghttp3_ksl *ksl, * |it| points to. It is undefined to call this function when * nghttp3_ksl_it_end(it) returns nonzero. */ -#define nghttp3_ksl_it_get(IT) \ - nghttp3_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->data +static inline void *nghttp3_ksl_it_get(const nghttp3_ksl_it *it) { + return nghttp3_ksl_nth_node(it->ksl, it->blk, it->i)->data; +} /* * nghttp3_ksl_it_next advances the iterator by one. It is undefined * if this function is called when nghttp3_ksl_it_end(it) returns * nonzero. */ -#define nghttp3_ksl_it_next(IT) \ - (++(IT)->i == (IT)->blk->n && (IT)->blk->next \ - ? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \ - : 0) +static inline void nghttp3_ksl_it_next(nghttp3_ksl_it *it) { + if (++it->i == it->blk->n && it->blk->next) { + it->blk = it->blk->next; + it->i = 0; + } +} /* * nghttp3_ksl_it_prev moves backward the iterator by one. It is @@ -310,8 +348,9 @@ void nghttp3_ksl_it_prev(nghttp3_ksl_it *it); * nghttp3_ksl_it_end returns nonzero if |it| points to the one beyond * the last node. */ -#define nghttp3_ksl_it_end(IT) \ - ((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL) +static inline int nghttp3_ksl_it_end(const nghttp3_ksl_it *it) { + return it->blk->n == it->i && it->blk->next == NULL; +} /* * nghttp3_ksl_it_begin returns nonzero if |it| points to the first @@ -325,27 +364,75 @@ int nghttp3_ksl_it_begin(const nghttp3_ksl_it *it); * It is undefined to call this function when nghttp3_ksl_it_end(it) * returns nonzero. */ -#define nghttp3_ksl_it_key(IT) \ - ((nghttp3_ksl_key *)nghttp3_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key) +static inline nghttp3_ksl_key *nghttp3_ksl_it_key(const nghttp3_ksl_it *it) { + return (nghttp3_ksl_key *)nghttp3_ksl_nth_node(it->ksl, it->blk, it->i)->key; +} /* * nghttp3_ksl_range_compar is an implementation of - * nghttp3_ksl_compar. lhs->ptr and rhs->ptr must point to - * nghttp3_range object and the function returns nonzero if (const - * nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range - * *)(rhs->ptr)->begin. + * nghttp3_ksl_compar. |lhs| and |rhs| must point to nghttp3_range + * object, and the function returns nonzero if ((const nghttp3_range + * *)lhs)->begin < ((const nghttp3_range *)rhs)->begin. */ int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs, const nghttp3_ksl_key *rhs); +/* + * nghttp3_ksl_range_search is an implementation of nghttp3_ksl_search + * that uses nghttp3_ksl_range_compar. + */ +size_t nghttp3_ksl_range_search(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, + const nghttp3_ksl_key *key); + /* * nghttp3_ksl_range_exclusive_compar is an implementation of - * nghttp3_ksl_compar. lhs->ptr and rhs->ptr must point to - * nghttp3_range object and the function returns nonzero if (const - * nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range - * *)(rhs->ptr)->begin and the 2 ranges do not intersect. + * nghttp3_ksl_compar. |lhs| and |rhs| must point to nghttp3_range + * object, and the function returns nonzero if ((const nghttp3_range + * *)lhs)->begin < ((const nghttp3_range *)rhs)->begin, and the 2 + * ranges do not intersect. */ int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs, const nghttp3_ksl_key *rhs); +/* + * nghttp3_ksl_range_exclusive_search is an implementation of + * nghttp3_ksl_search that uses nghttp3_ksl_range_exclusive_compar. + */ +size_t nghttp3_ksl_range_exclusive_search(const nghttp3_ksl *ksl, + nghttp3_ksl_blk *blk, + const nghttp3_ksl_key *key); + +/* + * nghttp3_ksl_uint64_less is an implementation of nghttp3_ksl_compar. + * |lhs| and |rhs| must point to uint64_t objects, and the function + * returns nonzero if *(uint64_t *)|lhs| < *(uint64_t *)|rhs|. + */ +int nghttp3_ksl_uint64_less(const nghttp3_ksl_key *lhs, + const nghttp3_ksl_key *rhs); + +/* + * nghttp3_ksl_uint64_less_search is an implementation of + * nghttp3_ksl_search that uses nghttp3_ksl_uint64_less. + */ +size_t nghttp3_ksl_uint64_less_search(const nghttp3_ksl *ksl, + nghttp3_ksl_blk *blk, + const nghttp3_ksl_key *key); + +/* + * nghttp3_ksl_int64_greater is an implementation of + * nghttp3_ksl_compar. |lhs| and |rhs| must point to int64_t objects, + * and the function returns nonzero if *(int64_t *)|lhs| > *(int64_t + * *)|rhs|. + */ +int nghttp3_ksl_int64_greater(const nghttp3_ksl_key *lhs, + const nghttp3_ksl_key *rhs); + +/* + * nghttp3_ksl_int64_greater_search is an implementation of + * nghttp3_ksl_search that uses nghttp3_ksl_int64_greater. + */ +size_t nghttp3_ksl_int64_greater_search(const nghttp3_ksl *ksl, + nghttp3_ksl_blk *blk, + const nghttp3_ksl_key *key); + #endif /* !defined(NGHTTP3_KSL_H) */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_macro.h b/deps/ngtcp2/nghttp3/lib/nghttp3_macro.h index a4e1dfea3cda00..ffe0ea70924327 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_macro.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_macro.h @@ -48,27 +48,27 @@ #define nghttp3_max_def(SUFFIX, T) \ static inline T nghttp3_max_##SUFFIX(T a, T b) { return a < b ? b : a; } -nghttp3_max_def(int8, int8_t); -nghttp3_max_def(int16, int16_t); -nghttp3_max_def(int32, int32_t); -nghttp3_max_def(int64, int64_t); -nghttp3_max_def(uint8, uint8_t); -nghttp3_max_def(uint16, uint16_t); -nghttp3_max_def(uint32, uint32_t); -nghttp3_max_def(uint64, uint64_t); -nghttp3_max_def(size, size_t); +nghttp3_max_def(int8, int8_t) +nghttp3_max_def(int16, int16_t) +nghttp3_max_def(int32, int32_t) +nghttp3_max_def(int64, int64_t) +nghttp3_max_def(uint8, uint8_t) +nghttp3_max_def(uint16, uint16_t) +nghttp3_max_def(uint32, uint32_t) +nghttp3_max_def(uint64, uint64_t) +nghttp3_max_def(size, size_t) #define nghttp3_min_def(SUFFIX, T) \ static inline T nghttp3_min_##SUFFIX(T a, T b) { return a < b ? a : b; } -nghttp3_min_def(int8, int8_t); -nghttp3_min_def(int16, int16_t); -nghttp3_min_def(int32, int32_t); -nghttp3_min_def(int64, int64_t); -nghttp3_min_def(uint8, uint8_t); -nghttp3_min_def(uint16, uint16_t); -nghttp3_min_def(uint32, uint32_t); -nghttp3_min_def(uint64, uint64_t); -nghttp3_min_def(size, size_t); +nghttp3_min_def(int8, int8_t) +nghttp3_min_def(int16, int16_t) +nghttp3_min_def(int32, int32_t) +nghttp3_min_def(int64, int64_t) +nghttp3_min_def(uint8, uint8_t) +nghttp3_min_def(uint16, uint16_t) +nghttp3_min_def(uint32, uint32_t) +nghttp3_min_def(uint64, uint64_t) +nghttp3_min_def(size, size_t) #endif /* !defined(NGHTTP3_MACRO_H) */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_map.c b/deps/ngtcp2/nghttp3/lib/nghttp3_map.c index cc5e42a2caf63f..f3165c81e61153 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_map.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_map.c @@ -32,12 +32,13 @@ #include "nghttp3_conv.h" -#define NGHTTP3_INITIAL_TABLE_LENBITS 4 +#define NGHTTP3_INITIAL_HASHBITS 4 -void nghttp3_map_init(nghttp3_map *map, const nghttp3_mem *mem) { +void nghttp3_map_init(nghttp3_map *map, uint64_t seed, const nghttp3_mem *mem) { map->mem = mem; map->hashbits = 0; map->table = NULL; + map->seed = seed; map->size = 0; } @@ -78,8 +79,14 @@ int nghttp3_map_each(const nghttp3_map *map, int (*func)(void *data, void *ptr), return 0; } -static size_t hash(nghttp3_map_key_type key, size_t bits) { - return (size_t)((key * 11400714819323198485llu) >> (64 - bits)); +static size_t map_hash(const nghttp3_map *map, nghttp3_map_key_type key) { + /* hasher from + https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs + We do not perform finalization here because we use top bits + anyway. */ + key += map->seed; + key *= 0xf1357aea2e62a9c5ull; + return (size_t)((key * 11400714819323198485llu) >> (64 - map->hashbits)); } static void map_bucket_swap(nghttp3_map_bucket *a, nghttp3_map_bucket *b) { @@ -110,24 +117,28 @@ void nghttp3_map_print_distance(const nghttp3_map *map) { continue; } - idx = hash(bkt->key, map->hashbits); + idx = map_hash(map, bkt->key); fprintf(stderr, "@%zu hash=%zu key=%" PRIu64 " base=%zu distance=%u\n", i, - hash(bkt->key, map->hashbits), bkt->key, idx, bkt->psl); + map_hash(map, bkt->key), bkt->key, idx, bkt->psl); } } #endif /* !defined(WIN32) */ -static int insert(nghttp3_map_bucket *table, size_t hashbits, - nghttp3_map_key_type key, void *data) { - size_t idx = hash(key, hashbits); - nghttp3_map_bucket b = {0, key, data}, *bkt; - size_t mask = (1u << hashbits) - 1; +static int map_insert(nghttp3_map *map, nghttp3_map_key_type key, void *data) { + size_t idx = map_hash(map, key); + nghttp3_map_bucket b = { + .key = key, + .data = data, + }; + nghttp3_map_bucket *bkt; + size_t mask = (1u << map->hashbits) - 1; for (;;) { - bkt = &table[idx]; + bkt = &map->table[idx]; if (bkt->data == NULL) { *bkt = b; + ++map->size; return 0; } @@ -148,15 +159,19 @@ static int insert(nghttp3_map_bucket *table, size_t hashbits, static int map_resize(nghttp3_map *map, size_t new_hashbits) { size_t i; - nghttp3_map_bucket *new_table; nghttp3_map_bucket *bkt; size_t tablelen; int rv; + nghttp3_map new_map = { + .table = nghttp3_mem_calloc(map->mem, 1u << new_hashbits, + sizeof(nghttp3_map_bucket)), + .mem = map->mem, + .seed = map->seed, + .hashbits = new_hashbits, + }; (void)rv; - new_table = nghttp3_mem_calloc(map->mem, 1u << new_hashbits, - sizeof(nghttp3_map_bucket)); - if (new_table == NULL) { + if (new_map.table == NULL) { return NGHTTP3_ERR_NOMEM; } @@ -169,15 +184,15 @@ static int map_resize(nghttp3_map *map, size_t new_hashbits) { continue; } - rv = insert(new_table, new_hashbits, bkt->key, bkt->data); + rv = map_insert(&new_map, bkt->key, bkt->data); assert(0 == rv); } } nghttp3_mem_free(map->mem, map->table); + map->table = new_map.table; map->hashbits = new_hashbits; - map->table = new_table; return 0; } @@ -187,30 +202,28 @@ int nghttp3_map_insert(nghttp3_map *map, nghttp3_map_key_type key, void *data) { assert(data); - /* Load factor is 0.75 */ + /* Load factor is 7/8 */ /* Under the very initial condition, that is map->size == 0 and - map->hashbits == 0, 4 > 3 still holds nicely. */ - if ((map->size + 1) * 4 > (1u << map->hashbits) * 3) { + map->hashbits == 0, 8 > 7 still holds nicely. */ + if ((map->size + 1) * 8 > (1u << map->hashbits) * 7) { if (map->hashbits) { rv = map_resize(map, map->hashbits + 1); if (rv != 0) { return rv; } } else { - rv = map_resize(map, NGHTTP3_INITIAL_TABLE_LENBITS); + rv = map_resize(map, NGHTTP3_INITIAL_HASHBITS); if (rv != 0) { return rv; } } } - rv = insert(map->table, map->hashbits, key, data); + rv = map_insert(map, key, data); if (rv != 0) { return rv; } - ++map->size; - return 0; } @@ -224,7 +237,7 @@ void *nghttp3_map_find(const nghttp3_map *map, nghttp3_map_key_type key) { return NULL; } - idx = hash(key, map->hashbits); + idx = map_hash(map, key); mask = (1u << map->hashbits) - 1; for (;;) { @@ -253,7 +266,7 @@ int nghttp3_map_remove(nghttp3_map *map, nghttp3_map_key_type key) { return NGHTTP3_ERR_INVALID_ARGUMENT; } - idx = hash(key, map->hashbits); + idx = map_hash(map, key); mask = (1u << map->hashbits) - 1; for (;;) { diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_map.h b/deps/ngtcp2/nghttp3/lib/nghttp3_map.h index 2b1a6ecab5cf4c..7496b486e17885 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_map.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_map.h @@ -48,6 +48,7 @@ typedef struct nghttp3_map_bucket { typedef struct nghttp3_map { nghttp3_map_bucket *table; const nghttp3_mem *mem; + uint64_t seed; size_t size; size_t hashbits; } nghttp3_map; @@ -55,7 +56,7 @@ typedef struct nghttp3_map { /* * nghttp3_map_init initializes the map |map|. */ -void nghttp3_map_init(nghttp3_map *map, const nghttp3_mem *mem); +void nghttp3_map_init(nghttp3_map *map, uint64_t seed, const nghttp3_mem *mem); /* * nghttp3_map_free deallocates any resources allocated for |map|. diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_pq.c b/deps/ngtcp2/nghttp3/lib/nghttp3_pq.c index feefcd6fc717c3..e35bcac4e43b8f 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_pq.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_pq.c @@ -164,20 +164,4 @@ int nghttp3_pq_empty(const nghttp3_pq *pq) { return pq->length == 0; } size_t nghttp3_pq_size(const nghttp3_pq *pq) { return pq->length; } -int nghttp3_pq_each(const nghttp3_pq *pq, nghttp3_pq_item_cb fun, void *arg) { - size_t i; - - if (pq->length == 0) { - return 0; - } - - for (i = 0; i < pq->length; ++i) { - if ((*fun)(pq->q[i], arg)) { - return 1; - } - } - - return 0; -} - void nghttp3_pq_clear(nghttp3_pq *pq) { pq->length = 0; } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_pq.h b/deps/ngtcp2/nghttp3/lib/nghttp3_pq.h index 3813b529473075..c4e47b16708b53 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_pq.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_pq.h @@ -112,17 +112,6 @@ int nghttp3_pq_empty(const nghttp3_pq *pq); */ size_t nghttp3_pq_size(const nghttp3_pq *pq); -typedef int (*nghttp3_pq_item_cb)(nghttp3_pq_entry *item, void *arg); - -/* - * nghttp3_pq_each applies |fun| to each item in |pq|. The |arg| is - * passed as arg parameter to callback function. This function must - * not change the ordering key. If the return value from callback is - * nonzero, this function returns 1 immediately without iterating - * remaining items. Otherwise this function returns 0. - */ -int nghttp3_pq_each(const nghttp3_pq *pq, nghttp3_pq_item_cb fun, void *arg); - /* * nghttp3_pq_remove removes |item| from |pq|. |pq| must contain * |item| otherwise the behavior is undefined. diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c index a1c7e7487c1a34..d2bac4830042ef 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c @@ -41,7 +41,12 @@ #define NGHTTP3_QPACK_MAX_QPACK_STREAMS 2000 /* Make scalar initialization form of nghttp3_qpack_static_entry */ -#define MAKE_STATIC_ENT(I, T, H) {I, T, H} +#define MAKE_STATIC_ENT(I, T, H) \ + { \ + .absidx = I, \ + .token = T, \ + .hash = H, \ + } /* Generated by mkstatichdtbl.py */ static nghttp3_qpack_static_entry token_stable[] = { @@ -166,9 +171,19 @@ static nghttp3_qpack_static_entry token_stable[] = { /* Make scalar initialization form of nghttp3_qpack_static_entry */ #define MAKE_STATIC_HD(N, V, T) \ { \ - {NULL, (uint8_t *)(N), sizeof((N)) - 1, -1}, \ - {NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, \ - T, \ + .name = \ + { \ + .base = (uint8_t *)(N), \ + .len = sizeof((N)) - 1, \ + .ref = -1, \ + }, \ + .value = \ + { \ + .base = (uint8_t *)(V), \ + .len = sizeof((V)) - 1, \ + .ref = -1, \ + }, \ + .token = T, \ } static nghttp3_qpack_static_header stable[] = { @@ -828,29 +843,12 @@ static void encoder_qpack_map_find(nghttp3_qpack_encoder *encoder, * ctx->max_dtable_capacity and it is initialized to 0. * |hard_max_dtable_capacity| is the upper bound of * ctx->max_dtable_capacity. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP3_ERR_NOMEM - * Out of memory. */ -static int qpack_context_init(nghttp3_qpack_context *ctx, - size_t hard_max_dtable_capacity, - size_t max_blocked_streams, - const nghttp3_mem *mem) { - int rv; - size_t len = 4096 / NGHTTP3_QPACK_ENTRY_OVERHEAD; - size_t len2; - - for (len2 = 1; len2 < len; len2 <<= 1) - ; - - rv = nghttp3_ringbuf_init(&ctx->dtable, len2, sizeof(nghttp3_qpack_entry *), - mem); - if (rv != 0) { - return rv; - } +static void qpack_context_init(nghttp3_qpack_context *ctx, + size_t hard_max_dtable_capacity, + size_t max_blocked_streams, + const nghttp3_mem *mem) { + nghttp3_ringbuf_init(&ctx->dtable, 0, sizeof(nghttp3_qpack_entry *), mem); ctx->mem = mem; ctx->dtable_size = 0; @@ -860,8 +858,6 @@ static int qpack_context_init(nghttp3_qpack_context *ctx, ctx->max_blocked_streams = max_blocked_streams; ctx->next_absidx = 0; ctx->bad = 0; - - return 0; } static void qpack_context_free(nghttp3_qpack_context *ctx) { @@ -898,19 +894,17 @@ static int max_cnt_greater(const nghttp3_ksl_key *lhs, return a->max_cnt > b->max_cnt || (a->max_cnt == b->max_cnt && a->id < b->id); } -int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder, - size_t hard_max_dtable_capacity, - const nghttp3_mem *mem) { - int rv; +nghttp3_ksl_search_def(max_cnt_greater, max_cnt_greater) - rv = qpack_context_init(&encoder->ctx, hard_max_dtable_capacity, 0, mem); - if (rv != 0) { - return rv; - } +void nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder, + size_t hard_max_dtable_capacity, uint64_t seed, + const nghttp3_mem *mem) { + qpack_context_init(&encoder->ctx, hard_max_dtable_capacity, 0, mem); - nghttp3_map_init(&encoder->streams, mem); + nghttp3_map_init(&encoder->streams, seed, mem); nghttp3_ksl_init(&encoder->blocked_streams, max_cnt_greater, + ksl_max_cnt_greater_search, sizeof(nghttp3_blocked_streams_key), mem); qpack_map_init(&encoder->dtable_map); @@ -925,8 +919,6 @@ int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder, encoder->flags = NGHTTP3_QPACK_ENCODER_FLAG_NONE; nghttp3_qpack_read_state_reset(&encoder->rstate); - - return 0; } static int map_stream_free(void *data, void *ptr) { @@ -1149,6 +1141,9 @@ int nghttp3_qpack_encoder_encode(nghttp3_qpack_encoder *encoder, int blocked_stream; nghttp3_qpack_stream *stream; + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); + if (encoder->ctx.bad) { return NGHTTP3_ERR_QPACK_FATAL; } @@ -1444,7 +1439,14 @@ int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder, uint32_t hash = 0; int32_t token; nghttp3_qpack_indexing_mode indexing_mode; - nghttp3_qpack_lookup_result sres = {-1, 0, -1}, dres = {-1, 0, -1}; + nghttp3_qpack_lookup_result sres = { + .index = -1, + .pb_index = -1, + }; + nghttp3_qpack_lookup_result dres = { + .index = -1, + .pb_index = -1, + }; nghttp3_qpack_entry *new_ent = NULL; int static_entry; int just_index = 0; @@ -1608,8 +1610,10 @@ int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder, nghttp3_qpack_lookup_result nghttp3_qpack_lookup_stable(const nghttp3_nv *nv, int32_t token, nghttp3_qpack_indexing_mode indexing_mode) { - nghttp3_qpack_lookup_result res = {(nghttp3_ssize)token_stable[token].absidx, - 0, -1}; + nghttp3_qpack_lookup_result res = { + .index = (nghttp3_ssize)token_stable[token].absidx, + .pb_index = -1, + }; nghttp3_qpack_static_entry *ent; nghttp3_qpack_static_header *hdr; size_t i; @@ -1639,7 +1643,10 @@ nghttp3_qpack_lookup_result nghttp3_qpack_encoder_lookup_dtable( nghttp3_qpack_encoder *encoder, const nghttp3_nv *nv, int32_t token, uint32_t hash, nghttp3_qpack_indexing_mode indexing_mode, uint64_t krcnt, int allow_blocking) { - nghttp3_qpack_lookup_result res = {-1, 0, -1}; + nghttp3_qpack_lookup_result res = { + .index = -1, + .pb_index = -1, + }; int exact_match = 0; nghttp3_qpack_entry *match, *pb_match; @@ -1694,7 +1701,6 @@ static int ref_max_cnt_greater(const nghttp3_pq_entry *lhsx, int nghttp3_qpack_stream_new(nghttp3_qpack_stream **pstream, int64_t stream_id, const nghttp3_mem *mem) { - int rv; nghttp3_qpack_stream *stream; stream = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream)); @@ -1702,12 +1708,8 @@ int nghttp3_qpack_stream_new(nghttp3_qpack_stream **pstream, int64_t stream_id, return NGHTTP3_ERR_NOMEM; } - rv = nghttp3_ringbuf_init(&stream->refs, 4, - sizeof(nghttp3_qpack_header_block_ref *), mem); - if (rv != 0) { - nghttp3_mem_free(mem, stream); - return rv; - } + nghttp3_ringbuf_init(&stream->refs, 0, + sizeof(nghttp3_qpack_header_block_ref *), mem); nghttp3_pq_init(&stream->max_cnts, ref_max_cnt_greater, mem); @@ -1759,17 +1761,23 @@ int nghttp3_qpack_stream_add_ref(nghttp3_qpack_stream *stream, int rv; if (nghttp3_ringbuf_full(&stream->refs)) { - rv = nghttp3_ringbuf_reserve(&stream->refs, - nghttp3_ringbuf_len(&stream->refs) * 2); + rv = nghttp3_ringbuf_reserve( + &stream->refs, + nghttp3_max_size(4, nghttp3_ringbuf_len(&stream->refs) * 2)); if (rv != 0) { return rv; } } + rv = nghttp3_pq_push(&stream->max_cnts, &ref->max_cnts_pe); + if (rv != 0) { + return rv; + } + dest = nghttp3_ringbuf_push_back(&stream->refs); *dest = ref; - return nghttp3_pq_push(&stream->max_cnts, &ref->max_cnts_pe); + return 0; } void nghttp3_qpack_stream_pop_ref(nghttp3_qpack_stream *stream) { @@ -1834,7 +1842,7 @@ static int qpack_encoder_write_indexed_name(nghttp3_qpack_encoder *encoder, int h = 0; hlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen); - if (hlen * 4 < nv->valuelen * 3) { + if (hlen < nv->valuelen) { h = 1; len += nghttp3_qpack_put_varint_len(hlen, 7) + hlen; } else { @@ -1925,7 +1933,7 @@ static int qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder, int nh = 0, vh = 0; nhlen = nghttp3_qpack_huffman_encode_count(nv->name, nv->namelen); - if (nhlen * 4 < nv->namelen * 3) { + if (nhlen < nv->namelen) { nh = 1; len = nghttp3_qpack_put_varint_len(nhlen, prefix) + nhlen; } else { @@ -1933,7 +1941,7 @@ static int qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder, } vhlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen); - if (vhlen * 4 < nv->valuelen * 3) { + if (vhlen < nv->valuelen) { vh = 1; len += nghttp3_qpack_put_varint_len(vhlen, 7) + vhlen; } else { @@ -2083,8 +2091,9 @@ int nghttp3_qpack_context_dtable_add(nghttp3_qpack_context *ctx, hash); if (nghttp3_ringbuf_full(&ctx->dtable)) { - rv = nghttp3_ringbuf_reserve(&ctx->dtable, - nghttp3_ringbuf_len(&ctx->dtable) * 2); + rv = nghttp3_ringbuf_reserve( + &ctx->dtable, + nghttp3_max_size(128, nghttp3_ringbuf_len(&ctx->dtable) * 2)); if (rv != 0) { goto fail; } @@ -2259,10 +2268,11 @@ void nghttp3_qpack_entry_free(nghttp3_qpack_entry *ent) { int nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder *encoder, nghttp3_qpack_stream *stream) { nghttp3_blocked_streams_key bsk = { - nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts), - nghttp3_qpack_header_block_ref, max_cnts_pe) - ->max_cnt, - (uint64_t)stream->stream_id}; + .max_cnt = nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts), + nghttp3_qpack_header_block_ref, max_cnts_pe) + ->max_cnt, + .id = (uint64_t)stream->stream_id, + }; return nghttp3_ksl_insert(&encoder->blocked_streams, NULL, &bsk, stream); } @@ -2270,10 +2280,11 @@ int nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder *encoder, void nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder *encoder, nghttp3_qpack_stream *stream) { nghttp3_blocked_streams_key bsk = { - nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts), - nghttp3_qpack_header_block_ref, max_cnts_pe) - ->max_cnt, - (uint64_t)stream->stream_id}; + .max_cnt = nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts), + nghttp3_qpack_header_block_ref, max_cnts_pe) + ->max_cnt, + .id = (uint64_t)stream->stream_id, + }; nghttp3_ksl_it it; /* This is purely debugging purpose only */ @@ -2287,7 +2298,9 @@ void nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder *encoder, void nghttp3_qpack_encoder_unblock(nghttp3_qpack_encoder *encoder, uint64_t max_cnt) { - nghttp3_blocked_streams_key bsk = {max_cnt, 0}; + nghttp3_blocked_streams_key bsk = { + .max_cnt = max_cnt, + }; nghttp3_ksl_it it; it = nghttp3_ksl_lower_bound(&encoder->blocked_streams, &bsk); @@ -2667,17 +2680,12 @@ void nghttp3_qpack_read_state_reset(nghttp3_qpack_read_state *rstate) { rstate->huffman_encoded = 0; } -int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder, - size_t hard_max_dtable_capacity, - size_t max_blocked_streams, - const nghttp3_mem *mem) { - int rv; - - rv = qpack_context_init(&decoder->ctx, hard_max_dtable_capacity, - max_blocked_streams, mem); - if (rv != 0) { - return rv; - } +void nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder, + size_t hard_max_dtable_capacity, + size_t max_blocked_streams, + const nghttp3_mem *mem) { + qpack_context_init(&decoder->ctx, hard_max_dtable_capacity, + max_blocked_streams, mem); decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE; decoder->opcode = 0; @@ -2687,8 +2695,6 @@ int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder, nghttp3_qpack_read_state_reset(&decoder->rstate); nghttp3_buf_init(&decoder->dbuf); - - return 0; } void nghttp3_qpack_decoder_free(nghttp3_qpack_decoder *decoder) { @@ -3171,6 +3177,7 @@ int nghttp3_qpack_decoder_dtable_static_add(nghttp3_qpack_decoder *decoder) { rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0); nghttp3_rcbuf_decref(qnv.value); + decoder->rstate.value = NULL; return rv; } @@ -3197,6 +3204,7 @@ int nghttp3_qpack_decoder_dtable_dynamic_add(nghttp3_qpack_decoder *decoder) { rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0); nghttp3_rcbuf_decref(qnv.value); + decoder->rstate.value = NULL; nghttp3_rcbuf_decref(qnv.name); return rv; @@ -3250,7 +3258,9 @@ int nghttp3_qpack_decoder_dtable_literal_add(nghttp3_qpack_decoder *decoder) { rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0); nghttp3_rcbuf_decref(qnv.value); + decoder->rstate.value = NULL; nghttp3_rcbuf_decref(qnv.name); + decoder->rstate.name = NULL; return rv; } @@ -3818,6 +3828,9 @@ int nghttp3_qpack_decoder_cancel_stream(nghttp3_qpack_decoder *decoder, uint8_t *p; int rv; + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); + if (qpack_decoder_dbuf_overflow(decoder)) { return NGHTTP3_ERR_QPACK_FATAL; } @@ -4059,10 +4072,9 @@ void nghttp3_qpack_decoder_emit_literal(nghttp3_qpack_decoder *decoder, sctx->rstate.value = NULL; } -int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder, - size_t hard_max_dtable_capacity, - const nghttp3_mem *mem) { - int rv; +int nghttp3_qpack_encoder_new2(nghttp3_qpack_encoder **pencoder, + size_t hard_max_dtable_capacity, uint64_t seed, + const nghttp3_mem *mem) { nghttp3_qpack_encoder *p; p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_encoder)); @@ -4070,16 +4082,19 @@ int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder, return NGHTTP3_ERR_NOMEM; } - rv = nghttp3_qpack_encoder_init(p, hard_max_dtable_capacity, mem); - if (rv != 0) { - return rv; - } + nghttp3_qpack_encoder_init(p, hard_max_dtable_capacity, seed, mem); *pencoder = p; return 0; } +int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder, + size_t hard_max_dtable_capacity, + const nghttp3_mem *mem) { + return nghttp3_qpack_encoder_new2(pencoder, hard_max_dtable_capacity, 0, mem); +} + void nghttp3_qpack_encoder_del(nghttp3_qpack_encoder *encoder) { const nghttp3_mem *mem; @@ -4098,6 +4113,9 @@ int nghttp3_qpack_stream_context_new(nghttp3_qpack_stream_context **psctx, const nghttp3_mem *mem) { nghttp3_qpack_stream_context *p; + assert(stream_id >= 0); + assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT); + p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream_context)); if (p == NULL) { return NGHTTP3_ERR_NOMEM; @@ -4127,7 +4145,6 @@ int nghttp3_qpack_decoder_new(nghttp3_qpack_decoder **pdecoder, size_t hard_max_dtable_capacity, size_t max_blocked_streams, const nghttp3_mem *mem) { - int rv; nghttp3_qpack_decoder *p; p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_decoder)); @@ -4135,11 +4152,8 @@ int nghttp3_qpack_decoder_new(nghttp3_qpack_decoder **pdecoder, return NGHTTP3_ERR_NOMEM; } - rv = nghttp3_qpack_decoder_init(p, hard_max_dtable_capacity, - max_blocked_streams, mem); - if (rv != 0) { - return rv; - } + nghttp3_qpack_decoder_init(p, hard_max_dtable_capacity, max_blocked_streams, + mem); *pdecoder = p; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.h b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.h index d2bb8a3581135b..77d264a533fba4 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.h @@ -269,17 +269,12 @@ struct nghttp3_qpack_encoder { /* * nghttp3_qpack_encoder_init initializes |encoder|. * |hard_max_dtable_capacity| is the upper bound of the dynamic table - * capacity. |mem| is a memory allocator. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP3_ERR_NOMEM - * Out of memory. + * capacity. |seed| is used to initialize nghttp3_map. |mem| is a + * memory allocator. */ -int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder, - size_t hard_max_dtable_capacity, - const nghttp3_mem *mem); +void nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder, + size_t hard_max_dtable_capacity, uint64_t seed, + const nghttp3_mem *mem); /* * nghttp3_qpack_encoder_free frees memory allocated for |encoder|. @@ -800,17 +795,11 @@ struct nghttp3_qpack_decoder { * |hard_max_dtable_capacity| is the upper bound of the dynamic table * capacity. |max_blocked_streams| is the maximum number of stream * which can be blocked. |mem| is a memory allocator. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * NGHTTP3_ERR_NOMEM - * Out of memory. */ -int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder, - size_t hard_max_dtable_capacity, - size_t max_blocked_streams, - const nghttp3_mem *mem); +void nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder, + size_t hard_max_dtable_capacity, + size_t max_blocked_streams, + const nghttp3_mem *mem); /* * nghttp3_qpack_decoder_free frees memory allocated for |decoder|. diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c index 3398f3f5080e60..dbc9a764e7bf26 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c @@ -88,7 +88,9 @@ nghttp3_qpack_huffman_decode(nghttp3_qpack_huffman_decode_context *ctx, int fin) { uint8_t *p = dest; const uint8_t *end = src + srclen; - nghttp3_qpack_huffman_decode_node node = {ctx->fstate, 0}; + nghttp3_qpack_huffman_decode_node node = { + .fstate = ctx->fstate, + }; const nghttp3_qpack_huffman_decode_node *t = &node; uint8_t c; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_range.c b/deps/ngtcp2/nghttp3/lib/nghttp3_range.c index af810a2c5929db..b5f95bb83fc852 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_range.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_range.c @@ -33,7 +33,7 @@ void nghttp3_range_init(nghttp3_range *r, uint64_t begin, uint64_t end) { nghttp3_range nghttp3_range_intersect(const nghttp3_range *a, const nghttp3_range *b) { - nghttp3_range r = {0, 0}; + nghttp3_range r = {0}; uint64_t begin = nghttp3_max_uint64(a->begin, b->begin); uint64_t end = nghttp3_min_uint64(a->end, b->end); diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c b/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c index 7d3ab39bf82a7f..ccd1d3e99ab55e 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c @@ -33,18 +33,21 @@ #include "nghttp3_macro.h" +#ifndef NDEBUG static int ispow2(size_t n) { -#if defined(_MSC_VER) && !defined(__clang__) && \ - (defined(_M_ARM) || (defined(_M_ARM64) && _MSC_VER < 1941)) +# if defined(DISABLE_POPCNT) || \ + (defined(_MSC_VER) && !defined(__clang__) && \ + (defined(_M_ARM) || (defined(_M_ARM64) && _MSC_VER < 1941))) return n && !(n & (n - 1)); -#elif defined(WIN32) +# elif defined(WIN32) return 1 == __popcnt((unsigned int)n); -#else /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \ - (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */ +# else /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \ + (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */ return 1 == __builtin_popcount((unsigned int)n); -#endif /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \ - (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */ +# endif /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \ + (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */ } +#endif /* !defined(NDEBUG) */ int nghttp3_ringbuf_init(nghttp3_ringbuf *rb, size_t nmemb, size_t size, const nghttp3_mem *mem) { diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.h b/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.h index b154290a51d5a5..691c40b93d61e0 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.h @@ -103,7 +103,9 @@ void nghttp3_ringbuf_resize(nghttp3_ringbuf *rb, size_t len); void *nghttp3_ringbuf_get(nghttp3_ringbuf *rb, size_t offset); /* nghttp3_ringbuf_len returns the number of elements stored. */ -#define nghttp3_ringbuf_len(RB) ((RB)->len) +static inline size_t nghttp3_ringbuf_len(const nghttp3_ringbuf *rb) { + return rb->len; +} /* nghttp3_ringbuf_full returns nonzero if |rb| is full. */ int nghttp3_ringbuf_full(nghttp3_ringbuf *rb); diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_settings.c b/deps/ngtcp2/nghttp3/lib/nghttp3_settings.c new file mode 100644 index 00000000000000..2b7cd2892b3cc9 --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_settings.c @@ -0,0 +1,95 @@ +/* + * nghttp3 + * + * Copyright (c) 2025 nghttp3 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 "nghttp3_settings.h" + +#include +#include + +#include "nghttp3_conv.h" +#include "nghttp3_unreachable.h" + +/* NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY is the upper bound of the + dynamic table capacity that QPACK encoder is willing to use. */ +#define NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY 4096 + +void nghttp3_settings_default_versioned(int settings_version, + nghttp3_settings *settings) { + size_t len = nghttp3_settingslen_version(settings_version); + + memset(settings, 0, len); + + switch (settings_version) { + case NGHTTP3_SETTINGS_VERSION: + case NGHTTP3_SETTINGS_V1: + settings->max_field_section_size = NGHTTP3_VARINT_MAX; + settings->qpack_encoder_max_dtable_capacity = + NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY; + + break; + } +} + +static void settings_copy(nghttp3_settings *dest, const nghttp3_settings *src, + int settings_version) { + assert(settings_version != NGHTTP3_SETTINGS_VERSION); + + memcpy(dest, src, nghttp3_settingslen_version(settings_version)); +} + +const nghttp3_settings * +nghttp3_settings_convert_to_latest(nghttp3_settings *dest, int settings_version, + const nghttp3_settings *src) { + if (settings_version == NGHTTP3_SETTINGS_VERSION) { + return src; + } + + nghttp3_settings_default(dest); + + settings_copy(dest, src, settings_version); + + return dest; +} + +void nghttp3_settings_convert_to_old(int settings_version, + nghttp3_settings *dest, + const nghttp3_settings *src) { + assert(settings_version != NGHTTP3_SETTINGS_VERSION); + + settings_copy(dest, src, settings_version); +} + +size_t nghttp3_settingslen_version(int settings_version) { + nghttp3_settings settings; + + switch (settings_version) { + case NGHTTP3_SETTINGS_VERSION: + return sizeof(settings); + case NGHTTP3_SETTINGS_V1: + return offsetof(nghttp3_settings, h3_datagram) + + sizeof(settings.h3_datagram); + default: + nghttp3_unreachable(); + } +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_settings.h b/deps/ngtcp2/nghttp3/lib/nghttp3_settings.h new file mode 100644 index 00000000000000..0632aafc489ee5 --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_settings.h @@ -0,0 +1,74 @@ +/* + * nghttp3 + * + * Copyright (c) 2025 nghttp3 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 NGHTTP3_SETTINGS_H +#define NGHTTP3_SETTINGS_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* defined(HAVE_CONFIG_H) */ + +#include + +/* + * nghttp3_settings_convert_to_latest converts |src| of version + * |settings_version| to the latest version NGHTTP3_SETTINGS_VERSION. + * + * |dest| must point to the latest version. |src| may be the older + * version, and if so, it may have fewer fields. Accessing those + * fields causes undefined behavior. + * + * If |settings_version| == NGHTTP3_SETTINGS_VERSION, no conversion is + * made, and |src| is returned. Otherwise, first |dest| is + * initialized via nghttp3_settings_default, and then all valid fields + * in |src| are copied into |dest|. Finally, |dest| is returned. + */ +const nghttp3_settings * +nghttp3_settings_convert_to_latest(nghttp3_settings *dest, int settings_version, + const nghttp3_settings *src); + +/* + * nghttp3_settings_convert_to_old converts |src| of the latest + * version to |dest| of version |settings_version|. + * + * |settings_version| must not be the latest version + * NGHTTP3_SETTINGS_VERSION. + * + * |dest| points to the older version, and it may have fewer fields. + * Accessing those fields causes undefined behavior. + * + * This function copies all valid fields in version |settings_version| + * from |src| to |dest|. + */ +void nghttp3_settings_convert_to_old(int settings_version, + nghttp3_settings *dest, + const nghttp3_settings *src); + +/* + * nghttp3_settingslen_version returns the effective length of + * nghttp3_settings at the version |settings_version|. + */ +size_t nghttp3_settingslen_version(int settings_version); + +#endif /* !defined(NGHTTP3_SETTINGS_H) */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c index 328cddd488fd6f..d6f8fac3c528bb 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c @@ -44,7 +44,7 @@ /* NGHTTP3_MIN_RBLEN is the minimum length of nghttp3_ringbuf */ #define NGHTTP3_MIN_RBLEN 4 -nghttp3_objalloc_def(stream, nghttp3_stream, oplent); +nghttp3_objalloc_def(stream, nghttp3_stream, oplent) int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, const nghttp3_stream_callbacks *callbacks, @@ -57,10 +57,19 @@ int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, return NGHTTP3_ERR_NOMEM; } - memset(stream, 0, sizeof(*stream)); - - stream->out_chunk_objalloc = out_chunk_objalloc; - stream->stream_objalloc = stream_objalloc; + *stream = (nghttp3_stream){ + .out_chunk_objalloc = out_chunk_objalloc, + .stream_objalloc = stream_objalloc, + .qpack_blocked_pe.index = NGHTTP3_PQ_BAD_INDEX, + .mem = mem, + .rx = + { + .http.status_code = -1, + .http.content_length = -1, + .http.pri.urgency = NGHTTP3_DEFAULT_URGENCY, + }, + .error_code = NGHTTP3_H3_NO_ERROR, + }; nghttp3_tnode_init(&stream->node, stream_id); @@ -71,13 +80,6 @@ int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, nghttp3_qpack_stream_context_init(&stream->qpack_sctx, stream_id, mem); - stream->qpack_blocked_pe.index = NGHTTP3_PQ_BAD_INDEX; - stream->mem = mem; - stream->rx.http.status_code = -1; - stream->rx.http.content_length = -1; - stream->rx.http.pri.urgency = NGHTTP3_DEFAULT_URGENCY; - stream->error_code = NGHTTP3_H3_NO_ERROR; - if (callbacks) { stream->callbacks = *callbacks; } @@ -140,7 +142,7 @@ static void delete_frq(nghttp3_ringbuf *frq, const nghttp3_mem *mem) { for (i = 0; i < len; ++i) { frent = nghttp3_ringbuf_get(frq, i); - switch (frent->fr.hd.type) { + switch (frent->fr.type) { case NGHTTP3_FRAME_HEADERS: nghttp3_frame_headers_free(&frent->fr.headers, mem); break; @@ -181,42 +183,45 @@ void nghttp3_stream_read_state_reset(nghttp3_stream_read_state *rstate) { nghttp3_ssize nghttp3_read_varint(nghttp3_varint_read_state *rvint, const uint8_t *begin, const uint8_t *end, int fin) { - const uint8_t *orig_begin = begin; - size_t len; + size_t len, vlen; + uint8_t *p; assert(begin != end); if (rvint->left == 0) { assert(rvint->acc == 0); - len = nghttp3_get_varintlen(begin); - if (len <= (size_t)(end - begin)) { + vlen = nghttp3_get_varintlen(begin); + len = nghttp3_min_size(vlen, (size_t)(end - begin)); + if (vlen <= len) { nghttp3_get_varint(&rvint->acc, begin); - return (nghttp3_ssize)len; + return (nghttp3_ssize)vlen; } if (fin) { return NGHTTP3_ERR_INVALID_ARGUMENT; } - rvint->acc = nghttp3_get_varint_fb(begin++); - rvint->left = len - 1; - } - - len = nghttp3_min_size(rvint->left, (size_t)(end - begin)); - end = begin + len; + p = (uint8_t *)&rvint->acc + (sizeof(rvint->acc) - vlen); + memcpy(p, begin, len); + *p &= 0x3f; + rvint->left = vlen - len; - for (; begin != end;) { - rvint->acc = (rvint->acc << 8) + *begin++; + return (nghttp3_ssize)len; } + len = nghttp3_min_size(rvint->left, (size_t)(end - begin)); + p = (uint8_t *)&rvint->acc + (sizeof(rvint->acc) - rvint->left); + memcpy(p, begin, len); rvint->left -= len; - if (fin && rvint->left) { + if (rvint->left == 0) { + rvint->acc = (int64_t)nghttp3_ntohl64((uint64_t)rvint->acc); + } else if (fin) { return NGHTTP3_ERR_INVALID_ARGUMENT; } - return (nghttp3_ssize)(begin - orig_begin); + return (nghttp3_ssize)len; } int nghttp3_stream_frq_add(nghttp3_stream *stream, @@ -250,7 +255,7 @@ int nghttp3_stream_fill_outq(nghttp3_stream *stream) { stream->unsent_bytes < NGHTTP3_MIN_UNSENT_BYTES;) { frent = nghttp3_ringbuf_get(frq, 0); - switch (frent->fr.hd.type) { + switch (frent->fr.type) { case NGHTTP3_FRAME_SETTINGS: rv = nghttp3_stream_write_settings(stream, frent); if (rv != 0) { @@ -290,6 +295,13 @@ int nghttp3_stream_fill_outq(nghttp3_stream *stream) { nghttp3_frame_priority_update_free(&frent->fr.priority_update, stream->mem); break; + case NGHTTP3_FRAME_ORIGIN: + rv = nghttp3_stream_write_origin(stream, frent); + if (rv != 0) { + return rv; + } + + break; default: /* TODO Not implemented */ break; @@ -301,12 +313,6 @@ int nghttp3_stream_fill_outq(nghttp3_stream *stream) { return 0; } -static void typed_buf_shared_init(nghttp3_typed_buf *tbuf, - const nghttp3_buf *chunk) { - nghttp3_typed_buf_init(tbuf, chunk, NGHTTP3_BUF_TYPE_SHARED); - tbuf->buf.pos = tbuf->buf.last; -} - int nghttp3_stream_write_stream_type(nghttp3_stream *stream) { size_t len = nghttp3_put_varintlen((int64_t)stream->type); nghttp3_buf *chunk; @@ -319,7 +325,7 @@ int nghttp3_stream_write_stream_type(nghttp3_stream *stream) { } chunk = nghttp3_stream_get_chunk(stream); - typed_buf_shared_init(&tbuf, chunk); + nghttp3_typed_buf_shared_init(&tbuf, chunk); chunk->last = nghttp3_put_varint(chunk->last, (int64_t)stream->type); tbuf.buf.last = chunk->last; @@ -336,12 +342,17 @@ int nghttp3_stream_write_settings(nghttp3_stream *stream, struct { nghttp3_frame_settings settings; nghttp3_settings_entry iv[15]; - } fr; + } fr = { + .settings = + { + .type = NGHTTP3_FRAME_SETTINGS, + .niv = 3, + }, + }; nghttp3_settings_entry *iv; nghttp3_settings *local_settings = frent->aux.settings.local_settings; + int64_t payloadlen; - fr.settings.hd.type = NGHTTP3_FRAME_SETTINGS; - fr.settings.niv = 3; iv = &fr.settings.iv[0]; iv[0].id = NGHTTP3_SETTINGS_ID_MAX_FIELD_SECTION_SIZE; @@ -365,7 +376,7 @@ int nghttp3_stream_write_settings(nghttp3_stream *stream, ++fr.settings.niv; } - len = nghttp3_frame_write_settings_len(&fr.settings.hd.length, &fr.settings); + len = nghttp3_frame_write_settings_len(&payloadlen, &fr.settings); rv = nghttp3_stream_ensure_chunk(stream, len); if (rv != 0) { @@ -373,9 +384,10 @@ int nghttp3_stream_write_settings(nghttp3_stream *stream, } chunk = nghttp3_stream_get_chunk(stream); - typed_buf_shared_init(&tbuf, chunk); + nghttp3_typed_buf_shared_init(&tbuf, chunk); - chunk->last = nghttp3_frame_write_settings(chunk->last, &fr.settings); + chunk->last = + nghttp3_frame_write_settings(chunk->last, &fr.settings, payloadlen); tbuf.buf.last = chunk->last; @@ -389,8 +401,9 @@ int nghttp3_stream_write_goaway(nghttp3_stream *stream, int rv; nghttp3_buf *chunk; nghttp3_typed_buf tbuf; + int64_t payloadlen; - len = nghttp3_frame_write_goaway_len(&fr->hd.length, fr); + len = nghttp3_frame_write_goaway_len(&payloadlen, fr); rv = nghttp3_stream_ensure_chunk(stream, len); if (rv != 0) { @@ -398,9 +411,9 @@ int nghttp3_stream_write_goaway(nghttp3_stream *stream, } chunk = nghttp3_stream_get_chunk(stream); - typed_buf_shared_init(&tbuf, chunk); + nghttp3_typed_buf_shared_init(&tbuf, chunk); - chunk->last = nghttp3_frame_write_goaway(chunk->last, fr); + chunk->last = nghttp3_frame_write_goaway(chunk->last, fr, payloadlen); tbuf.buf.last = chunk->last; @@ -414,8 +427,9 @@ int nghttp3_stream_write_priority_update(nghttp3_stream *stream, int rv; nghttp3_buf *chunk; nghttp3_typed_buf tbuf; + int64_t payloadlen; - len = nghttp3_frame_write_priority_update_len(&fr->hd.length, fr); + len = nghttp3_frame_write_priority_update_len(&payloadlen, fr); rv = nghttp3_stream_ensure_chunk(stream, len); if (rv != 0) { @@ -423,12 +437,52 @@ int nghttp3_stream_write_priority_update(nghttp3_stream *stream, } chunk = nghttp3_stream_get_chunk(stream); - typed_buf_shared_init(&tbuf, chunk); + nghttp3_typed_buf_shared_init(&tbuf, chunk); + + chunk->last = + nghttp3_frame_write_priority_update(chunk->last, fr, payloadlen); + + tbuf.buf.last = chunk->last; + + return nghttp3_stream_outq_add(stream, &tbuf); +} + +int nghttp3_stream_write_origin(nghttp3_stream *stream, + nghttp3_frame_entry *frent) { + nghttp3_frame_origin *fr = &frent->fr.origin; + nghttp3_buf *chunk; + nghttp3_buf buf; + nghttp3_typed_buf tbuf; + int rv; + + rv = nghttp3_stream_ensure_chunk( + stream, nghttp3_frame_write_hd_len(fr->type, (int64_t)fr->origin_list.len)); + if (rv != 0) { + return rv; + } + + chunk = nghttp3_stream_get_chunk(stream); + nghttp3_typed_buf_shared_init(&tbuf, chunk); - chunk->last = nghttp3_frame_write_priority_update(chunk->last, fr); + chunk->last = + nghttp3_frame_write_hd(chunk->last, fr->type, (int64_t)fr->origin_list.len); tbuf.buf.last = chunk->last; + rv = nghttp3_stream_outq_add(stream, &tbuf); + if (rv != 0) { + return rv; + } + + if (fr->origin_list.len == 0) { + return 0; + } + + nghttp3_buf_wrap_init(&buf, (uint8_t *)fr->origin_list.base, + fr->origin_list.len); + buf.last = buf.end; + nghttp3_typed_buf_init(&tbuf, &buf, NGHTTP3_BUF_TYPE_ALIEN_NO_ACK); + return nghttp3_stream_outq_add(stream, &tbuf); } @@ -455,26 +509,25 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream, size_t len; nghttp3_buf *chunk; nghttp3_typed_buf tbuf; - nghttp3_frame_hd hd; uint8_t raw_pbuf[16]; size_t pbuflen, rbuflen, ebuflen; + int64_t payloadlen; nghttp3_buf_wrap_init(&pbuf, raw_pbuf, sizeof(raw_pbuf)); rv = nghttp3_qpack_encoder_encode(qenc, &pbuf, rbuf, ebuf, stream->node.id, nva, nvlen); if (rv != 0) { - goto fail; + return rv; } pbuflen = nghttp3_buf_len(&pbuf); rbuflen = nghttp3_buf_len(rbuf); ebuflen = nghttp3_buf_len(ebuf); - hd.type = frame_type; - hd.length = (int64_t)(pbuflen + rbuflen); + payloadlen = (int64_t)(pbuflen + rbuflen); - len = nghttp3_frame_write_hd_len(&hd) + pbuflen; + len = nghttp3_frame_write_hd_len(frame_type, payloadlen) + pbuflen; if (rbuflen <= NGHTTP3_STREAM_MAX_COPY_THRES) { len += rbuflen; @@ -482,13 +535,13 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream, rv = nghttp3_stream_ensure_chunk(stream, len); if (rv != 0) { - goto fail; + return rv; } chunk = nghttp3_stream_get_chunk(stream); - typed_buf_shared_init(&tbuf, chunk); + nghttp3_typed_buf_shared_init(&tbuf, chunk); - chunk->last = nghttp3_frame_write_hd(chunk->last, &hd); + chunk->last = nghttp3_frame_write_hd(chunk->last, frame_type, payloadlen); chunk->last = nghttp3_cpymem(chunk->last, pbuf.pos, pbuflen); nghttp3_buf_init(&pbuf); @@ -498,13 +551,13 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream, rv = nghttp3_stream_outq_add(stream, &tbuf); if (rv != 0) { - goto fail; + return rv; } nghttp3_typed_buf_init(&tbuf, rbuf, NGHTTP3_BUF_TYPE_PRIVATE); rv = nghttp3_stream_outq_add(stream, &tbuf); if (rv != 0) { - goto fail; + return rv; } nghttp3_buf_init(rbuf); } else if (rbuflen) { @@ -513,7 +566,7 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream, rv = nghttp3_stream_outq_add(stream, &tbuf); if (rv != 0) { - goto fail; + return rv; } nghttp3_buf_reset(rbuf); } @@ -532,18 +585,18 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream, rv = nghttp3_stream_ensure_chunk(qenc_stream, ebuflen); if (rv != 0) { - goto fail; + return rv; } chunk = nghttp3_stream_get_chunk(qenc_stream); - typed_buf_shared_init(&tbuf, chunk); + nghttp3_typed_buf_shared_init(&tbuf, chunk); chunk->last = nghttp3_cpymem(chunk->last, ebuf->pos, ebuflen); tbuf.buf.last = chunk->last; rv = nghttp3_stream_outq_add(qenc_stream, &tbuf); if (rv != 0) { - goto fail; + return rv; } nghttp3_buf_reset(ebuf); } @@ -553,10 +606,6 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream, assert(0 == nghttp3_buf_len(ebuf)); return 0; - -fail: - - return rv; } int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof, @@ -570,7 +619,6 @@ int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof, nghttp3_conn *conn = stream->conn; int64_t datalen; uint32_t flags = 0; - nghttp3_frame_hd hd; nghttp3_vec vec[8]; nghttp3_vec *v; nghttp3_ssize sveccnt; @@ -624,10 +672,7 @@ int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof, } } - hd.type = NGHTTP3_FRAME_DATA; - hd.length = datalen; - - len = nghttp3_frame_write_hd_len(&hd); + len = nghttp3_frame_write_hd_len(NGHTTP3_FRAME_DATA, datalen); rv = nghttp3_stream_ensure_chunk(stream, len); if (rv != 0) { @@ -635,9 +680,10 @@ int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof, } chunk = nghttp3_stream_get_chunk(stream); - typed_buf_shared_init(&tbuf, chunk); + nghttp3_typed_buf_shared_init(&tbuf, chunk); - chunk->last = nghttp3_frame_write_hd(chunk->last, &hd); + chunk->last = + nghttp3_frame_write_hd(chunk->last, NGHTTP3_FRAME_DATA, datalen); tbuf.buf.last = chunk->last; @@ -690,7 +736,7 @@ int nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream *stream) { } chunk = nghttp3_stream_get_chunk(stream); - typed_buf_shared_init(&tbuf, chunk); + nghttp3_typed_buf_shared_init(&tbuf, chunk); nghttp3_qpack_decoder_write_decoder(qdec, chunk); @@ -717,17 +763,16 @@ int nghttp3_stream_outq_add(nghttp3_stream *stream, if (len) { dest = nghttp3_ringbuf_get(outq, len - 1); if (dest->type == tbuf->type && dest->type == NGHTTP3_BUF_TYPE_SHARED && - dest->buf.begin == tbuf->buf.begin && dest->buf.last == tbuf->buf.pos) { + dest->buf.end == tbuf->buf.end && dest->buf.last == tbuf->buf.pos) { /* If we have already written last entry, adjust outq_idx and offset so that this entry is eligible to send. */ if (len == stream->outq_idx) { --stream->outq_idx; - stream->outq_offset = nghttp3_buf_len(&dest->buf); } dest->buf.last = tbuf->buf.last; - /* TODO Is this required? */ - dest->buf.end = tbuf->buf.end; + + assert(dest->buf.end == tbuf->buf.end); return 0; } @@ -817,34 +862,24 @@ size_t nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, nghttp3_ringbuf *outq = &stream->outq; size_t len = nghttp3_ringbuf_len(outq); size_t i = stream->outq_idx; - uint64_t offset = stream->outq_offset; size_t buflen; nghttp3_vec *vbegin = vec, *vend = vec + veccnt; nghttp3_typed_buf *tbuf; assert(veccnt > 0); - if (i < len) { + for (; i < len && vec != vend; ++i) { tbuf = nghttp3_ringbuf_get(outq, i); buflen = nghttp3_buf_len(&tbuf->buf); - if (offset < buflen) { - vec->base = tbuf->buf.pos + offset; - vec->len = (size_t)(buflen - offset); - ++vec; - } else { - /* This is the only case that satisfies offset >= buflen */ - assert(0 == offset); - assert(0 == buflen); + if (buflen == 0) { + continue; } - ++i; + vec->base = tbuf->buf.pos; + vec->len = buflen; - for (; i < len && vec != vend; ++i, ++vec) { - tbuf = nghttp3_ringbuf_get(outq, i); - vec->base = tbuf->buf.pos; - vec->len = nghttp3_buf_len(&tbuf->buf); - } + ++vec; } /* TODO Rework this if we have finished implementing HTTP @@ -859,26 +894,27 @@ void nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n) { nghttp3_ringbuf *outq = &stream->outq; size_t i; size_t len = nghttp3_ringbuf_len(outq); - uint64_t offset = stream->outq_offset + n; size_t buflen; nghttp3_typed_buf *tbuf; + stream->unsent_bytes -= n; + for (i = stream->outq_idx; i < len; ++i) { tbuf = nghttp3_ringbuf_get(outq, i); buflen = nghttp3_buf_len(&tbuf->buf); - if (offset >= buflen) { - offset -= buflen; - continue; + if (n < buflen) { + tbuf->buf.pos += n; + + break; } - break; + tbuf->buf.pos = tbuf->buf.last; + n -= buflen; } - assert(i < len || offset == 0); + assert(i < len || n == 0); - stream->unsent_bytes -= n; stream->outq_idx = i; - stream->outq_offset = offset; } int nghttp3_stream_outq_write_done(nghttp3_stream *stream) { @@ -898,13 +934,13 @@ static void stream_pop_outq_entry(nghttp3_stream *stream, nghttp3_buf_free(&tbuf->buf, stream->mem); break; case NGHTTP3_BUF_TYPE_ALIEN: + case NGHTTP3_BUF_TYPE_ALIEN_NO_ACK: break; case NGHTTP3_BUF_TYPE_SHARED: assert(nghttp3_ringbuf_len(chunks)); chunk = nghttp3_ringbuf_get(chunks, 0); - assert(chunk->begin == tbuf->buf.begin); assert(chunk->end == tbuf->buf.end); if (chunk->last == tbuf->buf.last) { @@ -927,14 +963,13 @@ static void stream_pop_outq_entry(nghttp3_stream *stream, int nghttp3_stream_update_ack_offset(nghttp3_stream *stream, uint64_t offset) { nghttp3_ringbuf *outq = &stream->outq; size_t buflen; - size_t npopped = 0; uint64_t nack; nghttp3_typed_buf *tbuf; int rv; for (; nghttp3_ringbuf_len(outq);) { tbuf = nghttp3_ringbuf_get(outq, 0); - buflen = nghttp3_buf_len(&tbuf->buf); + buflen = (size_t)(tbuf->buf.last - tbuf->buf.begin); /* For NGHTTP3_BUF_TYPE_ALIEN, we never add 0 length buffer. */ if (tbuf->type == NGHTTP3_BUF_TYPE_ALIEN && stream->ack_offset < offset && @@ -949,17 +984,13 @@ int nghttp3_stream_update_ack_offset(nghttp3_stream *stream, uint64_t offset) { } } - if (offset >= stream->ack_base + buflen) { + if (stream->outq_idx > 0 && offset >= stream->ack_base + buflen) { stream_pop_outq_entry(stream, tbuf); stream->ack_base += buflen; stream->ack_offset = stream->ack_base; - ++npopped; - if (stream->outq_idx + 1 == npopped) { - stream->outq_offset = 0; - break; - } + --stream->outq_idx; continue; } @@ -967,13 +998,6 @@ int nghttp3_stream_update_ack_offset(nghttp3_stream *stream, uint64_t offset) { break; } - assert(stream->outq_idx + 1 >= npopped); - if (stream->outq_idx >= npopped) { - stream->outq_idx -= npopped; - } else { - stream->outq_idx = 0; - } - stream->ack_offset = offset; return 0; @@ -1045,19 +1069,17 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, switch (stream->rx.hstate) { case NGHTTP3_HTTP_STATE_NONE: - return NGHTTP3_ERR_H3_INTERNAL_ERROR; + nghttp3_unreachable(); case NGHTTP3_HTTP_STATE_REQ_INITIAL: - switch (event) { - case NGHTTP3_HTTP_EVENT_HEADERS_BEGIN: - stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN; - return 0; - default: + if (event != NGHTTP3_HTTP_EVENT_HEADERS_BEGIN) { return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; } + + stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN; + + return 0; case NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN: - if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) { - return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; - } + assert(NGHTTP3_HTTP_EVENT_HEADERS_END == event); stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_HEADERS_END; return 0; case NGHTTP3_HTTP_STATE_REQ_HEADERS_END: @@ -1080,12 +1102,10 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END; return 0; default: - return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; + nghttp3_unreachable(); } case NGHTTP3_HTTP_STATE_REQ_DATA_BEGIN: - if (event != NGHTTP3_HTTP_EVENT_DATA_END) { - return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; - } + assert(NGHTTP3_HTTP_EVENT_DATA_END == event); stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_DATA_END; return 0; case NGHTTP3_HTTP_STATE_REQ_DATA_END: @@ -1108,12 +1128,10 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END; return 0; default: - return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; + nghttp3_unreachable(); } case NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN: - if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) { - return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; - } + assert(NGHTTP3_HTTP_EVENT_HEADERS_END == event); stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_TRAILERS_END; return 0; case NGHTTP3_HTTP_STATE_REQ_TRAILERS_END: @@ -1129,7 +1147,7 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END; return 0; case NGHTTP3_HTTP_STATE_REQ_END: - return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; + return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; case NGHTTP3_HTTP_STATE_RESP_INITIAL: if (event != NGHTTP3_HTTP_EVENT_HEADERS_BEGIN) { return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; @@ -1137,9 +1155,7 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN; return 0; case NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN: - if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) { - return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; - } + assert(NGHTTP3_HTTP_EVENT_HEADERS_END == event); stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_HEADERS_END; return 0; case NGHTTP3_HTTP_STATE_RESP_HEADERS_END: @@ -1169,12 +1185,10 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END; return 0; default: - return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; + nghttp3_unreachable(); } case NGHTTP3_HTTP_STATE_RESP_DATA_BEGIN: - if (event != NGHTTP3_HTTP_EVENT_DATA_END) { - return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; - } + assert(NGHTTP3_HTTP_EVENT_DATA_END == event); stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_DATA_END; return 0; case NGHTTP3_HTTP_STATE_RESP_DATA_END: @@ -1197,17 +1211,15 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END; return 0; default: - return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; + nghttp3_unreachable(); } case NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN: - if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) { - return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; - } + assert(NGHTTP3_HTTP_EVENT_HEADERS_END == event); stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_TRAILERS_END; return 0; case NGHTTP3_HTTP_STATE_RESP_TRAILERS_END: if (event != NGHTTP3_HTTP_EVENT_MSG_END) { - return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; + return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; } rv = nghttp3_http_on_remote_end_stream(stream); if (rv != 0) { @@ -1216,7 +1228,7 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END; return 0; case NGHTTP3_HTTP_STATE_RESP_END: - return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; + return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; default: nghttp3_unreachable(); } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h index 7d296febf9135f..759cf687a0c108 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h @@ -69,6 +69,8 @@ typedef enum nghttp3_ctrl_stream_state { NGHTTP3_CTRL_STREAM_STATE_SETTINGS_VALUE, NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE_PRI_ELEM_ID, NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE, + NGHTTP3_CTRL_STREAM_STATE_ORIGIN_ORIGIN_LEN, + NGHTTP3_CTRL_STREAM_STATE_ORIGIN_ASCII_ORIGIN, } nghttp3_ctrl_stream_state; typedef enum nghttp3_req_stream_state { @@ -129,10 +131,6 @@ typedef struct nghttp3_stream_read_state { /* NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED indicates that server received PRIORITY_UPDATE frame for this stream. */ #define NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED 0x0800u -/* NGHTTP3_STREAM_FLAG_HTTP_ERROR indicates that - NGHTTP3_ERR_MALFORMED_HTTP_HEADER error is encountered while - processing incoming HTTP fields. */ -#define NGHTTP3_STREAM_FLAG_HTTP_ERROR 0x1000u typedef enum nghttp3_stream_http_state { NGHTTP3_HTTP_STATE_NONE, @@ -223,9 +221,6 @@ struct nghttp3_stream { uint64_t unsent_bytes; /* outq_idx is an index into outq where next write is made. */ size_t outq_idx; - /* outq_offset is write offset relative to the element at outq_idx - in outq. */ - uint64_t outq_offset; /* ack_base is the number of bytes acknowledged by a remote endpoint where the first element in outq is positioned at. */ uint64_t ack_base; @@ -255,7 +250,7 @@ struct nghttp3_stream { }; }; -nghttp3_objalloc_decl(stream, nghttp3_stream, oplent); +nghttp3_objalloc_decl(stream, nghttp3_stream, oplent) typedef struct nghttp3_frame_entry { nghttp3_frame fr; @@ -322,6 +317,9 @@ int nghttp3_stream_write_goaway(nghttp3_stream *stream, int nghttp3_stream_write_priority_update(nghttp3_stream *stream, nghttp3_frame_entry *frent); +int nghttp3_stream_write_origin(nghttp3_stream *stream, + nghttp3_frame_entry *frent); + int nghttp3_stream_ensure_chunk(nghttp3_stream *stream, size_t need); nghttp3_buf *nghttp3_stream_get_chunk(nghttp3_stream *stream); diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_version.c b/deps/ngtcp2/nghttp3/lib/nghttp3_version.c index 939821d84eac3d..b88e2255b2556d 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_version.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_version.c @@ -28,8 +28,11 @@ #include -static nghttp3_info version = {NGHTTP3_VERSION_AGE, NGHTTP3_VERSION_NUM, - NGHTTP3_VERSION}; +static nghttp3_info version = { + .age = NGHTTP3_VERSION_AGE, + .version_num = NGHTTP3_VERSION_NUM, + .version_str = NGHTTP3_VERSION, +}; const nghttp3_info *nghttp3_version(int least_version) { if (least_version > NGHTTP3_VERSION_NUM) { diff --git a/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c b/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c index d0328cf40c21ea..cee089d3944d18 100644 --- a/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c +++ b/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c @@ -30,38 +30,46 @@ #include #include -#define SF_STATE_DICT 0x08u -#define SF_STATE_LIST 0x10u -#define SF_STATE_ITEM 0x18u +#ifdef __AVX2__ +# include +#endif /* __AVX2__ */ -#define SF_STATE_INNER_LIST 0x04u +#define SFPARSE_STATE_DICT 0x08u +#define SFPARSE_STATE_LIST 0x10u +#define SFPARSE_STATE_ITEM 0x18u -#define SF_STATE_BEFORE 0x00u -#define SF_STATE_BEFORE_PARAMS 0x01u -#define SF_STATE_PARAMS 0x02u -#define SF_STATE_AFTER 0x03u +#define SFPARSE_STATE_INNER_LIST 0x04u -#define SF_STATE_OP_MASK 0x03u +#define SFPARSE_STATE_BEFORE 0x00u +#define SFPARSE_STATE_BEFORE_PARAMS 0x01u +#define SFPARSE_STATE_PARAMS 0x02u +#define SFPARSE_STATE_AFTER 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 SFPARSE_STATE_OP_MASK 0x03u -#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 SFPARSE_SET_STATE_AFTER(NAME) \ + (SFPARSE_STATE_##NAME | SFPARSE_STATE_AFTER) +#define SFPARSE_SET_STATE_BEFORE_PARAMS(NAME) \ + (SFPARSE_STATE_##NAME | SFPARSE_STATE_BEFORE_PARAMS) +#define SFPARSE_SET_STATE_INNER_LIST_BEFORE(NAME) \ + (SFPARSE_STATE_##NAME | SFPARSE_STATE_INNER_LIST | SFPARSE_STATE_BEFORE) -#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 SFPARSE_STATE_DICT_AFTER SFPARSE_SET_STATE_AFTER(DICT) +#define SFPARSE_STATE_DICT_BEFORE_PARAMS SFPARSE_SET_STATE_BEFORE_PARAMS(DICT) +#define SFPARSE_STATE_DICT_INNER_LIST_BEFORE \ + SFPARSE_SET_STATE_INNER_LIST_BEFORE(DICT) -#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 SFPARSE_STATE_LIST_AFTER SFPARSE_SET_STATE_AFTER(LIST) +#define SFPARSE_STATE_LIST_BEFORE_PARAMS SFPARSE_SET_STATE_BEFORE_PARAMS(LIST) +#define SFPARSE_STATE_LIST_INNER_LIST_BEFORE \ + SFPARSE_SET_STATE_INNER_LIST_BEFORE(LIST) -#define SF_STATE_INITIAL 0x00u +#define SFPARSE_STATE_ITEM_AFTER SFPARSE_SET_STATE_AFTER(ITEM) +#define SFPARSE_STATE_ITEM_BEFORE_PARAMS SFPARSE_SET_STATE_BEFORE_PARAMS(ITEM) +#define SFPARSE_STATE_ITEM_INNER_LIST_BEFORE \ + SFPARSE_SET_STATE_INNER_LIST_BEFORE(ITEM) + +#define SFPARSE_STATE_INITIAL 0x00u #define DIGIT_CASES \ case '0': \ @@ -380,40 +388,108 @@ static int is_ws(uint8_t c) { } } -static int parser_eof(sf_parser *sfp) { return sfp->pos == sfp->end; } +#ifdef __AVX2__ +# ifdef _MSC_VER +# include + +static int ctz(unsigned int v) { + unsigned long n; + + /* Assume that v is not 0. */ + _BitScanForward(&n, v); + + return (int)n; +} +# else /* !_MSC_VER */ +# define ctz __builtin_ctz +# endif /* !_MSC_VER */ +#endif /* __AVX2__ */ + +static int parser_eof(sfparse_parser *sfp) { return sfp->pos == sfp->end; } -static void parser_discard_ows(sf_parser *sfp) { +static void parser_discard_ows(sfparse_parser *sfp) { for (; !parser_eof(sfp) && is_ws(*sfp->pos); ++sfp->pos) ; } -static void parser_discard_sp(sf_parser *sfp) { +static void parser_discard_sp(sfparse_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; +static void parser_set_op_state(sfparse_parser *sfp, uint32_t op) { + sfp->state &= ~SFPARSE_STATE_OP_MASK; sfp->state |= op; } -static void parser_unset_inner_list_state(sf_parser *sfp) { - sfp->state &= ~SF_STATE_INNER_LIST; +static void parser_unset_inner_list_state(sfparse_parser *sfp) { + sfp->state &= ~SFPARSE_STATE_INNER_LIST; +} + +#ifdef __AVX2__ +static const uint8_t *find_char_key(const uint8_t *first, const uint8_t *last) { + const __m256i us = _mm256_set1_epi8('_'); + const __m256i ds = _mm256_set1_epi8('-'); + const __m256i dot = _mm256_set1_epi8('.'); + const __m256i ast = _mm256_set1_epi8('*'); + const __m256i r0l = _mm256_set1_epi8('0' - 1); + const __m256i r0r = _mm256_set1_epi8('9' + 1); + const __m256i r1l = _mm256_set1_epi8('a' - 1); + const __m256i r1r = _mm256_set1_epi8('z' + 1); + __m256i s, x; + uint32_t m; + + for (; first != last; first += 32) { + s = _mm256_loadu_si256((void *)first); + + x = _mm256_cmpeq_epi8(s, us); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, ds), x); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, dot), x); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, ast), x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r0l), _mm256_cmpgt_epi8(r0r, s)), + x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r1l), _mm256_cmpgt_epi8(r1r, s)), + x); + + m = ~(uint32_t)_mm256_movemask_epi8(x); + if (m) { + return first + ctz(m); + } + } + + return last; } +#endif /* __AVX2__ */ -static int parser_key(sf_parser *sfp, sf_vec *dest) { +static int parser_key(sfparse_parser *sfp, sfparse_vec *dest) { const uint8_t *base; +#ifdef __AVX2__ + const uint8_t *last; +#endif /* __AVX2__ */ switch (*sfp->pos) { case '*': LCALPHA_CASES: break; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } base = sfp->pos++; +#ifdef __AVX2__ + if (sfp->end - sfp->pos >= 32) { + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + + sfp->pos = find_char_key(sfp->pos, last); + if (sfp->pos != last) { + goto fin; + } + } +#endif /* __AVX2__ */ + for (; !parser_eof(sfp); ++sfp->pos) { switch (*sfp->pos) { case '_': @@ -428,6 +504,9 @@ static int parser_key(sf_parser *sfp, sf_vec *dest) { break; } +#ifdef __AVX2__ +fin: +#endif /* __AVX2__ */ if (dest) { dest->base = (uint8_t *)base; dest->len = (size_t)(sfp->pos - dest->base); @@ -436,7 +515,7 @@ static int parser_key(sf_parser *sfp, sf_vec *dest) { return 0; } -static int parser_number(sf_parser *sfp, sf_value *dest) { +static int parser_number(sfparse_parser *sfp, sfparse_value *dest) { int sign = 1; int64_t value = 0; size_t len = 0; @@ -445,7 +524,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { if (*sfp->pos == '-') { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } sign = -1; @@ -457,7 +536,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { switch (*sfp->pos) { DIGIT_CASES: if (++len > 15) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } value *= 10; @@ -470,13 +549,13 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { } if (len == 0) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } if (parser_eof(sfp) || *sfp->pos != '.') { if (dest) { - dest->type = SF_TYPE_INTEGER; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_INTEGER; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->integer = value * sign; } @@ -486,7 +565,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { /* decimal */ if (len > 12) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } fpos = len; @@ -497,7 +576,7 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { switch (*sfp->pos) { DIGIT_CASES: if (++len > 15) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } value *= 10; @@ -510,12 +589,12 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { } if (fpos == len || len - fpos > 3) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } if (dest) { - dest->type = SF_TYPE_DECIMAL; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_DECIMAL; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->decimal.numer = value * sign; switch (len - fpos) { @@ -537,9 +616,9 @@ static int parser_number(sf_parser *sfp, sf_value *dest) { return 0; } -static int parser_date(sf_parser *sfp, sf_value *dest) { +static int parser_date(sfparse_parser *sfp, sfparse_value *dest) { int rv; - sf_value val; + sfparse_value val; /* The first byte has already been validated by the caller. */ assert('@' == *sfp->pos); @@ -547,7 +626,7 @@ static int parser_date(sf_parser *sfp, sf_value *dest) { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } rv = parser_number(sfp, &val); @@ -555,27 +634,93 @@ static int parser_date(sf_parser *sfp, sf_value *dest) { return rv; } - if (val.type != SF_TYPE_INTEGER) { - return SF_ERR_PARSE_ERROR; + if (val.type != SFPARSE_TYPE_INTEGER) { + return SFPARSE_ERR_PARSE; } if (dest) { *dest = val; - dest->type = SF_TYPE_DATE; + dest->type = SFPARSE_TYPE_DATE; } return 0; } -static int parser_string(sf_parser *sfp, sf_value *dest) { +#ifdef __AVX2__ +static const uint8_t *find_char_string(const uint8_t *first, + const uint8_t *last) { + const __m256i bs = _mm256_set1_epi8('\\'); + const __m256i dq = _mm256_set1_epi8('"'); + const __m256i del = _mm256_set1_epi8(0x7f); + const __m256i sp = _mm256_set1_epi8(' '); + __m256i s, x; + uint32_t m; + + for (; first != last; first += 32) { + s = _mm256_loadu_si256((void *)first); + + x = _mm256_cmpgt_epi8(sp, s); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, bs), x); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, dq), x); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, del), x); + + m = (uint32_t)_mm256_movemask_epi8(x); + if (m) { + return first + ctz(m); + } + } + + return last; +} +#endif /* __AVX2__ */ + +static int parser_string(sfparse_parser *sfp, sfparse_value *dest) { const uint8_t *base; - uint32_t flags = SF_VALUE_FLAG_NONE; +#ifdef __AVX2__ + const uint8_t *last; +#endif /* __AVX2__ */ + uint32_t flags = SFPARSE_VALUE_FLAG_NONE; /* The first byte has already been validated by the caller. */ assert('"' == *sfp->pos); base = ++sfp->pos; +#ifdef __AVX2__ + for (; sfp->end - sfp->pos >= 32; ++sfp->pos) { + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + + sfp->pos = find_char_string(sfp->pos, last); + if (sfp->pos == last) { + break; + } + + switch (*sfp->pos) { + case '\\': + ++sfp->pos; + if (parser_eof(sfp)) { + return SFPARSE_ERR_PARSE; + } + + switch (*sfp->pos) { + case '"': + case '\\': + flags = SFPARSE_VALUE_FLAG_ESCAPED_STRING; + + break; + default: + return SFPARSE_ERR_PARSE; + } + + break; + case '"': + goto fin; + default: + return SFPARSE_ERR_PARSE; + } + } +#endif /* __AVX2__ */ + for (; !parser_eof(sfp); ++sfp->pos) { switch (*sfp->pos) { X20_21_CASES: @@ -585,45 +730,116 @@ static int parser_string(sf_parser *sfp, sf_value *dest) { case '\\': ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } switch (*sfp->pos) { case '"': case '\\': - flags = SF_VALUE_FLAG_ESCAPED_STRING; + flags = SFPARSE_VALUE_FLAG_ESCAPED_STRING; break; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } 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; - } + goto fin; + default: + return SFPARSE_ERR_PARSE; + } + } - ++sfp->pos; + return SFPARSE_ERR_PARSE; - return 0; - default: - return SF_ERR_PARSE_ERROR; +fin: + if (dest) { + dest->type = SFPARSE_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; +} + +#ifdef __AVX2__ +static const uint8_t *find_char_token(const uint8_t *first, + const uint8_t *last) { + /* r0: !..:, excluding "(), + r1: A..Z + r2: ^..~, excluding {} */ + const __m256i r0l = _mm256_set1_epi8('!' - 1); + const __m256i r0r = _mm256_set1_epi8(':' + 1); + const __m256i dq = _mm256_set1_epi8('"'); + const __m256i prl = _mm256_set1_epi8('('); + const __m256i prr = _mm256_set1_epi8(')'); + const __m256i comma = _mm256_set1_epi8(','); + const __m256i r1l = _mm256_set1_epi8('A' - 1); + const __m256i r1r = _mm256_set1_epi8('Z' + 1); + const __m256i r2l = _mm256_set1_epi8('^' - 1); + const __m256i r2r = _mm256_set1_epi8('~' + 1); + const __m256i cbl = _mm256_set1_epi8('{'); + const __m256i cbr = _mm256_set1_epi8('}'); + __m256i s, x; + uint32_t m; + + for (; first != last; first += 32) { + s = _mm256_loadu_si256((void *)first); + + x = _mm256_andnot_si256( + _mm256_cmpeq_epi8(s, comma), + _mm256_andnot_si256( + _mm256_cmpeq_epi8(s, prr), + _mm256_andnot_si256( + _mm256_cmpeq_epi8(s, prl), + _mm256_andnot_si256(_mm256_cmpeq_epi8(s, dq), + _mm256_and_si256(_mm256_cmpgt_epi8(s, r0l), + _mm256_cmpgt_epi8(r0r, s)))))); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r1l), _mm256_cmpgt_epi8(r1r, s)), + x); + x = _mm256_or_si256( + _mm256_andnot_si256( + _mm256_cmpeq_epi8(s, cbr), + _mm256_andnot_si256(_mm256_cmpeq_epi8(s, cbl), + _mm256_and_si256(_mm256_cmpgt_epi8(s, r2l), + _mm256_cmpgt_epi8(r2r, s)))), + x); + + m = ~(uint32_t)_mm256_movemask_epi8(x); + if (m) { + return first + ctz(m); } } - return SF_ERR_PARSE_ERROR; + return last; } +#endif /* __AVX2__ */ -static int parser_token(sf_parser *sfp, sf_value *dest) { +static int parser_token(sfparse_parser *sfp, sfparse_value *dest) { const uint8_t *base; +#ifdef __AVX2__ + const uint8_t *last; +#endif /* __AVX2__ */ /* The first byte has already been validated by the caller. */ base = sfp->pos++; +#ifdef __AVX2__ + if (sfp->end - sfp->pos >= 32) { + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + + sfp->pos = find_char_token(sfp->pos, last); + if (sfp->pos != last) { + goto fin; + } + } +#endif /* __AVX2__ */ + for (; !parser_eof(sfp); ++sfp->pos) { switch (*sfp->pos) { TOKEN_CASES: @@ -633,9 +849,12 @@ static int parser_token(sf_parser *sfp, sf_value *dest) { break; } +#ifdef __AVX2__ +fin: +#endif /* __AVX2__ */ if (dest) { - dest->type = SF_TYPE_TOKEN; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_TOKEN; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->vec.base = (uint8_t *)base; dest->vec.len = (size_t)(sfp->pos - base); } @@ -643,14 +862,63 @@ static int parser_token(sf_parser *sfp, sf_value *dest) { return 0; } -static int parser_byteseq(sf_parser *sfp, sf_value *dest) { +#ifdef __AVX2__ +static const uint8_t *find_char_byteseq(const uint8_t *first, + const uint8_t *last) { + const __m256i pls = _mm256_set1_epi8('+'); + const __m256i fs = _mm256_set1_epi8('/'); + const __m256i r0l = _mm256_set1_epi8('0' - 1); + const __m256i r0r = _mm256_set1_epi8('9' + 1); + const __m256i r1l = _mm256_set1_epi8('A' - 1); + const __m256i r1r = _mm256_set1_epi8('Z' + 1); + const __m256i r2l = _mm256_set1_epi8('a' - 1); + const __m256i r2r = _mm256_set1_epi8('z' + 1); + __m256i s, x; + uint32_t m; + + for (; first != last; first += 32) { + s = _mm256_loadu_si256((void *)first); + + x = _mm256_cmpeq_epi8(s, pls); + x = _mm256_or_si256(_mm256_cmpeq_epi8(s, fs), x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r0l), _mm256_cmpgt_epi8(r0r, s)), + x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r1l), _mm256_cmpgt_epi8(r1r, s)), + x); + x = _mm256_or_si256( + _mm256_and_si256(_mm256_cmpgt_epi8(s, r2l), _mm256_cmpgt_epi8(r2r, s)), + x); + + m = ~(uint32_t)_mm256_movemask_epi8(x); + if (m) { + return first + ctz(m); + } + } + + return last; +} +#endif /* __AVX2__ */ + +static int parser_byteseq(sfparse_parser *sfp, sfparse_value *dest) { const uint8_t *base; +#ifdef __AVX2__ + const uint8_t *last; +#endif /* __AVX2__ */ /* The first byte has already been validated by the caller. */ assert(':' == *sfp->pos); base = ++sfp->pos; +#ifdef __AVX2__ + if (sfp->end - sfp->pos >= 32) { + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + sfp->pos = find_char_byteseq(sfp->pos, last); + } +#endif /* __AVX2__ */ + for (; !parser_eof(sfp); ++sfp->pos) { switch (*sfp->pos) { case '+': @@ -662,12 +930,12 @@ static int parser_byteseq(sf_parser *sfp, sf_value *dest) { switch ((sfp->pos - base) & 0x3) { case 0: case 1: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; case 2: ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } if (*sfp->pos == '=') { @@ -682,27 +950,27 @@ static int parser_byteseq(sf_parser *sfp, sf_value *dest) { } if (parser_eof(sfp) || *sfp->pos != ':') { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } goto fin; case ':': if (((sfp->pos - base) & 0x3) == 1) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } goto fin; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } } - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; fin: if (dest) { - dest->type = SF_TYPE_BYTESEQ; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_BYTESEQ; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->vec.len = (size_t)(sfp->pos - base); dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; } @@ -712,7 +980,7 @@ static int parser_byteseq(sf_parser *sfp, sf_value *dest) { return 0; } -static int parser_boolean(sf_parser *sfp, sf_value *dest) { +static int parser_boolean(sfparse_parser *sfp, sfparse_value *dest) { int b; /* The first byte has already been validated by the caller. */ @@ -721,7 +989,7 @@ static int parser_boolean(sf_parser *sfp, sf_value *dest) { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } switch (*sfp->pos) { @@ -734,14 +1002,14 @@ static int parser_boolean(sf_parser *sfp, sf_value *dest) { break; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } ++sfp->pos; if (dest) { - dest->type = SF_TYPE_BOOLEAN; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_BOOLEAN; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->boolean = b; } @@ -847,7 +1115,7 @@ static void utf8_decode(uint32_t *state, uint8_t byte) { /* End of utf8 dfa */ -static int parser_dispstring(sf_parser *sfp, sf_value *dest) { +static int parser_dispstring(sfparse_parser *sfp, sfparse_value *dest) { const uint8_t *base; uint8_t c; uint32_t utf8state = UTF8_ACCEPT; @@ -857,7 +1125,7 @@ static int parser_dispstring(sf_parser *sfp, sf_value *dest) { ++sfp->pos; if (parser_eof(sfp) || *sfp->pos != '"') { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } base = ++sfp->pos; @@ -866,32 +1134,32 @@ static int parser_dispstring(sf_parser *sfp, sf_value *dest) { switch (*sfp->pos) { X00_1F_CASES: X7F_FF_CASES: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; case '%': ++sfp->pos; if (sfp->pos + 2 > sfp->end) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } if (pctdecode(&c, &sfp->pos) != 0) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } utf8_decode(&utf8state, c); if (utf8state == UTF8_REJECT) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; case '"': if (utf8state != UTF8_ACCEPT) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } if (dest) { - dest->type = SF_TYPE_DISPSTRING; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_DISPSTRING; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->vec.len = (size_t)(sfp->pos - base); dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; } @@ -901,17 +1169,17 @@ static int parser_dispstring(sf_parser *sfp, sf_value *dest) { return 0; default: if (utf8state != UTF8_ACCEPT) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } ++sfp->pos; } } - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } -static int parser_bare_item(sf_parser *sfp, sf_value *dest) { +static int parser_bare_item(sfparse_parser *sfp, sfparse_value *dest) { switch (*sfp->pos) { case '"': return parser_string(sfp, dest); @@ -930,28 +1198,29 @@ static int parser_bare_item(sf_parser *sfp, sf_value *dest) { case '%': return parser_dispstring(sfp, dest); default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } } -static int parser_skip_inner_list(sf_parser *sfp); +static int parser_skip_inner_list(sfparse_parser *sfp); -int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { +int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key, + sfparse_value *dest_value) { int rv; - switch (sfp->state & SF_STATE_OP_MASK) { - case SF_STATE_BEFORE: + switch (sfp->state & SFPARSE_STATE_OP_MASK) { + case SFPARSE_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); + case SFPARSE_STATE_BEFORE_PARAMS: + parser_set_op_state(sfp, SFPARSE_STATE_PARAMS); break; - case SF_STATE_PARAMS: + case SFPARSE_STATE_PARAMS: break; default: assert(0); @@ -959,16 +1228,16 @@ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { } if (parser_eof(sfp) || *sfp->pos != ';') { - parser_set_op_state(sfp, SF_STATE_AFTER); + parser_set_op_state(sfp, SFPARSE_STATE_AFTER); - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } ++sfp->pos; parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } rv = parser_key(sfp, dest_key); @@ -978,8 +1247,8 @@ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { if (parser_eof(sfp) || *sfp->pos != '=') { if (dest_value) { - dest_value->type = SF_TYPE_BOOLEAN; - dest_value->flags = SF_VALUE_FLAG_NONE; + dest_value->type = SFPARSE_TYPE_BOOLEAN; + dest_value->flags = SFPARSE_VALUE_FLAG_NONE; dest_value->boolean = 1; } @@ -989,23 +1258,23 @@ int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } return parser_bare_item(sfp, dest_value); } -static int parser_skip_params(sf_parser *sfp) { +static int parser_skip_params(sfparse_parser *sfp) { int rv; for (;;) { - rv = sf_parser_param(sfp, NULL, NULL); + rv = sfparse_parser_param(sfp, NULL, NULL); switch (rv) { case 0: break; - case SF_ERR_EOF: + case SFPARSE_ERR_EOF: return 0; - case SF_ERR_PARSE_ERROR: + case SFPARSE_ERR_PARSE: return rv; default: assert(0); @@ -1014,45 +1283,45 @@ static int parser_skip_params(sf_parser *sfp) { } } -int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { +int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest) { int rv; - switch (sfp->state & SF_STATE_OP_MASK) { - case SF_STATE_BEFORE: + switch (sfp->state & SFPARSE_STATE_OP_MASK) { + case SFPARSE_STATE_BEFORE: parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; - case SF_STATE_BEFORE_PARAMS: + case SFPARSE_STATE_BEFORE_PARAMS: rv = parser_skip_params(sfp); if (rv != 0) { return rv; } - /* Technically, we are entering SF_STATE_AFTER, but we will set + /* Technically, we are entering SFPARSE_STATE_AFTER, but we will set another state without reading the state. */ - /* parser_set_op_state(sfp, SF_STATE_AFTER); */ + /* parser_set_op_state(sfp, SFPARSE_STATE_AFTER); */ /* fall through */ - case SF_STATE_AFTER: + case SFPARSE_STATE_AFTER: if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } switch (*sfp->pos) { case ' ': parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; case ')': break; default: - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; @@ -1065,9 +1334,9 @@ int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { ++sfp->pos; parser_unset_inner_list_state(sfp); - parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + parser_set_op_state(sfp, SFPARSE_STATE_BEFORE_PARAMS); - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } rv = parser_bare_item(sfp, dest); @@ -1075,22 +1344,22 @@ int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { return rv; } - parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + parser_set_op_state(sfp, SFPARSE_STATE_BEFORE_PARAMS); return 0; } -static int parser_skip_inner_list(sf_parser *sfp) { +static int parser_skip_inner_list(sfparse_parser *sfp) { int rv; for (;;) { - rv = sf_parser_inner_list(sfp, NULL); + rv = sfparse_parser_inner_list(sfp, NULL); switch (rv) { case 0: break; - case SF_ERR_EOF: + case SFPARSE_ERR_EOF: return 0; - case SF_ERR_PARSE_ERROR: + case SFPARSE_ERR_PARSE: return rv; default: assert(0); @@ -1099,39 +1368,39 @@ static int parser_skip_inner_list(sf_parser *sfp) { } } -static int parser_next_key_or_item(sf_parser *sfp) { +static int parser_next_key_or_item(sfparse_parser *sfp) { parser_discard_ows(sfp); if (parser_eof(sfp)) { - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } if (*sfp->pos != ',') { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } ++sfp->pos; parser_discard_ows(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } return 0; } -static int parser_dict_value(sf_parser *sfp, sf_value *dest) { +static int parser_dict_value(sfparse_parser *sfp, sfparse_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->type = SFPARSE_TYPE_BOOLEAN; + dest->flags = SFPARSE_VALUE_FLAG_NONE; dest->boolean = 1; } - sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + sfp->state = SFPARSE_STATE_DICT_BEFORE_PARAMS; return 0; } @@ -1139,18 +1408,18 @@ static int parser_dict_value(sf_parser *sfp, sf_value *dest) { ++sfp->pos; if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } if (*sfp->pos == '(') { if (dest) { - dest->type = SF_TYPE_INNER_LIST; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_INNER_LIST; + dest->flags = SFPARSE_VALUE_FLAG_NONE; } ++sfp->pos; - sfp->state = SF_STATE_DICT_INNER_LIST_BEFORE; + sfp->state = SFPARSE_STATE_DICT_INNER_LIST_BEFORE; return 0; } @@ -1160,41 +1429,42 @@ static int parser_dict_value(sf_parser *sfp, sf_value *dest) { return rv; } - sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + sfp->state = SFPARSE_STATE_DICT_BEFORE_PARAMS; return 0; } -int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { +int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key, + sfparse_value *dest_value) { int rv; switch (sfp->state) { - case SF_STATE_DICT_INNER_LIST_BEFORE: + case SFPARSE_STATE_DICT_INNER_LIST_BEFORE: rv = parser_skip_inner_list(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_DICT_BEFORE_PARAMS: + case SFPARSE_STATE_DICT_BEFORE_PARAMS: rv = parser_skip_params(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_DICT_AFTER: + case SFPARSE_STATE_DICT_AFTER: rv = parser_next_key_or_item(sfp); if (rv != 0) { return rv; } break; - case SF_STATE_INITIAL: + case SFPARSE_STATE_INITIAL: parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } break; @@ -1211,36 +1481,36 @@ int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { return parser_dict_value(sfp, dest_value); } -int sf_parser_list(sf_parser *sfp, sf_value *dest) { +int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest) { int rv; switch (sfp->state) { - case SF_STATE_LIST_INNER_LIST_BEFORE: + case SFPARSE_STATE_LIST_INNER_LIST_BEFORE: rv = parser_skip_inner_list(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_LIST_BEFORE_PARAMS: + case SFPARSE_STATE_LIST_BEFORE_PARAMS: rv = parser_skip_params(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_LIST_AFTER: + case SFPARSE_STATE_LIST_AFTER: rv = parser_next_key_or_item(sfp); if (rv != 0) { return rv; } break; - case SF_STATE_INITIAL: + case SFPARSE_STATE_INITIAL: parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; } break; @@ -1251,13 +1521,13 @@ int sf_parser_list(sf_parser *sfp, sf_value *dest) { if (*sfp->pos == '(') { if (dest) { - dest->type = SF_TYPE_INNER_LIST; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_INNER_LIST; + dest->flags = SFPARSE_VALUE_FLAG_NONE; } ++sfp->pos; - sfp->state = SF_STATE_LIST_INNER_LIST_BEFORE; + sfp->state = SFPARSE_STATE_LIST_INNER_LIST_BEFORE; return 0; } @@ -1267,45 +1537,45 @@ int sf_parser_list(sf_parser *sfp, sf_value *dest) { return rv; } - sfp->state = SF_STATE_LIST_BEFORE_PARAMS; + sfp->state = SFPARSE_STATE_LIST_BEFORE_PARAMS; return 0; } -int sf_parser_item(sf_parser *sfp, sf_value *dest) { +int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest) { int rv; switch (sfp->state) { - case SF_STATE_INITIAL: + case SFPARSE_STATE_INITIAL: parser_discard_sp(sfp); if (parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } break; - case SF_STATE_ITEM_INNER_LIST_BEFORE: + case SFPARSE_STATE_ITEM_INNER_LIST_BEFORE: rv = parser_skip_inner_list(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_ITEM_BEFORE_PARAMS: + case SFPARSE_STATE_ITEM_BEFORE_PARAMS: rv = parser_skip_params(sfp); if (rv != 0) { return rv; } /* fall through */ - case SF_STATE_ITEM_AFTER: + case SFPARSE_STATE_ITEM_AFTER: parser_discard_sp(sfp); if (!parser_eof(sfp)) { - return SF_ERR_PARSE_ERROR; + return SFPARSE_ERR_PARSE; } - return SF_ERR_EOF; + return SFPARSE_ERR_EOF; default: assert(0); abort(); @@ -1313,13 +1583,13 @@ int sf_parser_item(sf_parser *sfp, sf_value *dest) { if (*sfp->pos == '(') { if (dest) { - dest->type = SF_TYPE_INNER_LIST; - dest->flags = SF_VALUE_FLAG_NONE; + dest->type = SFPARSE_TYPE_INNER_LIST; + dest->flags = SFPARSE_VALUE_FLAG_NONE; } ++sfp->pos; - sfp->state = SF_STATE_ITEM_INNER_LIST_BEFORE; + sfp->state = SFPARSE_STATE_ITEM_INNER_LIST_BEFORE; return 0; } @@ -1329,12 +1599,13 @@ int sf_parser_item(sf_parser *sfp, sf_value *dest) { return rv; } - sfp->state = SF_STATE_ITEM_BEFORE_PARAMS; + sfp->state = SFPARSE_STATE_ITEM_BEFORE_PARAMS; return 0; } -void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { +void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data, + size_t datalen) { if (datalen == 0) { sfp->pos = sfp->end = NULL; } else { @@ -1342,10 +1613,10 @@ void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { sfp->end = data + datalen; } - sfp->state = SF_STATE_INITIAL; + sfp->state = SFPARSE_STATE_INITIAL; } -void sf_unescape(sf_vec *dest, const sf_vec *src) { +void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src) { const uint8_t *p, *q; uint8_t *o; size_t len, slen; @@ -1381,23 +1652,22 @@ void sf_unescape(sf_vec *dest, const sf_vec *src) { } } -void sf_base64decode(sf_vec *dest, const sf_vec *src) { +void sfparse_base64decode(sfparse_vec *dest, const sfparse_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}; + -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; @@ -1478,7 +1748,7 @@ void sf_base64decode(sf_vec *dest, const sf_vec *src) { dest->len = (size_t)(o - dest->base); } -void sf_pctdecode(sf_vec *dest, const sf_vec *src) { +void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src) { const uint8_t *p, *q; uint8_t *o; size_t len, slen; diff --git a/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.h b/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.h index 01cc947d4d61bc..9341221a099438 100644 --- a/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.h +++ b/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.h @@ -31,90 +31,90 @@ libcurl) */ #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) # define WIN32 -#endif +#endif /* (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) */ #ifdef __cplusplus extern "C" { -#endif +#endif /* defined(__cplusplus) */ #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) */ +#else /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */ # include -#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +#endif /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */ #include #include /** * @enum * - * :type:`sf_type` defines value type. + * :type:`sfparse_type` defines value type. */ -typedef enum sf_type { +typedef enum sfparse_type { /** - * :enum:`SF_TYPE_BOOLEAN` indicates boolean type. + * :enum:`SFPARSE_TYPE_BOOLEAN` indicates boolean type. */ - SF_TYPE_BOOLEAN, + SFPARSE_TYPE_BOOLEAN, /** - * :enum:`SF_TYPE_INTEGER` indicates integer type. + * :enum:`SFPARSE_TYPE_INTEGER` indicates integer type. */ - SF_TYPE_INTEGER, + SFPARSE_TYPE_INTEGER, /** - * :enum:`SF_TYPE_DECIMAL` indicates decimal type. + * :enum:`SFPARSE_TYPE_DECIMAL` indicates decimal type. */ - SF_TYPE_DECIMAL, + SFPARSE_TYPE_DECIMAL, /** - * :enum:`SF_TYPE_STRING` indicates string type. + * :enum:`SFPARSE_TYPE_STRING` indicates string type. */ - SF_TYPE_STRING, + SFPARSE_TYPE_STRING, /** - * :enum:`SF_TYPE_TOKEN` indicates token type. + * :enum:`SFPARSE_TYPE_TOKEN` indicates token type. */ - SF_TYPE_TOKEN, + SFPARSE_TYPE_TOKEN, /** - * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type. + * :enum:`SFPARSE_TYPE_BYTESEQ` indicates byte sequence type. */ - SF_TYPE_BYTESEQ, + SFPARSE_TYPE_BYTESEQ, /** - * :enum:`SF_TYPE_INNER_LIST` indicates inner list type. + * :enum:`SFPARSE_TYPE_INNER_LIST` indicates inner list type. */ - SF_TYPE_INNER_LIST, + SFPARSE_TYPE_INNER_LIST, /** - * :enum:`SF_TYPE_DATE` indicates date type. + * :enum:`SFPARSE_TYPE_DATE` indicates date type. */ - SF_TYPE_DATE, + SFPARSE_TYPE_DATE, /** - * :enum:`SF_TYPE_DISPSTRING` indicates display string type. + * :enum:`SFPARSE_TYPE_DISPSTRING` indicates display string type. */ - SF_TYPE_DISPSTRING -} sf_type; + SFPARSE_TYPE_DISPSTRING +} sfparse_type; /** * @macro * - * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has + * :macro:`SFPARSE_ERR_PARSE` indicates fatal parse error has * occurred, and it is not possible to continue the processing. */ -#define SF_ERR_PARSE_ERROR -1 +#define SFPARSE_ERR_PARSE -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. + * :macro:`SFPARSE_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 +#define SFPARSE_ERR_EOF -2 /** * @struct * - * :type:`sf_vec` stores sequence of bytes. + * :type:`sfparse_vec` stores sequence of bytes. */ -typedef struct sf_vec { +typedef struct sfparse_vec { /** * :member:`base` points to the beginning of the sequence of bytes. */ @@ -123,29 +123,29 @@ typedef struct sf_vec { * :member:`len` is the number of bytes contained in this sequence. */ size_t len; -} sf_vec; +} sfparse_vec; /** * @macro * - * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set. + * :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set. */ -#define SF_VALUE_FLAG_NONE 0x0u +#define SFPARSE_VALUE_FLAG_NONE 0x0u /** * @macro * - * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string + * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` indicates that a string * contains escaped character(s). */ -#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u +#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1u /** * @struct * - * :type:`sf_decimal` contains decimal value. + * :type:`sfparse_decimal` contains decimal value. */ -typedef struct sf_decimal { +typedef struct sfparse_decimal { /** * :member:`numer` contains numerator of the decimal value. */ @@ -154,275 +154,289 @@ typedef struct sf_decimal { * :member:`denom` contains denominator of the decimal value. */ int64_t denom; -} sf_decimal; +} sfparse_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`. + * :type:`sfparse_value` stores a Structured Field item. For Inner + * List, only type is set to + * :enum:`sfparse_type.SFPARSE_TYPE_INNER_LIST`. In order to read the + * items contained in an inner list, call `sfparse_parser_inner_list`. */ -typedef struct sf_value { +typedef struct sfparse_value { /** * :member:`type` is the type of the value contained in this * particular object. */ - sf_type type; + sfparse_type type; /** * :member:`flags` is bitwise OR of one or more of - * :macro:`SF_VALUE_FLAG_* `. + * :macro:`SFPARSE_VALUE_FLAG_* `. */ uint32_t flags; /** * @anonunion_start * - * @sf_value_value + * @sfparse_value_value */ union { /** * :member:`boolean` contains boolean value if :member:`type` == - * :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0 - * indicates false. + * :enum:`sfparse_type.SFPARSE_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`. + * either :enum:`sfparse_type.SFPARSE_TYPE_INTEGER` or + * :enum:`sfparse_type.SFPARSE_TYPE_DATE`. */ int64_t integer; /** * :member:`decimal` contains decimal value if :member:`type` == - * :enum:`sf_type.SF_TYPE_DECIMAL`. + * :enum:`sfparse_type.SFPARSE_TYPE_DECIMAL`. */ - sf_decimal decimal; + sfparse_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`, :enum:`sf_type.SF_TYPE_BYTESEQ`, - * or :enum:`sf_type.SF_TYPE_DISPSTRING`. + * either :enum:`sfparse_type.SFPARSE_TYPE_STRING`, + * :enum:`sfparse_type.SFPARSE_TYPE_TOKEN`, + * :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, or + * :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`. * - * 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:`sfparse_type.SFPARSE_TYPE_STRING`, this field + * contains one or more escaped characters if :member:`flags` has + * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` set. To unescape + * the string, use `sfparse_unescape`. * - * For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64 - * encoded string. To decode this byte string, use - * `sf_base64decode`. + * For :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, this field + * contains base64 encoded string. To decode this byte string, + * use `sfparse_base64decode`. * - * For :enum:`sf_type.SF_TYPE_DISPSTRING`, this field may contain - * percent-encoded UTF-8 byte sequences. To decode it, use - * `sf_pctdecode`. + * For :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`, this field + * may contain percent-encoded UTF-8 byte sequences. To decode + * it, use `sfparse_pctdecode`. * - * If :member:`vec.len ` == 0, :member:`vec.base - * ` is guaranteed to be NULL. + * If :member:`vec.len ` == 0, :member:`vec.base + * ` is guaranteed to be NULL. */ - sf_vec vec; + sfparse_vec vec; /** * @anonunion_end */ }; -} sf_value; +} sfparse_value; /** * @struct * - * :type:`sf_parser` is the Structured Field Values parser. Use - * `sf_parser_init` to initialize it. + * :type:`sfparse_parser` is the Structured Field Values parser. Use + * `sfparse_parser_init` to initialize it. */ -typedef struct sf_parser { +typedef struct sfparse_parser { /* all fields are private */ const uint8_t *pos; const uint8_t *end; uint32_t state; -} sf_parser; +} sfparse_parser; /** * @function * - * `sf_parser_init` initializes |sfp| with the given buffer pointed by - * |data| of length |datalen|. + * `sfparse_parser_init` initializes |sfp| with the given data encoded + * in Structured Field Values pointed by |data| of length |datalen|. */ -void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen); +void sfparse_parser_init(sfparse_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| + * `sfparse_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 + * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all parameters + * have read, and caller can continue to read rest of the values. If + * it returns :macro:`SFPARSE_ERR_PARSE`, it encountered fatal error * while parsing field value. */ -int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); +int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key, + sfparse_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. + * `sfparse_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`. + * calling `sfparse_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. + * error code. If it returns :macro:`SFPARSE_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` + * :macro:`SFPARSE_ERR_EOF` * All values in the dictionary have read. - * :macro:`SF_ERR_PARSE_ERROR` + * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ -int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); +int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key, + sfparse_value *dest_value); /** * @function * - * `sf_parser_list` reads the next list item. If this function + * `sfparse_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`. + * calling `sfparse_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. + * error code. If it returns :macro:`SFPARSE_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` + * :macro:`SFPARSE_ERR_EOF` * All values in the list have read. - * :macro:`SF_ERR_PARSE_ERROR` + * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ -int sf_parser_list(sf_parser *sfp, sf_value *dest); +int sfparse_parser_list(sfparse_parser *sfp, sfparse_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. + * `sfparse_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`. + * calling `sfparse_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. + * :macro:`SFPARSE_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` + * :macro:`SFPARSE_ERR_EOF` * There is nothing left to read. - * :macro:`SF_ERR_PARSE_ERROR` + * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ -int sf_parser_item(sf_parser *sfp, sf_value *dest); +int sfparse_parser_item(sfparse_parser *sfp, sfparse_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. + * `sfparse_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`. + * calling `sfparse_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 + * error code. If it returns :macro:`SFPARSE_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. + * `sfparse_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` + * :macro:`SFPARSE_ERR_EOF` * All values in the inner list have read. - * :macro:`SF_ERR_PARSE_ERROR` + * :macro:`SFPARSE_ERR_PARSE` * It encountered fatal error while parsing field value. */ -int sf_parser_inner_list(sf_parser *sfp, sf_value *dest); +int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_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. + * `sfparse_unescape` copies |src| to |dest| by removing escapes + * (``\``). |src| should be the pointer to + * :member:`sfparse_value.vec` of type + * :enum:`sfparse_type.SFPARSE_TYPE_STRING` produced by either + * `sfparse_parser_dict`, `sfparse_parser_list`, + * `sfparse_parser_inner_list`, `sfparse_parser_item`, or + * `sfparse_parser_param`, otherwise the behavior is undefined. * - * :member:`dest->base ` must point to the buffer that - * has sufficient space to store the unescaped string. + * :member:`dest->base ` must point to the buffer + * that has sufficient space to store the unescaped string. The + * memory areas pointed by :member:`dest->base ` and + * :member:`src->base ` must not overlap. * * This function sets the length of unescaped string to - * :member:`dest->len `. + * :member:`dest->len `. */ -void sf_unescape(sf_vec *dest, const sf_vec *src); +void sfparse_unescape(sfparse_vec *dest, const sfparse_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. + * `sfparse_base64decode` decodes Base64 encoded string |src| and + * writes the result into |dest|. |src| should be the pointer to + * :member:`sfparse_value.vec` of type + * :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ` produced by either + * `sfparse_parser_dict`, `sfparse_parser_list`, + * `sfparse_parser_inner_list`, `sfparse_parser_item`, or + * `sfparse_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. + * :member:`dest->base ` must point to the buffer + * that has sufficient space to store the decoded byte string. * * This function sets the length of decoded byte string to - * :member:`dest->len `. + * :member:`dest->len `. */ -void sf_base64decode(sf_vec *dest, const sf_vec *src); +void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src); /** * @function * - * `sf_pctdecode` decodes percent-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_DISPSTRING` - * 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. + * `sfparse_pctdecode` decodes percent-encoded string |src| and writes + * the result into |dest|. |src| should be the pointer to + * :member:`sfparse_value.vec` of type + * :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING` produced by either + * `sfparse_parser_dict`, `sfparse_parser_list`, + * `sfparse_parser_inner_list`, `sfparse_parser_item`, or + * `sfparse_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. + * :member:`dest->base ` must point to the buffer + * that has sufficient space to store the decoded byte string. The + * memory areas pointed by :member:`dest->base ` and + * :member:`src->base ` must not overlap. * * This function sets the length of decoded byte string to - * :member:`dest->len `. + * :member:`dest->len `. */ -void sf_pctdecode(sf_vec *dest, const sf_vec *src); +void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src); #ifdef __cplusplus } -#endif +#endif /* defined(__cplusplus) */ -#endif /* SFPARSE_H */ +#endif /* !defined(SFPARSE_H) */