diff --git a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h index cd10e4def7019b..9c25c9aaf6d9bf 100644 --- a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h +++ b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h @@ -68,6 +68,12 @@ extern "C" { # endif /* !BUILDING_NGHTTP3 */ #endif /* !defined(WIN32) */ +#ifdef _MSC_VER +# define NGHTTP3_ALIGN(N) __declspec(align(N)) +#else /* !_MSC_VER */ +# define NGHTTP3_ALIGN(N) __attribute__((aligned(N))) +#endif /* !_MSC_VER */ + /** * @typedef * @@ -722,6 +728,16 @@ NGHTTP3_EXTERN void nghttp3_buf_reset(nghttp3_buf *buf); */ #define NGHTTP3_NV_FLAG_NO_COPY_VALUE 0x04u +/** + * @macro + * + * :macro:`NGHTTP3_NV_FLAG_TRY_INDEX` gives a hint to QPACK encoder to + * index a header field which is not indexed by default. This is just + * a hint, and QPACK encoder might not encode the field in various + * reasons. + */ +#define NGHTTP3_NV_FLAG_TRY_INDEX 0x08u + /** * @struct * @@ -1071,8 +1087,8 @@ typedef struct nghttp3_qpack_nv { nghttp3_rcbuf *value; /** * :member:`token` is :type:`nghttp3_qpack_token` value of - * :member:`name`. It could be -1 if we have no token for that - * header field name. + * :member:`name`. It could be -1 if we have no token for that + * header field name. */ int32_t token; /** @@ -1804,8 +1820,8 @@ typedef int (*nghttp3_reset_stream)(nghttp3_conn *conn, int64_t stream_id, typedef int (*nghttp3_shutdown)(nghttp3_conn *conn, int64_t id, void *conn_user_data); -#define NGHTTP3_CALLBACKS_VERSION_V1 1 -#define NGHTTP3_CALLBACKS_VERSION NGHTTP3_CALLBACKS_VERSION_V1 +#define NGHTTP3_CALLBACKS_V1 1 +#define NGHTTP3_CALLBACKS_VERSION NGHTTP3_CALLBACKS_V1 /** * @struct @@ -1889,8 +1905,8 @@ typedef struct nghttp3_callbacks { nghttp3_shutdown shutdown; } nghttp3_callbacks; -#define NGHTTP3_SETTINGS_VERSION_V1 1 -#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_VERSION_V1 +#define NGHTTP3_SETTINGS_V1 1 +#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_V1 /** * @struct @@ -1924,11 +1940,15 @@ typedef struct nghttp3_settings { size_t qpack_blocked_streams; /** * :member:`enable_connect_protocol`, if set to nonzero, enables - * Extended CONNECT Method (see - * https://www.ietf.org/archive/id/draft-ietf-httpbis-h3-websockets-00.html). - * Client ignores this field. + * Extended CONNECT Method (see :rfc:`9220`). Client ignores this + * field. */ - int enable_connect_protocol; + uint8_t enable_connect_protocol; + /** + * :member:`h3_datagram`, if set to nonzero, enables HTTP/3 + * Datagrams (see :rfc:`9297`). + */ + uint8_t h3_datagram; } nghttp3_settings; /** @@ -2359,7 +2379,7 @@ NGHTTP3_EXTERN int nghttp3_conn_submit_shutdown_notice(nghttp3_conn *conn); * called after `nghttp3_conn_submit_shutdown_notice` and a couple of * RTT. After calling this function, the local endpoint starts * rejecting new incoming streams. The existing streams are processed - * normally. + * normally. See also `nghttp3_conn_is_drained`. */ NGHTTP3_EXTERN int nghttp3_conn_shutdown(nghttp3_conn *conn); @@ -2417,12 +2437,15 @@ NGHTTP3_EXTERN uint64_t nghttp3_conn_get_frame_payload_left(nghttp3_conn *conn, */ #define NGHTTP3_URGENCY_LEVELS (NGHTTP3_URGENCY_LOW + 1) +#define NGHTTP3_PRI_V1 1 +#define NGHTTP3_PRI_VERSION NGHTTP3_PRI_V1 + /** * @struct * * :type:`nghttp3_pri` represents HTTP priority. */ -typedef struct nghttp3_pri { +typedef struct NGHTTP3_ALIGN(8) nghttp3_pri { /** * :member:`urgency` is the urgency of a stream, it must be in * [:macro:`NGHTTP3_URGENCY_HIGH`, :macro:`NGHTTP3_URGENCY_LOW`], @@ -2435,7 +2458,7 @@ typedef struct nghttp3_pri { * incrementally. If inc is 1, it can be processed incrementally. * Other value is not permitted. */ - int inc; + uint8_t inc; } nghttp3_pri; /** @@ -2452,26 +2475,53 @@ typedef struct nghttp3_pri { * This function returns 0 if it succeeds, or one of the following * negative error codes: * + * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` + * |stream_id| is not a client initiated bidirectional stream ID. * :macro:`NGHTTP3_ERR_STREAM_NOT_FOUND` * Stream not found. */ -NGHTTP3_EXTERN int nghttp3_conn_get_stream_priority(nghttp3_conn *conn, - nghttp3_pri *dest, - int64_t stream_id); +NGHTTP3_EXTERN int nghttp3_conn_get_stream_priority_versioned( + nghttp3_conn *conn, int pri_version, nghttp3_pri *dest, int64_t stream_id); + +/** + * @function + * + * `nghttp3_conn_set_client_stream_priority` updates priority of a + * stream denoted by |stream_id| with the value pointed by |data| of + * length |datalen|, which should be a serialized :rfc:`9218` priority + * field value. |stream_id| must identify client initiated + * bidirectional stream. + * + * This function must not be called if |conn| is initialized as + * server. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` + * |stream_id| is not a client initiated bidirectional stream ID. + * :macro:`NGHTTP3_ERR_STREAM_NOT_FOUND` + * Stream not found. + * :macro:`NGHTTP3_ERR_NOMEM` + * Out of memory. + */ +NGHTTP3_EXTERN int nghttp3_conn_set_client_stream_priority(nghttp3_conn *conn, + int64_t stream_id, + const uint8_t *data, + size_t datalen); /** * @function * - * `nghttp3_conn_set_stream_priority` updates priority of a stream - * denoted by |stream_id| with the value pointed by |pri|. + * `nghttp3_conn_set_server_stream_priority` updates priority of a + * stream denoted by |stream_id| with the value pointed by |pri|. * |stream_id| must identify client initiated bidirectional stream. * - * Both client and server can update stream priority with this - * function. + * This function must not be called if |conn| is initialized as + * client. * - * If server updates stream priority with this function, it completely - * overrides stream priority set by client and the attempts to update - * priority by client are ignored. + * This function completely overrides stream priority set by client + * and the attempts to update priority by client are ignored. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -2483,9 +2533,9 @@ NGHTTP3_EXTERN int nghttp3_conn_get_stream_priority(nghttp3_conn *conn, * :macro:`NGHTTP3_ERR_NOMEM` * Out of memory. */ -NGHTTP3_EXTERN int nghttp3_conn_set_stream_priority(nghttp3_conn *conn, - int64_t stream_id, - const nghttp3_pri *pri); +NGHTTP3_EXTERN int nghttp3_conn_set_server_stream_priority_versioned( + nghttp3_conn *conn, int64_t stream_id, int pri_version, + const nghttp3_pri *pri); /** * @function @@ -2530,21 +2580,11 @@ NGHTTP3_EXTERN int nghttp3_check_header_value(const uint8_t *value, size_t len); /** * @function * - * `nghttp3_http_parse_priority` parses priority HTTP header field - * stored in the buffer pointed by |value| of length |len|. If it - * successfully processed header field value, it stores the result - * into |*dest|. This function just overwrites what it sees in the - * header field value and does not initialize any field in |*dest|. - * - * This function returns 0 if it succeeds, or one of the following - * negative error codes: - * - * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` - * The function could not parse the provided value. + * `nghttp3_conn_is_drained` returns nonzero if + * `nghttp3_conn_shutdown` has been called, and there is no active + * remote streams. This function is for server use only. */ -NGHTTP3_EXTERN int nghttp3_http_parse_priority(nghttp3_pri *dest, - const uint8_t *value, - size_t len); +NGHTTP3_EXTERN int nghttp3_conn_is_drained(nghttp3_conn *conn); /** * @macrosection @@ -2639,6 +2679,24 @@ NGHTTP3_EXTERN int nghttp3_err_is_fatal(int liberr); (CALLBACKS), NGHTTP3_SETTINGS_VERSION, \ (SETTINGS), (MEM), (USER_DATA)) +/* + * `nghttp3_conn_set_server_stream_priority` is a wrapper around + * `nghttp3_conn_set_server_stream_priority_versioned` to set the + * correct struct version. + */ +#define nghttp3_conn_set_server_stream_priority(CONN, STREAM_ID, PRI) \ + nghttp3_conn_set_server_stream_priority_versioned( \ + (CONN), (STREAM_ID), NGHTTP3_PRI_VERSION, (PRI)) + +/* + * `nghttp3_conn_get_stream_priority` is a wrapper around + * `nghttp3_conn_get_stream_priority_versioned` to set the correct + * struct version. + */ +#define nghttp3_conn_get_stream_priority(CONN, DEST, STREAM_ID) \ + nghttp3_conn_get_stream_priority_versioned((CONN), NGHTTP3_PRI_VERSION, \ + (DEST), (STREAM_ID)) + #ifdef __cplusplus } #endif diff --git a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h index bc57eb2cfcf2d6..70511620e4fdcd 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 "0.7.0" +#define NGHTTP3_VERSION "0.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 0x000700 +#define NGHTTP3_VERSION_NUM 0x000b00 #endif /* NGHTTP3_VERSION_H */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c index 1fbb72c98af2f2..dc244ccf399883 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c @@ -33,6 +33,7 @@ #include "nghttp3_err.h" #include "nghttp3_conv.h" #include "nghttp3_http.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. */ @@ -56,7 +57,7 @@ static int conn_call_begin_headers(nghttp3_conn *conn, nghttp3_stream *stream) { return 0; } - rv = conn->callbacks.begin_headers(conn, stream->node.nid.id, conn->user_data, + rv = conn->callbacks.begin_headers(conn, stream->node.id, conn->user_data, stream->user_data); if (rv != 0) { /* TODO Allow ignore headers */ @@ -74,8 +75,8 @@ static int conn_call_end_headers(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.end_headers(conn, stream->node.nid.id, fin, - conn->user_data, stream->user_data); + rv = conn->callbacks.end_headers(conn, stream->node.id, fin, conn->user_data, + stream->user_data); if (rv != 0) { /* TODO Allow ignore headers */ return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -92,8 +93,8 @@ static int conn_call_begin_trailers(nghttp3_conn *conn, return 0; } - rv = conn->callbacks.begin_trailers(conn, stream->node.nid.id, - conn->user_data, stream->user_data); + rv = conn->callbacks.begin_trailers(conn, stream->node.id, conn->user_data, + stream->user_data); if (rv != 0) { /* TODO Allow ignore headers */ return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -110,8 +111,8 @@ static int conn_call_end_trailers(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.end_trailers(conn, stream->node.nid.id, fin, - conn->user_data, stream->user_data); + rv = conn->callbacks.end_trailers(conn, stream->node.id, fin, conn->user_data, + stream->user_data); if (rv != 0) { /* TODO Allow ignore headers */ return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -127,7 +128,7 @@ static int conn_call_end_stream(nghttp3_conn *conn, nghttp3_stream *stream) { return 0; } - rv = conn->callbacks.end_stream(conn, stream->node.nid.id, conn->user_data, + rv = conn->callbacks.end_stream(conn, stream->node.id, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -144,7 +145,7 @@ static int conn_call_stop_sending(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.stop_sending(conn, stream->node.nid.id, app_error_code, + rv = conn->callbacks.stop_sending(conn, stream->node.id, app_error_code, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -161,7 +162,7 @@ static int conn_call_reset_stream(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.reset_stream(conn, stream->node.nid.id, app_error_code, + rv = conn->callbacks.reset_stream(conn, stream->node.id, app_error_code, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -179,7 +180,7 @@ static int conn_call_deferred_consume(nghttp3_conn *conn, return 0; } - rv = conn->callbacks.deferred_consume(conn, stream->node.nid.id, nconsumed, + rv = conn->callbacks.deferred_consume(conn, stream->node.id, nconsumed, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -204,7 +205,7 @@ static int cycle_less(const nghttp3_pq_entry *lhsx, const nghttp3_tnode *rhs = nghttp3_struct_of(rhsx, nghttp3_tnode, pe); if (lhs->cycle == rhs->cycle) { - return lhs->seq < rhs->seq; + return lhs->id < rhs->id; } return rhs->cycle - lhs->cycle <= NGHTTP3_TNODE_MAX_CYCLE_GAP; @@ -264,7 +265,6 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version, nghttp3_settings_default(&conn->remote.settings); conn->mem = mem; conn->user_data = user_data; - conn->next_seq = 0; conn->server = server; conn->rx.goaway_id = NGHTTP3_VARINT_MAX + 1; conn->tx.goaway_id = NGHTTP3_VARINT_MAX + 1; @@ -454,12 +454,6 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id, stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; } } - } else if (nghttp3_stream_uni(stream_id) && - stream->type == NGHTTP3_STREAM_TYPE_PUSH) { - if (stream->rx.hstate == NGHTTP3_HTTP_STATE_NONE) { - stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL; - stream->tx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL; - } } if (srclen == 0 && !fin) { @@ -603,8 +597,7 @@ nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream, } break; default: - /* unreachable */ - assert(0); + nghttp3_unreachable(); } if (nconsumed < 0) { @@ -1013,8 +1006,7 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, nghttp3_stream_read_state_reset(rstate); break; default: - /* unreachable */ - assert(0); + nghttp3_unreachable(); } } @@ -1022,7 +1014,7 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn, } static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream) { - int bidi = nghttp3_client_stream_bidi(stream->node.nid.id); + int bidi = nghttp3_client_stream_bidi(stream->node.id); int rv; rv = conn_call_deferred_consume(conn, stream, @@ -1032,16 +1024,21 @@ static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream) { } if (bidi && conn->callbacks.stream_close) { - rv = conn->callbacks.stream_close(conn, stream->node.nid.id, - stream->error_code, conn->user_data, - stream->user_data); + rv = conn->callbacks.stream_close(conn, stream->node.id, stream->error_code, + conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; } } - rv = nghttp3_map_remove(&conn->streams, - (nghttp3_map_key_type)stream->node.nid.id); + if (conn->server && nghttp3_client_stream_bidi(stream->node.id)) { + assert(conn->remote.bidi.num_streams > 0); + + --conn->remote.bidi.num_streams; + } + + rv = + nghttp3_map_remove(&conn->streams, (nghttp3_map_key_type)stream->node.id); assert(0 == rv); @@ -1058,7 +1055,7 @@ static int conn_process_blocked_stream_data(nghttp3_conn *conn, int rv; size_t len; - assert(nghttp3_client_stream_bidi(stream->node.nid.id)); + assert(nghttp3_client_stream_bidi(stream->node.id)); for (;;) { len = nghttp3_ringbuf_len(&stream->inq); @@ -1149,16 +1146,17 @@ static nghttp3_tnode *stream_get_sched_node(nghttp3_stream *stream) { } static int conn_update_stream_priority(nghttp3_conn *conn, - nghttp3_stream *stream, uint8_t pri) { - assert(nghttp3_client_stream_bidi(stream->node.nid.id)); + nghttp3_stream *stream, + const nghttp3_pri *pri) { + assert(nghttp3_client_stream_bidi(stream->node.id)); - if (stream->node.pri == pri) { + if (nghttp3_pri_eq(&stream->node.pri, pri)) { return 0; } nghttp3_conn_unschedule_stream(conn, stream); - stream->node.pri = pri; + stream->node.pri = *pri; if (nghttp3_stream_require_schedule(stream)) { return nghttp3_conn_schedule_stream(conn, stream); @@ -1286,8 +1284,7 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, rv = conn_call_begin_trailers(conn, stream); break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } if (rv != 0) { @@ -1377,9 +1374,7 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, rv = 0; break; default: - /* Unreachable */ - assert(0); - abort(); + nghttp3_unreachable(); } if (rv != 0) { @@ -1398,7 +1393,7 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, (stream->rx.http.flags & NGHTTP3_HTTP_FLAG_PRIORITY) && !(stream->flags & NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED) && !(stream->flags & NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET)) { - rv = conn_update_stream_priority(conn, stream, stream->rx.http.pri); + rv = conn_update_stream_priority(conn, stream, &stream->rx.http.pri); if (rv != 0) { return rv; } @@ -1412,8 +1407,7 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc, rv = conn_call_end_trailers(conn, stream, p == end && fin); break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } if (rv != 0) { @@ -1505,7 +1499,7 @@ int nghttp3_conn_on_data(nghttp3_conn *conn, nghttp3_stream *stream, return 0; } - rv = conn->callbacks.recv_data(conn, stream->node.nid.id, data, datalen, + rv = conn->callbacks.recv_data(conn, stream->node.id, data, datalen, conn->user_data, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -1515,11 +1509,9 @@ int nghttp3_conn_on_data(nghttp3_conn *conn, nghttp3_stream *stream, } static nghttp3_pq *conn_get_sched_pq(nghttp3_conn *conn, nghttp3_tnode *tnode) { - uint32_t urgency = nghttp3_pri_uint8_urgency(tnode->pri); - - assert(urgency < NGHTTP3_URGENCY_LEVELS); + assert(tnode->pri.urgency < NGHTTP3_URGENCY_LEVELS); - return &conn->sched[urgency].spq; + return &conn->sched[tnode->pri.urgency].spq; } static nghttp3_ssize conn_decode_headers(nghttp3_conn *conn, @@ -1552,8 +1544,7 @@ static nghttp3_ssize conn_decode_headers(nghttp3_conn *conn, recv_header = conn->callbacks.recv_trailer; break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } http = &stream->rx.http; @@ -1606,17 +1597,15 @@ static nghttp3_ssize conn_decode_headers(nghttp3_conn *conn, break; case 0: if (recv_header) { - rv = recv_header(conn, stream->node.nid.id, nv.token, nv.name, - nv.value, nv.flags, conn->user_data, - stream->user_data); + rv = recv_header(conn, stream->node.id, nv.token, nv.name, nv.value, + nv.flags, conn->user_data, stream->user_data); if (rv != 0) { rv = NGHTTP3_ERR_CALLBACK_FAILURE; } } break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } nghttp3_rcbuf_decref(nv.name); @@ -1684,13 +1673,32 @@ int nghttp3_conn_on_settings_entry_received(nghttp3_conn *conn, if (!conn->server) { break; } - if (ent->value != 0 && ent->value != 1) { + + switch (ent->value) { + case 0: + if (dest->enable_connect_protocol) { + return NGHTTP3_ERR_H3_SETTINGS_ERROR; + } + + break; + case 1: + break; + default: return NGHTTP3_ERR_H3_SETTINGS_ERROR; } - if (ent->value == 0 && dest->enable_connect_protocol) { + + dest->enable_connect_protocol = (uint8_t)ent->value; + break; + case NGHTTP3_SETTINGS_ID_H3_DATAGRAM: + switch (ent->value) { + case 0: + case 1: + break; + default: return NGHTTP3_ERR_H3_SETTINGS_ERROR; } - dest->enable_connect_protocol = (int)ent->value; + + dest->h3_datagram = (uint8_t)ent->value; break; case NGHTTP3_H2_SETTINGS_ID_ENABLE_PUSH: case NGHTTP3_H2_SETTINGS_ID_MAX_CONCURRENT_STREAMS: @@ -1744,7 +1752,7 @@ conn_on_priority_update_stream(nghttp3_conn *conn, return rv; } - stream->node.pri = nghttp3_pri_to_uint8(&fr->pri); + stream->node.pri = fr->pri; stream->flags |= NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED; return 0; @@ -1756,8 +1764,7 @@ conn_on_priority_update_stream(nghttp3_conn *conn, stream->flags |= NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED; - return conn_update_stream_priority(conn, stream, - nghttp3_pri_to_uint8(&fr->pri)); + return conn_update_stream_priority(conn, stream, &fr->pri); } int nghttp3_conn_on_priority_update(nghttp3_conn *conn, @@ -1794,7 +1801,7 @@ int nghttp3_conn_create_stream(nghttp3_conn *conn, nghttp3_stream **pstream, conn_stream_acked_data, }; - rv = nghttp3_stream_new(&stream, stream_id, conn->next_seq, &callbacks, + rv = nghttp3_stream_new(&stream, stream_id, &callbacks, &conn->out_chunk_objalloc, &conn->stream_objalloc, conn->mem); if (rv != 0) { @@ -1803,14 +1810,17 @@ int nghttp3_conn_create_stream(nghttp3_conn *conn, nghttp3_stream **pstream, stream->conn = conn; - rv = nghttp3_map_insert(&conn->streams, - (nghttp3_map_key_type)stream->node.nid.id, stream); + rv = nghttp3_map_insert(&conn->streams, (nghttp3_map_key_type)stream->node.id, + stream); if (rv != 0) { nghttp3_stream_del(stream); return rv; } - ++conn->next_seq; + if (conn->server && nghttp3_client_stream_bidi(stream_id)) { + ++conn->remote.bidi.num_streams; + } + *pstream = stream; return 0; @@ -1910,14 +1920,14 @@ static nghttp3_ssize conn_writev_stream(nghttp3_conn *conn, int64_t *pstream_id, } } - if (!nghttp3_stream_uni(stream->node.nid.id) && conn->tx.qenc && + if (!nghttp3_stream_uni(stream->node.id) && conn->tx.qenc && !nghttp3_stream_is_blocked(conn->tx.qenc)) { n = nghttp3_stream_writev(conn->tx.qenc, pfin, vec, veccnt); if (n < 0) { return n; } if (n) { - *pstream_id = conn->tx.qenc->node.nid.id; + *pstream_id = conn->tx.qenc->node.id; return n; } } @@ -1932,7 +1942,7 @@ static nghttp3_ssize conn_writev_stream(nghttp3_conn *conn, int64_t *pstream_id, return 0; } - *pstream_id = stream->node.nid.id; + *pstream_id = stream->node.id; return n; } @@ -1990,7 +2000,7 @@ nghttp3_ssize nghttp3_conn_writev_stream(nghttp3_conn *conn, return ncnt; } - if (nghttp3_client_stream_bidi(stream->node.nid.id) && + if (nghttp3_client_stream_bidi(stream->node.id) && !nghttp3_stream_require_schedule(stream)) { nghttp3_conn_unschedule_stream(conn, stream); } @@ -2033,7 +2043,7 @@ int nghttp3_conn_add_write_offset(nghttp3_conn *conn, int64_t stream_id, stream->unscheduled_nwrite += n; - if (!nghttp3_client_stream_bidi(stream->node.nid.id)) { + if (!nghttp3_client_stream_bidi(stream->node.id)) { return 0; } @@ -2065,7 +2075,7 @@ 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; + nghttp3_frame_entry frent = {0}; rv = nghttp3_nva_copy(&nnva, nva, nvlen, conn->mem); if (rv != 0) { @@ -2235,7 +2245,7 @@ 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; + nghttp3_frame_entry frent = {0}; int rv; assert(conn->tx.ctrl); @@ -2258,7 +2268,7 @@ int nghttp3_conn_submit_shutdown_notice(nghttp3_conn *conn) { } int nghttp3_conn_shutdown(nghttp3_conn *conn) { - nghttp3_frame_entry frent; + nghttp3_frame_entry frent = {0}; int rv; assert(conn->tx.ctrl); @@ -2279,7 +2289,8 @@ int nghttp3_conn_shutdown(nghttp3_conn *conn) { } conn->tx.goaway_id = frent.fr.goaway.id; - conn->flags |= NGHTTP3_CONN_FLAG_GOAWAY_QUEUED; + conn->flags |= + NGHTTP3_CONN_FLAG_GOAWAY_QUEUED | NGHTTP3_CONN_FLAG_SHUTDOWN_COMMENCED; return 0; } @@ -2305,7 +2316,7 @@ void nghttp3_conn_block_stream(nghttp3_conn *conn, int64_t stream_id) { stream->flags |= NGHTTP3_STREAM_FLAG_FC_BLOCKED; stream->unscheduled_nwrite = 0; - if (nghttp3_client_stream_bidi(stream->node.nid.id)) { + if (nghttp3_client_stream_bidi(stream->node.id)) { nghttp3_conn_unschedule_stream(conn, stream); } } @@ -2320,7 +2331,7 @@ void nghttp3_conn_shutdown_stream_write(nghttp3_conn *conn, int64_t stream_id) { stream->flags |= NGHTTP3_STREAM_FLAG_SHUT_WR; stream->unscheduled_nwrite = 0; - if (nghttp3_client_stream_bidi(stream->node.nid.id)) { + if (nghttp3_client_stream_bidi(stream->node.id)) { nghttp3_conn_unschedule_stream(conn, stream); } } @@ -2334,7 +2345,7 @@ int nghttp3_conn_unblock_stream(nghttp3_conn *conn, int64_t stream_id) { stream->flags &= (uint16_t)~NGHTTP3_STREAM_FLAG_FC_BLOCKED; - if (nghttp3_client_stream_bidi(stream->node.nid.id) && + if (nghttp3_client_stream_bidi(stream->node.id) && nghttp3_stream_require_schedule(stream)) { return nghttp3_conn_ensure_stream_scheduled(conn, stream); } @@ -2364,7 +2375,7 @@ int nghttp3_conn_resume_stream(nghttp3_conn *conn, int64_t stream_id) { stream->flags &= (uint16_t)~NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED; - if (nghttp3_client_stream_bidi(stream->node.nid.id) && + if (nghttp3_client_stream_bidi(stream->node.id) && nghttp3_stream_require_schedule(stream)) { return nghttp3_conn_ensure_stream_scheduled(conn, stream); } @@ -2381,7 +2392,6 @@ int nghttp3_conn_close_stream(nghttp3_conn *conn, int64_t stream_id, } if (nghttp3_stream_uni(stream_id) && - stream->type != NGHTTP3_STREAM_TYPE_PUSH && stream->type != NGHTTP3_STREAM_TYPE_UNKNOWN) { return NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM; } @@ -2468,9 +2478,12 @@ uint64_t nghttp3_conn_get_frame_payload_left(nghttp3_conn *conn, return (uint64_t)stream->rstate.left; } -int nghttp3_conn_get_stream_priority(nghttp3_conn *conn, nghttp3_pri *dest, - int64_t stream_id) { +int nghttp3_conn_get_stream_priority_versioned(nghttp3_conn *conn, + int pri_version, + nghttp3_pri *dest, + int64_t stream_id) { nghttp3_stream *stream; + (void)pri_version; assert(conn->server); @@ -2483,19 +2496,20 @@ int nghttp3_conn_get_stream_priority(nghttp3_conn *conn, nghttp3_pri *dest, return NGHTTP3_ERR_STREAM_NOT_FOUND; } - dest->urgency = nghttp3_pri_uint8_urgency(stream->node.pri); - dest->inc = nghttp3_pri_uint8_inc(stream->node.pri); + *dest = stream->node.pri; return 0; } -int nghttp3_conn_set_stream_priority(nghttp3_conn *conn, int64_t stream_id, - const nghttp3_pri *pri) { +int nghttp3_conn_set_client_stream_priority(nghttp3_conn *conn, + int64_t stream_id, + const uint8_t *data, + size_t datalen) { nghttp3_stream *stream; - nghttp3_frame_entry frent; + nghttp3_frame_entry frent = {0}; + uint8_t *buf = NULL; - assert(pri->urgency < NGHTTP3_URGENCY_LEVELS); - assert(pri->inc == 0 || pri->inc == 1); + assert(!conn->server); if (!nghttp3_client_stream_bidi(stream_id)) { return NGHTTP3_ERR_INVALID_ARGUMENT; @@ -2506,19 +2520,48 @@ int nghttp3_conn_set_stream_priority(nghttp3_conn *conn, int64_t stream_id, return NGHTTP3_ERR_STREAM_NOT_FOUND; } - if (conn->server) { - stream->flags |= NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET; + if (datalen) { + buf = nghttp3_mem_malloc(conn->mem, datalen); + if (buf == NULL) { + return NGHTTP3_ERR_NOMEM; + } - return conn_update_stream_priority(conn, stream, nghttp3_pri_to_uint8(pri)); + memcpy(buf, data, datalen); } frent.fr.hd.type = NGHTTP3_FRAME_PRIORITY_UPDATE; frent.fr.priority_update.pri_elem_id = stream_id; - frent.fr.priority_update.pri = *pri; + frent.fr.priority_update.data = buf; + frent.fr.priority_update.datalen = datalen; return nghttp3_stream_frq_add(conn->tx.ctrl, &frent); } +int nghttp3_conn_set_server_stream_priority_versioned(nghttp3_conn *conn, + int64_t stream_id, + int pri_version, + const nghttp3_pri *pri) { + nghttp3_stream *stream; + (void)pri_version; + + assert(conn->server); + assert(pri->urgency < NGHTTP3_URGENCY_LEVELS); + assert(pri->inc == 0 || pri->inc == 1); + + if (!nghttp3_client_stream_bidi(stream_id)) { + return NGHTTP3_ERR_INVALID_ARGUMENT; + } + + stream = nghttp3_conn_find_stream(conn, stream_id); + if (stream == NULL) { + return NGHTTP3_ERR_STREAM_NOT_FOUND; + } + + stream->flags |= NGHTTP3_STREAM_FLAG_SERVER_PRIORITY_SET; + + return conn_update_stream_priority(conn, stream, pri); +} + int nghttp3_conn_is_remote_qpack_encoder_stream(nghttp3_conn *conn, int64_t stream_id) { nghttp3_stream *stream; @@ -2531,6 +2574,15 @@ int nghttp3_conn_is_remote_qpack_encoder_stream(nghttp3_conn *conn, return stream && stream->type == NGHTTP3_STREAM_TYPE_QPACK_ENCODER; } +int nghttp3_conn_is_drained(nghttp3_conn *conn) { + assert(conn->server); + + return (conn->flags & NGHTTP3_CONN_FLAG_SHUTDOWN_COMMENCED) && + conn->remote.bidi.num_streams == 0 && + 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; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h index fa7071e4b1ddb7..fef4917e2661a6 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.h @@ -62,6 +62,9 @@ /* NGHTTP3_CONN_FLAG_QPACK_DECODER_OPENED is set when a QPACK decoder stream has opened. */ #define NGHTTP3_CONN_FLAG_QPACK_DECODER_OPENED 0x0008u +/* NGHTTP3_CONN_FLAG_SHUTDOWN_COMMENCED is set when graceful shutdown + has started. */ +#define NGHTTP3_CONN_FLAG_SHUTDOWN_COMMENCED 0x0010u /* NGHTTP3_CONN_FLAG_GOAWAY_RECVED indicates that GOAWAY frame has received. */ #define NGHTTP3_CONN_FLAG_GOAWAY_RECVED 0x0020u @@ -90,7 +93,6 @@ struct nghttp3_conn { void *user_data; int server; uint16_t flags; - uint64_t next_seq; struct { nghttp3_settings settings; @@ -109,6 +111,10 @@ struct nghttp3_conn { initiated bidirectional stream ID the remote endpoint can issue. This field is used on server side only. */ uint64_t max_client_streams; + /* num_streams is the number of client initiated bidirectional + streams that are currently open. This field is for server + use only. */ + size_t num_streams; } bidi; nghttp3_settings settings; } remote; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c index cb340ab5a11363..edd0adc4d0ff0a 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c @@ -29,6 +29,7 @@ #include #include "nghttp3_str.h" +#include "nghttp3_unreachable.h" int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p) { union { @@ -38,7 +39,7 @@ int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p) { uint64_t n64; } n; - *plen = 1u << (*p >> 6); + *plen = (size_t)(1u << (*p >> 6)); switch (*plen) { case 1: @@ -57,34 +58,25 @@ int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p) { return (int64_t)nghttp3_ntohl64(n.n64); } - assert(0); - abort(); + nghttp3_unreachable(); } int64_t nghttp3_get_varint_fb(const uint8_t *p) { return *p & 0x3f; } -size_t nghttp3_get_varint_len(const uint8_t *p) { return 1u << (*p >> 6); } +size_t nghttp3_get_varintlen(const uint8_t *p) { + return (size_t)(1u << (*p >> 6)); +} uint8_t *nghttp3_put_uint64be(uint8_t *p, uint64_t n) { n = nghttp3_htonl64(n); return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n)); } -uint8_t *nghttp3_put_uint48be(uint8_t *p, uint64_t n) { - n = nghttp3_htonl64(n); - return nghttp3_cpymem(p, ((const uint8_t *)&n) + 2, 6); -} - uint8_t *nghttp3_put_uint32be(uint8_t *p, uint32_t n) { n = htonl(n); return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n)); } -uint8_t *nghttp3_put_uint24be(uint8_t *p, uint32_t n) { - n = htonl(n); - return nghttp3_cpymem(p, ((const uint8_t *)&n) + 1, 3); -} - uint8_t *nghttp3_put_uint16be(uint8_t *p, uint16_t n) { n = htons(n); return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n)); @@ -112,7 +104,7 @@ uint8_t *nghttp3_put_varint(uint8_t *p, int64_t n) { return rv; } -size_t nghttp3_put_varint_len(int64_t n) { +size_t nghttp3_put_varintlen(int64_t n) { if (n < 64) { return 1; } @@ -129,7 +121,3 @@ size_t nghttp3_put_varint_len(int64_t n) { uint64_t nghttp3_ord_stream_id(int64_t stream_id) { return (uint64_t)(stream_id >> 2) + 1; } - -uint8_t nghttp3_pri_to_uint8(const nghttp3_pri *pri) { - return (uint8_t)((uint32_t)pri->inc << 7 | pri->urgency); -} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h index 23555be7cac027..2905457fe1f110 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h @@ -106,9 +106,9 @@ STIN uint16_t htons(uint16_t hostshort) { STIN uint32_t ntohl(uint32_t netlong) { uint32_t res; unsigned char *p = (unsigned char *)&netlong; - res = *p++ << 24; - res += *p++ << 16; - res += *p++ << 8; + res = (uint32_t)(*p++ << 24); + res += (uint32_t)(*p++ << 16); + res += (uint32_t)(*p++ << 8); res += *p; return res; } @@ -116,7 +116,7 @@ STIN uint32_t ntohl(uint32_t netlong) { STIN uint16_t ntohs(uint16_t netshort) { uint16_t res; unsigned char *p = (unsigned char *)&netshort; - res = *p++ << 8; + res = (uint16_t)(*p++ << 8); res += *p; return res; } @@ -137,10 +137,10 @@ int64_t nghttp3_get_varint(size_t *plen, const uint8_t *p); int64_t nghttp3_get_varint_fb(const uint8_t *p); /* - * nghttp3_get_varint_len returns the required number of bytes to read + * nghttp3_get_varintlen returns the required number of bytes to read * variable-length integer starting at |p|. */ -size_t nghttp3_get_varint_len(const uint8_t *p); +size_t nghttp3_get_varintlen(const uint8_t *p); /* * nghttp3_put_uint64be writes |n| in host byte order in |p| in @@ -149,13 +149,6 @@ size_t nghttp3_get_varint_len(const uint8_t *p); */ uint8_t *nghttp3_put_uint64be(uint8_t *p, uint64_t n); -/* - * nghttp3_put_uint48be writes |n| in host byte order in |p| in - * network byte order. It writes only least significant 48 bits. It - * returns the one beyond of the last written position. - */ -uint8_t *nghttp3_put_uint48be(uint8_t *p, uint64_t n); - /* * nghttp3_put_uint32be writes |n| in host byte order in |p| in * network byte order. It returns the one beyond of the last written @@ -163,13 +156,6 @@ uint8_t *nghttp3_put_uint48be(uint8_t *p, uint64_t n); */ uint8_t *nghttp3_put_uint32be(uint8_t *p, uint32_t n); -/* - * nghttp3_put_uint24be writes |n| in host byte order in |p| in - * network byte order. It writes only least significant 24 bits. It - * returns the one beyond of the last written position. - */ -uint8_t *nghttp3_put_uint24be(uint8_t *p, uint32_t n); - /* * nghttp3_put_uint16be writes |n| in host byte order in |p| in * network byte order. It returns the one beyond of the last written @@ -184,10 +170,10 @@ uint8_t *nghttp3_put_uint16be(uint8_t *p, uint16_t n); uint8_t *nghttp3_put_varint(uint8_t *p, int64_t n); /* - * nghttp3_put_varint_len returns the required number of bytes to + * nghttp3_put_varintlen returns the required number of bytes to * encode |n|. */ -size_t nghttp3_put_varint_len(int64_t n); +size_t nghttp3_put_varintlen(int64_t n); /* * nghttp3_ord_stream_id returns the ordinal number of |stream_id|. @@ -200,22 +186,4 @@ uint64_t nghttp3_ord_stream_id(int64_t stream_id); */ #define NGHTTP3_PRI_INC_MASK (1 << 7) -/* - * nghttp3_pri_to_uint8 encodes |pri| into uint8_t variable. - */ -uint8_t nghttp3_pri_to_uint8(const nghttp3_pri *pri); - -/* - * nghttp3_pri_uint8_urgency extracts urgency from |PRI| which is - * supposed to be constructed by nghttp3_pri_to_uint8. - */ -#define nghttp3_pri_uint8_urgency(PRI) \ - ((uint32_t)((PRI) & ~NGHTTP3_PRI_INC_MASK)) - -/* - * nghttp3_pri_uint8_inc extracts inc from |PRI| which is supposed to - * be constructed by nghttp3_pri_to_uint8. - */ -#define nghttp3_pri_uint8_inc(PRI) (((PRI)&NGHTTP3_PRI_INC_MASK) != 0) - #endif /* NGHTTP3_CONV_H */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c index 38c395ebe16162..1488a9af2ea060 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.c @@ -38,7 +38,7 @@ uint8_t *nghttp3_frame_write_hd(uint8_t *p, const nghttp3_frame_hd *hd) { } size_t nghttp3_frame_write_hd_len(const nghttp3_frame_hd *hd) { - return nghttp3_put_varint_len(hd->type) + nghttp3_put_varint_len(hd->length); + return nghttp3_put_varintlen(hd->type) + nghttp3_put_varintlen(hd->length); } uint8_t *nghttp3_frame_write_settings(uint8_t *p, @@ -61,14 +61,14 @@ size_t nghttp3_frame_write_settings_len(int64_t *ppayloadlen, size_t i; for (i = 0; i < fr->niv; ++i) { - payloadlen += nghttp3_put_varint_len((int64_t)fr->iv[i].id) + - nghttp3_put_varint_len((int64_t)fr->iv[i].value); + payloadlen += nghttp3_put_varintlen((int64_t)fr->iv[i].id) + + nghttp3_put_varintlen((int64_t)fr->iv[i].value); } *ppayloadlen = (int64_t)payloadlen; - return nghttp3_put_varint_len(NGHTTP3_FRAME_SETTINGS) + - nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen; + return nghttp3_put_varintlen(NGHTTP3_FRAME_SETTINGS) + + nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; } uint8_t *nghttp3_frame_write_goaway(uint8_t *p, @@ -81,12 +81,12 @@ uint8_t *nghttp3_frame_write_goaway(uint8_t *p, size_t nghttp3_frame_write_goaway_len(int64_t *ppayloadlen, const nghttp3_frame_goaway *fr) { - size_t payloadlen = nghttp3_put_varint_len(fr->id); + size_t payloadlen = nghttp3_put_varintlen(fr->id); *ppayloadlen = (int64_t)payloadlen; - return nghttp3_put_varint_len(NGHTTP3_FRAME_GOAWAY) + - nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen; + return nghttp3_put_varintlen(NGHTTP3_FRAME_GOAWAY) + + nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; } uint8_t * @@ -94,17 +94,8 @@ nghttp3_frame_write_priority_update(uint8_t *p, const nghttp3_frame_priority_update *fr) { p = nghttp3_frame_write_hd(p, &fr->hd); p = nghttp3_put_varint(p, fr->pri_elem_id); - - assert(fr->pri.urgency <= NGHTTP3_URGENCY_LOW); - - *p++ = 'u'; - *p++ = '='; - *p++ = (uint8_t)('0' + fr->pri.urgency); - - if (fr->pri.inc) { -#define NGHTTP3_PRIORITY_INCREMENTAL ", i" - p = nghttp3_cpymem(p, (const uint8_t *)NGHTTP3_PRIORITY_INCREMENTAL, - sizeof(NGHTTP3_PRIORITY_INCREMENTAL) - 1); + if (fr->datalen) { + p = nghttp3_cpymem(p, fr->data, fr->datalen); } return p; @@ -112,13 +103,12 @@ nghttp3_frame_write_priority_update(uint8_t *p, size_t nghttp3_frame_write_priority_update_len( int64_t *ppayloadlen, const nghttp3_frame_priority_update *fr) { - size_t payloadlen = nghttp3_put_varint_len(fr->pri_elem_id) + sizeof("u=U") - - 1 + (fr->pri.inc ? sizeof(", i") - 1 : 0); + size_t payloadlen = nghttp3_put_varintlen(fr->pri_elem_id) + fr->datalen; *ppayloadlen = (int64_t)payloadlen; - return nghttp3_put_varint_len(fr->hd.type) + - nghttp3_put_varint_len((int64_t)payloadlen) + payloadlen; + return nghttp3_put_varintlen(fr->hd.type) + + nghttp3_put_varintlen((int64_t)payloadlen) + payloadlen; } int nghttp3_nva_copy(nghttp3_nv **pnva, const nghttp3_nv *nva, size_t nvlen, @@ -202,3 +192,12 @@ void nghttp3_frame_headers_free(nghttp3_frame_headers *fr, nghttp3_nva_del(fr->nva, mem); } + +void nghttp3_frame_priority_update_free(nghttp3_frame_priority_update *fr, + const nghttp3_mem *mem) { + if (fr == NULL) { + return; + } + + nghttp3_mem_free(mem, fr->data); +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h index b64bbc4ecb9667..52407d1284cce1 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_frame.h @@ -42,8 +42,7 @@ typedef enum nghttp3_frame_type { NGHTTP3_FRAME_PUSH_PROMISE = 0x05, NGHTTP3_FRAME_GOAWAY = 0x07, NGHTTP3_FRAME_MAX_PUSH_ID = 0x0d, - /* PRIORITY_UPDATE: - https://tools.ietf.org/html/draft-ietf-httpbis-priority-03 */ + /* PRIORITY_UPDATE: https://datatracker.ietf.org/doc/html/rfc9218 */ NGHTTP3_FRAME_PRIORITY_UPDATE = 0x0f0700, NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID = 0x0f0701, } nghttp3_frame_type; @@ -74,6 +73,7 @@ typedef struct nghttp3_frame_headers { #define NGHTTP3_SETTINGS_ID_QPACK_MAX_TABLE_CAPACITY 0x01 #define NGHTTP3_SETTINGS_ID_QPACK_BLOCKED_STREAMS 0x07 #define NGHTTP3_SETTINGS_ID_ENABLE_CONNECT_PROTOCOL 0x08 +#define NGHTTP3_SETTINGS_ID_H3_DATAGRAM 0x33 #define NGHTTP3_H2_SETTINGS_ID_ENABLE_PUSH 0x2 #define NGHTTP3_H2_SETTINGS_ID_MAX_CONCURRENT_STREAMS 0x3 @@ -103,7 +103,17 @@ typedef struct nghttp3_frame_priority_update { NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID. It is undefined otherwise. */ int64_t pri_elem_id; - nghttp3_pri pri; + /* When sending this frame, data should point to the buffer + containing a serialized priority field value and its length is + set to datalen. On reception, pri contains the decoded priority + header value. */ + union { + nghttp3_pri pri; + struct { + uint8_t *data; + size_t datalen; + }; + }; } nghttp3_frame_priority_update; typedef union nghttp3_frame { @@ -212,4 +222,11 @@ void nghttp3_nva_del(nghttp3_nv *nva, const nghttp3_mem *mem); void nghttp3_frame_headers_free(nghttp3_frame_headers *fr, const nghttp3_mem *mem); +/* + * nghttp3_frame_priority_update_free frees memory allocated for |fr|. + * This function should only be called for an outgoing frame. + */ +void nghttp3_frame_priority_update_free(nghttp3_frame_priority_update *fr, + const nghttp3_mem *mem); + #endif /* NGHTTP3_FRAME_H */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_http.c b/deps/ngtcp2/nghttp3/lib/nghttp3_http.c index 5e06d8c47658e1..3b287a06e3afbb 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_http.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_http.c @@ -31,6 +31,8 @@ #include "nghttp3_stream.h" #include "nghttp3_macro.h" #include "nghttp3_conv.h" +#include "nghttp3_unreachable.h" +#include "sfparse.h" static uint8_t downcase(uint8_t c) { return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c; @@ -105,717 +107,61 @@ static int check_path_flags(nghttp3_http_state *http) { (http->flags & NGHTTP3_HTTP_FLAG_PATH_ASTERISK))); } -/* Generated by genchartbl.py */ -static const int SF_KEY_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, - 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */, - 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */, - 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */, - 0 /* ( */, 0 /* ) */, 1 /* * */, 0 /* + */, 0 /* , */, - 1 /* - */, 1 /* . */, 0 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, - 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */, - 0 /* A */, 0 /* B */, 0 /* C */, 0 /* D */, 0 /* E */, - 0 /* F */, 0 /* G */, 0 /* H */, 0 /* I */, 0 /* J */, - 0 /* K */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */, - 0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* T */, - 0 /* U */, 0 /* V */, 0 /* W */, 0 /* X */, 0 /* Y */, - 0 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */, - 1 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */, - 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static nghttp3_ssize sf_parse_key(const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - - if ((*p < 'a' || 'z' < *p) && *p != '*') { - return -1; - } - - for (; p != end && SF_KEY_CHARS[*p]; ++p) - ; - - return p - begin; -} - -static nghttp3_ssize sf_parse_integer_or_decimal(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - int sign = 1; - int64_t value = 0; - int type = NGHTTP3_SF_VALUE_TYPE_INTEGER; - size_t len = 0; - size_t fpos = 0; - size_t i; - - if (*p == '-') { - if (++p == end) { - return -1; - } - - sign = -1; - } - - if (*p < '0' || '9' < *p) { - return -1; - } - - for (; p != end; ++p) { - switch (*p) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - value *= 10; - value += *p - '0'; - - if (++len > 15) { - return -1; - } - - break; - case '.': - if (type != NGHTTP3_SF_VALUE_TYPE_INTEGER) { - goto fin; - } - - if (len > 12) { - return -1; - } - fpos = len; - type = NGHTTP3_SF_VALUE_TYPE_DECIMAL; - - break; - default: - goto fin; - }; - } - -fin: - switch (type) { - case NGHTTP3_SF_VALUE_TYPE_INTEGER: - if (dest) { - dest->type = (uint8_t)type; - dest->i = value * sign; - } - - return p - begin; - case NGHTTP3_SF_VALUE_TYPE_DECIMAL: - if (fpos == len || len - fpos > 3) { - return -1; - } - - if (dest) { - dest->type = (uint8_t)type; - dest->d = (double)value; - for (i = len - fpos; i > 0; --i) { - dest->d /= (double)10; - } - dest->d *= sign; - } - - return p - begin; - default: - assert(0); - abort(); - } -} - -/* Generated by genchartbl.py */ -static const int SF_DQUOTE_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, - 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */, - 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 1 /* SPC */, 1 /* ! */, 0 /* " */, - 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* , */, - 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, - 1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* @ */, - 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */, - 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */, - 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */, - 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */, - 1 /* Z */, 1 /* [ */, 0 /* \ */, 1 /* ] */, 1 /* ^ */, - 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* | */, - 1 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static nghttp3_ssize sf_parse_string(nghttp3_sf_value *dest, - const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - - if (*p++ != '"') { - return -1; - } - - for (; p != end; ++p) { - switch (*p) { - case '\\': - if (++p == end) { - return -1; - } - - switch (*p) { - case '"': - case '\\': - break; - default: - return -1; - } - - break; - case '"': - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_STRING; - dest->s.base = begin + 1; - dest->s.len = (size_t)(p - dest->s.base); - } - - ++p; - - return p - begin; - default: - if (!SF_DQUOTE_CHARS[*p]) { - return -1; - } - } - } - - return -1; -} - -/* Generated by genchartbl.py */ -static const int SF_TOKEN_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, - 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */, - 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 0 /* SPC */, 1 /* ! */, 0 /* " */, - 1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */, - 0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* , */, - 1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 0 /* ; */, - 0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */, - 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */, - 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */, - 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */, - 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */, - 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */, - 1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* | */, - 0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static nghttp3_ssize sf_parse_token(nghttp3_sf_value *dest, - const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - - if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') { - return -1; - } - - for (; p != end && SF_TOKEN_CHARS[*p]; ++p) - ; - - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_TOKEN; - dest->s.base = begin; - dest->s.len = (size_t)(p - begin); - } - - return p - begin; -} - -/* Generated by genchartbl.py */ -static const int SF_BYTESEQ_CHARS[] = { - 0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */, - 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */, - 0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */, - 0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */, - 0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */, - 0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */, - 0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */, - 0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */, - 0 /* ( */, 0 /* ) */, 0 /* * */, 1 /* + */, 0 /* , */, - 0 /* - */, 0 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */, - 1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, - 1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */, - 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */, - 1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */, - 1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */, - 1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, - 1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */, - 1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */, - 1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */, - 0 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */, - 1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */, - 1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */, - 1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */, - 1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */, - 1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */, - 0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */, - 0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, - 0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */, - 0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */, - 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */, - 0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, - 0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */, - 0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */, - 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */, - 0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, - 0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */, - 0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */, - 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */, - 0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, - 0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */, - 0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */, - 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */, - 0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, - 0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */, - 0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */, - 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */, - 0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, - 0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */, - 0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */, - 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */, - 0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, - 0 /* 0xff */, -}; - -static nghttp3_ssize sf_parse_byteseq(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - - if (*p++ != ':') { - return -1; - } - - for (; p != end; ++p) { - switch (*p) { - case ':': - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_BYTESEQ; - dest->s.base = begin + 1; - dest->s.len = (size_t)(p - dest->s.base); - } - - ++p; - - return p - begin; - default: - if (!SF_BYTESEQ_CHARS[*p]) { - return -1; - } - } - } - - return -1; -} - -static nghttp3_ssize sf_parse_boolean(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - int b; - - if (*p++ != '?') { - return -1; - } - - if (p == end) { - return -1; - } - - switch (*p++) { - case '0': - b = 0; - break; - case '1': - b = 1; - break; - default: - return -1; - } - - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_BOOLEAN; - dest->b = b; - } - - return p - begin; -} - -static nghttp3_ssize sf_parse_bare_item(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - switch (*begin) { - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return sf_parse_integer_or_decimal(dest, begin, end); - case '"': - return sf_parse_string(dest, begin, end); - case '*': - return sf_parse_token(dest, begin, end); - case ':': - return sf_parse_byteseq(dest, begin, end); - case '?': - return sf_parse_boolean(dest, begin, end); +static int is_ws(uint8_t c) { + switch (c) { + case ' ': + case '\t': + return 1; default: - if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) { - return sf_parse_token(dest, begin, end); - } - return -1; - } -} - -#define sf_discard_sp_end_err(BEGIN, END, ERR) \ - for (;; ++(BEGIN)) { \ - if ((BEGIN) == (END)) { \ - return (ERR); \ - } \ - if (*(BEGIN) != ' ') { \ - break; \ - } \ - } - -static nghttp3_ssize sf_parse_params(const uint8_t *begin, const uint8_t *end) { - const uint8_t *p = begin; - nghttp3_ssize slen; - - for (; p != end && *p == ';';) { - ++p; - - sf_discard_sp_end_err(p, end, -1); - - slen = sf_parse_key(p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - if (p == end || *p != '=') { - /* Boolean true */ - } else if (++p == end) { - return -1; - } else { - slen = sf_parse_bare_item(NULL, p, end); - if (slen < 0) { - return -1; - } - - p += slen; - } - } - - return p - begin; -} - -static nghttp3_ssize sf_parse_item(nghttp3_sf_value *dest, const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - nghttp3_ssize slen; - - slen = sf_parse_bare_item(dest, p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - slen = sf_parse_params(p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - return p - begin; -} - -nghttp3_ssize nghttp3_sf_parse_item(nghttp3_sf_value *dest, - const uint8_t *begin, const uint8_t *end) { - return sf_parse_item(dest, begin, end); -} - -static nghttp3_ssize sf_parse_inner_list(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - const uint8_t *p = begin; - nghttp3_ssize slen; - - if (*p++ != '(') { - return -1; - } - - for (;;) { - sf_discard_sp_end_err(p, end, -1); - - if (*p == ')') { - ++p; - - slen = sf_parse_params(p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - if (dest) { - dest->type = NGHTTP3_SF_VALUE_TYPE_INNER_LIST; - } - - return p - begin; - } - - slen = sf_parse_item(NULL, p, end); - if (slen < 0) { - return -1; - } - - p += slen; - - if (p == end || (*p != ' ' && *p != ')')) { - return -1; - } - } -} - -nghttp3_ssize nghttp3_sf_parse_inner_list(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - return sf_parse_inner_list(dest, begin, end); -} - -static nghttp3_ssize sf_parse_item_or_inner_list(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end) { - if (*begin == '(') { - return sf_parse_inner_list(dest, begin, end); + return 0; } - - return sf_parse_item(dest, begin, end); } -#define sf_discard_ows(BEGIN, END) \ - for (;; ++(BEGIN)) { \ - if ((BEGIN) == (END)) { \ - goto fin; \ - } \ - if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \ - break; \ - } \ - } - -#define sf_discard_ows_end_err(BEGIN, END, ERR) \ - for (;; ++(BEGIN)) { \ - if ((BEGIN) == (END)) { \ - return (ERR); \ - } \ - if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \ - break; \ - } \ - } - int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value, size_t valuelen) { - const uint8_t *p = value, *end = value + valuelen; - nghttp3_ssize slen; - nghttp3_sf_value val; nghttp3_pri pri = *dest; - const uint8_t *key; - size_t keylen; + sf_parser sfp; + sf_vec key; + sf_value val; + int rv; + + sf_parser_init(&sfp, value, valuelen); - for (; p != end && *p == ' '; ++p) - ; + for (;;) { + rv = sf_parser_dict(&sfp, &key, &val); + if (rv != 0) { + if (rv == SF_ERR_EOF) { + break; + } - for (; p != end;) { - slen = sf_parse_key(p, end); - if (slen < 0) { return NGHTTP3_ERR_INVALID_ARGUMENT; } - key = p; - keylen = (size_t)slen; - - p += slen; - - if (p == end || *p != '=') { - /* Boolean true */ - val.type = NGHTTP3_SF_VALUE_TYPE_BOOLEAN; - val.b = 1; + if (key.len != 1) { + continue; + } - slen = sf_parse_params(p, end); - if (slen < 0) { + switch (key.base[0]) { + case 'i': + if (val.type != SF_TYPE_BOOLEAN) { return NGHTTP3_ERR_INVALID_ARGUMENT; } - } else if (++p == end) { - return NGHTTP3_ERR_INVALID_ARGUMENT; - } else { - slen = sf_parse_item_or_inner_list(&val, p, end); - if (slen < 0) { - return NGHTTP3_ERR_INVALID_ARGUMENT; - } - } - - p += slen; - if (keylen == 1) { - switch (key[0]) { - case 'i': - if (val.type != NGHTTP3_SF_VALUE_TYPE_BOOLEAN) { - return NGHTTP3_ERR_INVALID_ARGUMENT; - } - - pri.inc = val.b; + pri.inc = (uint8_t)val.boolean; - break; - case 'u': - if (val.type != NGHTTP3_SF_VALUE_TYPE_INTEGER || - val.i < NGHTTP3_URGENCY_HIGH || NGHTTP3_URGENCY_LOW < val.i) { - return NGHTTP3_ERR_INVALID_ARGUMENT; - } - - pri.urgency = (uint32_t)val.i; - - break; + break; + case 'u': + if (val.type != SF_TYPE_INTEGER || val.integer < NGHTTP3_URGENCY_HIGH || + NGHTTP3_URGENCY_LOW < val.integer) { + return NGHTTP3_ERR_INVALID_ARGUMENT; } - } - sf_discard_ows(p, end); + pri.urgency = (uint32_t)val.integer; - if (*p++ != ',') { - return NGHTTP3_ERR_INVALID_ARGUMENT; + break; } - - sf_discard_ows_end_err(p, end, NGHTTP3_ERR_INVALID_ARGUMENT); } -fin: *dest = pri; return 0; @@ -931,11 +277,10 @@ static int http_request_on_header(nghttp3_http_state *http, break; case NGHTTP3_QPACK_TOKEN_PRIORITY: if (!trailers && !(http->flags & NGHTTP3_HTTP_FLAG_BAD_PRIORITY)) { - pri.urgency = nghttp3_pri_uint8_urgency(http->pri); - pri.inc = nghttp3_pri_uint8_inc(http->pri); + pri = http->pri; if (nghttp3_http_parse_priority(&pri, nv->value->base, nv->value->len) == 0) { - http->pri = nghttp3_pri_to_uint8(&pri); + http->pri = pri; http->flags |= NGHTTP3_HTTP_FLAG_PRIORITY; } else { http->flags &= ~NGHTTP3_HTTP_FLAG_PRIORITY; @@ -1637,10 +982,9 @@ int nghttp3_check_header_value(const uint8_t *value, size_t len) { case 0: return 1; case 1: - return !(*value == ' ' || *value == '\t'); + return !is_ws(*value); default: - if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' || - *(value + len - 1) == '\t') { + if (is_ws(*value) || is_ws(*(value + len - 1))) { return 0; } } @@ -1652,3 +996,7 @@ int nghttp3_check_header_value(const uint8_t *value, size_t len) { } return 1; } + +int nghttp3_pri_eq(const nghttp3_pri *a, const nghttp3_pri *b) { + return a->urgency == b->urgency && a->inc == b->inc; +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_http.h b/deps/ngtcp2/nghttp3/lib/nghttp3_http.h index 1617348ad14d78..575d9c267e1b68 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_http.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_http.h @@ -150,53 +150,24 @@ int nghttp3_http_on_data_chunk(nghttp3_stream *stream, size_t n); void nghttp3_http_record_request_method(nghttp3_stream *stream, const nghttp3_nv *nva, size_t nvlen); -/* - * RFC 8941 Structured Field Values. - */ -typedef enum nghttp3_sf_value_type { - NGHTTP3_SF_VALUE_TYPE_BOOLEAN, - NGHTTP3_SF_VALUE_TYPE_INTEGER, - NGHTTP3_SF_VALUE_TYPE_DECIMAL, - NGHTTP3_SF_VALUE_TYPE_STRING, - NGHTTP3_SF_VALUE_TYPE_TOKEN, - NGHTTP3_SF_VALUE_TYPE_BYTESEQ, - NGHTTP3_SF_VALUE_TYPE_INNER_LIST, -} nghttp3_sf_value_type; - -/* - * nghttp3_sf_value stores Structured Field Values item. For Inner - * List, only type is set to NGHTTP3_SF_VALUE_TYPE_INNER_LIST. - */ -typedef struct nghttp3_sf_value { - uint8_t type; - union { - int b; - int64_t i; - double d; - struct { - const uint8_t *base; - size_t len; - } s; - }; -} nghttp3_sf_value; - -/* - * nghttp3_sf_parse_item parses the input sequence [|begin|, |end|) - * and stores the parsed an Item in |dest|. It returns the number of - * bytes consumed if it succeeds, or -1. This function is declared - * here for unit tests. +/** + * @function + * + * `nghttp3_http_parse_priority` parses priority HTTP header field + * stored in the buffer pointed by |value| of length |len|. If it + * successfully processed header field value, it stores the result + * into |*dest|. This function just overwrites what it sees in the + * header field value and does not initialize any field in |*dest|. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`NGHTTP3_ERR_INVALID_ARGUMENT` + * The function could not parse the provided value. */ -nghttp3_ssize nghttp3_sf_parse_item(nghttp3_sf_value *dest, - const uint8_t *begin, const uint8_t *end); +int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value, + size_t len); -/* - * nghttp3_sf_parse_inner_list parses the input sequence [|begin|, |end|) - * and stores the parsed an Inner List in |dest|. It returns the number of - * bytes consumed if it succeeds, or -1. This function is declared - * here for unit tests. - */ -nghttp3_ssize nghttp3_sf_parse_inner_list(nghttp3_sf_value *dest, - const uint8_t *begin, - const uint8_t *end); +int nghttp3_pri_eq(const nghttp3_pri *a, const nghttp3_pri *b); #endif /* NGHTTP3_HTTP_H */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c index ddb3dd6d84bf8a..428c06a82c6bfb 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack.c @@ -32,6 +32,7 @@ #include "nghttp3_str.h" #include "nghttp3_macro.h" #include "nghttp3_debug.h" +#include "nghttp3_unreachable.h" /* NGHTTP3_QPACK_MAX_QPACK_STREAMS is the maximum number of concurrent nghttp3_qpack_stream object to handle a client which never cancel @@ -1099,7 +1100,7 @@ static void qpack_encoder_remove_stream(nghttp3_qpack_encoder *encoder, /* * reserve_buf_internal ensures that |buf| contains at least * |extra_size| of free space. In other words, if this function - * succeeds, nghttp2_buf_left(buf) >= extra_size holds. |min_size| is + * succeeds, nghttp3_buf_left(buf) >= extra_size holds. |min_size| is * the minimum size of buffer. The allocated buffer has at least * |min_size| bytes. * @@ -1281,6 +1282,19 @@ int nghttp3_qpack_encoder_stream_is_blocked(nghttp3_qpack_encoder *encoder, return stream && encoder->krcnt < nghttp3_qpack_stream_get_max_cnt(stream); } +static uint32_t qpack_hash_name(const nghttp3_nv *nv) { + /* 32 bit FNV-1a: http://isthe.com/chongo/tech/comp/fnv/ */ + uint32_t h = 2166136261u; + size_t i; + + for (i = 0; i < nv->namelen; ++i) { + h ^= nv->name[i]; + h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24); + } + + return h; +} + /* * qpack_encoder_decide_indexing_mode determines and returns indexing * mode for header field |nv|. |token| is a token of header field @@ -1310,6 +1324,10 @@ qpack_encoder_decide_indexing_mode(nghttp3_qpack_encoder *encoder, case NGHTTP3_QPACK_TOKEN_IF_NONE_MATCH: case NGHTTP3_QPACK_TOKEN_LOCATION: case NGHTTP3_QPACK_TOKEN_SET_COOKIE: + if (nv->flags & NGHTTP3_NV_FLAG_TRY_INDEX) { + break; + } + return NGHTTP3_QPACK_INDEXING_MODE_LITERAL; case NGHTTP3_QPACK_TOKEN_HOST: case NGHTTP3_QPACK_TOKEN_TE: @@ -1317,6 +1335,10 @@ qpack_encoder_decide_indexing_mode(nghttp3_qpack_encoder *encoder, case NGHTTP3_QPACK_TOKEN_PRIORITY: break; default: + if (nv->flags & NGHTTP3_NV_FLAG_TRY_INDEX) { + break; + } + if (token >= 1000) { return NGHTTP3_QPACK_INDEXING_MODE_LITERAL; } @@ -1428,6 +1450,17 @@ int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder, token = qpack_lookup_token(nv->name, nv->namelen); static_entry = token != -1 && (size_t)token < nghttp3_arraylen(token_stable); + + indexing_mode = qpack_encoder_decide_indexing_mode(encoder, nv, token); + + if (static_entry) { + sres = nghttp3_qpack_lookup_stable(nv, token, indexing_mode); + if (sres.index != -1 && sres.name_value_match) { + return nghttp3_qpack_encoder_write_static_indexed(encoder, rbuf, + (size_t)sres.index); + } + } + if (static_entry) { hash = token_stable[token].hash; } else { @@ -1444,21 +1477,12 @@ int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder, case NGHTTP3_QPACK_TOKEN_PRIORITY: hash = 2498028297u; break; + default: + hash = qpack_hash_name(nv); } } - indexing_mode = qpack_encoder_decide_indexing_mode(encoder, nv, token); - - if (static_entry) { - sres = nghttp3_qpack_lookup_stable(nv, token, indexing_mode); - if (sres.index != -1 && sres.name_value_match) { - return nghttp3_qpack_encoder_write_static_indexed(encoder, rbuf, - (size_t)sres.index); - } - } - - if (hash && - nghttp3_map_size(&encoder->streams) < NGHTTP3_QPACK_MAX_QPACK_STREAMS) { + if (nghttp3_map_size(&encoder->streams) < NGHTTP3_QPACK_MAX_QPACK_STREAMS) { dres = nghttp3_qpack_encoder_lookup_dtable(encoder, nv, token, hash, indexing_mode, encoder->krcnt, allow_blocking); @@ -2552,18 +2576,14 @@ nghttp3_ssize nghttp3_qpack_encoder_read_decoder(nghttp3_qpack_encoder *encoder, (int64_t)encoder->rstate.left); break; default: - /* unreachable */ - assert(0); - break; + nghttp3_unreachable(); } encoder->state = NGHTTP3_QPACK_DS_STATE_OPCODE; nghttp3_qpack_read_state_reset(&encoder->rstate); break; default: - /* unreachable */ - assert(0); - break; + nghttp3_unreachable(); } } @@ -2838,24 +2858,26 @@ nghttp3_ssize nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder *decoder, goto fail; } - if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_DUPLICATE) { + switch (decoder->opcode) { + case NGHTTP3_QPACK_ES_OPCODE_DUPLICATE: rv = nghttp3_qpack_decoder_dtable_duplicate_add(decoder); if (rv != 0) { goto fail; } + decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE; nghttp3_qpack_read_state_reset(&decoder->rstate); - break; - } - if (decoder->opcode == NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED) { + break; + case NGHTTP3_QPACK_ES_OPCODE_INSERT_INDEXED: decoder->rstate.prefix = 7; decoder->state = NGHTTP3_QPACK_ES_STATE_CHECK_VALUE_HUFFMAN; + break; + default: + nghttp3_unreachable(); } - /* Unreachable */ - assert(0); break; case NGHTTP3_QPACK_ES_STATE_CHECK_NAME_HUFFMAN: qpack_read_state_check_huffman(&decoder->rstate, *p); @@ -3010,9 +3032,7 @@ nghttp3_ssize nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder *decoder, rv = nghttp3_qpack_decoder_dtable_literal_add(decoder); break; default: - /* Unreachable */ - assert(0); - abort(); + nghttp3_unreachable(); } if (rv != 0) { goto fail; @@ -3045,9 +3065,7 @@ nghttp3_ssize nghttp3_qpack_decoder_read_encoder(nghttp3_qpack_decoder *decoder, rv = nghttp3_qpack_decoder_dtable_literal_add(decoder); break; default: - /* Unreachable */ - assert(0); - abort(); + nghttp3_unreachable(); } if (rv != 0) { goto fail; @@ -3430,8 +3448,7 @@ nghttp3_qpack_decoder_read_request(nghttp3_qpack_decoder *decoder, sctx->state = NGHTTP3_QPACK_RS_STATE_CHECK_VALUE_HUFFMAN; break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } break; case NGHTTP3_QPACK_RS_STATE_CHECK_NAME_HUFFMAN: @@ -3589,8 +3606,7 @@ nghttp3_qpack_decoder_read_request(nghttp3_qpack_decoder *decoder, nghttp3_qpack_decoder_emit_literal(decoder, sctx, nv); break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT; @@ -3627,8 +3643,7 @@ nghttp3_qpack_decoder_read_request(nghttp3_qpack_decoder *decoder, nghttp3_qpack_decoder_emit_literal(decoder, sctx, nv); break; default: - /* Unreachable */ - assert(0); + nghttp3_unreachable(); } *pflags |= NGHTTP3_QPACK_DECODE_FLAG_EMIT; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c b/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c index 5e7775f1a5a597..61a7d06cad306f 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_ringbuf.c @@ -33,7 +33,8 @@ #include "nghttp3_macro.h" -#if defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || defined(_M_ARM64)) +#if defined(_MSC_VER) && !defined(__clang__) && \ + (defined(_M_ARM) || defined(_M_ARM64)) unsigned int __popcnt(unsigned int x) { unsigned int c = 0; for (; x; ++c) { diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c index e655a7ec01d10b..8cd1427ed655b4 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.c @@ -35,6 +35,7 @@ #include "nghttp3_str.h" #include "nghttp3_http.h" #include "nghttp3_vec.h" +#include "nghttp3_unreachable.h" /* NGHTTP3_STREAM_MAX_COPY_THRES is the maximum size of buffer which makes a copy to outq. */ @@ -44,12 +45,11 @@ #define NGHTTP3_MIN_RBLEN 4 int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, - uint64_t seq, const nghttp3_stream_callbacks *callbacks, + const nghttp3_stream_callbacks *callbacks, nghttp3_objalloc *out_chunk_objalloc, nghttp3_objalloc *stream_objalloc, const nghttp3_mem *mem) { nghttp3_stream *stream = nghttp3_objalloc_stream_get(stream_objalloc); - nghttp3_node_id nid; if (stream == NULL) { return NGHTTP3_ERR_NOMEM; @@ -60,10 +60,7 @@ int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, stream->out_chunk_objalloc = out_chunk_objalloc; stream->stream_objalloc = stream_objalloc; - nghttp3_tnode_init( - &stream->node, - nghttp3_node_id_init(&nid, NGHTTP3_NODE_ID_TYPE_STREAM, stream_id), seq, - NGHTTP3_DEFAULT_URGENCY); + nghttp3_tnode_init(&stream->node, stream_id); nghttp3_ringbuf_init(&stream->frq, 0, sizeof(nghttp3_frame_entry), mem); nghttp3_ringbuf_init(&stream->chunks, 0, sizeof(nghttp3_buf), mem); @@ -77,7 +74,7 @@ int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, stream->tx.offset = 0; stream->rx.http.status_code = -1; stream->rx.http.content_length = -1; - stream->rx.http.pri = NGHTTP3_DEFAULT_URGENCY; + stream->rx.http.pri.urgency = NGHTTP3_DEFAULT_URGENCY; stream->error_code = NGHTTP3_H3_NO_ERROR; if (callbacks) { @@ -146,6 +143,9 @@ static void delete_frq(nghttp3_ringbuf *frq, const nghttp3_mem *mem) { case NGHTTP3_FRAME_HEADERS: nghttp3_frame_headers_free(&frent->fr.headers, mem); break; + case NGHTTP3_FRAME_PRIORITY_UPDATE: + nghttp3_frame_priority_update_free(&frent->fr.priority_update, mem); + break; default: break; } @@ -188,7 +188,7 @@ nghttp3_ssize nghttp3_read_varint(nghttp3_varint_read_state *rvint, if (rvint->left == 0) { assert(rvint->acc == 0); - rvint->left = nghttp3_get_varint_len(src); + rvint->left = nghttp3_get_varintlen(src); if (rvint->left <= srclen) { rvint->acc = nghttp3_get_varint(&nread, src); rvint->left = 0; @@ -248,7 +248,7 @@ int nghttp3_stream_fill_outq(nghttp3_stream *stream) { int data_eof; int rv; - for (; nghttp3_ringbuf_len(frq) && !nghttp3_stream_outq_is_full(stream) && + for (; nghttp3_ringbuf_len(frq) && stream->unsent_bytes < NGHTTP3_MIN_UNSENT_BYTES;) { frent = nghttp3_ringbuf_get(frq, 0); @@ -289,6 +289,8 @@ int nghttp3_stream_fill_outq(nghttp3_stream *stream) { if (rv != 0) { return rv; } + nghttp3_frame_priority_update_free(&frent->fr.priority_update, + stream->mem); break; default: /* TODO Not implemented */ @@ -308,7 +310,7 @@ static void typed_buf_shared_init(nghttp3_typed_buf *tbuf, } int nghttp3_stream_write_stream_type(nghttp3_stream *stream) { - size_t len = nghttp3_put_varint_len((int64_t)stream->type); + size_t len = nghttp3_put_varintlen((int64_t)stream->type); nghttp3_buf *chunk; nghttp3_typed_buf tbuf; int rv; @@ -351,10 +353,18 @@ int nghttp3_stream_write_settings(nghttp3_stream *stream, iv[2].id = NGHTTP3_SETTINGS_ID_QPACK_BLOCKED_STREAMS; iv[2].value = local_settings->qpack_blocked_streams; + if (local_settings->h3_datagram) { + iv[fr.settings.niv].id = NGHTTP3_SETTINGS_ID_H3_DATAGRAM; + iv[fr.settings.niv].value = 1; + + ++fr.settings.niv; + } + if (local_settings->enable_connect_protocol) { + iv[fr.settings.niv].id = NGHTTP3_SETTINGS_ID_ENABLE_CONNECT_PROTOCOL; + iv[fr.settings.niv].value = 1; + ++fr.settings.niv; - iv[3].id = NGHTTP3_SETTINGS_ID_ENABLE_CONNECT_PROTOCOL; - iv[3].value = 1; } len = nghttp3_frame_write_settings_len(&fr.settings.hd.length, &fr.settings); @@ -453,8 +463,8 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream, nghttp3_buf_wrap_init(&pbuf, raw_pbuf, sizeof(raw_pbuf)); - rv = nghttp3_qpack_encoder_encode(qenc, &pbuf, rbuf, ebuf, - stream->node.nid.id, nva, nvlen); + rv = nghttp3_qpack_encoder_encode(qenc, &pbuf, rbuf, ebuf, stream->node.id, + nva, nvlen); if (rv != 0) { goto fail; } @@ -574,8 +584,8 @@ int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof, *peof = 0; - sveccnt = read_data(conn, stream->node.nid.id, vec, nghttp3_arraylen(vec), - &flags, conn->user_data, stream->user_data); + sveccnt = read_data(conn, stream->node.id, vec, nghttp3_arraylen(vec), &flags, + conn->user_data, stream->user_data); if (sveccnt < 0) { if (sveccnt == NGHTTP3_ERR_WOULDBLOCK) { stream->flags |= NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED; @@ -691,11 +701,6 @@ int nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream *stream) { return nghttp3_stream_outq_add(stream, &tbuf); } -int nghttp3_stream_outq_is_full(nghttp3_stream *stream) { - /* TODO Verify that the limit is reasonable. */ - return nghttp3_ringbuf_len(&stream->outq) >= 1024; -} - int nghttp3_stream_outq_add(nghttp3_stream *stream, const nghttp3_typed_buf *tbuf) { nghttp3_ringbuf *outq = &stream->outq; @@ -813,7 +818,7 @@ nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, nghttp3_vec *vec, size_t veccnt) { nghttp3_ringbuf *outq = &stream->outq; size_t len = nghttp3_ringbuf_len(outq); - size_t i; + size_t i = stream->outq_idx; uint64_t offset = stream->outq_offset; size_t buflen; nghttp3_vec *vbegin = vec, *vend = vec + veccnt; @@ -821,25 +826,27 @@ nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, assert(veccnt > 0); - for (i = stream->outq_idx; i < len; ++i) { + if (i < len) { tbuf = nghttp3_ringbuf_get(outq, i); buflen = nghttp3_buf_len(&tbuf->buf); - if (offset >= buflen) { - offset -= buflen; - continue; + + 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); } - vec->base = tbuf->buf.pos + offset; - vec->len = (size_t)(buflen - offset); - ++vec; ++i; - break; - } - 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); + 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); + } } /* TODO Rework this if we have finished implementing HTTP @@ -915,8 +922,7 @@ static int stream_pop_outq_entry(nghttp3_stream *stream, } break; default: - assert(0); - abort(); + nghttp3_unreachable(); }; nghttp3_ringbuf_pop_front(&stream->outq); @@ -940,7 +946,7 @@ int nghttp3_stream_add_ack_offset(nghttp3_stream *stream, uint64_t n) { if (tbuf->type == NGHTTP3_BUF_TYPE_ALIEN) { nack = nghttp3_min(offset, (uint64_t)buflen) - stream->ack_done; if (stream->callbacks.acked_data) { - rv = stream->callbacks.acked_data(stream, stream->node.nid.id, nack, + rv = stream->callbacks.acked_data(stream, stream->node.id, nack, stream->user_data); if (rv != 0) { return NGHTTP3_ERR_CALLBACK_FAILURE; @@ -1221,8 +1227,7 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream, case NGHTTP3_HTTP_STATE_RESP_END: return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; default: - assert(0); - abort(); + nghttp3_unreachable(); } } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h index 06292738a17e93..9908d43dc06045 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_stream.h @@ -195,9 +195,8 @@ typedef struct nghttp3_http_state { /* recv_content_length is the number of body bytes received so far. */ int64_t recv_content_length; + nghttp3_pri pri; uint32_t flags; - /* pri is a stream priority produced by nghttp3_pri_to_uint8. */ - uint8_t pri; } nghttp3_http_state; struct nghttp3_stream { @@ -272,7 +271,7 @@ typedef struct nghttp3_frame_entry { } nghttp3_frame_entry; int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, - uint64_t seq, const nghttp3_stream_callbacks *callbacks, + const nghttp3_stream_callbacks *callbacks, nghttp3_objalloc *out_chunk_objalloc, nghttp3_objalloc *stream_objalloc, const nghttp3_mem *mem); @@ -298,8 +297,6 @@ nghttp3_ssize nghttp3_stream_writev(nghttp3_stream *stream, int *pfin, int nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream *stream); -int nghttp3_stream_outq_is_full(nghttp3_stream *stream); - int nghttp3_stream_outq_add(nghttp3_stream *stream, const nghttp3_typed_buf *tbuf); diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c b/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c index 36e738c3469aca..d9c5e598699512 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.c @@ -31,26 +31,12 @@ #include "nghttp3_conn.h" #include "nghttp3_conv.h" -nghttp3_node_id *nghttp3_node_id_init(nghttp3_node_id *nid, - nghttp3_node_id_type type, int64_t id) { - nid->type = type; - nid->id = id; - return nid; -} - -int nghttp3_node_id_eq(const nghttp3_node_id *a, const nghttp3_node_id *b) { - return a->type == b->type && a->id == b->id; -} - -void nghttp3_tnode_init(nghttp3_tnode *tnode, const nghttp3_node_id *nid, - uint64_t seq, uint8_t pri) { - assert(nghttp3_pri_uint8_urgency(pri) < NGHTTP3_URGENCY_LEVELS); - +void nghttp3_tnode_init(nghttp3_tnode *tnode, int64_t id) { tnode->pe.index = NGHTTP3_PQ_BAD_INDEX; - tnode->nid = *nid; - tnode->seq = seq; + tnode->id = id; tnode->cycle = 0; - tnode->pri = pri; + tnode->pri.urgency = NGHTTP3_DEFAULT_URGENCY; + tnode->pri.inc = 0; } void nghttp3_tnode_free(nghttp3_tnode *tnode) { (void)tnode; } @@ -86,12 +72,11 @@ int nghttp3_tnode_schedule(nghttp3_tnode *tnode, nghttp3_pq *pq, uint64_t penalty = nwrite / NGHTTP3_STREAM_MIN_WRITELEN; if (tnode->pe.index == NGHTTP3_PQ_BAD_INDEX) { - tnode->cycle = pq_get_first_cycle(pq) + - ((nwrite == 0 || !nghttp3_pri_uint8_inc(tnode->pri)) - ? 0 - : nghttp3_max(1, penalty)); + tnode->cycle = + pq_get_first_cycle(pq) + + ((nwrite == 0 || !tnode->pri.inc) ? 0 : nghttp3_max(1, penalty)); } else if (nwrite > 0) { - if (!nghttp3_pri_uint8_inc(tnode->pri) || nghttp3_pq_size(pq) == 1) { + if (!tnode->pri.inc || nghttp3_pq_size(pq) == 1) { return 0; } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h b/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h index f71dcf5ee31ad6..1abc1e62519381 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_tnode.h @@ -35,33 +35,16 @@ #define NGHTTP3_TNODE_MAX_CYCLE_GAP (1llu << 24) -typedef enum nghttp3_node_id_type { - NGHTTP3_NODE_ID_TYPE_STREAM = 0x00, - NGHTTP3_NODE_ID_TYPE_PUSH = 0x01, -} nghttp3_node_id_type; - -typedef struct nghttp3_node_id { - nghttp3_node_id_type type; - int64_t id; -} nghttp3_node_id; - -nghttp3_node_id *nghttp3_node_id_init(nghttp3_node_id *nid, - nghttp3_node_id_type type, int64_t id); - -int nghttp3_node_id_eq(const nghttp3_node_id *a, const nghttp3_node_id *b); - typedef struct nghttp3_tnode { nghttp3_pq_entry pe; size_t num_children; - nghttp3_node_id nid; - uint64_t seq; + int64_t id; uint64_t cycle; /* pri is a stream priority produced by nghttp3_pri_to_uint8. */ - uint8_t pri; + nghttp3_pri pri; } nghttp3_tnode; -void nghttp3_tnode_init(nghttp3_tnode *tnode, const nghttp3_node_id *nid, - uint64_t seq, uint8_t pri); +void nghttp3_tnode_init(nghttp3_tnode *tnode, int64_t id); void nghttp3_tnode_free(nghttp3_tnode *tnode); diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.c b/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.c new file mode 100644 index 00000000000000..6fea89b802b12d --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.c @@ -0,0 +1,72 @@ +/* + * nghttp3 + * + * Copyright (c) 2022 nghttp3 contributors + * Copyright (c) 2022 ngtcp2 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_unreachable.h" + +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#ifdef WIN32 +# include +#endif /* WIN32 */ + +void nghttp3_unreachable_fail(const char *file, int line, const char *func) { + char *buf; + size_t buflen; + int rv; + +#define NGHTTP3_UNREACHABLE_TEMPLATE "%s:%d %s: Unreachable.\n" + + rv = snprintf(NULL, 0, NGHTTP3_UNREACHABLE_TEMPLATE, file, line, func); + if (rv < 0) { + abort(); + } + + /* here we explicitly use system malloc */ + buflen = (size_t)rv + 1; + buf = malloc(buflen); + if (buf == NULL) { + abort(); + } + + rv = snprintf(buf, buflen, NGHTTP3_UNREACHABLE_TEMPLATE, file, line, func); + if (rv < 0) { + abort(); + } + +#ifndef WIN32 + while (write(STDERR_FILENO, buf, (size_t)rv) == -1 && errno == EINTR) + ; +#else /* WIN32 */ + _write(_fileno(stderr), buf, (unsigned int)rv); +#endif /* WIN32 */ + + free(buf); + + abort(); +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.h b/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.h new file mode 100644 index 00000000000000..c3520a479e302e --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_unreachable.h @@ -0,0 +1,47 @@ +/* + * nghttp3 + * + * Copyright (c) 2022 nghttp3 contributors + * Copyright (c) 2022 ngtcp2 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_UNREACHABLE_H +#define NGHTTP3_UNREACHABLE_H + +#ifdef HAVE_CONFIG_H +# include +#endif /* HAVE_CONFIG_H */ + +#include + +#define nghttp3_unreachable() \ + nghttp3_unreachable_fail(__FILE__, __LINE__, __func__) + +#ifdef _MSC_VER +__declspec(noreturn) +#endif /* _MSC_VER */ + void nghttp3_unreachable_fail(const char *file, int line, const char *func) +#ifndef _MSC_VER + __attribute__((noreturn)) +#endif /* !_MSC_VER */ + ; + +#endif /* NGHTTP3_UNREACHABLE_H */ diff --git a/deps/ngtcp2/nghttp3/lib/sfparse.c b/deps/ngtcp2/nghttp3/lib/sfparse.c new file mode 100644 index 00000000000000..efa2850c9d661d --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/sfparse.c @@ -0,0 +1,1146 @@ +/* + * sfparse + * + * Copyright (c) 2023 sfparse contributors + * Copyright (c) 2019 nghttp3 contributors + * Copyright (c) 2015 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "sfparse.h" + +#include +#include +#include + +#define SF_STATE_DICT 0x08u +#define SF_STATE_LIST 0x10u +#define SF_STATE_ITEM 0x18u + +#define SF_STATE_INNER_LIST 0x04u + +#define SF_STATE_BEFORE 0x00u +#define SF_STATE_BEFORE_PARAMS 0x01u +#define SF_STATE_PARAMS 0x02u +#define SF_STATE_AFTER 0x03u + +#define SF_STATE_OP_MASK 0x03u + +#define SF_SET_STATE_AFTER(NAME) (SF_STATE_##NAME | SF_STATE_AFTER) +#define SF_SET_STATE_BEFORE_PARAMS(NAME) \ + (SF_STATE_##NAME | SF_STATE_BEFORE_PARAMS) +#define SF_SET_STATE_INNER_LIST_BEFORE(NAME) \ + (SF_STATE_##NAME | SF_STATE_INNER_LIST | SF_STATE_BEFORE) + +#define SF_STATE_DICT_AFTER SF_SET_STATE_AFTER(DICT) +#define SF_STATE_DICT_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(DICT) +#define SF_STATE_DICT_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(DICT) + +#define SF_STATE_LIST_AFTER SF_SET_STATE_AFTER(LIST) +#define SF_STATE_LIST_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(LIST) +#define SF_STATE_LIST_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(LIST) + +#define SF_STATE_ITEM_AFTER SF_SET_STATE_AFTER(ITEM) +#define SF_STATE_ITEM_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(ITEM) +#define SF_STATE_ITEM_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(ITEM) + +#define SF_STATE_INITIAL 0x00u + +#define DIGIT_CASES \ + case '0': \ + case '1': \ + case '2': \ + case '3': \ + case '4': \ + case '5': \ + case '6': \ + case '7': \ + case '8': \ + case '9' + +#define LCALPHA_CASES \ + case 'a': \ + case 'b': \ + case 'c': \ + case 'd': \ + case 'e': \ + case 'f': \ + case 'g': \ + case 'h': \ + case 'i': \ + case 'j': \ + case 'k': \ + case 'l': \ + case 'm': \ + case 'n': \ + case 'o': \ + case 'p': \ + case 'q': \ + case 'r': \ + case 's': \ + case 't': \ + case 'u': \ + case 'v': \ + case 'w': \ + case 'x': \ + case 'y': \ + case 'z' + +#define UCALPHA_CASES \ + case 'A': \ + case 'B': \ + case 'C': \ + case 'D': \ + case 'E': \ + case 'F': \ + case 'G': \ + case 'H': \ + case 'I': \ + case 'J': \ + case 'K': \ + case 'L': \ + case 'M': \ + case 'N': \ + case 'O': \ + case 'P': \ + case 'Q': \ + case 'R': \ + case 'S': \ + case 'T': \ + case 'U': \ + case 'V': \ + case 'W': \ + case 'X': \ + case 'Y': \ + case 'Z' + +#define ALPHA_CASES \ + UCALPHA_CASES: \ + LCALPHA_CASES + +#define X20_21_CASES \ + case ' ': \ + case '!' + +#define X23_5B_CASES \ + case '#': \ + case '$': \ + case '%': \ + case '&': \ + case '\'': \ + case '(': \ + case ')': \ + case '*': \ + case '+': \ + case ',': \ + case '-': \ + case '.': \ + case '/': \ + DIGIT_CASES: \ + case ':': \ + case ';': \ + case '<': \ + case '=': \ + case '>': \ + case '?': \ + case '@': \ + UCALPHA_CASES: \ + case '[' + +#define X5D_7E_CASES \ + case ']': \ + case '^': \ + case '_': \ + case '`': \ + LCALPHA_CASES: \ + case '{': \ + case '|': \ + case '}': \ + case '~' + +static int is_ws(uint8_t c) { + switch (c) { + case ' ': + case '\t': + return 1; + default: + return 0; + } +} + +static int parser_eof(sf_parser *sfp) { return sfp->pos == sfp->end; } + +static void parser_discard_ows(sf_parser *sfp) { + for (; !parser_eof(sfp) && is_ws(*sfp->pos); ++sfp->pos) + ; +} + +static void parser_discard_sp(sf_parser *sfp) { + for (; !parser_eof(sfp) && *sfp->pos == ' '; ++sfp->pos) + ; +} + +static void parser_set_op_state(sf_parser *sfp, uint32_t op) { + sfp->state &= ~SF_STATE_OP_MASK; + sfp->state |= op; +} + +static void parser_unset_inner_list_state(sf_parser *sfp) { + sfp->state &= ~SF_STATE_INNER_LIST; +} + +static int parser_key(sf_parser *sfp, sf_vec *dest) { + const uint8_t *base; + + switch (*sfp->pos) { + case '*': + LCALPHA_CASES: + break; + default: + return SF_ERR_PARSE_ERROR; + } + + base = sfp->pos++; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + case '_': + case '-': + case '.': + case '*': + DIGIT_CASES: + LCALPHA_CASES: + continue; + } + + break; + } + + if (dest) { + dest->base = (uint8_t *)base; + dest->len = (size_t)(sfp->pos - dest->base); + } + + return 0; +} + +static int parser_number(sf_parser *sfp, sf_value *dest) { + int sign = 1; + int64_t value = 0; + size_t len = 0; + size_t fpos = 0; + + if (*sfp->pos == '-') { + ++sfp->pos; + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + sign = -1; + } + + assert(!parser_eof(sfp)); + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + DIGIT_CASES: + if (++len > 15) { + return SF_ERR_PARSE_ERROR; + } + + value *= 10; + value += *sfp->pos - '0'; + + continue; + } + + break; + } + + if (len == 0) { + return SF_ERR_PARSE_ERROR; + } + + if (parser_eof(sfp) || *sfp->pos != '.') { + if (dest) { + dest->type = SF_TYPE_INTEGER; + dest->flags = SF_VALUE_FLAG_NONE; + dest->integer = value * sign; + } + + return 0; + } + + /* decimal */ + + if (len > 12) { + return SF_ERR_PARSE_ERROR; + } + + fpos = len; + + ++sfp->pos; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + DIGIT_CASES: + if (++len > 15) { + return SF_ERR_PARSE_ERROR; + } + + value *= 10; + value += *sfp->pos - '0'; + + continue; + } + + break; + } + + if (fpos == len || len - fpos > 3) { + return SF_ERR_PARSE_ERROR; + } + + if (dest) { + dest->type = SF_TYPE_DECIMAL; + dest->flags = SF_VALUE_FLAG_NONE; + dest->decimal.numer = value * sign; + + switch (len - fpos) { + case 1: + dest->decimal.denom = 10; + + break; + case 2: + dest->decimal.denom = 100; + + break; + case 3: + dest->decimal.denom = 1000; + + break; + } + } + + return 0; +} + +static int parser_date(sf_parser *sfp, sf_value *dest) { + int rv; + sf_value val; + + /* The first byte has already been validated by the caller. */ + assert('@' == *sfp->pos); + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + rv = parser_number(sfp, &val); + if (rv != 0) { + return rv; + } + + if (val.type != SF_TYPE_INTEGER) { + return SF_ERR_PARSE_ERROR; + } + + if (dest) { + *dest = val; + dest->type = SF_TYPE_DATE; + } + + return 0; +} + +static int parser_string(sf_parser *sfp, sf_value *dest) { + const uint8_t *base; + uint32_t flags = SF_VALUE_FLAG_NONE; + + /* The first byte has already been validated by the caller. */ + assert('"' == *sfp->pos); + + base = ++sfp->pos; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + X20_21_CASES: + X23_5B_CASES: + X5D_7E_CASES: + break; + case '\\': + ++sfp->pos; + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + switch (*sfp->pos) { + case '"': + case '\\': + flags = SF_VALUE_FLAG_ESCAPED_STRING; + + break; + default: + return SF_ERR_PARSE_ERROR; + } + + break; + case '"': + if (dest) { + dest->type = SF_TYPE_STRING; + dest->flags = flags; + dest->vec.len = (size_t)(sfp->pos - base); + dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; + } + + ++sfp->pos; + + return 0; + default: + return SF_ERR_PARSE_ERROR; + } + } + + return SF_ERR_PARSE_ERROR; +} + +static int parser_token(sf_parser *sfp, sf_value *dest) { + const uint8_t *base; + + /* The first byte has already been validated by the caller. */ + base = sfp->pos++; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + case '!': + case '#': + case '$': + case '%': + case '&': + case '\'': + case '*': + case '+': + case '-': + case '.': + case '^': + case '_': + case '`': + case '|': + case '~': + case ':': + case '/': + DIGIT_CASES: + ALPHA_CASES: + continue; + } + + break; + } + + if (dest) { + dest->type = SF_TYPE_TOKEN; + dest->flags = SF_VALUE_FLAG_NONE; + dest->vec.base = (uint8_t *)base; + dest->vec.len = (size_t)(sfp->pos - base); + } + + return 0; +} + +static int parser_byteseq(sf_parser *sfp, sf_value *dest) { + const uint8_t *base; + + /* The first byte has already been validated by the caller. */ + assert(':' == *sfp->pos); + + base = ++sfp->pos; + + for (; !parser_eof(sfp); ++sfp->pos) { + switch (*sfp->pos) { + case '+': + case '/': + DIGIT_CASES: + ALPHA_CASES: + continue; + case '=': + switch ((sfp->pos - base) & 0x3) { + case 0: + case 1: + return SF_ERR_PARSE_ERROR; + case 2: + switch (*(sfp->pos - 1)) { + case 'A': + case 'Q': + case 'g': + case 'w': + break; + default: + return SF_ERR_PARSE_ERROR; + } + + ++sfp->pos; + + if (parser_eof(sfp) || *sfp->pos != '=') { + return SF_ERR_PARSE_ERROR; + } + + break; + case 3: + switch (*(sfp->pos - 1)) { + case 'A': + case 'E': + case 'I': + case 'M': + case 'Q': + case 'U': + case 'Y': + case 'c': + case 'g': + case 'k': + case 'o': + case 's': + case 'w': + case '0': + case '4': + case '8': + break; + default: + return SF_ERR_PARSE_ERROR; + } + + break; + } + + ++sfp->pos; + + if (parser_eof(sfp) || *sfp->pos != ':') { + return SF_ERR_PARSE_ERROR; + } + + goto fin; + case ':': + if ((sfp->pos - base) & 0x3) { + return SF_ERR_PARSE_ERROR; + } + + goto fin; + default: + return SF_ERR_PARSE_ERROR; + } + } + + return SF_ERR_PARSE_ERROR; + +fin: + if (dest) { + dest->type = SF_TYPE_BYTESEQ; + dest->flags = SF_VALUE_FLAG_NONE; + dest->vec.len = (size_t)(sfp->pos - base); + dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base; + } + + ++sfp->pos; + + return 0; +} + +static int parser_boolean(sf_parser *sfp, sf_value *dest) { + int b; + + /* The first byte has already been validated by the caller. */ + assert('?' == *sfp->pos); + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + switch (*sfp->pos) { + case '0': + b = 0; + + break; + case '1': + b = 1; + + break; + default: + return SF_ERR_PARSE_ERROR; + } + + ++sfp->pos; + + if (dest) { + dest->type = SF_TYPE_BOOLEAN; + dest->flags = SF_VALUE_FLAG_NONE; + dest->boolean = b; + } + + return 0; +} + +static int parser_bare_item(sf_parser *sfp, sf_value *dest) { + switch (*sfp->pos) { + case '"': + return parser_string(sfp, dest); + case '-': + DIGIT_CASES: + return parser_number(sfp, dest); + case '@': + return parser_date(sfp, dest); + case ':': + return parser_byteseq(sfp, dest); + case '?': + return parser_boolean(sfp, dest); + case '*': + ALPHA_CASES: + return parser_token(sfp, dest); + default: + return SF_ERR_PARSE_ERROR; + } +} + +static int parser_skip_inner_list(sf_parser *sfp); + +int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { + int rv; + + switch (sfp->state & SF_STATE_OP_MASK) { + case SF_STATE_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_BEFORE_PARAMS: + parser_set_op_state(sfp, SF_STATE_PARAMS); + + break; + case SF_STATE_PARAMS: + break; + default: + assert(0); + abort(); + } + + if (parser_eof(sfp) || *sfp->pos != ';') { + parser_set_op_state(sfp, SF_STATE_AFTER); + + return SF_ERR_EOF; + } + + ++sfp->pos; + + parser_discard_sp(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + rv = parser_key(sfp, dest_key); + if (rv != 0) { + return rv; + } + + if (parser_eof(sfp) || *sfp->pos != '=') { + if (dest_value) { + dest_value->type = SF_TYPE_BOOLEAN; + dest_value->flags = SF_VALUE_FLAG_NONE; + dest_value->boolean = 1; + } + + return 0; + } + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + return parser_bare_item(sfp, dest_value); +} + +static int parser_skip_params(sf_parser *sfp) { + int rv; + + for (;;) { + rv = sf_parser_param(sfp, NULL, NULL); + switch (rv) { + case 0: + break; + case SF_ERR_EOF: + return 0; + case SF_ERR_PARSE_ERROR: + return rv; + default: + assert(0); + abort(); + } + } +} + +int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) { + int rv; + + switch (sfp->state & SF_STATE_OP_MASK) { + case SF_STATE_BEFORE: + parser_discard_sp(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + break; + case SF_STATE_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* Technically, we are entering SF_STATE_AFTER, but we will set + another state without reading the state. */ + /* parser_set_op_state(sfp, SF_STATE_AFTER); */ + + /* fall through */ + case SF_STATE_AFTER: + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + switch (*sfp->pos) { + case ' ': + parser_discard_sp(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + break; + case ')': + break; + default: + return SF_ERR_PARSE_ERROR; + } + + break; + default: + assert(0); + abort(); + } + + if (*sfp->pos == ')') { + ++sfp->pos; + + parser_unset_inner_list_state(sfp); + parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + + return SF_ERR_EOF; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS); + + return 0; +} + +static int parser_skip_inner_list(sf_parser *sfp) { + int rv; + + for (;;) { + rv = sf_parser_inner_list(sfp, NULL); + switch (rv) { + case 0: + break; + case SF_ERR_EOF: + return 0; + case SF_ERR_PARSE_ERROR: + return rv; + default: + assert(0); + abort(); + } + } +} + +static int parser_next_key_or_item(sf_parser *sfp) { + parser_discard_ows(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_EOF; + } + + if (*sfp->pos != ',') { + return SF_ERR_PARSE_ERROR; + } + + ++sfp->pos; + + parser_discard_ows(sfp); + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + return 0; +} + +static int parser_dict_value(sf_parser *sfp, sf_value *dest) { + int rv; + + if (parser_eof(sfp) || *(sfp->pos) != '=') { + /* Boolean true */ + if (dest) { + dest->type = SF_TYPE_BOOLEAN; + dest->flags = SF_VALUE_FLAG_NONE; + dest->boolean = 1; + } + + sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + + return 0; + } + + ++sfp->pos; + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + if (*sfp->pos == '(') { + if (dest) { + dest->type = SF_TYPE_INNER_LIST; + dest->flags = SF_VALUE_FLAG_NONE; + } + + ++sfp->pos; + + sfp->state = SF_STATE_DICT_INNER_LIST_BEFORE; + + return 0; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + sfp->state = SF_STATE_DICT_BEFORE_PARAMS; + + return 0; +} + +int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) { + int rv; + + switch (sfp->state) { + case SF_STATE_DICT_INNER_LIST_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_DICT_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_DICT_AFTER: + rv = parser_next_key_or_item(sfp); + if (rv != 0) { + return rv; + } + + break; + case SF_STATE_INITIAL: + parser_discard_sp(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_EOF; + } + + break; + default: + assert(0); + abort(); + } + + rv = parser_key(sfp, dest_key); + if (rv != 0) { + return rv; + } + + return parser_dict_value(sfp, dest_value); +} + +int sf_parser_list(sf_parser *sfp, sf_value *dest) { + int rv; + + switch (sfp->state) { + case SF_STATE_LIST_INNER_LIST_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_LIST_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_LIST_AFTER: + rv = parser_next_key_or_item(sfp); + if (rv != 0) { + return rv; + } + + break; + case SF_STATE_INITIAL: + parser_discard_sp(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_EOF; + } + + break; + default: + assert(0); + abort(); + } + + if (*sfp->pos == '(') { + if (dest) { + dest->type = SF_TYPE_INNER_LIST; + dest->flags = SF_VALUE_FLAG_NONE; + } + + ++sfp->pos; + + sfp->state = SF_STATE_LIST_INNER_LIST_BEFORE; + + return 0; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + sfp->state = SF_STATE_LIST_BEFORE_PARAMS; + + return 0; +} + +int sf_parser_item(sf_parser *sfp, sf_value *dest) { + int rv; + + switch (sfp->state) { + case SF_STATE_INITIAL: + parser_discard_sp(sfp); + + if (parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + break; + case SF_STATE_ITEM_INNER_LIST_BEFORE: + rv = parser_skip_inner_list(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_ITEM_BEFORE_PARAMS: + rv = parser_skip_params(sfp); + if (rv != 0) { + return rv; + } + + /* fall through */ + case SF_STATE_ITEM_AFTER: + parser_discard_sp(sfp); + + if (!parser_eof(sfp)) { + return SF_ERR_PARSE_ERROR; + } + + return SF_ERR_EOF; + default: + assert(0); + abort(); + } + + if (*sfp->pos == '(') { + if (dest) { + dest->type = SF_TYPE_INNER_LIST; + dest->flags = SF_VALUE_FLAG_NONE; + } + + ++sfp->pos; + + sfp->state = SF_STATE_ITEM_INNER_LIST_BEFORE; + + return 0; + } + + rv = parser_bare_item(sfp, dest); + if (rv != 0) { + return rv; + } + + sfp->state = SF_STATE_ITEM_BEFORE_PARAMS; + + return 0; +} + +void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) { + if (datalen == 0) { + sfp->pos = sfp->end = NULL; + } else { + sfp->pos = data; + sfp->end = data + datalen; + } + + sfp->state = SF_STATE_INITIAL; +} + +void sf_unescape(sf_vec *dest, const sf_vec *src) { + const uint8_t *p, *q; + uint8_t *o; + size_t len, slen; + + if (src->len == 0) { + *dest = *src; + + return; + } + + o = dest->base; + p = src->base; + len = src->len; + + for (;;) { + q = memchr(p, '\\', len); + if (q == NULL) { + if (len == src->len) { + *dest = *src; + + return; + } + + memcpy(o, p, len); + o += len; + + break; + } + + slen = (size_t)(q - p); + memcpy(o, p, slen); + o += slen; + + p = q + 1; + *o++ = *p++; + len -= slen + 2; + } + + dest->len = (size_t)(o - dest->base); +} + +void sf_base64decode(sf_vec *dest, const sf_vec *src) { + static const int index_tbl[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1}; + uint8_t *o; + const uint8_t *p, *end; + uint32_t n; + size_t i; + int idx; + + assert((src->len & 0x3) == 0); + + if (src->len == 0) { + *dest = *src; + + return; + } + + o = dest->base; + p = src->base; + end = src->base + src->len; + + for (; p != end;) { + n = 0; + + for (i = 1; i <= 4; ++i, ++p) { + idx = index_tbl[*p]; + + if (idx == -1) { + assert(i > 2); + + if (i == 3) { + assert(*p == '=' && *(p + 1) == '=' && p + 2 == end); + + *o++ = (uint8_t)(n >> 16); + + goto fin; + } + + assert(*p == '=' && p + 1 == end); + + *o++ = (uint8_t)(n >> 16); + *o++ = (n >> 8) & 0xffu; + + goto fin; + } + + n += (uint32_t)(idx << (24 - i * 6)); + } + + *o++ = (uint8_t)(n >> 16); + *o++ = (n >> 8) & 0xffu; + *o++ = n & 0xffu; + } + +fin: + dest->len = (size_t)(o - dest->base); +} diff --git a/deps/ngtcp2/nghttp3/lib/sfparse.h b/deps/ngtcp2/nghttp3/lib/sfparse.h new file mode 100644 index 00000000000000..1474db1429acea --- /dev/null +++ b/deps/ngtcp2/nghttp3/lib/sfparse.h @@ -0,0 +1,409 @@ +/* + * sfparse + * + * Copyright (c) 2023 sfparse contributors + * Copyright (c) 2019 nghttp3 contributors + * Copyright (c) 2015 nghttp2 contributors + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef SFPARSE_H +#define SFPARSE_H + +/* Define WIN32 when build target is Win32 API (borrowed from + libcurl) */ +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_MSC_VER) && (_MSC_VER < 1800) +/* MSVC < 2013 does not have inttypes.h because it is not C99 + compliant. See compiler macros and version number in + https://sourceforge.net/p/predef/wiki/Compilers/ */ +# include +#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +# include +#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ +#include +#include + +/** + * @enum + * + * :type:`sf_type` defines value type. + */ +typedef enum sf_type { + /** + * :enum:`SF_TYPE_BOOLEAN` indicates boolean type. + */ + SF_TYPE_BOOLEAN, + /** + * :enum:`SF_TYPE_INTEGER` indicates integer type. + */ + SF_TYPE_INTEGER, + /** + * :enum:`SF_TYPE_DECIMAL` indicates decimal type. + */ + SF_TYPE_DECIMAL, + /** + * :enum:`SF_TYPE_STRING` indicates string type. + */ + SF_TYPE_STRING, + /** + * :enum:`SF_TYPE_TOKEN` indicates token type. + */ + SF_TYPE_TOKEN, + /** + * :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type. + */ + SF_TYPE_BYTESEQ, + /** + * :enum:`SF_TYPE_INNER_LIST` indicates inner list type. + */ + SF_TYPE_INNER_LIST, + /** + * :enum:`SF_TYPE_DATE` indicates date type. + */ + SF_TYPE_DATE +} sf_type; + +/** + * @macro + * + * :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has + * occurred, and it is not possible to continue the processing. + */ +#define SF_ERR_PARSE_ERROR -1 + +/** + * @macro + * + * :macro:`SF_ERR_EOF` indicates that there is nothing left to read. + * The context of this error varies depending on the function that + * returns this error code. + */ +#define SF_ERR_EOF -2 + +/** + * @struct + * + * :type:`sf_vec` stores sequence of bytes. + */ +typedef struct sf_vec { + /** + * :member:`base` points to the beginning of the sequence of bytes. + */ + uint8_t *base; + /** + * :member:`len` is the number of bytes contained in this sequence. + */ + size_t len; +} sf_vec; + +/** + * @macro + * + * :macro:`SF_VALUE_FLAG_NONE` indicates no flag set. + */ +#define SF_VALUE_FLAG_NONE 0x0u + +/** + * @macro + * + * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string + * contains escaped character(s). + */ +#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u + +/** + * @struct + * + * :type:`sf_decimal` contains decimal value. + */ +typedef struct sf_decimal { + /** + * :member:`numer` contains numerator of the decimal value. + */ + int64_t numer; + /** + * :member:`denom` contains denominator of the decimal value. + */ + int64_t denom; +} sf_decimal; + +/** + * @struct + * + * :type:`sf_value` stores a Structured Field item. For Inner List, + * only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order + * to read the items contained in an inner list, call + * `sf_parser_inner_list`. + */ +typedef struct sf_value { + /** + * :member:`type` is the type of the value contained in this + * particular object. + */ + sf_type type; + /** + * :member:`flags` is bitwise OR of one or more of + * :macro:`SF_VALUE_FLAG_* `. + */ + uint32_t flags; + /** + * @anonunion_start + * + * @sf_value_value + */ + union { + /** + * :member:`boolean` contains boolean value if :member:`type` == + * :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0 + * indicates false. + */ + int boolean; + /** + * :member:`integer` contains integer value if :member:`type` is + * either :enum:`sf_type.SF_TYPE_INTEGER` or + * :enum:`sf_type.SF_TYPE_DATE`. + */ + int64_t integer; + /** + * :member:`decimal` contains decimal value if :member:`type` == + * :enum:`sf_type.SF_TYPE_DECIMAL`. + */ + sf_decimal decimal; + /** + * :member:`vec` contains sequence of bytes if :member:`type` is + * either :enum:`sf_type.SF_TYPE_STRING`, + * :enum:`sf_type.SF_TYPE_TOKEN`, or + * :enum:`sf_type.SF_TYPE_BYTESEQ`. + * + * For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or + * more escaped characters if :member:`flags` has + * :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the + * string, use `sf_unescape`. + * + * For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64 + * encoded string. To decode this byte string, use + * `sf_base64decode`. + * + * If :member:`vec.len ` == 0, :member:`vec.base + * ` is guaranteed to be NULL. + */ + sf_vec vec; + /** + * @anonunion_end + */ + }; +} sf_value; + +/** + * @struct + * + * :type:`sf_parser` is the Structured Field Values parser. Use + * `sf_parser_init` to initialize it. + */ +typedef struct sf_parser { + /* all fields are private */ + const uint8_t *pos; + const uint8_t *end; + uint32_t state; +} sf_parser; + +/** + * @function + * + * `sf_parser_init` initializes |sfp| with the given buffer pointed by + * |data| of length |datalen|. + */ +void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen); + +/** + * @function + * + * `sf_parser_param` reads a parameter. If this function returns 0, + * it stores parameter key and value in |dest_key| and |dest_value| + * respectively, if they are not NULL. + * + * This function does no effort to find duplicated keys. Same key may + * be reported more than once. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all parameters have + * read, and caller can continue to read rest of the values. If it + * returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error + * while parsing field value. + */ +int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); + +/** + * @function + * + * `sf_parser_dict` reads the next dictionary key and value pair. If + * this function returns 0, it stores the key and value in |dest_key| + * and |dest_value| respectively, if they are not NULL. + * + * Caller can optionally read parameters attached to the pair by + * calling `sf_parser_param`. + * + * This function does no effort to find duplicated keys. Same key may + * be reported more than once. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all key and value + * pairs have been read, and there is nothing left to read. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * All values in the dictionary have read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); + +/** + * @function + * + * `sf_parser_list` reads the next list item. If this function + * returns 0, it stores the item in |dest| if it is not NULL. + * + * Caller can optionally read parameters attached to the item by + * calling `sf_parser_param`. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all values in the + * list have been read, and there is nothing left to read. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * All values in the list have read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_list(sf_parser *sfp, sf_value *dest); + +/** + * @function + * + * `sf_parser_item` reads a single item. If this function returns 0, + * it stores the item in |dest| if it is not NULL. + * + * This function is only used for the field value that consists of a + * single item. + * + * Caller can optionally read parameters attached to the item by + * calling `sf_parser_param`. + * + * Caller should call this function again to make sure that there is + * nothing left to read. If this 2nd function call returns + * :macro:`SF_ERR_EOF`, all data have been processed successfully. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * There is nothing left to read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_item(sf_parser *sfp, sf_value *dest); + +/** + * @function + * + * `sf_parser_inner_list` reads the next inner list item. If this + * function returns 0, it stores the item in |dest| if it is not NULL. + * + * Caller can optionally read parameters attached to the item by + * calling `sf_parser_param`. + * + * Caller should keep calling this function until it returns negative + * error code. If it returns :macro:`SF_ERR_EOF`, all values in this + * inner list have been read, and caller can optionally read + * parameters attached to this inner list by calling + * `sf_parser_param`. Then caller can continue to read rest of the + * values. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :macro:`SF_ERR_EOF` + * All values in the inner list have read. + * :macro:`SF_ERR_PARSE_ERROR` + * It encountered fatal error while parsing field value. + */ +int sf_parser_inner_list(sf_parser *sfp, sf_value *dest); + +/** + * @function + * + * `sf_unescape` copies |src| to |dest| by removing escapes (``\``). + * |src| should be the pointer to :member:`sf_value.vec` of type + * :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`, + * `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or + * `sf_parser_param`, otherwise the behavior is undefined. + * + * :member:`dest->base ` must point to the buffer that + * has sufficient space to store the unescaped string. + * + * If there is no escape character in |src|, |*src| is assigned to + * |*dest|. This includes the case that :member:`src->len + * ` == 0. + * + * This function sets the length of unescaped string to + * :member:`dest->len `. + */ +void sf_unescape(sf_vec *dest, const sf_vec *src); + +/** + * @function + * + * `sf_base64decode` decodes Base64 encoded string |src| and writes + * the result into |dest|. |src| should be the pointer to + * :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ` + * produced by either `sf_parser_dict`, `sf_parser_list`, + * `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`, + * otherwise the behavior is undefined. + * + * :member:`dest->base ` must point to the buffer that + * has sufficient space to store the decoded byte string. + * + * If :member:`src->len ` == 0, |*src| is assigned to + * |*dest|. + * + * This function sets the length of decoded byte string to + * :member:`dest->len `. + */ +void sf_base64decode(sf_vec *dest, const sf_vec *src); + +#ifdef __cplusplus +} +#endif + +#endif /* SFPARSE_H */