deps: update nghttp3 to 1.13.1
Some checks are pending
Coverage Linux (without intl) / coverage-linux-without-intl (push) Waiting to run
Coverage Linux / coverage-linux (push) Waiting to run
Coverage Windows / coverage-windows (push) Waiting to run
Test and upload documentation to artifacts / build-docs (push) Waiting to run
Linters / lint-addon-docs (push) Waiting to run
Linters / lint-cpp (push) Waiting to run
Linters / format-cpp (push) Waiting to run
Linters / lint-js-and-md (push) Waiting to run
Linters / lint-nix (push) Waiting to run
Linters / lint-py (push) Waiting to run
Linters / lint-yaml (push) Waiting to run
Linters / lint-sh (push) Waiting to run
Linters / lint-codeowners (push) Waiting to run
Linters / lint-pr-url (push) Waiting to run
Linters / lint-readme (push) Waiting to run
Notify on Push / Notify on Force Push on `main` (push) Waiting to run
Notify on Push / Notify on Push on `main` with invalid message (push) Waiting to run
Scorecard supply-chain security / Scorecard analysis (push) Waiting to run

PR-URL: https://github.com/nodejs/node/pull/60046
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
Node.js GitHub Bot 2025-12-27 17:14:40 +00:00 committed by GitHub
parent 0804ec4cfe
commit 15bdf38fd8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 6851 additions and 4767 deletions

View File

@ -81,6 +81,59 @@ extern "C" {
*/
typedef ptrdiff_t nghttp3_ssize;
/**
* @typedef
*
* :type:`nghttp3_tstamp` is a timestamp with nanosecond resolution.
* ``UINT64_MAX`` is an invalid value, and it is often used to
* indicate that no value is set. This type is available since
* v1.12.0.
*/
typedef uint64_t nghttp3_tstamp;
/**
* @typedef
*
* :type:`nghttp3_duration` is a period of time in nanosecond
* resolution. ``UINT64_MAX`` is an invalid value, and it is often
* used to indicate that no value is set. This type is available
* since v1.12.0.
*/
typedef uint64_t nghttp3_duration;
/**
* @macro
*
* :macro:`NGHTTP3_NANOSECONDS` is a count of tick which corresponds
* to 1 nanosecond. This macro is available since v1.12.0.
*/
#define NGHTTP3_NANOSECONDS ((nghttp3_duration)1ULL)
/**
* @macro
*
* :macro:`NGHTTP3_MICROSECONDS` is a count of tick which corresponds
* to 1 microsecond. This macro is available since v1.12.0.
*/
#define NGHTTP3_MICROSECONDS ((nghttp3_duration)(1000ULL * NGHTTP3_NANOSECONDS))
/**
* @macro
*
* :macro:`NGHTTP3_MILLISECONDS` is a count of tick which corresponds
* to 1 millisecond. This macro is available since v1.12.0.
*/
#define NGHTTP3_MILLISECONDS \
((nghttp3_duration)(1000ULL * NGHTTP3_MICROSECONDS))
/**
* @macro
*
* :macro:`NGHTTP3_SECONDS` is a count of tick which corresponds to 1
* second. This macro is available since v1.12.0.
*/
#define NGHTTP3_SECONDS ((nghttp3_duration)(1000ULL * NGHTTP3_MILLISECONDS))
/**
* @macro
*
@ -264,6 +317,14 @@ typedef ptrdiff_t nghttp3_ssize;
* allowed.
*/
#define NGHTTP3_ERR_H3_STREAM_CREATION_ERROR -609
/**
* @macro
*
* :macro:`NGHTTP3_ERR_H3_EXCESSIVE_LOAD` indicates that a local
* endpoint detected that its remote endpoint is exhibiting a behavior
* that might generating excessive load.
*/
#define NGHTTP3_ERR_H3_EXCESSIVE_LOAD -610
/**
* @macro
*
@ -1090,6 +1151,32 @@ typedef struct nghttp3_qpack_nv {
uint8_t flags;
} nghttp3_qpack_nv;
/**
* @enum
*
* :type:`nghttp3_qpack_indexing_strat` defines the QPACK dynamic
* table indexing strategies for fields not defined in
* :type:`nghttp3_qpack_token`. This type is available since v1.13.0.
*/
typedef enum nghttp3_qpack_indexing_strat {
/**
* :enum:`NGHTTP3_QPACK_INDEXING_STRAT_NONE` does not index any
* fields not defined in :type:`nghttp3_qpack_token`. This is the
* default strategy. You can still use
* :macro:`NGHTTP3_NV_FLAG_TRY_INDEX` to index a particular field.
* This enum is available since v1.13.0.
*/
NGHTTP3_QPACK_INDEXING_STRAT_NONE,
/**
* :enum:`NGHTTP3_QPACK_INDEXING_STRAT_EAGER` indexes all fields not
* defined in :type:`nghttp3_qpack_token`. Please note that QPACK
* encoder might not index the field in various reasons. This enum
* is available since v1.13.0.
*/
NGHTTP3_QPACK_INDEXING_STRAT_EAGER
} nghttp3_qpack_indexing_strat;
/**
* @struct
*
@ -1238,6 +1325,18 @@ NGHTTP3_EXTERN void
nghttp3_qpack_encoder_set_max_blocked_streams(nghttp3_qpack_encoder *encoder,
size_t max_blocked_streams);
/**
* @function
*
* `nghttp3_qpack_encoder_set_indexing_strat` sets the dynamic table
* indexing strategy |strat| to |encoder|. This function is available
* since v1.13.0.
*/
NGHTTP3_EXTERN void
nghttp3_qpack_encoder_set_indexing_strat(nghttp3_qpack_encoder *encoder,
nghttp3_qpack_indexing_strat strat);
/**
* @function
*
@ -1638,7 +1737,9 @@ typedef struct nghttp3_conn nghttp3_conn;
#define NGHTTP3_SETTINGS_V1 1
#define NGHTTP3_SETTINGS_V2 2
#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_V2
#define NGHTTP3_SETTINGS_V3 3
#define NGHTTP3_SETTINGS_V4 4
#define NGHTTP3_SETTINGS_VERSION NGHTTP3_SETTINGS_V4
/**
* @struct
@ -1700,6 +1801,31 @@ typedef struct nghttp3_settings {
* server uses this field. This field is available since v1.11.0.
*/
const nghttp3_vec *origin_list;
/* The following fields have been added since NGHTTP3_SETTINGS_V3. */
/**
* :member:`glitch_ratelim_burst` is the maximum number of tokens
* available to "glitch" rate limiter. "glitch" is a suspicious
* activity from a remote endpoint. If detected, certain amount of
* tokens are consumed. If no tokens are available to consume, the
* connection is closed. The rate of token generation is specified
* by :member:`glitch_ratelim_rate`. This feature is enabled only
* when `nghttp3_conn_read_stream2` is used. This field has been
* available since v1.12.0.
*/
uint64_t glitch_ratelim_burst;
/**
* :member:`glitch_ratelim_rate` is the number of tokens generated
* per second. See :member:`glitch_ratelim_burst` for "glitch" rate
* limiter. This field has been available since v1.12.0.
*/
uint64_t glitch_ratelim_rate;
/**
* :member:`qpack_indexing_strat` defines the QPACK dynamic table
* indexing strategy for those fields that are not defined in
* :type:`nghttp3_qpack_token`. This field has been available since
* v1.13.0.
*/
nghttp3_qpack_indexing_strat qpack_indexing_strat;
} nghttp3_settings;
/**
@ -2113,6 +2239,10 @@ typedef struct nghttp3_callbacks {
* <nghttp3_settings.qpack_blocked_streams>` = 0
* - :member:`enable_connect_protocol
* <nghttp3_settings.enable_connect_protocol>` = 0
* - :member:`glitch_ratelim_burst
* <nghttp3_settings.glitch_ratelim_burst>` = 1000
* - :member:`glitch_ratelim_rate
* <nghttp3_settings.glitch_ratelim_rate>` = 33
*/
NGHTTP3_EXTERN void
nghttp3_settings_default_versioned(int settings_version,
@ -2209,6 +2339,11 @@ NGHTTP3_EXTERN int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn,
/**
* @function
*
* .. warning::
*
* Deprecated since v1.12.0. Use `nghttp3_conn_read_stream2`
* instead.
*
* `nghttp3_conn_read_stream` reads data |src| of length |srclen| on
* stream identified by |stream_id|. It returns the number of bytes
* consumed. The "consumed" means that application can increase flow
@ -2237,6 +2372,42 @@ NGHTTP3_EXTERN nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn,
const uint8_t *src,
size_t srclen, int fin);
/**
* @function
*
* `nghttp3_conn_read_stream2` reads data |src| of length |srclen| on
* stream identified by |stream_id|. It returns the number of bytes
* consumed. The "consumed" means that application can increase flow
* control credit (both stream and connection) of underlying QUIC
* connection by that amount. It does not include the amount of data
* carried by DATA frame which contains application data (excluding
* any control or QPACK unidirectional streams). See
* :type:`nghttp3_recv_data` to handle those bytes. If |fin| is
* nonzero, this is the last data from remote endpoint in this stream.
* |ts| is the current timestamp, and must be non-decreasing. It
* should be obtained from the clock that is steadily increasing.
*
* This function returns the number of bytes consumed, or one of the
* following negative error codes:
*
* :macro:`NGHTTP3_ERR_NOMEM`
* Out of memory.
* :macro:`NGHTTP3_ERR_CALLBACK_FAILURE`
* User callback failed.
*
* It may return the other error codes. The negative error code means
* that |conn| encountered a connection error, and the connection must
* be closed. Calling nghttp3 API other than `nghttp3_conn_del`
* causes undefined behavior.
*
* This function is available since v1.12.0.
*/
NGHTTP3_EXTERN nghttp3_ssize nghttp3_conn_read_stream2(nghttp3_conn *conn,
int64_t stream_id,
const uint8_t *src,
size_t srclen, int fin,
nghttp3_tstamp ts);
/**
* @function
*

View File

@ -31,7 +31,7 @@
*
* Version number of the nghttp3 library release.
*/
#define NGHTTP3_VERSION "1.11.0"
#define NGHTTP3_VERSION "1.13.1"
/**
* @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 0x010b00
#define NGHTTP3_VERSION_NUM 0x010d01
#endif /* !defined(NGHTTP3_VERSION_H) */

View File

@ -72,7 +72,7 @@ int nghttp3_balloc_get(nghttp3_balloc *balloc, void **pbuf, size_t n) {
return NGHTTP3_ERR_NOMEM;
}
hd = (nghttp3_memblock_hd *)(void *)p;
hd = (void *)p;
hd->next = balloc->head;
balloc->head = hd;
nghttp3_buf_wrap_init(

View File

@ -231,6 +231,15 @@ static int conn_call_end_origin(nghttp3_conn *conn) {
return 0;
}
static int conn_glitch_ratelim_drain(nghttp3_conn *conn, uint64_t n,
nghttp3_tstamp ts) {
if (ts == UINT64_MAX) {
return 0;
}
return nghttp3_ratelim_drain(&conn->glitch_rlim, n, ts);
}
static int ricnt_less(const nghttp3_pq_entry *lhsx,
const nghttp3_pq_entry *rhsx) {
nghttp3_stream *lhs =
@ -300,6 +309,8 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version,
nghttp3_qpack_encoder_init(
&conn->qenc, settings->qpack_encoder_max_dtable_capacity, ++map_seed, mem);
nghttp3_qpack_encoder_set_indexing_strat(&conn->qenc,
settings->qpack_indexing_strat);
nghttp3_pq_init(&conn->qpack_blocked_streams, ricnt_less, mem);
@ -309,6 +320,9 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version,
nghttp3_idtr_init(&conn->remote.bidi.idtr, mem);
nghttp3_ratelim_init(&conn->glitch_rlim, settings->glitch_ratelim_burst,
settings->glitch_ratelim_rate, 0);
conn->callbacks = *callbacks;
conn->local.settings = *settings;
if (server) {
@ -427,6 +441,13 @@ static int conn_bidi_idtr_open(nghttp3_conn *conn, int64_t stream_id) {
nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id,
const uint8_t *src, size_t srclen,
int fin) {
return nghttp3_conn_read_stream2(conn, stream_id, src, srclen, fin,
UINT64_MAX);
}
nghttp3_ssize nghttp3_conn_read_stream2(nghttp3_conn *conn, int64_t stream_id,
const uint8_t *src, size_t srclen,
int fin, nghttp3_tstamp ts) {
nghttp3_stream *stream;
size_t bidi_nproc;
int rv;
@ -517,13 +538,14 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id,
}
if (nghttp3_stream_uni(stream_id)) {
return nghttp3_conn_read_uni(conn, stream, src, srclen, fin);
return nghttp3_conn_read_uni(conn, stream, src, srclen, fin, ts);
}
if (fin) {
stream->flags |= NGHTTP3_STREAM_FLAG_READ_EOF;
}
return nghttp3_conn_read_bidi(conn, &bidi_nproc, stream, src, srclen, fin);
return nghttp3_conn_read_bidi(conn, &bidi_nproc, stream, src, srclen, fin,
ts);
}
static nghttp3_ssize conn_read_type(nghttp3_conn *conn, nghttp3_stream *stream,
@ -586,8 +608,8 @@ static nghttp3_ssize conn_read_type(nghttp3_conn *conn, nghttp3_stream *stream,
static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream);
nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream,
const uint8_t *src, size_t srclen,
int fin) {
const uint8_t *src, size_t srclen, int fin,
nghttp3_tstamp ts) {
nghttp3_ssize nread = 0;
nghttp3_ssize nconsumed = 0;
int rv;
@ -603,6 +625,12 @@ nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream,
return NGHTTP3_ERR_H3_GENERAL_PROTOCOL_ERROR;
}
/* Receiving too frequent 0 length unidirectional stream is
suspicious. */
if (conn_glitch_ratelim_drain(conn, 1, ts) != 0) {
return NGHTTP3_ERR_H3_EXCESSIVE_LOAD;
}
rv = conn_delete_stream(conn, stream);
assert(0 == rv);
@ -620,6 +648,21 @@ nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream,
src += nread;
srclen -= (size_t)nread;
if (stream->type == NGHTTP3_STREAM_TYPE_UNKNOWN) {
/* Receiving too frequent unknown stream type is suspicious.*/
if (conn_glitch_ratelim_drain(conn, 1, ts) != 0) {
return NGHTTP3_ERR_H3_EXCESSIVE_LOAD;
}
if (!fin) {
rv = conn_call_stop_sending(conn, stream,
NGHTTP3_H3_STREAM_CREATION_ERROR);
if (rv != 0) {
return rv;
}
}
}
if (srclen == 0) {
return nread;
}
@ -630,13 +673,13 @@ nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream,
if (fin) {
return NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM;
}
nconsumed = nghttp3_conn_read_control(conn, stream, src, srclen);
nconsumed = nghttp3_conn_read_control(conn, stream, src, srclen, ts);
break;
case NGHTTP3_STREAM_TYPE_QPACK_ENCODER:
if (fin) {
return NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM;
}
nconsumed = nghttp3_conn_read_qpack_encoder(conn, src, srclen);
nconsumed = nghttp3_conn_read_qpack_encoder(conn, src, srclen, ts);
break;
case NGHTTP3_STREAM_TYPE_QPACK_DECODER:
if (fin) {
@ -646,14 +689,6 @@ nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream,
break;
case NGHTTP3_STREAM_TYPE_UNKNOWN:
nconsumed = (nghttp3_ssize)srclen;
if (fin) {
break;
}
rv = conn_call_stop_sending(conn, stream, NGHTTP3_H3_STREAM_CREATION_ERROR);
if (rv != 0) {
return rv;
}
break;
default:
nghttp3_unreachable();
@ -677,7 +712,8 @@ static int frame_fin(nghttp3_stream_read_state *rstate, size_t len) {
nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
nghttp3_stream *stream,
const uint8_t *src, size_t srclen) {
const uint8_t *src, size_t srclen,
nghttp3_tstamp ts) {
const uint8_t *p = src, *end = src + srclen;
int rv;
nghttp3_stream_read_state *rstate = &stream->rstate;
@ -775,12 +811,23 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
if (rstate->left == 0) {
return NGHTTP3_ERR_H3_FRAME_ERROR;
}
/* We do not expect too frequent priority updates. */
if (conn_glitch_ratelim_drain(conn, 1, ts) != 0) {
return NGHTTP3_ERR_H3_EXCESSIVE_LOAD;
}
rstate->state = NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE_PRI_ELEM_ID;
break;
case NGHTTP3_FRAME_PRIORITY_UPDATE_PUSH_ID:
/* We do not support push */
return NGHTTP3_ERR_H3_ID_ERROR;
case NGHTTP3_FRAME_ORIGIN:
/* We do not expect too frequent ORIGIN frames. */
if (conn_glitch_ratelim_drain(conn, 1, ts) != 0) {
return NGHTTP3_ERR_H3_EXCESSIVE_LOAD;
}
if (conn->server ||
(!conn->callbacks.recv_origin && !conn->callbacks.end_origin)) {
busy = 1;
@ -815,6 +862,11 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
case NGHTTP3_H2_FRAME_CONTINUATION:
return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
default:
/* We do not expect too frequent unknown frames. */
if (conn_glitch_ratelim_drain(conn, 1, ts) != 0) {
return NGHTTP3_ERR_H3_EXCESSIVE_LOAD;
}
/* TODO Handle reserved frame type */
busy = 1;
rstate->state = NGHTTP3_CTRL_STREAM_STATE_IGN_FRAME;
@ -971,6 +1023,12 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
return NGHTTP3_ERR_H3_ID_ERROR;
}
/* Receiving same GOAWAY ID is suspicious. */
if (conn->rx.goaway_id == rvint->acc &&
conn_glitch_ratelim_drain(conn, 1, ts) != 0) {
return NGHTTP3_ERR_H3_EXCESSIVE_LOAD;
}
conn->flags |= NGHTTP3_CONN_FLAG_GOAWAY_RECVED;
conn->rx.goaway_id = rvint->acc;
nghttp3_varint_read_state_reset(rvint);
@ -1005,6 +1063,12 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
return NGHTTP3_ERR_H3_FRAME_ERROR;
}
/* Receiving same MAX_PUSH_ID is suspicious. */
if (conn->local.uni.max_pushes == (uint64_t)rvint->acc + 1 &&
conn_glitch_ratelim_drain(conn, 1, ts) != 0) {
return NGHTTP3_ERR_H3_EXCESSIVE_LOAD;
}
conn->local.uni.max_pushes = (uint64_t)rvint->acc + 1;
nghttp3_varint_read_state_reset(rvint);
@ -1263,11 +1327,23 @@ static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream) {
return rv;
}
if (bidi && conn->callbacks.stream_close) {
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;
if (bidi) {
if (stream->qpack_blocked_pe.index != NGHTTP3_PQ_BAD_INDEX) {
nghttp3_conn_qpack_blocked_streams_remove(conn, stream);
rv = nghttp3_qpack_decoder_cancel_stream(&conn->qdec, stream->node.id);
if (rv != 0) {
return rv;
}
}
if (conn->callbacks.stream_close) {
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;
}
}
}
@ -1288,7 +1364,8 @@ static int conn_delete_stream(nghttp3_conn *conn, nghttp3_stream *stream) {
}
static int conn_process_blocked_stream_data(nghttp3_conn *conn,
nghttp3_stream *stream) {
nghttp3_stream *stream,
nghttp3_tstamp ts) {
nghttp3_buf *buf;
size_t nproc;
nghttp3_ssize nconsumed;
@ -1307,7 +1384,7 @@ static int conn_process_blocked_stream_data(nghttp3_conn *conn,
nconsumed = nghttp3_conn_read_bidi(
conn, &nproc, stream, buf->pos, nghttp3_buf_len(buf),
len == 1 && (stream->flags & NGHTTP3_STREAM_FLAG_READ_EOF));
len == 1 && (stream->flags & NGHTTP3_STREAM_FLAG_READ_EOF), ts);
if (nconsumed < 0) {
return (int)nconsumed;
}
@ -1329,22 +1406,12 @@ static int conn_process_blocked_stream_data(nghttp3_conn *conn,
}
}
if (!(stream->flags & NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED) &&
(stream->flags & NGHTTP3_STREAM_FLAG_CLOSED)) {
assert(stream->qpack_blocked_pe.index == NGHTTP3_PQ_BAD_INDEX);
rv = conn_delete_stream(conn, stream);
if (rv != 0) {
return rv;
}
}
return 0;
}
nghttp3_ssize nghttp3_conn_read_qpack_encoder(nghttp3_conn *conn,
const uint8_t *src,
size_t srclen) {
const uint8_t *src, size_t srclen,
nghttp3_tstamp ts) {
nghttp3_ssize nconsumed =
nghttp3_qpack_decoder_read_encoder(&conn->qdec, src, srclen);
nghttp3_stream *stream;
@ -1366,7 +1433,7 @@ nghttp3_ssize nghttp3_conn_read_qpack_encoder(nghttp3_conn *conn,
stream->qpack_blocked_pe.index = NGHTTP3_PQ_BAD_INDEX;
stream->flags &= (uint16_t)~NGHTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED;
rv = conn_process_blocked_stream_data(conn, stream);
rv = conn_process_blocked_stream_data(conn, stream, ts);
if (rv != 0) {
return rv;
}
@ -1407,7 +1474,8 @@ static int conn_update_stream_priority(nghttp3_conn *conn,
nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc,
nghttp3_stream *stream, const uint8_t *src,
size_t srclen, int fin) {
size_t srclen, int fin,
nghttp3_tstamp ts) {
const uint8_t *p = src, *end = src ? src + srclen : src;
int rv;
nghttp3_stream_read_state *rstate = &stream->rstate;
@ -1546,6 +1614,11 @@ nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc,
case NGHTTP3_H2_FRAME_CONTINUATION:
return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
default:
/* We do not expect too frequent unknown frames. */
if (conn_glitch_ratelim_drain(conn, 1, ts) != 0) {
return NGHTTP3_ERR_H3_EXCESSIVE_LOAD;
}
/* TODO Handle reserved frame type */
busy = 1;
rstate->state = NGHTTP3_REQ_STREAM_STATE_IGN_FRAME;
@ -2602,10 +2675,9 @@ int nghttp3_conn_is_stream_writable(nghttp3_conn *conn, int64_t stream_id) {
return 0;
}
return (stream->flags &
(NGHTTP3_STREAM_FLAG_FC_BLOCKED |
NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED | NGHTTP3_STREAM_FLAG_SHUT_WR |
NGHTTP3_STREAM_FLAG_CLOSED)) == 0;
return (stream->flags & (NGHTTP3_STREAM_FLAG_FC_BLOCKED |
NGHTTP3_STREAM_FLAG_READ_DATA_BLOCKED |
NGHTTP3_STREAM_FLAG_SHUT_WR)) == 0;
}
int nghttp3_conn_resume_stream(nghttp3_conn *conn, int64_t stream_id) {
@ -2642,12 +2714,7 @@ int nghttp3_conn_close_stream(nghttp3_conn *conn, int64_t stream_id,
nghttp3_conn_unschedule_stream(conn, stream);
if (stream->qpack_blocked_pe.index == NGHTTP3_PQ_BAD_INDEX) {
return conn_delete_stream(conn, stream);
}
stream->flags |= NGHTTP3_STREAM_FLAG_CLOSED;
return 0;
return conn_delete_stream(conn, stream);
}
int nghttp3_conn_shutdown_stream_read(nghttp3_conn *conn, int64_t stream_id) {
@ -2685,6 +2752,14 @@ void nghttp3_conn_qpack_blocked_streams_pop(nghttp3_conn *conn) {
nghttp3_pq_pop(&conn->qpack_blocked_streams);
}
void nghttp3_conn_qpack_blocked_streams_remove(nghttp3_conn *conn,
nghttp3_stream *stream) {
assert(!nghttp3_pq_empty(&conn->qpack_blocked_streams));
assert(stream->qpack_blocked_pe.index != NGHTTP3_PQ_BAD_INDEX);
nghttp3_pq_remove(&conn->qpack_blocked_streams, &stream->qpack_blocked_pe);
}
void nghttp3_conn_set_max_client_streams_bidi(nghttp3_conn *conn,
uint64_t max_streams) {
assert(conn->server);

View File

@ -37,6 +37,7 @@
#include "nghttp3_tnode.h"
#include "nghttp3_idtr.h"
#include "nghttp3_gaptr.h"
#include "nghttp3_ratelim.h"
/* NGHTTP3_QPACK_ENCODER_MAX_TABLE_CAPACITY is the maximum dynamic
table size for QPACK encoder. */
@ -84,6 +85,7 @@ struct nghttp3_conn {
nghttp3_qpack_decoder qdec;
nghttp3_qpack_encoder qenc;
nghttp3_pq qpack_blocked_streams;
nghttp3_ratelim glitch_rlim;
struct {
nghttp3_pq spq;
} sched[NGHTTP3_URGENCY_LEVELS];
@ -180,18 +182,20 @@ int nghttp3_conn_create_stream(nghttp3_conn *conn, nghttp3_stream **pstream,
nghttp3_ssize nghttp3_conn_read_bidi(nghttp3_conn *conn, size_t *pnproc,
nghttp3_stream *stream, const uint8_t *src,
size_t srclen, int fin);
size_t srclen, int fin, nghttp3_tstamp ts);
nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream,
const uint8_t *src, size_t srclen, int fin);
const uint8_t *src, size_t srclen, int fin,
nghttp3_tstamp ts);
nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
nghttp3_stream *stream,
const uint8_t *src, size_t srclen);
const uint8_t *src, size_t srclen,
nghttp3_tstamp ts);
nghttp3_ssize nghttp3_conn_read_qpack_encoder(nghttp3_conn *conn,
const uint8_t *src,
size_t srclen);
const uint8_t *src, size_t srclen,
nghttp3_tstamp ts);
nghttp3_ssize nghttp3_conn_read_qpack_decoder(nghttp3_conn *conn,
const uint8_t *src,
@ -216,6 +220,9 @@ int nghttp3_conn_qpack_blocked_streams_push(nghttp3_conn *conn,
void nghttp3_conn_qpack_blocked_streams_pop(nghttp3_conn *conn);
void nghttp3_conn_qpack_blocked_streams_remove(nghttp3_conn *conn,
nghttp3_stream *stream);
int nghttp3_conn_schedule_stream(nghttp3_conn *conn, nghttp3_stream *stream);
int nghttp3_conn_ensure_stream_scheduled(nghttp3_conn *conn,

View File

@ -74,6 +74,8 @@ const char *nghttp3_strerror(int liberr) {
return "ERR_H3_SETTINGS_ERROR";
case NGHTTP3_ERR_H3_STREAM_CREATION_ERROR:
return "ERR_H3_STREAM_CREATION_ERROR";
case NGHTTP3_ERR_H3_EXCESSIVE_LOAD:
return "ERR_H3_EXCESSIVE_LOAD";
case NGHTTP3_ERR_NOMEM:
return "ERR_NOMEM";
case NGHTTP3_ERR_CALLBACK_FAILURE:
@ -116,6 +118,8 @@ uint64_t nghttp3_err_infer_quic_app_error_code(int liberr) {
return NGHTTP3_H3_SETTINGS_ERROR;
case NGHTTP3_ERR_H3_STREAM_CREATION_ERROR:
return NGHTTP3_H3_STREAM_CREATION_ERROR;
case NGHTTP3_ERR_H3_EXCESSIVE_LOAD:
return NGHTTP3_H3_EXCESSIVE_LOAD;
case NGHTTP3_ERR_MALFORMED_HTTP_HEADER:
case NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING:
return NGHTTP3_H3_MESSAGE_ERROR;

View File

@ -180,72 +180,19 @@ int nghttp3_pri_parse_priority_versioned(int pri_version, nghttp3_pri *dest,
return nghttp3_http_parse_priority(dest, value, valuelen);
}
/* Generated by genauthroitychartbl.py */
static char VALID_AUTHORITY_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 /* " */, 0 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
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 */, 1 /* [ */,
0 /* \ */, 1 /* ] */, 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 /* } */, 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 const char VALID_AUTHORITY_CHARS[256] = {
['!'] = 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, ['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, ['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,
};
static int check_authority(const uint8_t *value, size_t len) {
@ -282,72 +229,18 @@ static int check_scheme(const uint8_t *value, size_t len) {
return 1;
}
/* Generated by genmethodchartbl.py */
static char VALID_METHOD_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 /* . */, 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 /* @ */, 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 const char VALID_METHOD_CHARS[256] = {
['!'] = 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, ['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,
['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,
};
static int check_method(const uint8_t *value, size_t len) {
@ -363,72 +256,44 @@ static int check_method(const uint8_t *value, size_t len) {
return 1;
}
/* Generated by genpathchartbl.py */
static char VALID_PATH_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 /* ! */, 1 /* " */, 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 /* [ */,
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 /* { */,
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
static const char VALID_PATH_CHARS[256] = {
['!'] = 1, ['"'] = 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, ['['] = 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,
['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1, [0x80] = 1, [0x81] = 1,
[0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1, [0x86] = 1, [0x87] = 1,
[0x88] = 1, [0x89] = 1, [0x8a] = 1, [0x8b] = 1, [0x8c] = 1, [0x8d] = 1,
[0x8e] = 1, [0x8f] = 1, [0x90] = 1, [0x91] = 1, [0x92] = 1, [0x93] = 1,
[0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1, [0x98] = 1, [0x99] = 1,
[0x9a] = 1, [0x9b] = 1, [0x9c] = 1, [0x9d] = 1, [0x9e] = 1, [0x9f] = 1,
[0xa0] = 1, [0xa1] = 1, [0xa2] = 1, [0xa3] = 1, [0xa4] = 1, [0xa5] = 1,
[0xa6] = 1, [0xa7] = 1, [0xa8] = 1, [0xa9] = 1, [0xaa] = 1, [0xab] = 1,
[0xac] = 1, [0xad] = 1, [0xae] = 1, [0xaf] = 1, [0xb0] = 1, [0xb1] = 1,
[0xb2] = 1, [0xb3] = 1, [0xb4] = 1, [0xb5] = 1, [0xb6] = 1, [0xb7] = 1,
[0xb8] = 1, [0xb9] = 1, [0xba] = 1, [0xbb] = 1, [0xbc] = 1, [0xbd] = 1,
[0xbe] = 1, [0xbf] = 1, [0xc0] = 1, [0xc1] = 1, [0xc2] = 1, [0xc3] = 1,
[0xc4] = 1, [0xc5] = 1, [0xc6] = 1, [0xc7] = 1, [0xc8] = 1, [0xc9] = 1,
[0xca] = 1, [0xcb] = 1, [0xcc] = 1, [0xcd] = 1, [0xce] = 1, [0xcf] = 1,
[0xd0] = 1, [0xd1] = 1, [0xd2] = 1, [0xd3] = 1, [0xd4] = 1, [0xd5] = 1,
[0xd6] = 1, [0xd7] = 1, [0xd8] = 1, [0xd9] = 1, [0xda] = 1, [0xdb] = 1,
[0xdc] = 1, [0xdd] = 1, [0xde] = 1, [0xdf] = 1, [0xe0] = 1, [0xe1] = 1,
[0xe2] = 1, [0xe3] = 1, [0xe4] = 1, [0xe5] = 1, [0xe6] = 1, [0xe7] = 1,
[0xe8] = 1, [0xe9] = 1, [0xea] = 1, [0xeb] = 1, [0xec] = 1, [0xed] = 1,
[0xee] = 1, [0xef] = 1, [0xf0] = 1, [0xf1] = 1, [0xf2] = 1, [0xf3] = 1,
[0xf4] = 1, [0xf5] = 1, [0xf6] = 1, [0xf7] = 1, [0xf8] = 1, [0xf9] = 1,
[0xfa] = 1, [0xfb] = 1, [0xfc] = 1, [0xfd] = 1, [0xfe] = 1, [0xff] = 1,
};
static int check_path(const uint8_t *value, size_t len) {
@ -795,60 +660,20 @@ void nghttp3_http_record_request_method(nghttp3_stream *stream,
}
}
/* Generated by gennmchartbl.py */
static const int VALID_HD_NAME_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
0 /* LF */, 0 /* VT */, 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 /* . */, 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 /* @ */,
-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 const int8_t VALID_HD_NAME_CHARS[256] = {
['!'] = 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, ['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, ['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,
};
int nghttp3_check_header_name(const uint8_t *name, size_t len) {
@ -889,72 +714,45 @@ static int http_check_nonempty_header_name(const uint8_t *name, size_t len) {
return 1;
}
/* Generated by genvchartbl.py */
static const int VALID_HD_VALUE_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,
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 /* ! */, 1 /* " */, 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 /* [ */,
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 /* { */,
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
static const char VALID_HD_VALUE_CHARS[256] = {
[0x09] = 1, [' '] = 1, ['!'] = 1, ['"'] = 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,
['['] = 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, ['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1,
[0x80] = 1, [0x81] = 1, [0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1,
[0x86] = 1, [0x87] = 1, [0x88] = 1, [0x89] = 1, [0x8a] = 1, [0x8b] = 1,
[0x8c] = 1, [0x8d] = 1, [0x8e] = 1, [0x8f] = 1, [0x90] = 1, [0x91] = 1,
[0x92] = 1, [0x93] = 1, [0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1,
[0x98] = 1, [0x99] = 1, [0x9a] = 1, [0x9b] = 1, [0x9c] = 1, [0x9d] = 1,
[0x9e] = 1, [0x9f] = 1, [0xa0] = 1, [0xa1] = 1, [0xa2] = 1, [0xa3] = 1,
[0xa4] = 1, [0xa5] = 1, [0xa6] = 1, [0xa7] = 1, [0xa8] = 1, [0xa9] = 1,
[0xaa] = 1, [0xab] = 1, [0xac] = 1, [0xad] = 1, [0xae] = 1, [0xaf] = 1,
[0xb0] = 1, [0xb1] = 1, [0xb2] = 1, [0xb3] = 1, [0xb4] = 1, [0xb5] = 1,
[0xb6] = 1, [0xb7] = 1, [0xb8] = 1, [0xb9] = 1, [0xba] = 1, [0xbb] = 1,
[0xbc] = 1, [0xbd] = 1, [0xbe] = 1, [0xbf] = 1, [0xc0] = 1, [0xc1] = 1,
[0xc2] = 1, [0xc3] = 1, [0xc4] = 1, [0xc5] = 1, [0xc6] = 1, [0xc7] = 1,
[0xc8] = 1, [0xc9] = 1, [0xca] = 1, [0xcb] = 1, [0xcc] = 1, [0xcd] = 1,
[0xce] = 1, [0xcf] = 1, [0xd0] = 1, [0xd1] = 1, [0xd2] = 1, [0xd3] = 1,
[0xd4] = 1, [0xd5] = 1, [0xd6] = 1, [0xd7] = 1, [0xd8] = 1, [0xd9] = 1,
[0xda] = 1, [0xdb] = 1, [0xdc] = 1, [0xdd] = 1, [0xde] = 1, [0xdf] = 1,
[0xe0] = 1, [0xe1] = 1, [0xe2] = 1, [0xe3] = 1, [0xe4] = 1, [0xe5] = 1,
[0xe6] = 1, [0xe7] = 1, [0xe8] = 1, [0xe9] = 1, [0xea] = 1, [0xeb] = 1,
[0xec] = 1, [0xed] = 1, [0xee] = 1, [0xef] = 1, [0xf0] = 1, [0xf1] = 1,
[0xf2] = 1, [0xf3] = 1, [0xf4] = 1, [0xf5] = 1, [0xf6] = 1, [0xf7] = 1,
[0xf8] = 1, [0xf9] = 1, [0xfa] = 1, [0xfb] = 1, [0xfc] = 1, [0xfd] = 1,
[0xfe] = 1, [0xff] = 1,
};
#ifdef __AVX2__

View File

@ -38,33 +38,31 @@ static nghttp3_ksl_blk null_blk;
nghttp3_objalloc_def(ksl_blk, nghttp3_ksl_blk, oplent)
static size_t ksl_nodelen(size_t keylen) {
assert(keylen >= sizeof(uint64_t));
return (sizeof(nghttp3_ksl_node) + keylen - sizeof(uint64_t) + 0x7u) &
~(uintptr_t)0x7u;
}
static size_t ksl_blklen(size_t nodelen) {
return sizeof(nghttp3_ksl_blk) + nodelen * NGHTTP3_KSL_MAX_NBLK -
static size_t ksl_blklen(size_t aligned_keylen) {
return sizeof(nghttp3_ksl_blk) + NGHTTP3_KSL_MAX_NBLK * aligned_keylen -
sizeof(uint64_t);
}
/*
* ksl_node_set_key sets |key| to |node|.
* ksl_set_nth_key sets |key| to |n|th node under |blk|.
*/
static void ksl_node_set_key(nghttp3_ksl *ksl, nghttp3_ksl_node *node,
const void *key) {
memcpy(node->key, key, ksl->keylen);
static void ksl_set_nth_key(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
size_t n, const nghttp3_ksl_key *key) {
memcpy(blk->keys + n * ksl->aligned_keylen, key, ksl->keylen);
}
void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar,
nghttp3_ksl_search search, size_t keylen,
const nghttp3_mem *mem) {
size_t nodelen = ksl_nodelen(keylen);
size_t aligned_keylen;
assert(keylen >= sizeof(uint64_t));
aligned_keylen = (keylen + 0x7u) & ~0x7u;
nghttp3_objalloc_init(&ksl->blkalloc,
(ksl_blklen(nodelen) + 0xfu) & ~(uintptr_t)0xfu, mem);
(ksl_blklen(aligned_keylen) + 0xfu) & ~(uintptr_t)0xfu,
mem);
ksl->head = NULL;
ksl->front = ksl->back = NULL;
@ -72,12 +70,12 @@ void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar,
ksl->search = search;
ksl->n = 0;
ksl->keylen = keylen;
ksl->nodelen = nodelen;
ksl->aligned_keylen = aligned_keylen;
}
static nghttp3_ksl_blk *ksl_blk_objalloc_new(nghttp3_ksl *ksl) {
return nghttp3_objalloc_ksl_blk_len_get(&ksl->blkalloc,
ksl_blklen(ksl->nodelen));
ksl_blklen(ksl->aligned_keylen));
}
static void ksl_blk_objalloc_del(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
@ -110,7 +108,7 @@ static void ksl_free_blk(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
if (!blk->leaf) {
for (i = 0; i < blk->n; ++i) {
ksl_free_blk(ksl, nghttp3_ksl_nth_node(ksl, blk, i)->blk);
ksl_free_blk(ksl, blk->nodes[i].blk);
}
}
@ -161,8 +159,10 @@ static nghttp3_ksl_blk *ksl_split_blk(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
rblk->n = blk->n / 2;
blk->n -= rblk->n;
memcpy(rblk->nodes, blk->nodes + ksl->nodelen * blk->n,
ksl->nodelen * rblk->n);
memcpy(rblk->nodes, blk->nodes + blk->n, rblk->n * sizeof(nghttp3_ksl_node));
memcpy(rblk->keys, blk->keys + blk->n * ksl->aligned_keylen,
rblk->n * ksl->aligned_keylen);
assert(blk->n >= NGHTTP3_KSL_MIN_NBLK);
assert(rblk->n >= NGHTTP3_KSL_MIN_NBLK);
@ -182,27 +182,25 @@ static nghttp3_ksl_blk *ksl_split_blk(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk) {
* Out of memory.
*/
static int ksl_split_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
nghttp3_ksl_node *node;
nghttp3_ksl_blk *lblk = nghttp3_ksl_nth_node(ksl, blk, i)->blk, *rblk;
nghttp3_ksl_blk *lblk = blk->nodes[i].blk, *rblk;
rblk = ksl_split_blk(ksl, lblk);
if (rblk == NULL) {
return NGHTTP3_ERR_NOMEM;
}
memmove(blk->nodes + (i + 2) * ksl->nodelen,
blk->nodes + (i + 1) * ksl->nodelen,
ksl->nodelen * (blk->n - (i + 1)));
memmove(blk->nodes + (i + 2), blk->nodes + (i + 1),
(blk->n - (i + 1)) * sizeof(nghttp3_ksl_node));
node = nghttp3_ksl_nth_node(ksl, blk, i + 1);
node->blk = rblk;
memmove(blk->keys + (i + 2) * ksl->aligned_keylen,
blk->keys + (i + 1) * ksl->aligned_keylen,
(blk->n - (i + 1)) * ksl->aligned_keylen);
blk->nodes[i + 1].blk = rblk;
++blk->n;
ksl_node_set_key(ksl, node,
nghttp3_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
ksl_set_nth_key(ksl, blk, i + 1, nghttp3_ksl_nth_key(ksl, rblk, rblk->n - 1));
node = nghttp3_ksl_nth_node(ksl, blk, i);
ksl_node_set_key(ksl, node,
nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
ksl_set_nth_key(ksl, blk, i, nghttp3_ksl_nth_key(ksl, lblk, lblk->n - 1));
return 0;
}
@ -219,7 +217,6 @@ static int ksl_split_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
*/
static int ksl_split_head(nghttp3_ksl *ksl) {
nghttp3_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
nghttp3_ksl_node *node;
rblk = ksl_split_blk(ksl, ksl->head);
if (rblk == NULL) {
@ -239,15 +236,11 @@ static int ksl_split_head(nghttp3_ksl *ksl) {
nhead->n = 2;
nhead->leaf = 0;
node = nghttp3_ksl_nth_node(ksl, nhead, 0);
ksl_node_set_key(ksl, node,
nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
node->blk = lblk;
ksl_set_nth_key(ksl, nhead, 0, nghttp3_ksl_nth_key(ksl, lblk, lblk->n - 1));
nhead->nodes[0].blk = lblk;
node = nghttp3_ksl_nth_node(ksl, nhead, 1);
ksl_node_set_key(ksl, node,
nghttp3_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
node->blk = rblk;
ksl_set_nth_key(ksl, nhead, 1, nghttp3_ksl_nth_key(ksl, rblk, rblk->n - 1));
nhead->nodes[1].blk = rblk;
ksl->head = nhead;
@ -262,16 +255,17 @@ static int ksl_split_head(nghttp3_ksl *ksl) {
*/
static void ksl_insert_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i,
const nghttp3_ksl_key *key, void *data) {
nghttp3_ksl_node *node;
assert(blk->n < NGHTTP3_KSL_MAX_NBLK);
memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
ksl->nodelen * (blk->n - i));
memmove(blk->nodes + (i + 1), blk->nodes + i,
(blk->n - i) * sizeof(nghttp3_ksl_node));
node = nghttp3_ksl_nth_node(ksl, blk, i);
ksl_node_set_key(ksl, node, key);
node->data = data;
memmove(blk->keys + (i + 1) * ksl->aligned_keylen,
blk->keys + i * ksl->aligned_keylen,
(blk->n - i) * ksl->aligned_keylen);
ksl_set_nth_key(ksl, blk, i, key);
blk->nodes[i].data = data;
++blk->n;
}
@ -303,8 +297,7 @@ int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
i = ksl->search(ksl, blk, key);
if (blk->leaf) {
if (i < blk->n &&
!ksl->compar(key, nghttp3_ksl_nth_node(ksl, blk, i)->key)) {
if (i < blk->n && !ksl->compar(key, nghttp3_ksl_nth_key(ksl, blk, i))) {
if (it) {
*it = nghttp3_ksl_end(ksl);
}
@ -325,17 +318,17 @@ int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
if (i == blk->n) {
/* This insertion extends the largest key in this subtree. */
for (; !blk->leaf;) {
node = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1);
node = &blk->nodes[blk->n - 1];
if (node->blk->n == NGHTTP3_KSL_MAX_NBLK) {
rv = ksl_split_node(ksl, blk, blk->n - 1);
if (rv != 0) {
return rv;
}
node = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1);
node = &blk->nodes[blk->n - 1];
}
ksl_node_set_key(ksl, node, key);
ksl_set_nth_key(ksl, blk, blk->n - 1, key);
blk = node->blk;
}
@ -349,7 +342,7 @@ int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
return 0;
}
node = nghttp3_ksl_nth_node(ksl, blk, i);
node = &blk->nodes[i];
if (node->blk->n == NGHTTP3_KSL_MAX_NBLK) {
rv = ksl_split_node(ksl, blk, i);
@ -357,11 +350,11 @@ int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
return rv;
}
if (ksl->compar((nghttp3_ksl_key *)node->key, key)) {
node = nghttp3_ksl_nth_node(ksl, blk, i + 1);
if (ksl->compar(nghttp3_ksl_nth_key(ksl, blk, i), key)) {
node = &blk->nodes[i + 1];
if (ksl->compar((nghttp3_ksl_key *)node->key, key)) {
ksl_node_set_key(ksl, node, key);
if (ksl->compar(nghttp3_ksl_nth_key(ksl, blk, i + 1), key)) {
ksl_set_nth_key(ksl, blk, i + 1, key);
}
}
}
@ -375,8 +368,12 @@ int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
* |i|.
*/
static void ksl_remove_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen,
ksl->nodelen * (blk->n - (i + 1)));
memmove(blk->nodes + i, blk->nodes + (i + 1),
(blk->n - (i + 1)) * sizeof(nghttp3_ksl_node));
memmove(blk->keys + i * ksl->aligned_keylen,
blk->keys + (i + 1) * ksl->aligned_keylen,
(blk->n - (i + 1)) * ksl->aligned_keylen);
--blk->n;
}
@ -398,15 +395,18 @@ static nghttp3_ksl_blk *ksl_merge_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
assert(i + 1 < blk->n);
lnode = nghttp3_ksl_nth_node(ksl, blk, i);
lnode = &blk->nodes[i];
lblk = lnode->blk;
rblk = nghttp3_ksl_nth_node(ksl, blk, i + 1)->blk;
rblk = blk->nodes[i + 1].blk;
assert(lblk->n + rblk->n < NGHTTP3_KSL_MAX_NBLK);
memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes,
ksl->nodelen * rblk->n);
memcpy(lblk->nodes + lblk->n, rblk->nodes,
rblk->n * sizeof(nghttp3_ksl_node));
memcpy(lblk->keys + lblk->n * ksl->aligned_keylen, rblk->keys,
rblk->n * ksl->aligned_keylen);
lblk->n += rblk->n;
lblk->next = rblk->next;
@ -424,8 +424,7 @@ static nghttp3_ksl_blk *ksl_merge_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
ksl->head = lblk;
} else {
ksl_remove_node(ksl, blk, i + 1);
ksl_node_set_key(ksl, lnode,
nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
ksl_set_nth_key(ksl, blk, i, nghttp3_ksl_nth_key(ksl, lblk, lblk->n - 1));
}
return lblk;
@ -443,8 +442,8 @@ static void ksl_shift_left(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
assert(i > 0);
lnode = nghttp3_ksl_nth_node(ksl, blk, i - 1);
rnode = nghttp3_ksl_nth_node(ksl, blk, i);
lnode = &blk->nodes[i - 1];
rnode = &blk->nodes[i];
lblk = lnode->blk;
rblk = rnode->blk;
@ -458,15 +457,20 @@ static void ksl_shift_left(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
assert(lblk->n <= NGHTTP3_KSL_MAX_NBLK - n);
assert(rblk->n >= NGHTTP3_KSL_MIN_NBLK + n);
memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes, ksl->nodelen * n);
memcpy(lblk->nodes + lblk->n, rblk->nodes, n * sizeof(nghttp3_ksl_node));
memcpy(lblk->keys + lblk->n * ksl->aligned_keylen, rblk->keys,
n * ksl->aligned_keylen);
lblk->n += (uint32_t)n;
rblk->n -= (uint32_t)n;
ksl_node_set_key(ksl, lnode,
nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
ksl_set_nth_key(ksl, blk, i - 1, nghttp3_ksl_nth_key(ksl, lblk, lblk->n - 1));
memmove(rblk->nodes, rblk->nodes + ksl->nodelen * n, ksl->nodelen * rblk->n);
memmove(rblk->nodes, rblk->nodes + n, rblk->n * sizeof(nghttp3_ksl_node));
memmove(rblk->keys, rblk->keys + n * ksl->aligned_keylen,
rblk->n * ksl->aligned_keylen);
}
/*
@ -481,8 +485,8 @@ static void ksl_shift_right(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
assert(i < blk->n - 1);
lnode = nghttp3_ksl_nth_node(ksl, blk, i);
rnode = nghttp3_ksl_nth_node(ksl, blk, i + 1);
lnode = &blk->nodes[i];
rnode = &blk->nodes[i + 1];
lblk = lnode->blk;
rblk = rnode->blk;
@ -496,15 +500,20 @@ static void ksl_shift_right(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i) {
assert(lblk->n >= NGHTTP3_KSL_MIN_NBLK + n);
assert(rblk->n <= NGHTTP3_KSL_MAX_NBLK - n);
memmove(rblk->nodes + ksl->nodelen * n, rblk->nodes, ksl->nodelen * rblk->n);
memmove(rblk->nodes + n, rblk->nodes, rblk->n * sizeof(nghttp3_ksl_node));
memmove(rblk->keys + n * ksl->aligned_keylen, rblk->keys,
rblk->n * ksl->aligned_keylen);
rblk->n += (uint32_t)n;
lblk->n -= (uint32_t)n;
memcpy(rblk->nodes, lblk->nodes + ksl->nodelen * lblk->n, ksl->nodelen * n);
memcpy(rblk->nodes, lblk->nodes + lblk->n, n * sizeof(nghttp3_ksl_node));
ksl_node_set_key(ksl, lnode,
nghttp3_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
memcpy(rblk->keys, lblk->keys + lblk->n * ksl->aligned_keylen,
n * ksl->aligned_keylen);
ksl_set_nth_key(ksl, blk, i, nghttp3_ksl_nth_key(ksl, lblk, lblk->n - 1));
}
/*
@ -553,8 +562,8 @@ int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
}
if (!blk->leaf && blk->n == 2 &&
nghttp3_ksl_nth_node(ksl, blk, 0)->blk->n == NGHTTP3_KSL_MIN_NBLK &&
nghttp3_ksl_nth_node(ksl, blk, 1)->blk->n == NGHTTP3_KSL_MIN_NBLK) {
blk->nodes[0].blk->n == NGHTTP3_KSL_MIN_NBLK &&
blk->nodes[1].blk->n == NGHTTP3_KSL_MIN_NBLK) {
blk = ksl_merge_node(ksl, blk, 0);
}
@ -570,7 +579,7 @@ int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
}
if (blk->leaf) {
if (ksl->compar(key, nghttp3_ksl_nth_node(ksl, blk, i)->key)) {
if (ksl->compar(key, nghttp3_ksl_nth_key(ksl, blk, i))) {
if (it) {
*it = nghttp3_ksl_end(ksl);
}
@ -592,7 +601,7 @@ int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
return 0;
}
node = nghttp3_ksl_nth_node(ksl, blk, i);
node = &blk->nodes[i];
if (node->blk->n > NGHTTP3_KSL_MIN_NBLK) {
blk = node->blk;
@ -601,16 +610,14 @@ int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
assert(node->blk->n == NGHTTP3_KSL_MIN_NBLK);
if (i + 1 < blk->n &&
nghttp3_ksl_nth_node(ksl, blk, i + 1)->blk->n > NGHTTP3_KSL_MIN_NBLK) {
if (i + 1 < blk->n && blk->nodes[i + 1].blk->n > NGHTTP3_KSL_MIN_NBLK) {
ksl_shift_left(ksl, blk, i + 1);
blk = node->blk;
continue;
}
if (i > 0 &&
nghttp3_ksl_nth_node(ksl, blk, i - 1)->blk->n > NGHTTP3_KSL_MIN_NBLK) {
if (i > 0 && blk->nodes[i - 1].blk->n > NGHTTP3_KSL_MIN_NBLK) {
ksl_shift_right(ksl, blk, i - 1);
blk = node->blk;
@ -662,7 +669,7 @@ nghttp3_ksl_it nghttp3_ksl_lower_bound_search(const nghttp3_ksl *ksl,
if (i == blk->n) {
/* This happens if descendant has smaller key. Fast forward to
find last node in this subtree. */
for (; !blk->leaf; blk = nghttp3_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
for (; !blk->leaf; blk = blk->nodes[blk->n - 1].blk)
;
if (blk->next) {
@ -677,7 +684,7 @@ nghttp3_ksl_it nghttp3_ksl_lower_bound_search(const nghttp3_ksl *ksl,
return it;
}
blk = nghttp3_ksl_nth_node(ksl, blk, i)->blk;
blk = blk->nodes[i].blk;
}
}
@ -685,6 +692,7 @@ void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key,
const nghttp3_ksl_key *new_key) {
nghttp3_ksl_blk *blk = ksl->head;
nghttp3_ksl_node *node;
const nghttp3_ksl_key *node_key;
size_t i;
assert(ksl->head);
@ -693,18 +701,19 @@ void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key,
i = ksl->search(ksl, blk, old_key);
assert(i < blk->n);
node = nghttp3_ksl_nth_node(ksl, blk, i);
node = &blk->nodes[i];
node_key = nghttp3_ksl_nth_key(ksl, blk, i);
if (blk->leaf) {
assert(key_equal(ksl->compar, (nghttp3_ksl_key *)node->key, old_key));
ksl_node_set_key(ksl, node, new_key);
assert(key_equal(ksl->compar, node_key, old_key));
ksl_set_nth_key(ksl, blk, i, new_key);
return;
}
if (key_equal(ksl->compar, (nghttp3_ksl_key *)node->key, old_key) ||
ksl->compar((nghttp3_ksl_key *)node->key, new_key)) {
ksl_node_set_key(ksl, node, new_key);
if (key_equal(ksl->compar, node_key, old_key) ||
ksl->compar(node_key, new_key)) {
ksl_set_nth_key(ksl, blk, i, new_key);
}
blk = node->blk;
@ -732,14 +741,13 @@ void nghttp3_ksl_clear(nghttp3_ksl *ksl) {
static void ksl_print(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
size_t level) {
size_t i;
nghttp3_ksl_node *node;
fprintf(stderr, "LV=%zu n=%u\n", level, blk->n);
if (blk->leaf) {
for (i = 0; i < blk->n; ++i) {
node = nghttp3_ksl_nth_node(ksl, blk, i);
fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key);
fprintf(stderr, " %" PRId64,
*(int64_t *)nghttp3_ksl_nth_key(ksl, blk, i));
}
fprintf(stderr, "\n");
@ -748,7 +756,7 @@ static void ksl_print(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
}
for (i = 0; i < blk->n; ++i) {
ksl_print(ksl, nghttp3_ksl_nth_node(ksl, blk, i)->blk, level + 1);
ksl_print(ksl, blk->nodes[i].blk, level + 1);
}
}

View File

@ -56,22 +56,13 @@ typedef struct nghttp3_ksl_blk nghttp3_ksl_blk;
/*
* nghttp3_ksl_node is a node which contains either nghttp3_ksl_blk or
* opaque data. If a node is an internal node, it contains
* nghttp3_ksl_blk. Otherwise, it has data. The key is stored at the
* location starting at key.
* nghttp3_ksl_blk. Otherwise, it has data.
*/
struct nghttp3_ksl_node {
union {
nghttp3_ksl_blk *blk;
void *data;
};
union {
uint64_t align;
/* key is a buffer to include key associated to this node.
Because the length of key is unknown until nghttp3_ksl_init is
called, the actual buffer will be allocated after this
field. */
uint8_t key[1];
};
};
/*
@ -89,14 +80,14 @@ struct nghttp3_ksl_blk {
uint32_t n;
/* leaf is nonzero if this block contains leaf nodes. */
uint32_t leaf;
nghttp3_ksl_node nodes[NGHTTP3_KSL_MAX_NBLK];
union {
uint64_t align;
/* nodes is a buffer to contain NGHTTP3_KSL_MAX_NBLK
nghttp3_ksl_node objects. Because nghttp3_ksl_node object
is allocated along with the additional variable length key
storage, the size of buffer is unknown until
nghttp3_ksl_init is called. */
uint8_t nodes[1];
/* keys is a buffer to include NGHTTP3_KSL_MAX_NBLK keys.
Because the length of key is unknown until nghttp3_ksl_init
is called, the actual buffer will be allocated after this
field. */
uint8_t keys[1];
};
};
@ -134,11 +125,10 @@ typedef size_t (*nghttp3_ksl_search)(const nghttp3_ksl *ksl,
nghttp3_ksl_blk *blk, \
const nghttp3_ksl_key *key) { \
size_t i; \
nghttp3_ksl_node *node; \
uint8_t *node_key; \
\
for (i = 0, node = (nghttp3_ksl_node *)(void *)blk->nodes; \
i < blk->n && COMPAR((nghttp3_ksl_key *)node->key, key); ++i, \
node = (nghttp3_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen)) \
for (i = 0, node_key = blk->keys; i < blk->n && COMPAR(node_key, key); \
++i, node_key += ksl->aligned_keylen) \
; \
\
return i; \
@ -172,9 +162,7 @@ struct nghttp3_ksl {
size_t n;
/* keylen is the size of key */
size_t keylen;
/* nodelen is the actual size of nghttp3_ksl_node including key
storage. */
size_t nodelen;
size_t aligned_keylen;
};
/*
@ -293,12 +281,12 @@ size_t nghttp3_ksl_len(const nghttp3_ksl *ksl);
void nghttp3_ksl_clear(nghttp3_ksl *ksl);
/*
* nghttp3_ksl_nth_node returns the |n|th node under |blk|.
* nghttp3_ksl_nth_key returns the |n|th key under |blk|.
*/
static inline nghttp3_ksl_node *nghttp3_ksl_nth_node(const nghttp3_ksl *ksl,
const nghttp3_ksl_blk *blk,
size_t n) {
return (nghttp3_ksl_node *)(void *)(blk->nodes + ksl->nodelen * n);
static inline const nghttp3_ksl_key *
nghttp3_ksl_nth_key(const nghttp3_ksl *ksl, const nghttp3_ksl_blk *blk,
size_t n) {
return blk->keys + n * ksl->aligned_keylen;
}
#ifndef WIN32
@ -322,7 +310,7 @@ void nghttp3_ksl_it_init(nghttp3_ksl_it *it, const nghttp3_ksl *ksl,
* nghttp3_ksl_it_end(it) returns nonzero.
*/
static inline void *nghttp3_ksl_it_get(const nghttp3_ksl_it *it) {
return nghttp3_ksl_nth_node(it->ksl, it->blk, it->i)->data;
return it->blk->nodes[it->i].data;
}
/*
@ -364,8 +352,9 @@ int nghttp3_ksl_it_begin(const nghttp3_ksl_it *it);
* It is undefined to call this function when nghttp3_ksl_it_end(it)
* returns nonzero.
*/
static inline nghttp3_ksl_key *nghttp3_ksl_it_key(const nghttp3_ksl_it *it) {
return (nghttp3_ksl_key *)nghttp3_ksl_nth_node(it->ksl, it->blk, it->i)->key;
static inline const nghttp3_ksl_key *
nghttp3_ksl_it_key(const nghttp3_ksl_it *it) {
return nghttp3_ksl_nth_key(it->ksl, it->blk, it->i);
}
/*

View File

@ -35,11 +35,10 @@
#define NGHTTP3_INITIAL_HASHBITS 4
void nghttp3_map_init(nghttp3_map *map, uint64_t seed, const nghttp3_mem *mem) {
map->mem = mem;
map->hashbits = 0;
map->table = NULL;
map->seed = seed;
map->size = 0;
*map = (nghttp3_map){
.mem = mem,
.seed = seed,
};
}
void nghttp3_map_free(nghttp3_map *map) {
@ -47,30 +46,27 @@ void nghttp3_map_free(nghttp3_map *map) {
return;
}
nghttp3_mem_free(map->mem, map->table);
nghttp3_mem_free(map->mem, map->keys);
}
int nghttp3_map_each(const nghttp3_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
int rv;
size_t i;
nghttp3_map_bucket *bkt;
size_t tablelen;
if (map->size == 0) {
return 0;
}
tablelen = 1u << map->hashbits;
tablelen = (size_t)1 << map->hashbits;
for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
if (map->psl[i] == 0) {
continue;
}
rv = func(bkt->data, ptr);
rv = func(map->data[i], ptr);
if (rv != 0) {
return rv;
}
@ -79,176 +75,228 @@ int nghttp3_map_each(const nghttp3_map *map, int (*func)(void *data, void *ptr),
return 0;
}
static size_t map_hash(const nghttp3_map *map, nghttp3_map_key_type key) {
/* hasher from
https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
We do not perform finalization here because we use top bits
anyway. */
/* Hasher from
https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
to maximize the output's sensitivity to all input bits. */
#define NGHTTP3_MAP_HASHER 0xf1357aea2e62a9c5ull
/* 64-bit Fibonacci hashing constant, Golden Ratio constant, to get
the high bits with the good distribution. */
#define NGHTTP3_MAP_FIBO 0x9e3779b97f4a7c15ull
static size_t map_index(const nghttp3_map *map, nghttp3_map_key_type key) {
key += map->seed;
key *= 0xf1357aea2e62a9c5ull;
return (size_t)((key * 11400714819323198485llu) >> (64 - map->hashbits));
}
static void map_bucket_swap(nghttp3_map_bucket *a, nghttp3_map_bucket *b) {
nghttp3_map_bucket c = *a;
*a = *b;
*b = c;
key *= NGHTTP3_MAP_HASHER;
return (size_t)((key * NGHTTP3_MAP_FIBO) >> (64 - map->hashbits));
}
#ifndef WIN32
void nghttp3_map_print_distance(const nghttp3_map *map) {
size_t i;
size_t idx;
nghttp3_map_bucket *bkt;
size_t tablelen;
if (map->size == 0) {
return;
}
tablelen = 1u << map->hashbits;
tablelen = (size_t)1 << map->hashbits;
for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
if (map->psl[i] == 0) {
fprintf(stderr, "@%zu <EMPTY>\n", i);
continue;
}
idx = map_hash(map, bkt->key);
fprintf(stderr, "@%zu hash=%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
map_hash(map, bkt->key), bkt->key, idx, bkt->psl);
idx = map_index(map, map->keys[i]);
fprintf(stderr, "@%zu key=%" PRIu64 " base=%zu distance=%u\n", i,
map->keys[i], idx, map->psl[i] - 1);
}
}
#endif /* !defined(WIN32) */
static int map_insert(nghttp3_map *map, nghttp3_map_key_type key, void *data) {
size_t idx = map_hash(map, key);
nghttp3_map_bucket b = {
.key = key,
.data = data,
};
nghttp3_map_bucket *bkt;
size_t mask = (1u << map->hashbits) - 1;
static void map_set_entry(nghttp3_map *map, size_t idx,
nghttp3_map_key_type key, void *data, size_t psl) {
map->keys[idx] = key;
map->data[idx] = data;
map->psl[idx] = (uint8_t)psl;
}
#define NGHTTP3_SWAP(TYPE, A, B) \
do { \
TYPE t = (TYPE) * (A); \
\
*(A) = *(B); \
*(B) = t; \
} while (0)
/*
* map_insert inserts |key| and |data| to |map|, and returns the index
* where the pair is stored if it succeeds. Otherwise, it returns one
* of the following negative error codes:
*
* NGHTTP3_ERR_INVALID_ARGUMENT
* The another data associated to |key| is already present.
*/
static nghttp3_ssize map_insert(nghttp3_map *map, nghttp3_map_key_type key,
void *data) {
size_t idx = map_index(map, key);
size_t mask = ((size_t)1 << map->hashbits) - 1;
size_t psl = 1;
size_t kpsl;
for (;;) {
bkt = &map->table[idx];
kpsl = map->psl[idx];
if (bkt->data == NULL) {
*bkt = b;
if (kpsl == 0) {
map_set_entry(map, idx, key, data, psl);
++map->size;
return 0;
return (nghttp3_ssize)idx;
}
if (b.psl > bkt->psl) {
map_bucket_swap(bkt, &b);
} else if (bkt->key == key) {
/* TODO This check is just a waste after first swap or if this
function is called from map_resize. That said, there is no
difference with or without this conditional in performance
wise. */
if (psl > kpsl) {
NGHTTP3_SWAP(nghttp3_map_key_type, &key, &map->keys[idx]);
NGHTTP3_SWAP(void *, &data, &map->data[idx]);
NGHTTP3_SWAP(uint8_t, &psl, &map->psl[idx]);
} else if (map->keys[idx] == key) {
/* This check ensures that no duplicate keys are inserted. But
it is just a waste after first swap or if this function is
called from map_resize. That said, there is no difference
with or without this conditional in performance wise. */
return NGHTTP3_ERR_INVALID_ARGUMENT;
}
++b.psl;
++psl;
idx = (idx + 1) & mask;
}
}
/* NGHTTP3_MAP_MAX_HASHBITS is the maximum number of bits used for
hash table. The theoretical limit of the maximum number of keys
that can be stored is 1 << NGHTTP3_MAP_MAX_HASHBITS. */
#define NGHTTP3_MAP_MAX_HASHBITS (sizeof(size_t) * 8 - 1)
static int map_resize(nghttp3_map *map, size_t new_hashbits) {
size_t i;
nghttp3_map_bucket *bkt;
size_t tablelen;
int rv;
nghttp3_ssize idx;
nghttp3_map new_map = {
.table = nghttp3_mem_calloc(map->mem, 1u << new_hashbits,
sizeof(nghttp3_map_bucket)),
.mem = map->mem,
.seed = map->seed,
.hashbits = new_hashbits,
};
(void)rv;
void *buf;
(void)idx;
if (new_map.table == NULL) {
if (new_hashbits > NGHTTP3_MAP_MAX_HASHBITS) {
return NGHTTP3_ERR_NOMEM;
}
tablelen = (size_t)1 << new_hashbits;
buf = nghttp3_mem_calloc(map->mem, tablelen,
sizeof(nghttp3_map_key_type) + sizeof(void *) +
sizeof(uint8_t));
if (buf == NULL) {
return NGHTTP3_ERR_NOMEM;
}
new_map.keys = buf;
new_map.data =
(void *)((uint8_t *)new_map.keys + tablelen * sizeof(nghttp3_map_key_type));
new_map.psl = (uint8_t *)new_map.data + tablelen * sizeof(void *);
if (map->size) {
tablelen = 1u << map->hashbits;
tablelen = (size_t)1 << map->hashbits;
for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
if (map->psl[i] == 0) {
continue;
}
rv = map_insert(&new_map, bkt->key, bkt->data);
idx = map_insert(&new_map, map->keys[i], map->data[i]);
assert(0 == rv);
/* map_insert must not fail because all keys are unique during
resize. */
assert(idx >= 0);
}
}
nghttp3_mem_free(map->mem, map->table);
map->table = new_map.table;
nghttp3_mem_free(map->mem, map->keys);
map->keys = new_map.keys;
map->data = new_map.data;
map->psl = new_map.psl;
map->hashbits = new_hashbits;
return 0;
}
/* NGHTTP3_MAX_PSL_RESIZE_THRESH is the maximum psl threshold. If
reached, resize the table. */
#define NGHTTP3_MAX_PSL_RESIZE_THRESH 128
int nghttp3_map_insert(nghttp3_map *map, nghttp3_map_key_type key, void *data) {
int rv;
size_t tablelen;
nghttp3_ssize idx;
assert(data);
/* Load factor is 7/8 */
/* Under the very initial condition, that is map->size == 0 and
map->hashbits == 0, 8 > 7 still holds nicely. */
if ((map->size + 1) * 8 > (1u << map->hashbits) * 7) {
if (map->hashbits) {
rv = map_resize(map, map->hashbits + 1);
if (rv != 0) {
return rv;
}
} else {
rv = map_resize(map, NGHTTP3_INITIAL_HASHBITS);
if (rv != 0) {
return rv;
}
/* tablelen is incorrect if map->hashbits == 0 which leads to
tablelen = 1, but it is only used to check the load factor, and
it works in this special case. */
tablelen = (size_t)1 << map->hashbits;
/* Load factor is 7 / 8. Because tablelen is power of 2, (tablelen
- (tablelen >> 3)) computes tablelen * 7 / 8. */
if (map->size + 1 >= (tablelen - (tablelen >> 3))) {
rv = map_resize(map, map->hashbits ? map->hashbits + 1
: NGHTTP3_INITIAL_HASHBITS);
if (rv != 0) {
return rv;
}
idx = map_insert(map, key, data);
if (idx < 0) {
return (int)idx;
}
return 0;
}
rv = map_insert(map, key, data);
if (rv != 0) {
return rv;
idx = map_insert(map, key, data);
if (idx < 0) {
return (int)idx;
}
return 0;
/* Resize if psl reaches really large value which is almost
improbable, but just in case. */
if (map->psl[idx] - 1 < NGHTTP3_MAX_PSL_RESIZE_THRESH) {
return 0;
}
return map_resize(map, map->hashbits + 1);
}
void *nghttp3_map_find(const nghttp3_map *map, nghttp3_map_key_type key) {
size_t idx;
nghttp3_map_bucket *bkt;
size_t psl = 0;
size_t psl = 1;
size_t mask;
if (map->size == 0) {
return NULL;
}
idx = map_hash(map, key);
mask = (1u << map->hashbits) - 1;
idx = map_index(map, key);
mask = ((size_t)1 << map->hashbits) - 1;
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL || psl > bkt->psl) {
if (psl > map->psl[idx]) {
return NULL;
}
if (bkt->key == key) {
return bkt->data;
if (map->keys[idx] == key) {
return map->data[idx];
}
++psl;
@ -258,38 +306,36 @@ void *nghttp3_map_find(const nghttp3_map *map, nghttp3_map_key_type key) {
int nghttp3_map_remove(nghttp3_map *map, nghttp3_map_key_type key) {
size_t idx;
nghttp3_map_bucket *b, *bkt;
size_t psl = 0;
size_t dest;
size_t psl = 1, kpsl;
size_t mask;
if (map->size == 0) {
return NGHTTP3_ERR_INVALID_ARGUMENT;
}
idx = map_hash(map, key);
mask = (1u << map->hashbits) - 1;
idx = map_index(map, key);
mask = ((size_t)1 << map->hashbits) - 1;
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL || psl > bkt->psl) {
if (psl > map->psl[idx]) {
return NGHTTP3_ERR_INVALID_ARGUMENT;
}
if (bkt->key == key) {
b = bkt;
if (map->keys[idx] == key) {
dest = idx;
idx = (idx + 1) & mask;
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL || bkt->psl == 0) {
b->data = NULL;
kpsl = map->psl[idx];
if (kpsl <= 1) {
map->psl[dest] = 0;
break;
}
--bkt->psl;
*b = *bkt;
b = bkt;
map_set_entry(map, dest, map->keys[idx], map->data[idx], kpsl - 1);
dest = idx;
idx = (idx + 1) & mask;
}
@ -309,7 +355,7 @@ void nghttp3_map_clear(nghttp3_map *map) {
return;
}
memset(map->table, 0, sizeof(*map->table) * (1u << map->hashbits));
memset(map->psl, 0, sizeof(*map->psl) * ((size_t)1 << map->hashbits));
map->size = 0;
}

View File

@ -39,14 +39,13 @@
typedef uint64_t nghttp3_map_key_type;
typedef struct nghttp3_map_bucket {
uint32_t psl;
nghttp3_map_key_type key;
void *data;
} nghttp3_map_bucket;
typedef struct nghttp3_map {
nghttp3_map_bucket *table;
nghttp3_map_key_type *keys;
void **data;
/* psl is the Probe Sequence Length. 0 has special meaning that the
element is not stored at i-th position if psl[i] == 0. Because
of this, the actual psl value is psl[i] - 1 if psl[i] > 0. */
uint8_t *psl;
const nghttp3_mem *mem;
uint64_t seed;
size_t size;

View File

@ -916,6 +916,7 @@ void nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder,
encoder->min_dtable_update = SIZE_MAX;
encoder->last_max_dtable_update = 0;
encoder->uninterrupted_decoderlen = 0;
encoder->indexing_strat = NGHTTP3_QPACK_INDEXING_STRAT_NONE;
encoder->flags = NGHTTP3_QPACK_ENCODER_FLAG_NONE;
nghttp3_qpack_read_state_reset(&encoder->rstate);
@ -960,6 +961,11 @@ void nghttp3_qpack_encoder_set_max_blocked_streams(
encoder->ctx.max_blocked_streams = max_blocked_streams;
}
void nghttp3_qpack_encoder_set_indexing_strat(
nghttp3_qpack_encoder *encoder, nghttp3_qpack_indexing_strat strat) {
encoder->indexing_strat = strat;
}
uint64_t nghttp3_qpack_encoder_get_min_cnt(nghttp3_qpack_encoder *encoder) {
assert(!nghttp3_pq_empty(&encoder->min_cnts));
@ -1313,6 +1319,20 @@ qpack_encoder_decide_indexing_mode(nghttp3_qpack_encoder *encoder,
}
break;
case -1:
switch (encoder->indexing_strat) {
case NGHTTP3_QPACK_INDEXING_STRAT_EAGER:
break;
case NGHTTP3_QPACK_INDEXING_STRAT_NONE:
if (nv->flags & NGHTTP3_NV_FLAG_TRY_INDEX) {
break;
}
return NGHTTP3_QPACK_INDEXING_MODE_LITERAL;
default:
nghttp3_unreachable();
}
break;
case NGHTTP3_QPACK_TOKEN__PATH:
case NGHTTP3_QPACK_TOKEN_AGE:
case NGHTTP3_QPACK_TOKEN_CONTENT_LENGTH:

View File

@ -261,6 +261,9 @@ struct nghttp3_qpack_encoder {
/* uninterrupted_decoderlen is the number of bytes read from decoder
stream without encoding a single field section. */
size_t uninterrupted_decoderlen;
/* indexing_strat is the indexing strategy for fields not defined in
nghttp3_qpack_token. */
nghttp3_qpack_indexing_strat indexing_strat;
/* flags is bitwise OR of zero or more of
NGHTTP3_QPACK_ENCODER_FLAG_*. */
uint8_t flags;

View File

@ -79,7 +79,9 @@ uint8_t *nghttp3_qpack_huffman_encode(uint8_t *dest, const uint8_t *src,
void nghttp3_qpack_huffman_decode_context_init(
nghttp3_qpack_huffman_decode_context *ctx) {
ctx->fstate = NGHTTP3_QPACK_HUFFMAN_ACCEPTED;
*ctx = (nghttp3_qpack_huffman_decode_context){
.flags = NGHTTP3_QPACK_HUFFMAN_ACCEPTED,
};
}
nghttp3_ssize
@ -88,10 +90,10 @@ nghttp3_qpack_huffman_decode(nghttp3_qpack_huffman_decode_context *ctx,
int fin) {
uint8_t *p = dest;
const uint8_t *end = src + srclen;
nghttp3_qpack_huffman_decode_node node = {
nghttp3_qpack_huffman_decode_node t = {
.fstate = ctx->fstate,
.flags = ctx->flags,
};
const nghttp3_qpack_huffman_decode_node *t = &node;
uint8_t c;
/* We use the decoding algorithm described in
@ -100,20 +102,21 @@ nghttp3_qpack_huffman_decode(nghttp3_qpack_huffman_decode_context *ctx,
- https://github.com/nghttp2/nghttp2/files/15141264/Prefix.pdf */
for (; src != end;) {
c = *src++;
t = &qpack_huffman_decode_table[t->fstate & 0x1ff][c >> 4];
if (t->fstate & NGHTTP3_QPACK_HUFFMAN_SYM) {
*p++ = t->sym;
t = qpack_huffman_decode_table[t.fstate][c >> 4];
if (t.flags & NGHTTP3_QPACK_HUFFMAN_SYM) {
*p++ = t.sym;
}
t = &qpack_huffman_decode_table[t->fstate & 0x1ff][c & 0xf];
if (t->fstate & NGHTTP3_QPACK_HUFFMAN_SYM) {
*p++ = t->sym;
t = qpack_huffman_decode_table[t.fstate][c & 0xf];
if (t.flags & NGHTTP3_QPACK_HUFFMAN_SYM) {
*p++ = t.sym;
}
}
ctx->fstate = t->fstate;
ctx->fstate = t.fstate;
ctx->flags = t.flags;
if (fin && !(ctx->fstate & NGHTTP3_QPACK_HUFFMAN_ACCEPTED)) {
if (fin && !(ctx->flags & NGHTTP3_QPACK_HUFFMAN_ACCEPTED)) {
return NGHTTP3_ERR_QPACK_FATAL;
}

View File

@ -49,9 +49,9 @@ uint8_t *nghttp3_qpack_huffman_encode(uint8_t *dest, const uint8_t *src,
typedef enum nghttp3_qpack_huffman_decode_flag {
/* FSA accepts this state as the end of huffman encoding
sequence. */
NGHTTP3_QPACK_HUFFMAN_ACCEPTED = 1 << 14,
NGHTTP3_QPACK_HUFFMAN_ACCEPTED = 1,
/* This state emits symbol */
NGHTTP3_QPACK_HUFFMAN_SYM = 1 << 15,
NGHTTP3_QPACK_HUFFMAN_SYM = 1 << 1,
} nghttp3_qpack_huffman_decode_flag;
typedef struct nghttp3_qpack_huffman_decode_node {
@ -63,6 +63,7 @@ typedef struct nghttp3_qpack_huffman_decode_node {
256 is a special node and it is a terminal state that means
decoding failed. */
uint16_t fstate;
uint8_t flags;
/* symbol if NGHTTP3_QPACK_HUFFMAN_SYM flag set */
uint8_t sym;
} nghttp3_qpack_huffman_decode_node;
@ -70,6 +71,7 @@ typedef struct nghttp3_qpack_huffman_decode_node {
typedef struct nghttp3_qpack_huffman_decode_context {
/* fstate is the current huffman decoding state. */
uint16_t fstate;
uint8_t flags;
} nghttp3_qpack_huffman_decode_context;
extern const nghttp3_qpack_huffman_decode_node qpack_huffman_decode_table[][16];

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
/*
* nghttp3
*
* Copyright (c) 2025 nghttp3 contributors
* Copyright (c) 2025 ngtcp2 contributors
* Copyright (c) 2023 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "nghttp3_ratelim.h"
#include <assert.h>
#include "nghttp3_macro.h"
void nghttp3_ratelim_init(nghttp3_ratelim *rlim, uint64_t burst, uint64_t rate,
nghttp3_tstamp ts) {
*rlim = (nghttp3_ratelim){
.burst = burst,
.rate = rate,
.tokens = burst,
.ts = ts,
};
}
/* ratelim_update updates rlim->tokens with the current |ts|. */
static void ratelim_update(nghttp3_ratelim *rlim, nghttp3_tstamp ts) {
uint64_t d, gain, gps;
assert(ts >= rlim->ts);
if (ts == rlim->ts) {
return;
}
d = ts - rlim->ts;
rlim->ts = ts;
if (rlim->rate > (UINT64_MAX - rlim->carry) / d) {
gain = UINT64_MAX;
} else {
gain = rlim->rate * d + rlim->carry;
}
gps = gain / NGHTTP3_SECONDS;
if (gps < rlim->burst && rlim->tokens < rlim->burst - gps) {
rlim->tokens += gps;
rlim->carry = gain % NGHTTP3_SECONDS;
return;
}
rlim->tokens = rlim->burst;
rlim->carry = 0;
}
int nghttp3_ratelim_drain(nghttp3_ratelim *rlim, uint64_t n,
nghttp3_tstamp ts) {
ratelim_update(rlim, ts);
if (rlim->tokens < n) {
return -1;
}
rlim->tokens -= n;
return 0;
}

View File

@ -0,0 +1,60 @@
/*
* nghttp3
*
* Copyright (c) 2025 nghttp3 contributors
* Copyright (c) 2025 ngtcp2 contributors
* Copyright (c) 2023 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NGHTTP3_RATELIM_H
#define NGHTTP3_RATELIM_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* defined(HAVE_CONFIG_H) */
#include <nghttp3/nghttp3.h>
typedef struct nghttp3_ratelim {
/* burst is the maximum number of tokens. */
uint64_t burst;
/* rate is the rate of token generation measured by token /
second. */
uint64_t rate;
/* tokens is the amount of tokens available to drain. */
uint64_t tokens;
/* carry is the partial token gained in sub-second period. It is
added to the computation in the next update round. */
uint64_t carry;
/* ts is the last timestamp that is known to this object. */
nghttp3_tstamp ts;
} nghttp3_ratelim;
/* nghttp3_ratelim_init initializes |rlim| with the given
parameters. */
void nghttp3_ratelim_init(nghttp3_ratelim *rlim, uint64_t burst, uint64_t rate,
nghttp3_tstamp ts);
/* nghttp3_ratelim_drain drains |n| from rlim->tokens. It returns 0 if
it succeeds, or -1. */
int nghttp3_ratelim_drain(nghttp3_ratelim *rlim, uint64_t n, nghttp3_tstamp ts);
#endif /* !defined(NGHTTP3_RATELIM_H) */

View File

@ -34,19 +34,8 @@
#include "nghttp3_macro.h"
#ifndef NDEBUG
static int ispow2(size_t n) {
# if defined(DISABLE_POPCNT) || \
(defined(_MSC_VER) && !defined(__clang__) && \
(defined(_M_ARM) || (defined(_M_ARM64) && _MSC_VER < 1941)))
return n && !(n & (n - 1));
# elif defined(WIN32)
return 1 == __popcnt((unsigned int)n);
# else /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \
(defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
return 1 == __builtin_popcount((unsigned int)n);
# endif /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \
(defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
}
/* Power-of-two test; simple portable bit trick. */
static int ispow2(size_t n) { return n && !(n & (n - 1)); }
#endif /* !defined(NDEBUG) */
int nghttp3_ringbuf_init(nghttp3_ringbuf *rb, size_t nmemb, size_t size,

View File

@ -42,6 +42,11 @@ void nghttp3_settings_default_versioned(int settings_version,
switch (settings_version) {
case NGHTTP3_SETTINGS_VERSION:
case NGHTTP3_SETTINGS_V3:
settings->glitch_ratelim_burst = NGHTTP3_DEFAULT_GLITCH_RATELIM_BURST;
settings->glitch_ratelim_rate = NGHTTP3_DEFAULT_GLITCH_RATELIM_RATE;
/* fall through */
case NGHTTP3_SETTINGS_V2:
case NGHTTP3_SETTINGS_V1:
settings->max_field_section_size = NGHTTP3_VARINT_MAX;
settings->qpack_encoder_max_dtable_capacity =
@ -86,6 +91,12 @@ size_t nghttp3_settingslen_version(int settings_version) {
switch (settings_version) {
case NGHTTP3_SETTINGS_VERSION:
return sizeof(settings);
case NGHTTP3_SETTINGS_V3:
return offsetof(nghttp3_settings, glitch_ratelim_rate) +
sizeof(settings.glitch_ratelim_rate);
case NGHTTP3_SETTINGS_V2:
return offsetof(nghttp3_settings, origin_list) +
sizeof(settings.origin_list);
case NGHTTP3_SETTINGS_V1:
return offsetof(nghttp3_settings, h3_datagram) +
sizeof(settings.h3_datagram);

View File

@ -31,6 +31,13 @@
#include <nghttp3/nghttp3.h>
/* NGHTTP3_DEFAULT_GLITCH_RATELIM_BURST is the maximum number of
tokens in glitch rate limiter. It is also the initial value. */
#define NGHTTP3_DEFAULT_GLITCH_RATELIM_BURST 1000
/* NGHTTP3_DEFAULT_GLITCH_RATELIM_RATE is the rate of tokens generated
per second for glitch rate limiter. */
#define NGHTTP3_DEFAULT_GLITCH_RATELIM_RATE 33
/*
* nghttp3_settings_convert_to_latest converts |src| of version
* |settings_version| to the latest version NGHTTP3_SETTINGS_VERSION.

View File

@ -125,8 +125,7 @@ static void delete_out_chunks(nghttp3_ringbuf *chunks,
buf = nghttp3_ringbuf_get(chunks, i);
if (nghttp3_buf_cap(buf) == NGHTTP3_STREAM_MIN_CHUNK_SIZE) {
nghttp3_objalloc_chunk_release(out_chunk_objalloc,
(nghttp3_chunk *)(void *)buf->begin);
nghttp3_objalloc_chunk_release(out_chunk_objalloc, (void *)buf->begin);
continue;
}
@ -946,7 +945,7 @@ static void stream_pop_outq_entry(nghttp3_stream *stream,
if (chunk->last == tbuf->buf.last) {
if (nghttp3_buf_cap(chunk) == NGHTTP3_STREAM_MIN_CHUNK_SIZE) {
nghttp3_objalloc_chunk_release(stream->out_chunk_objalloc,
(nghttp3_chunk *)(void *)chunk->begin);
(void *)chunk->begin);
} else {
nghttp3_buf_free(chunk, stream->mem);
}
@ -955,7 +954,7 @@ static void stream_pop_outq_entry(nghttp3_stream *stream,
break;
default:
nghttp3_unreachable();
};
}
nghttp3_ringbuf_pop_front(&stream->outq);
}

View File

@ -114,10 +114,6 @@ typedef struct nghttp3_stream_read_state {
/* NGHTTP3_STREAM_FLAG_READ_EOF indicates that remote endpoint sent
fin. */
#define NGHTTP3_STREAM_FLAG_READ_EOF 0x0020u
/* NGHTTP3_STREAM_FLAG_CLOSED indicates that QUIC stream was closed.
nghttp3_stream object can still alive because it might be blocked
by QPACK decoder. */
#define NGHTTP3_STREAM_FLAG_CLOSED 0x0040u
/* NGHTTP3_STREAM_FLAG_SHUT_WR indicates that any further write
operation to a stream is prohibited. */
#define NGHTTP3_STREAM_FLAG_SHUT_WR 0x0100u
@ -135,7 +131,6 @@ typedef struct nghttp3_stream_read_state {
typedef enum nghttp3_stream_http_state {
NGHTTP3_HTTP_STATE_NONE,
NGHTTP3_HTTP_STATE_REQ_INITIAL,
NGHTTP3_HTTP_STATE_REQ_BEGIN,
NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN,
NGHTTP3_HTTP_STATE_REQ_HEADERS_END,
NGHTTP3_HTTP_STATE_REQ_DATA_BEGIN,
@ -144,7 +139,6 @@ typedef enum nghttp3_stream_http_state {
NGHTTP3_HTTP_STATE_REQ_TRAILERS_END,
NGHTTP3_HTTP_STATE_REQ_END,
NGHTTP3_HTTP_STATE_RESP_INITIAL,
NGHTTP3_HTTP_STATE_RESP_BEGIN,
NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN,
NGHTTP3_HTTP_STATE_RESP_HEADERS_END,
NGHTTP3_HTTP_STATE_RESP_DATA_BEGIN,

22
deps/ngtcp2/nghttp3/lib/sfparse/COPYING vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License
Copyright (c) 2023 sfparse 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.

1787
deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -78,6 +78,7 @@
'nghttp3/lib/nghttp3_qpack_huffman.c',
'nghttp3/lib/nghttp3_qpack_huffman_data.c',
'nghttp3/lib/nghttp3_range.c',
'nghttp3/lib/nghttp3_ratelim.c',
'nghttp3/lib/nghttp3_rcbuf.c',
'nghttp3/lib/nghttp3_ringbuf.c',
'nghttp3/lib/nghttp3_settings.c',

View File

@ -45,6 +45,9 @@ Session::Application_Options::operator const nghttp3_settings() const {
.h3_datagram = enable_datagrams,
// TODO(@jasnell): Support origin frames?
.origin_list = nullptr,
.glitch_ratelim_burst = 1000,
.glitch_ratelim_rate = 33,
.qpack_indexing_strat = NGHTTP3_QPACK_INDEXING_STRAT_NONE,
};
}