deps: update nghttp3 to 1.10.1

This commit is contained in:
nodejs-github-bot 2025-06-08 00:40:38 +00:00 committed by github-actions[bot]
parent 3b111eb3f5
commit 5da29ecec4
26 changed files with 1144 additions and 753 deletions

View File

@ -2106,7 +2106,7 @@ NGHTTP3_EXTERN int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn,
* control credit (both stream and connection) of underlying QUIC * control credit (both stream and connection) of underlying QUIC
* connection by that amount. It does not include the amount of data * connection by that amount. It does not include the amount of data
* carried by DATA frame which contains application data (excluding * carried by DATA frame which contains application data (excluding
* any control or QPACK unidirectional streams) . See * any control or QPACK unidirectional streams). See
* :type:`nghttp3_recv_data` to handle those bytes. If |fin| is * :type:`nghttp3_recv_data` to handle those bytes. If |fin| is
* nonzero, this is the last data from remote endpoint in this stream. * nonzero, this is the last data from remote endpoint in this stream.
* *
@ -2480,8 +2480,6 @@ typedef struct nghttp3_data_reader {
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* :macro:`NGHTTP3_ERR_INVALID_ARGUMENT`
* |stream_id| identifies unidirectional stream.
* :macro:`NGHTTP3_ERR_CONN_CLOSING` * :macro:`NGHTTP3_ERR_CONN_CLOSING`
* Connection is shutting down, and no new stream is allowed. * Connection is shutting down, and no new stream is allowed.
* :macro:`NGHTTP3_ERR_STREAM_IN_USE` * :macro:`NGHTTP3_ERR_STREAM_IN_USE`

View File

@ -31,7 +31,7 @@
* *
* Version number of the nghttp3 library release. * Version number of the nghttp3 library release.
*/ */
#define NGHTTP3_VERSION "1.6.0" #define NGHTTP3_VERSION "1.10.1"
/** /**
* @macro * @macro
@ -41,6 +41,6 @@
* number, 8 bits for minor and 8 bits for patch. Version 1.2.3 * number, 8 bits for minor and 8 bits for patch. Version 1.2.3
* becomes 0x010203. * becomes 0x010203.
*/ */
#define NGHTTP3_VERSION_NUM 0x010600 #define NGHTTP3_VERSION_NUM 0x010a01
#endif /* !defined(NGHTTP3_VERSION_H) */ #endif /* !defined(NGHTTP3_VERSION_H) */

View File

@ -50,6 +50,10 @@ size_t nghttp3_buf_cap(const nghttp3_buf *buf) {
return (size_t)(buf->end - buf->begin); return (size_t)(buf->end - buf->begin);
} }
size_t nghttp3_buf_offset(const nghttp3_buf *buf) {
return (size_t)(buf->pos - buf->begin);
}
void nghttp3_buf_reset(nghttp3_buf *buf) { buf->pos = buf->last = buf->begin; } void nghttp3_buf_reset(nghttp3_buf *buf) { buf->pos = buf->last = buf->begin; }
int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem) { int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem) {
@ -87,4 +91,12 @@ void nghttp3_typed_buf_init(nghttp3_typed_buf *tbuf, const nghttp3_buf *buf,
nghttp3_buf_type type) { nghttp3_buf_type type) {
tbuf->buf = *buf; tbuf->buf = *buf;
tbuf->type = type; tbuf->type = type;
tbuf->buf.begin = tbuf->buf.pos;
}
void nghttp3_typed_buf_shared_init(nghttp3_typed_buf *tbuf,
const nghttp3_buf *chunk) {
tbuf->buf = *chunk;
tbuf->type = NGHTTP3_BUF_TYPE_SHARED;
tbuf->buf.begin = tbuf->buf.pos = tbuf->buf.last;
} }

View File

@ -42,6 +42,12 @@ void nghttp3_buf_wrap_init(nghttp3_buf *buf, uint8_t *src, size_t len);
*/ */
size_t nghttp3_buf_cap(const nghttp3_buf *buf); size_t nghttp3_buf_cap(const nghttp3_buf *buf);
/*
* nghttp3_buf_offset returns the distance from tbuf->begin to
* tbuf->pos. In other words, it returns buf->pos - buf->begin.
*/
size_t nghttp3_buf_offset(const nghttp3_buf *buf);
int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem); int nghttp3_buf_reserve(nghttp3_buf *buf, size_t size, const nghttp3_mem *mem);
/* /*
@ -69,6 +75,13 @@ typedef struct nghttp3_typed_buf {
void nghttp3_typed_buf_init(nghttp3_typed_buf *tbuf, const nghttp3_buf *buf, void nghttp3_typed_buf_init(nghttp3_typed_buf *tbuf, const nghttp3_buf *buf,
nghttp3_buf_type type); nghttp3_buf_type type);
/*
* nghttp3_typed_buf_shared_init initializes |tbuf| of type
* NGHTTP3_BUF_TYPE_SHARED.
*/
void nghttp3_typed_buf_shared_init(nghttp3_typed_buf *tbuf,
const nghttp3_buf *chunk);
void nghttp3_typed_buf_free(nghttp3_typed_buf *tbuf); void nghttp3_typed_buf_free(nghttp3_typed_buf *tbuf);
#endif /* !defined(NGHTTP3_BUF_H) */ #endif /* !defined(NGHTTP3_BUF_H) */

View File

@ -39,7 +39,7 @@
dynamic table capacity that QPACK encoder is willing to use. */ dynamic table capacity that QPACK encoder is willing to use. */
#define NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY 4096 #define NGHTTP3_QPACK_ENCODER_MAX_DTABLE_CAPACITY 4096
nghttp3_objalloc_def(chunk, nghttp3_chunk, oplent); nghttp3_objalloc_def(chunk, nghttp3_chunk, oplent)
/* /*
* conn_remote_stream_uni returns nonzero if |stream_id| is remote * conn_remote_stream_uni returns nonzero if |stream_id| is remote
@ -233,12 +233,16 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version,
const nghttp3_callbacks *callbacks, int settings_version, const nghttp3_callbacks *callbacks, int settings_version,
const nghttp3_settings *settings, const nghttp3_mem *mem, const nghttp3_settings *settings, const nghttp3_mem *mem,
void *user_data) { void *user_data) {
int rv;
nghttp3_conn *conn; nghttp3_conn *conn;
size_t i; size_t i;
(void)callbacks_version; (void)callbacks_version;
(void)settings_version; (void)settings_version;
assert(settings->max_field_section_size <= NGHTTP3_VARINT_MAX);
assert(settings->qpack_max_dtable_capacity <= NGHTTP3_VARINT_MAX);
assert(settings->qpack_encoder_max_dtable_capacity <= NGHTTP3_VARINT_MAX);
assert(settings->qpack_blocked_streams <= NGHTTP3_VARINT_MAX);
if (mem == NULL) { if (mem == NULL) {
mem = nghttp3_mem_default(); mem = nghttp3_mem_default();
} }
@ -254,18 +258,11 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version,
nghttp3_map_init(&conn->streams, mem); nghttp3_map_init(&conn->streams, mem);
rv = nghttp3_qpack_decoder_init(&conn->qdec, settings->qpack_max_dtable_capacity,
nghttp3_qpack_decoder_init(&conn->qdec, settings->qpack_max_dtable_capacity, settings->qpack_blocked_streams, mem);
settings->qpack_blocked_streams, mem);
if (rv != 0) {
goto qdec_init_fail;
}
rv = nghttp3_qpack_encoder_init( nghttp3_qpack_encoder_init(&conn->qenc,
&conn->qenc, settings->qpack_encoder_max_dtable_capacity, mem); settings->qpack_encoder_max_dtable_capacity, mem);
if (rv != 0) {
goto qenc_init_fail;
}
nghttp3_pq_init(&conn->qpack_blocked_streams, ricnt_less, mem); nghttp3_pq_init(&conn->qpack_blocked_streams, ricnt_less, mem);
@ -291,16 +288,6 @@ static int conn_new(nghttp3_conn **pconn, int server, int callbacks_version,
*pconn = conn; *pconn = conn;
return 0; return 0;
qenc_init_fail:
nghttp3_qpack_decoder_free(&conn->qdec);
qdec_init_fail:
nghttp3_map_free(&conn->streams);
nghttp3_objalloc_free(&conn->stream_objalloc);
nghttp3_objalloc_free(&conn->out_chunk_objalloc);
nghttp3_mem_free(mem, conn);
return rv;
} }
int nghttp3_conn_client_new_versioned(nghttp3_conn **pconn, int nghttp3_conn_client_new_versioned(nghttp3_conn **pconn,
@ -399,6 +386,9 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id,
size_t bidi_nproc; size_t bidi_nproc;
int rv; int rv;
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
stream = nghttp3_conn_find_stream(conn, stream_id); stream = nghttp3_conn_find_stream(conn, stream_id);
if (stream == NULL) { if (stream == NULL) {
/* TODO Assert idtr */ /* TODO Assert idtr */
@ -434,6 +424,10 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id,
return rv; return rv;
} }
} }
} else if (!nghttp3_client_stream_uni(stream_id)) {
/* server does not expect to receive new server initiated
bidirectional or unidirectional stream from client. */
return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR;
} else { } else {
/* unidirectional stream */ /* unidirectional stream */
if (srclen == 0 && fin) { if (srclen == 0 && fin) {
@ -448,7 +442,7 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id,
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL;
stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL;
} else if (nghttp3_stream_uni(stream_id)) { } else if (nghttp3_server_stream_uni(stream_id)) {
if (srclen == 0 && fin) { if (srclen == 0 && fin) {
return 0; return 0;
} }
@ -461,17 +455,16 @@ nghttp3_ssize nghttp3_conn_read_stream(nghttp3_conn *conn, int64_t stream_id,
stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL; stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL;
stream->tx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL; stream->tx.hstate = NGHTTP3_HTTP_STATE_RESP_INITIAL;
} else { } else {
/* client doesn't expect to receive new bidirectional stream /* client doesn't expect to receive new bidirectional stream or
from server. */ client initiated unidirectional stream from server. */
return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR; return NGHTTP3_ERR_H3_STREAM_CREATION_ERROR;
} }
} else if (conn->server) { } else if (conn->server) {
if (nghttp3_client_stream_bidi(stream_id)) { assert(nghttp3_client_stream_bidi(stream_id) ||
if (stream->rx.hstate == NGHTTP3_HTTP_STATE_NONE) { nghttp3_client_stream_uni(stream_id));
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; } else {
stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL; assert(nghttp3_client_stream_bidi(stream_id) ||
} nghttp3_server_stream_uni(stream_id));
}
} }
if (srclen == 0 && !fin) { if (srclen == 0 && !fin) {
@ -608,6 +601,9 @@ nghttp3_ssize nghttp3_conn_read_uni(nghttp3_conn *conn, nghttp3_stream *stream,
break; break;
case NGHTTP3_STREAM_TYPE_UNKNOWN: case NGHTTP3_STREAM_TYPE_UNKNOWN:
nconsumed = (nghttp3_ssize)srclen; nconsumed = (nghttp3_ssize)srclen;
if (fin) {
break;
}
rv = conn_call_stop_sending(conn, stream, NGHTTP3_H3_STREAM_CREATION_ERROR); rv = conn_call_stop_sending(conn, stream, NGHTTP3_H3_STREAM_CREATION_ERROR);
if (rv != 0) { if (rv != 0) {
@ -665,7 +661,7 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
nghttp3_varint_read_state_reset(rvint); nghttp3_varint_read_state_reset(rvint);
rstate->state = NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH; rstate->state = NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH;
if (p == end) { if (p == end) {
break; return (nghttp3_ssize)nconsumed;
} }
/* Fall through */ /* Fall through */
case NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH: case NGHTTP3_CTRL_STREAM_STATE_FRAME_LENGTH:
@ -973,6 +969,10 @@ nghttp3_ssize nghttp3_conn_read_control(nghttp3_conn *conn,
rstate->state = NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE; rstate->state = NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE;
if (p == end) {
return (nghttp3_ssize)nconsumed;
}
/* Fall through */ /* Fall through */
case NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE: case NGHTTP3_CTRL_STREAM_STATE_PRIORITY_UPDATE:
/* We need to buffer Priority Field Value because it might be /* We need to buffer Priority Field Value because it might be
@ -1792,6 +1792,8 @@ conn_on_priority_update_stream(nghttp3_conn *conn,
stream->node.pri = fr->pri; stream->node.pri = fr->pri;
stream->flags |= NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED; stream->flags |= NGHTTP3_STREAM_FLAG_PRIORITY_UPDATE_RECVED;
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL;
stream->tx.hstate = NGHTTP3_HTTP_STATE_REQ_INITIAL;
return 0; return 0;
} }
@ -1836,7 +1838,7 @@ int nghttp3_conn_create_stream(nghttp3_conn *conn, nghttp3_stream **pstream,
nghttp3_stream *stream; nghttp3_stream *stream;
int rv; int rv;
nghttp3_stream_callbacks callbacks = { nghttp3_stream_callbacks callbacks = {
conn_stream_acked_data, .acked_data = conn_stream_acked_data,
}; };
rv = nghttp3_stream_new(&stream, stream_id, &callbacks, rv = nghttp3_stream_new(&stream, stream_id, &callbacks,
@ -1874,6 +1876,8 @@ int nghttp3_conn_bind_control_stream(nghttp3_conn *conn, int64_t stream_id) {
nghttp3_frame_entry frent; nghttp3_frame_entry frent;
int rv; int rv;
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
assert(!conn->server || nghttp3_server_stream_uni(stream_id)); assert(!conn->server || nghttp3_server_stream_uni(stream_id));
assert(conn->server || nghttp3_client_stream_uni(stream_id)); assert(conn->server || nghttp3_client_stream_uni(stream_id));
@ -1906,6 +1910,10 @@ int nghttp3_conn_bind_qpack_streams(nghttp3_conn *conn, int64_t qenc_stream_id,
nghttp3_stream *stream; nghttp3_stream *stream;
int rv; int rv;
assert(qenc_stream_id >= 0);
assert(qenc_stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
assert(qdec_stream_id >= 0);
assert(qdec_stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
assert(!conn->server || nghttp3_server_stream_uni(qenc_stream_id)); assert(!conn->server || nghttp3_server_stream_uni(qenc_stream_id));
assert(!conn->server || nghttp3_server_stream_uni(qdec_stream_id)); assert(!conn->server || nghttp3_server_stream_uni(qdec_stream_id));
assert(conn->server || nghttp3_client_stream_uni(qenc_stream_id)); assert(conn->server || nghttp3_client_stream_uni(qenc_stream_id));
@ -2194,13 +2202,11 @@ int nghttp3_conn_submit_request(nghttp3_conn *conn, int64_t stream_id,
assert(!conn->server); assert(!conn->server);
assert(conn->tx.qenc); assert(conn->tx.qenc);
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
assert(nghttp3_client_stream_bidi(stream_id)); assert(nghttp3_client_stream_bidi(stream_id));
/* TODO Should we check that stream_id is client stream_id? */
/* TODO Check GOAWAY last stream ID */ /* TODO Check GOAWAY last stream ID */
if (nghttp3_stream_uni(stream_id)) {
return NGHTTP3_ERR_INVALID_ARGUMENT;
}
if (conn->flags & NGHTTP3_CONN_FLAG_GOAWAY_RECVED) { if (conn->flags & NGHTTP3_CONN_FLAG_GOAWAY_RECVED) {
return NGHTTP3_ERR_CONN_CLOSING; return NGHTTP3_ERR_CONN_CLOSING;
@ -2454,6 +2460,9 @@ int nghttp3_conn_close_stream(nghttp3_conn *conn, int64_t stream_id,
int nghttp3_conn_shutdown_stream_read(nghttp3_conn *conn, int64_t stream_id) { int nghttp3_conn_shutdown_stream_read(nghttp3_conn *conn, int64_t stream_id) {
nghttp3_stream *stream; nghttp3_stream *stream;
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
if (!nghttp3_client_stream_bidi(stream_id)) { if (!nghttp3_client_stream_bidi(stream_id)) {
return 0; return 0;
} }
@ -2515,6 +2524,9 @@ uint64_t nghttp3_conn_get_frame_payload_left(nghttp3_conn *conn,
nghttp3_stream *stream; nghttp3_stream *stream;
int uni = 0; int uni = 0;
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
if (!nghttp3_client_stream_bidi(stream_id)) { if (!nghttp3_client_stream_bidi(stream_id)) {
uni = conn_remote_stream_uni(conn, stream_id); uni = conn_remote_stream_uni(conn, stream_id);
if (!uni) { if (!uni) {
@ -2542,6 +2554,8 @@ int nghttp3_conn_get_stream_priority_versioned(nghttp3_conn *conn,
(void)pri_version; (void)pri_version;
assert(conn->server); assert(conn->server);
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
if (!nghttp3_client_stream_bidi(stream_id)) { if (!nghttp3_client_stream_bidi(stream_id)) {
return NGHTTP3_ERR_INVALID_ARGUMENT; return NGHTTP3_ERR_INVALID_ARGUMENT;
@ -2566,6 +2580,8 @@ int nghttp3_conn_set_client_stream_priority(nghttp3_conn *conn,
uint8_t *buf = NULL; uint8_t *buf = NULL;
assert(!conn->server); assert(!conn->server);
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
if (!nghttp3_client_stream_bidi(stream_id)) { if (!nghttp3_client_stream_bidi(stream_id)) {
return NGHTTP3_ERR_INVALID_ARGUMENT; return NGHTTP3_ERR_INVALID_ARGUMENT;
@ -2603,6 +2619,8 @@ int nghttp3_conn_set_server_stream_priority_versioned(nghttp3_conn *conn,
assert(conn->server); assert(conn->server);
assert(pri->urgency < NGHTTP3_URGENCY_LEVELS); assert(pri->urgency < NGHTTP3_URGENCY_LEVELS);
assert(pri->inc == 0 || pri->inc == 1); assert(pri->inc == 0 || pri->inc == 1);
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
if (!nghttp3_client_stream_bidi(stream_id)) { if (!nghttp3_client_stream_bidi(stream_id)) {
return NGHTTP3_ERR_INVALID_ARGUMENT; return NGHTTP3_ERR_INVALID_ARGUMENT;

View File

@ -76,7 +76,7 @@ typedef struct nghttp3_chunk {
nghttp3_opl_entry oplent; nghttp3_opl_entry oplent;
} nghttp3_chunk; } nghttp3_chunk;
nghttp3_objalloc_decl(chunk, nghttp3_chunk, oplent); nghttp3_objalloc_decl(chunk, nghttp3_chunk, oplent)
struct nghttp3_conn { struct nghttp3_conn {
nghttp3_objalloc out_chunk_objalloc; nghttp3_objalloc out_chunk_objalloc;

View File

@ -66,8 +66,6 @@ const uint8_t *nghttp3_get_varint(int64_t *dest, const uint8_t *p) {
} }
} }
int64_t nghttp3_get_varint_fb(const uint8_t *p) { return *p & 0x3f; }
size_t nghttp3_get_varintlen(const uint8_t *p) { size_t nghttp3_get_varintlen(const uint8_t *p) {
return (size_t)(1u << (*p >> 6)); return (size_t)(1u << (*p >> 6));
} }

View File

@ -135,12 +135,6 @@ STIN uint16_t ntohs(uint16_t netshort) {
*/ */
const uint8_t *nghttp3_get_varint(int64_t *dest, const uint8_t *p); const uint8_t *nghttp3_get_varint(int64_t *dest, const uint8_t *p);
/*
* nghttp3_get_varint_fb reads first byte of encoded variable-length
* integer from |p|.
*/
int64_t nghttp3_get_varint_fb(const uint8_t *p);
/* /*
* nghttp3_get_varintlen returns the required number of bytes to read * nghttp3_get_varintlen returns the required number of bytes to read
* variable-length integer starting at |p|. * variable-length integer starting at |p|.

View File

@ -29,14 +29,16 @@
#include <assert.h> #include <assert.h>
void nghttp3_gaptr_init(nghttp3_gaptr *gaptr, const nghttp3_mem *mem) { void nghttp3_gaptr_init(nghttp3_gaptr *gaptr, const nghttp3_mem *mem) {
nghttp3_ksl_init(&gaptr->gap, nghttp3_ksl_range_compar, sizeof(nghttp3_range), nghttp3_ksl_init(&gaptr->gap, nghttp3_ksl_range_compar,
mem); nghttp3_ksl_range_search, sizeof(nghttp3_range), mem);
gaptr->mem = mem; gaptr->mem = mem;
} }
static int gaptr_gap_init(nghttp3_gaptr *gaptr) { static int gaptr_gap_init(nghttp3_gaptr *gaptr) {
nghttp3_range range = {0, UINT64_MAX}; nghttp3_range range = {
.end = UINT64_MAX,
};
return nghttp3_ksl_insert(&gaptr->gap, NULL, &range, NULL); return nghttp3_ksl_insert(&gaptr->gap, NULL, &range, NULL);
} }
@ -52,7 +54,11 @@ void nghttp3_gaptr_free(nghttp3_gaptr *gaptr) {
int nghttp3_gaptr_push(nghttp3_gaptr *gaptr, uint64_t offset, int nghttp3_gaptr_push(nghttp3_gaptr *gaptr, uint64_t offset,
uint64_t datalen) { uint64_t datalen) {
int rv; int rv;
nghttp3_range k, m, l, r, q = {offset, offset + datalen}; nghttp3_range k, m, l, r;
nghttp3_range q = {
.begin = offset,
.end = offset + datalen,
};
nghttp3_ksl_it it; nghttp3_ksl_it it;
if (nghttp3_ksl_len(&gaptr->gap) == 0) { if (nghttp3_ksl_len(&gaptr->gap) == 0) {
@ -62,8 +68,8 @@ int nghttp3_gaptr_push(nghttp3_gaptr *gaptr, uint64_t offset,
} }
} }
it = nghttp3_ksl_lower_bound_compar(&gaptr->gap, &q, it = nghttp3_ksl_lower_bound_search(&gaptr->gap, &q,
nghttp3_ksl_range_exclusive_compar); nghttp3_ksl_range_exclusive_search);
for (; !nghttp3_ksl_it_end(&it);) { for (; !nghttp3_ksl_it_end(&it);) {
k = *(nghttp3_range *)nghttp3_ksl_it_key(&it); k = *(nghttp3_range *)nghttp3_ksl_it_key(&it);
@ -112,7 +118,10 @@ uint64_t nghttp3_gaptr_first_gap_offset(nghttp3_gaptr *gaptr) {
nghttp3_range nghttp3_gaptr_get_first_gap_after(nghttp3_gaptr *gaptr, nghttp3_range nghttp3_gaptr_get_first_gap_after(nghttp3_gaptr *gaptr,
uint64_t offset) { uint64_t offset) {
nghttp3_range q = {offset, offset + 1}; nghttp3_range q = {
.begin = offset,
.end = offset + 1,
};
nghttp3_ksl_it it; nghttp3_ksl_it it;
if (nghttp3_ksl_len(&gaptr->gap) == 0) { if (nghttp3_ksl_len(&gaptr->gap) == 0) {
@ -120,8 +129,8 @@ nghttp3_range nghttp3_gaptr_get_first_gap_after(nghttp3_gaptr *gaptr,
return r; return r;
} }
it = nghttp3_ksl_lower_bound_compar(&gaptr->gap, &q, it = nghttp3_ksl_lower_bound_search(&gaptr->gap, &q,
nghttp3_ksl_range_exclusive_compar); nghttp3_ksl_range_exclusive_search);
assert(!nghttp3_ksl_it_end(&it)); assert(!nghttp3_ksl_it_end(&it));
@ -130,7 +139,10 @@ nghttp3_range nghttp3_gaptr_get_first_gap_after(nghttp3_gaptr *gaptr,
int nghttp3_gaptr_is_pushed(nghttp3_gaptr *gaptr, uint64_t offset, int nghttp3_gaptr_is_pushed(nghttp3_gaptr *gaptr, uint64_t offset,
uint64_t datalen) { uint64_t datalen) {
nghttp3_range q = {offset, offset + datalen}; nghttp3_range q = {
.begin = offset,
.end = offset + datalen,
};
nghttp3_ksl_it it; nghttp3_ksl_it it;
nghttp3_range m; nghttp3_range m;
@ -138,8 +150,11 @@ int nghttp3_gaptr_is_pushed(nghttp3_gaptr *gaptr, uint64_t offset,
return 0; return 0;
} }
it = nghttp3_ksl_lower_bound_compar(&gaptr->gap, &q, it = nghttp3_ksl_lower_bound_search(&gaptr->gap, &q,
nghttp3_ksl_range_exclusive_compar); nghttp3_ksl_range_exclusive_search);
assert(!nghttp3_ksl_it_end(&it));
m = nghttp3_range_intersect(&q, (nghttp3_range *)nghttp3_ksl_it_key(&it)); m = nghttp3_range_intersect(&q, (nghttp3_range *)nghttp3_ksl_it_key(&it));
return nghttp3_range_len(&m) == 0; return nghttp3_range_len(&m) == 0;

View File

@ -69,11 +69,11 @@ static int64_t parse_uint(const uint8_t *s, size_t len) {
} }
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
if ('0' <= s[i] && s[i] <= '9') { if ('0' <= s[i] && s[i] <= '9') {
if (n > INT64_MAX / 10) { if (n > (int64_t)NGHTTP3_MAX_VARINT / 10) {
return -1; return -1;
} }
n *= 10; n *= 10;
if (n > INT64_MAX - (s[i] - '0')) { if (n > (int64_t)NGHTTP3_MAX_VARINT - (s[i] - '0')) {
return -1; return -1;
} }
n += s[i] - '0'; n += s[i] - '0';
@ -124,17 +124,17 @@ static int is_ws(uint8_t c) {
int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value, int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value,
size_t valuelen) { size_t valuelen) {
nghttp3_pri pri = *dest; nghttp3_pri pri = *dest;
sf_parser sfp; sfparse_parser sfp;
sf_vec key; sfparse_vec key;
sf_value val; sfparse_value val;
int rv; int rv;
sf_parser_init(&sfp, value, valuelen); sfparse_parser_init(&sfp, value, valuelen);
for (;;) { for (;;) {
rv = sf_parser_dict(&sfp, &key, &val); rv = sfparse_parser_dict(&sfp, &key, &val);
if (rv != 0) { if (rv != 0) {
if (rv == SF_ERR_EOF) { if (rv == SFPARSE_ERR_EOF) {
break; break;
} }
@ -147,7 +147,7 @@ int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value,
switch (key.base[0]) { switch (key.base[0]) {
case 'i': case 'i':
if (val.type != SF_TYPE_BOOLEAN) { if (val.type != SFPARSE_TYPE_BOOLEAN) {
return NGHTTP3_ERR_INVALID_ARGUMENT; return NGHTTP3_ERR_INVALID_ARGUMENT;
} }
@ -155,7 +155,8 @@ int nghttp3_http_parse_priority(nghttp3_pri *dest, const uint8_t *value,
break; break;
case 'u': case 'u':
if (val.type != SF_TYPE_INTEGER || val.integer < NGHTTP3_URGENCY_HIGH || if (val.type != SFPARSE_TYPE_INTEGER ||
val.integer < NGHTTP3_URGENCY_HIGH ||
NGHTTP3_URGENCY_LOW < val.integer) { NGHTTP3_URGENCY_LOW < val.integer) {
return NGHTTP3_ERR_INVALID_ARGUMENT; return NGHTTP3_ERR_INVALID_ARGUMENT;
} }
@ -197,7 +198,7 @@ static char VALID_AUTHORITY_CHARS[] = {
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */,
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */, 0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */, 1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */, 1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
@ -548,6 +549,9 @@ static int http_request_on_header(nghttp3_http_state *http,
break; break;
case NGHTTP3_QPACK_TOKEN_PRIORITY: case NGHTTP3_QPACK_TOKEN_PRIORITY:
if (!nghttp3_check_header_value(nv->value->base, nv->value->len)) { if (!nghttp3_check_header_value(nv->value->base, nv->value->len)) {
http->flags &= ~NGHTTP3_HTTP_FLAG_PRIORITY;
http->flags |= NGHTTP3_HTTP_FLAG_BAD_PRIORITY;
return NGHTTP3_ERR_REMOVE_HTTP_HEADER; return NGHTTP3_ERR_REMOVE_HTTP_HEADER;
} }
@ -991,7 +995,11 @@ int nghttp3_check_header_value(const uint8_t *value, size_t len) {
case 0: case 0:
return 1; return 1;
case 1: case 1:
return !is_ws(*value); if (is_ws(*value)) {
return 0;
}
break;
default: default:
if (is_ws(*value) || is_ws(*(value + len - 1))) { if (is_ws(*value) || is_ws(*(value + len - 1))) {
return 0; return 0;

View File

@ -34,9 +34,9 @@
#include "nghttp3_mem.h" #include "nghttp3_mem.h"
#include "nghttp3_range.h" #include "nghttp3_range.h"
static nghttp3_ksl_blk null_blk = {{{NULL, NULL, 0, 0, {0}}}}; static nghttp3_ksl_blk null_blk;
nghttp3_objalloc_def(ksl_blk, nghttp3_ksl_blk, oplent); nghttp3_objalloc_def(ksl_blk, nghttp3_ksl_blk, oplent)
static size_t ksl_nodelen(size_t keylen) { static size_t ksl_nodelen(size_t keylen) {
assert(keylen >= sizeof(uint64_t)); assert(keylen >= sizeof(uint64_t));
@ -59,7 +59,8 @@ static void ksl_node_set_key(nghttp3_ksl *ksl, nghttp3_ksl_node *node,
} }
void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar, void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar,
size_t keylen, const nghttp3_mem *mem) { nghttp3_ksl_search search, size_t keylen,
const nghttp3_mem *mem) {
size_t nodelen = ksl_nodelen(keylen); size_t nodelen = ksl_nodelen(keylen);
nghttp3_objalloc_init(&ksl->blkalloc, nghttp3_objalloc_init(&ksl->blkalloc,
@ -68,6 +69,7 @@ void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar,
ksl->head = NULL; ksl->head = NULL;
ksl->front = ksl->back = NULL; ksl->front = ksl->back = NULL;
ksl->compar = compar; ksl->compar = compar;
ksl->search = search;
ksl->n = 0; ksl->n = 0;
ksl->keylen = keylen; ksl->keylen = keylen;
ksl->nodelen = nodelen; ksl->nodelen = nodelen;
@ -274,20 +276,6 @@ static void ksl_insert_node(nghttp3_ksl *ksl, nghttp3_ksl_blk *blk, size_t i,
++blk->n; ++blk->n;
} }
static size_t ksl_search(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key,
nghttp3_ksl_compar compar) {
size_t i;
nghttp3_ksl_node *node;
for (i = 0, node = (nghttp3_ksl_node *)(void *)blk->nodes;
i < blk->n && compar((nghttp3_ksl_key *)node->key, key);
++i, node = (nghttp3_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen))
;
return i;
}
int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it, int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
const nghttp3_ksl_key *key, void *data) { const nghttp3_ksl_key *key, void *data) {
nghttp3_ksl_blk *blk; nghttp3_ksl_blk *blk;
@ -312,7 +300,7 @@ int nghttp3_ksl_insert(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
blk = ksl->head; blk = ksl->head;
for (;;) { for (;;) {
i = ksl_search(ksl, blk, key, ksl->compar); i = ksl->search(ksl, blk, key);
if (blk->leaf) { if (blk->leaf) {
if (i < blk->n && if (i < blk->n &&
@ -571,7 +559,7 @@ int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
} }
for (;;) { for (;;) {
i = ksl_search(ksl, blk, key, ksl->compar); i = ksl->search(ksl, blk, key);
if (i == blk->n) { if (i == blk->n) {
if (it) { if (it) {
@ -642,12 +630,12 @@ int nghttp3_ksl_remove(nghttp3_ksl *ksl, nghttp3_ksl_it *it,
nghttp3_ksl_it nghttp3_ksl_lower_bound(const nghttp3_ksl *ksl, nghttp3_ksl_it nghttp3_ksl_lower_bound(const nghttp3_ksl *ksl,
const nghttp3_ksl_key *key) { const nghttp3_ksl_key *key) {
return nghttp3_ksl_lower_bound_compar(ksl, key, ksl->compar); return nghttp3_ksl_lower_bound_search(ksl, key, ksl->search);
} }
nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(const nghttp3_ksl *ksl, nghttp3_ksl_it nghttp3_ksl_lower_bound_search(const nghttp3_ksl *ksl,
const nghttp3_ksl_key *key, const nghttp3_ksl_key *key,
nghttp3_ksl_compar compar) { nghttp3_ksl_search search) {
nghttp3_ksl_blk *blk = ksl->head; nghttp3_ksl_blk *blk = ksl->head;
nghttp3_ksl_it it; nghttp3_ksl_it it;
size_t i; size_t i;
@ -658,7 +646,7 @@ nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(const nghttp3_ksl *ksl,
} }
for (;;) { for (;;) {
i = ksl_search(ksl, blk, key, compar); i = search(ksl, blk, key);
if (blk->leaf) { if (blk->leaf) {
if (i == blk->n && blk->next) { if (i == blk->n && blk->next) {
@ -702,7 +690,7 @@ void nghttp3_ksl_update_key(nghttp3_ksl *ksl, const nghttp3_ksl_key *old_key,
assert(ksl->head); assert(ksl->head);
for (;;) { for (;;) {
i = ksl_search(ksl, blk, old_key, ksl->compar); i = ksl->search(ksl, blk, old_key);
assert(i < blk->n); assert(i < blk->n);
node = nghttp3_ksl_nth_node(ksl, blk, i); node = nghttp3_ksl_nth_node(ksl, blk, i);
@ -825,9 +813,50 @@ int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs,
return a->begin < b->begin; return a->begin < b->begin;
} }
nghttp3_ksl_search_def(range, nghttp3_ksl_range_compar)
size_t nghttp3_ksl_range_search(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key) {
return ksl_range_search(ksl, blk, key);
}
int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs, int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs,
const nghttp3_ksl_key *rhs) { const nghttp3_ksl_key *rhs) {
const nghttp3_range *a = lhs, *b = rhs; const nghttp3_range *a = lhs, *b = rhs;
return a->begin < b->begin && !(nghttp3_max_uint64(a->begin, b->begin) < return a->begin < b->begin && !(nghttp3_max_uint64(a->begin, b->begin) <
nghttp3_min_uint64(a->end, b->end)); nghttp3_min_uint64(a->end, b->end));
} }
nghttp3_ksl_search_def(range_exclusive, nghttp3_ksl_range_exclusive_compar)
size_t nghttp3_ksl_range_exclusive_search(const nghttp3_ksl *ksl,
nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key) {
return ksl_range_exclusive_search(ksl, blk, key);
}
int nghttp3_ksl_uint64_less(const nghttp3_ksl_key *lhs,
const nghttp3_ksl_key *rhs) {
return *(uint64_t *)lhs < *(uint64_t *)rhs;
}
nghttp3_ksl_search_def(uint64_less, nghttp3_ksl_uint64_less)
size_t nghttp3_ksl_uint64_less_search(const nghttp3_ksl *ksl,
nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key) {
return ksl_uint64_less_search(ksl, blk, key);
}
int nghttp3_ksl_int64_greater(const nghttp3_ksl_key *lhs,
const nghttp3_ksl_key *rhs) {
return *(int64_t *)lhs > *(int64_t *)rhs;
}
nghttp3_ksl_search_def(int64_greater, nghttp3_ksl_int64_greater)
size_t nghttp3_ksl_int64_greater_search(const nghttp3_ksl *ksl,
nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key) {
return ksl_int64_greater_search(ksl, blk, key);
}

View File

@ -104,7 +104,7 @@ struct nghttp3_ksl_blk {
}; };
}; };
nghttp3_objalloc_decl(ksl_blk, nghttp3_ksl_blk, oplent); nghttp3_objalloc_decl(ksl_blk, nghttp3_ksl_blk, oplent)
/* /*
* nghttp3_ksl_compar is a function type which returns nonzero if key * nghttp3_ksl_compar is a function type which returns nonzero if key
@ -115,6 +115,35 @@ typedef int (*nghttp3_ksl_compar)(const nghttp3_ksl_key *lhs,
typedef struct nghttp3_ksl nghttp3_ksl; typedef struct nghttp3_ksl nghttp3_ksl;
/*
* nghttp3_ksl_search is a function to search for the first element in
* |blk|->nodes which is not ordered before |key|. It returns the
* index of such element. It returns |blk|->n if there is no such
* element.
*/
typedef size_t (*nghttp3_ksl_search)(const nghttp3_ksl *ksl,
nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key);
/*
* nghttp3_ksl_search_def is a macro to implement nghttp3_ksl_search
* with COMPAR which is supposed to be nghttp3_ksl_compar.
*/
#define nghttp3_ksl_search_def(NAME, COMPAR) \
static size_t ksl_##NAME##_search(const nghttp3_ksl *ksl, \
nghttp3_ksl_blk *blk, \
const nghttp3_ksl_key *key) { \
size_t i; \
nghttp3_ksl_node *node; \
\
for (i = 0, node = (nghttp3_ksl_node *)(void *)blk->nodes; \
i < blk->n && COMPAR((nghttp3_ksl_key *)node->key, key); ++i, \
node = (nghttp3_ksl_node *)(void *)((uint8_t *)node + ksl->nodelen)) \
; \
\
return i; \
}
typedef struct nghttp3_ksl_it nghttp3_ksl_it; typedef struct nghttp3_ksl_it nghttp3_ksl_it;
/* /*
@ -138,6 +167,7 @@ struct nghttp3_ksl {
/* back points to the last leaf block. */ /* back points to the last leaf block. */
nghttp3_ksl_blk *back; nghttp3_ksl_blk *back;
nghttp3_ksl_compar compar; nghttp3_ksl_compar compar;
nghttp3_ksl_search search;
/* n is the number of elements stored. */ /* n is the number of elements stored. */
size_t n; size_t n;
/* keylen is the size of key */ /* keylen is the size of key */
@ -149,11 +179,13 @@ struct nghttp3_ksl {
/* /*
* nghttp3_ksl_init initializes |ksl|. |compar| specifies compare * nghttp3_ksl_init initializes |ksl|. |compar| specifies compare
* function. |keylen| is the length of key and must be at least * function. |search| is a search function which must use |compar|.
* |keylen| is the length of key and must be at least
* sizeof(uint64_t). * sizeof(uint64_t).
*/ */
void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar, void nghttp3_ksl_init(nghttp3_ksl *ksl, nghttp3_ksl_compar compar,
size_t keylen, const nghttp3_mem *mem); nghttp3_ksl_search search, size_t keylen,
const nghttp3_mem *mem);
/* /*
* nghttp3_ksl_free frees resources allocated for |ksl|. If |ksl| is * nghttp3_ksl_free frees resources allocated for |ksl|. If |ksl| is
@ -218,12 +250,12 @@ nghttp3_ksl_it nghttp3_ksl_lower_bound(const nghttp3_ksl *ksl,
const nghttp3_ksl_key *key); const nghttp3_ksl_key *key);
/* /*
* nghttp3_ksl_lower_bound_compar works like nghttp3_ksl_lower_bound, * nghttp3_ksl_lower_bound_search works like nghttp3_ksl_lower_bound,
* but it takes custom function |compar| to do lower bound search. * but it takes custom function |search| to do lower bound search.
*/ */
nghttp3_ksl_it nghttp3_ksl_lower_bound_compar(const nghttp3_ksl *ksl, nghttp3_ksl_it nghttp3_ksl_lower_bound_search(const nghttp3_ksl *ksl,
const nghttp3_ksl_key *key, const nghttp3_ksl_key *key,
nghttp3_ksl_compar compar); nghttp3_ksl_search search);
/* /*
* nghttp3_ksl_update_key replaces the key of nodes which has * nghttp3_ksl_update_key replaces the key of nodes which has
@ -330,22 +362,69 @@ int nghttp3_ksl_it_begin(const nghttp3_ksl_it *it);
/* /*
* nghttp3_ksl_range_compar is an implementation of * nghttp3_ksl_range_compar is an implementation of
* nghttp3_ksl_compar. lhs->ptr and rhs->ptr must point to * nghttp3_ksl_compar. |lhs| and |rhs| must point to nghttp3_range
* nghttp3_range object and the function returns nonzero if (const * object, and the function returns nonzero if ((const nghttp3_range
* nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range * *)lhs)->begin < ((const nghttp3_range *)rhs)->begin.
* *)(rhs->ptr)->begin.
*/ */
int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs, int nghttp3_ksl_range_compar(const nghttp3_ksl_key *lhs,
const nghttp3_ksl_key *rhs); const nghttp3_ksl_key *rhs);
/*
* nghttp3_ksl_range_search is an implementation of nghttp3_ksl_search
* that uses nghttp3_ksl_range_compar.
*/
size_t nghttp3_ksl_range_search(const nghttp3_ksl *ksl, nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key);
/* /*
* nghttp3_ksl_range_exclusive_compar is an implementation of * nghttp3_ksl_range_exclusive_compar is an implementation of
* nghttp3_ksl_compar. lhs->ptr and rhs->ptr must point to * nghttp3_ksl_compar. |lhs| and |rhs| must point to nghttp3_range
* nghttp3_range object and the function returns nonzero if (const * object, and the function returns nonzero if ((const nghttp3_range
* nghttp3_range *)(lhs->ptr)->begin < (const nghttp3_range * *)lhs)->begin < ((const nghttp3_range *)rhs)->begin, and the 2
* *)(rhs->ptr)->begin and the 2 ranges do not intersect. * ranges do not intersect.
*/ */
int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs, int nghttp3_ksl_range_exclusive_compar(const nghttp3_ksl_key *lhs,
const nghttp3_ksl_key *rhs); const nghttp3_ksl_key *rhs);
/*
* nghttp3_ksl_range_exclusive_search is an implementation of
* nghttp3_ksl_search that uses nghttp3_ksl_range_exclusive_compar.
*/
size_t nghttp3_ksl_range_exclusive_search(const nghttp3_ksl *ksl,
nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key);
/*
* nghttp3_ksl_uint64_less is an implementation of nghttp3_ksl_compar.
* |lhs| and |rhs| must point to uint64_t objects, and the function
* returns nonzero if *(uint64_t *)|lhs| < *(uint64_t *)|rhs|.
*/
int nghttp3_ksl_uint64_less(const nghttp3_ksl_key *lhs,
const nghttp3_ksl_key *rhs);
/*
* nghttp3_ksl_uint64_less_search is an implementation of
* nghttp3_ksl_search that uses nghttp3_ksl_uint64_less.
*/
size_t nghttp3_ksl_uint64_less_search(const nghttp3_ksl *ksl,
nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key);
/*
* nghttp3_ksl_int64_greater is an implementation of
* nghttp3_ksl_compar. |lhs| and |rhs| must point to int64_t objects,
* and the function returns nonzero if *(int64_t *)|lhs| > *(int64_t
* *)|rhs|.
*/
int nghttp3_ksl_int64_greater(const nghttp3_ksl_key *lhs,
const nghttp3_ksl_key *rhs);
/*
* nghttp3_ksl_int64_greater_search is an implementation of
* nghttp3_ksl_search that uses nghttp3_ksl_int64_greater.
*/
size_t nghttp3_ksl_int64_greater_search(const nghttp3_ksl *ksl,
nghttp3_ksl_blk *blk,
const nghttp3_ksl_key *key);
#endif /* !defined(NGHTTP3_KSL_H) */ #endif /* !defined(NGHTTP3_KSL_H) */

View File

@ -48,27 +48,27 @@
#define nghttp3_max_def(SUFFIX, T) \ #define nghttp3_max_def(SUFFIX, T) \
static inline T nghttp3_max_##SUFFIX(T a, T b) { return a < b ? b : a; } static inline T nghttp3_max_##SUFFIX(T a, T b) { return a < b ? b : a; }
nghttp3_max_def(int8, int8_t); nghttp3_max_def(int8, int8_t)
nghttp3_max_def(int16, int16_t); nghttp3_max_def(int16, int16_t)
nghttp3_max_def(int32, int32_t); nghttp3_max_def(int32, int32_t)
nghttp3_max_def(int64, int64_t); nghttp3_max_def(int64, int64_t)
nghttp3_max_def(uint8, uint8_t); nghttp3_max_def(uint8, uint8_t)
nghttp3_max_def(uint16, uint16_t); nghttp3_max_def(uint16, uint16_t)
nghttp3_max_def(uint32, uint32_t); nghttp3_max_def(uint32, uint32_t)
nghttp3_max_def(uint64, uint64_t); nghttp3_max_def(uint64, uint64_t)
nghttp3_max_def(size, size_t); nghttp3_max_def(size, size_t)
#define nghttp3_min_def(SUFFIX, T) \ #define nghttp3_min_def(SUFFIX, T) \
static inline T nghttp3_min_##SUFFIX(T a, T b) { return a < b ? a : b; } static inline T nghttp3_min_##SUFFIX(T a, T b) { return a < b ? a : b; }
nghttp3_min_def(int8, int8_t); nghttp3_min_def(int8, int8_t)
nghttp3_min_def(int16, int16_t); nghttp3_min_def(int16, int16_t)
nghttp3_min_def(int32, int32_t); nghttp3_min_def(int32, int32_t)
nghttp3_min_def(int64, int64_t); nghttp3_min_def(int64, int64_t)
nghttp3_min_def(uint8, uint8_t); nghttp3_min_def(uint8, uint8_t)
nghttp3_min_def(uint16, uint16_t); nghttp3_min_def(uint16, uint16_t)
nghttp3_min_def(uint32, uint32_t); nghttp3_min_def(uint32, uint32_t)
nghttp3_min_def(uint64, uint64_t); nghttp3_min_def(uint64, uint64_t)
nghttp3_min_def(size, size_t); nghttp3_min_def(size, size_t)
#endif /* !defined(NGHTTP3_MACRO_H) */ #endif /* !defined(NGHTTP3_MACRO_H) */

View File

@ -120,7 +120,11 @@ void nghttp3_map_print_distance(const nghttp3_map *map) {
static int insert(nghttp3_map_bucket *table, size_t hashbits, static int insert(nghttp3_map_bucket *table, size_t hashbits,
nghttp3_map_key_type key, void *data) { nghttp3_map_key_type key, void *data) {
size_t idx = hash(key, hashbits); size_t idx = hash(key, hashbits);
nghttp3_map_bucket b = {0, key, data}, *bkt; nghttp3_map_bucket b = {
.key = key,
.data = data,
};
nghttp3_map_bucket *bkt;
size_t mask = (1u << hashbits) - 1; size_t mask = (1u << hashbits) - 1;
for (;;) { for (;;) {

View File

@ -164,20 +164,4 @@ int nghttp3_pq_empty(const nghttp3_pq *pq) { return pq->length == 0; }
size_t nghttp3_pq_size(const nghttp3_pq *pq) { return pq->length; } size_t nghttp3_pq_size(const nghttp3_pq *pq) { return pq->length; }
int nghttp3_pq_each(const nghttp3_pq *pq, nghttp3_pq_item_cb fun, void *arg) {
size_t i;
if (pq->length == 0) {
return 0;
}
for (i = 0; i < pq->length; ++i) {
if ((*fun)(pq->q[i], arg)) {
return 1;
}
}
return 0;
}
void nghttp3_pq_clear(nghttp3_pq *pq) { pq->length = 0; } void nghttp3_pq_clear(nghttp3_pq *pq) { pq->length = 0; }

View File

@ -112,17 +112,6 @@ int nghttp3_pq_empty(const nghttp3_pq *pq);
*/ */
size_t nghttp3_pq_size(const nghttp3_pq *pq); size_t nghttp3_pq_size(const nghttp3_pq *pq);
typedef int (*nghttp3_pq_item_cb)(nghttp3_pq_entry *item, void *arg);
/*
* nghttp3_pq_each applies |fun| to each item in |pq|. The |arg| is
* passed as arg parameter to callback function. This function must
* not change the ordering key. If the return value from callback is
* nonzero, this function returns 1 immediately without iterating
* remaining items. Otherwise this function returns 0.
*/
int nghttp3_pq_each(const nghttp3_pq *pq, nghttp3_pq_item_cb fun, void *arg);
/* /*
* nghttp3_pq_remove removes |item| from |pq|. |pq| must contain * nghttp3_pq_remove removes |item| from |pq|. |pq| must contain
* |item| otherwise the behavior is undefined. * |item| otherwise the behavior is undefined.

View File

@ -41,7 +41,12 @@
#define NGHTTP3_QPACK_MAX_QPACK_STREAMS 2000 #define NGHTTP3_QPACK_MAX_QPACK_STREAMS 2000
/* Make scalar initialization form of nghttp3_qpack_static_entry */ /* Make scalar initialization form of nghttp3_qpack_static_entry */
#define MAKE_STATIC_ENT(I, T, H) {I, T, H} #define MAKE_STATIC_ENT(I, T, H) \
{ \
.absidx = I, \
.token = T, \
.hash = H, \
}
/* Generated by mkstatichdtbl.py */ /* Generated by mkstatichdtbl.py */
static nghttp3_qpack_static_entry token_stable[] = { static nghttp3_qpack_static_entry token_stable[] = {
@ -166,9 +171,19 @@ static nghttp3_qpack_static_entry token_stable[] = {
/* Make scalar initialization form of nghttp3_qpack_static_entry */ /* Make scalar initialization form of nghttp3_qpack_static_entry */
#define MAKE_STATIC_HD(N, V, T) \ #define MAKE_STATIC_HD(N, V, T) \
{ \ { \
{NULL, (uint8_t *)(N), sizeof((N)) - 1, -1}, \ .name = \
{NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, \ { \
T, \ .base = (uint8_t *)(N), \
.len = sizeof((N)) - 1, \
.ref = -1, \
}, \
.value = \
{ \
.base = (uint8_t *)(V), \
.len = sizeof((V)) - 1, \
.ref = -1, \
}, \
.token = T, \
} }
static nghttp3_qpack_static_header stable[] = { static nghttp3_qpack_static_header stable[] = {
@ -828,29 +843,12 @@ static void encoder_qpack_map_find(nghttp3_qpack_encoder *encoder,
* ctx->max_dtable_capacity and it is initialized to 0. * ctx->max_dtable_capacity and it is initialized to 0.
* |hard_max_dtable_capacity| is the upper bound of * |hard_max_dtable_capacity| is the upper bound of
* ctx->max_dtable_capacity. * ctx->max_dtable_capacity.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP3_ERR_NOMEM
* Out of memory.
*/ */
static int qpack_context_init(nghttp3_qpack_context *ctx, static void qpack_context_init(nghttp3_qpack_context *ctx,
size_t hard_max_dtable_capacity, size_t hard_max_dtable_capacity,
size_t max_blocked_streams, size_t max_blocked_streams,
const nghttp3_mem *mem) { const nghttp3_mem *mem) {
int rv; nghttp3_ringbuf_init(&ctx->dtable, 0, sizeof(nghttp3_qpack_entry *), mem);
size_t len = 4096 / NGHTTP3_QPACK_ENTRY_OVERHEAD;
size_t len2;
for (len2 = 1; len2 < len; len2 <<= 1)
;
rv = nghttp3_ringbuf_init(&ctx->dtable, len2, sizeof(nghttp3_qpack_entry *),
mem);
if (rv != 0) {
return rv;
}
ctx->mem = mem; ctx->mem = mem;
ctx->dtable_size = 0; ctx->dtable_size = 0;
@ -860,8 +858,6 @@ static int qpack_context_init(nghttp3_qpack_context *ctx,
ctx->max_blocked_streams = max_blocked_streams; ctx->max_blocked_streams = max_blocked_streams;
ctx->next_absidx = 0; ctx->next_absidx = 0;
ctx->bad = 0; ctx->bad = 0;
return 0;
} }
static void qpack_context_free(nghttp3_qpack_context *ctx) { static void qpack_context_free(nghttp3_qpack_context *ctx) {
@ -898,19 +894,17 @@ static int max_cnt_greater(const nghttp3_ksl_key *lhs,
return a->max_cnt > b->max_cnt || (a->max_cnt == b->max_cnt && a->id < b->id); return a->max_cnt > b->max_cnt || (a->max_cnt == b->max_cnt && a->id < b->id);
} }
int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder, nghttp3_ksl_search_def(max_cnt_greater, max_cnt_greater)
size_t hard_max_dtable_capacity,
const nghttp3_mem *mem) {
int rv;
rv = qpack_context_init(&encoder->ctx, hard_max_dtable_capacity, 0, mem); void nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder,
if (rv != 0) { size_t hard_max_dtable_capacity,
return rv; const nghttp3_mem *mem) {
} qpack_context_init(&encoder->ctx, hard_max_dtable_capacity, 0, mem);
nghttp3_map_init(&encoder->streams, mem); nghttp3_map_init(&encoder->streams, mem);
nghttp3_ksl_init(&encoder->blocked_streams, max_cnt_greater, nghttp3_ksl_init(&encoder->blocked_streams, max_cnt_greater,
ksl_max_cnt_greater_search,
sizeof(nghttp3_blocked_streams_key), mem); sizeof(nghttp3_blocked_streams_key), mem);
qpack_map_init(&encoder->dtable_map); qpack_map_init(&encoder->dtable_map);
@ -925,8 +919,6 @@ int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder,
encoder->flags = NGHTTP3_QPACK_ENCODER_FLAG_NONE; encoder->flags = NGHTTP3_QPACK_ENCODER_FLAG_NONE;
nghttp3_qpack_read_state_reset(&encoder->rstate); nghttp3_qpack_read_state_reset(&encoder->rstate);
return 0;
} }
static int map_stream_free(void *data, void *ptr) { static int map_stream_free(void *data, void *ptr) {
@ -1149,6 +1141,9 @@ int nghttp3_qpack_encoder_encode(nghttp3_qpack_encoder *encoder,
int blocked_stream; int blocked_stream;
nghttp3_qpack_stream *stream; nghttp3_qpack_stream *stream;
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
if (encoder->ctx.bad) { if (encoder->ctx.bad) {
return NGHTTP3_ERR_QPACK_FATAL; return NGHTTP3_ERR_QPACK_FATAL;
} }
@ -1444,7 +1439,14 @@ int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder,
uint32_t hash = 0; uint32_t hash = 0;
int32_t token; int32_t token;
nghttp3_qpack_indexing_mode indexing_mode; nghttp3_qpack_indexing_mode indexing_mode;
nghttp3_qpack_lookup_result sres = {-1, 0, -1}, dres = {-1, 0, -1}; nghttp3_qpack_lookup_result sres = {
.index = -1,
.pb_index = -1,
};
nghttp3_qpack_lookup_result dres = {
.index = -1,
.pb_index = -1,
};
nghttp3_qpack_entry *new_ent = NULL; nghttp3_qpack_entry *new_ent = NULL;
int static_entry; int static_entry;
int just_index = 0; int just_index = 0;
@ -1608,8 +1610,10 @@ int nghttp3_qpack_encoder_encode_nv(nghttp3_qpack_encoder *encoder,
nghttp3_qpack_lookup_result nghttp3_qpack_lookup_result
nghttp3_qpack_lookup_stable(const nghttp3_nv *nv, int32_t token, nghttp3_qpack_lookup_stable(const nghttp3_nv *nv, int32_t token,
nghttp3_qpack_indexing_mode indexing_mode) { nghttp3_qpack_indexing_mode indexing_mode) {
nghttp3_qpack_lookup_result res = {(nghttp3_ssize)token_stable[token].absidx, nghttp3_qpack_lookup_result res = {
0, -1}; .index = (nghttp3_ssize)token_stable[token].absidx,
.pb_index = -1,
};
nghttp3_qpack_static_entry *ent; nghttp3_qpack_static_entry *ent;
nghttp3_qpack_static_header *hdr; nghttp3_qpack_static_header *hdr;
size_t i; size_t i;
@ -1639,7 +1643,10 @@ nghttp3_qpack_lookup_result nghttp3_qpack_encoder_lookup_dtable(
nghttp3_qpack_encoder *encoder, const nghttp3_nv *nv, int32_t token, nghttp3_qpack_encoder *encoder, const nghttp3_nv *nv, int32_t token,
uint32_t hash, nghttp3_qpack_indexing_mode indexing_mode, uint64_t krcnt, uint32_t hash, nghttp3_qpack_indexing_mode indexing_mode, uint64_t krcnt,
int allow_blocking) { int allow_blocking) {
nghttp3_qpack_lookup_result res = {-1, 0, -1}; nghttp3_qpack_lookup_result res = {
.index = -1,
.pb_index = -1,
};
int exact_match = 0; int exact_match = 0;
nghttp3_qpack_entry *match, *pb_match; nghttp3_qpack_entry *match, *pb_match;
@ -1694,7 +1701,6 @@ static int ref_max_cnt_greater(const nghttp3_pq_entry *lhsx,
int nghttp3_qpack_stream_new(nghttp3_qpack_stream **pstream, int64_t stream_id, int nghttp3_qpack_stream_new(nghttp3_qpack_stream **pstream, int64_t stream_id,
const nghttp3_mem *mem) { const nghttp3_mem *mem) {
int rv;
nghttp3_qpack_stream *stream; nghttp3_qpack_stream *stream;
stream = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream)); stream = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream));
@ -1702,12 +1708,8 @@ int nghttp3_qpack_stream_new(nghttp3_qpack_stream **pstream, int64_t stream_id,
return NGHTTP3_ERR_NOMEM; return NGHTTP3_ERR_NOMEM;
} }
rv = nghttp3_ringbuf_init(&stream->refs, 4, nghttp3_ringbuf_init(&stream->refs, 0,
sizeof(nghttp3_qpack_header_block_ref *), mem); sizeof(nghttp3_qpack_header_block_ref *), mem);
if (rv != 0) {
nghttp3_mem_free(mem, stream);
return rv;
}
nghttp3_pq_init(&stream->max_cnts, ref_max_cnt_greater, mem); nghttp3_pq_init(&stream->max_cnts, ref_max_cnt_greater, mem);
@ -1759,17 +1761,23 @@ int nghttp3_qpack_stream_add_ref(nghttp3_qpack_stream *stream,
int rv; int rv;
if (nghttp3_ringbuf_full(&stream->refs)) { if (nghttp3_ringbuf_full(&stream->refs)) {
rv = nghttp3_ringbuf_reserve(&stream->refs, rv = nghttp3_ringbuf_reserve(
nghttp3_ringbuf_len(&stream->refs) * 2); &stream->refs,
nghttp3_max_size(4, nghttp3_ringbuf_len(&stream->refs) * 2));
if (rv != 0) { if (rv != 0) {
return rv; return rv;
} }
} }
rv = nghttp3_pq_push(&stream->max_cnts, &ref->max_cnts_pe);
if (rv != 0) {
return rv;
}
dest = nghttp3_ringbuf_push_back(&stream->refs); dest = nghttp3_ringbuf_push_back(&stream->refs);
*dest = ref; *dest = ref;
return nghttp3_pq_push(&stream->max_cnts, &ref->max_cnts_pe); return 0;
} }
void nghttp3_qpack_stream_pop_ref(nghttp3_qpack_stream *stream) { void nghttp3_qpack_stream_pop_ref(nghttp3_qpack_stream *stream) {
@ -1834,7 +1842,7 @@ static int qpack_encoder_write_indexed_name(nghttp3_qpack_encoder *encoder,
int h = 0; int h = 0;
hlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen); hlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen);
if (hlen * 4 < nv->valuelen * 3) { if (hlen < nv->valuelen) {
h = 1; h = 1;
len += nghttp3_qpack_put_varint_len(hlen, 7) + hlen; len += nghttp3_qpack_put_varint_len(hlen, 7) + hlen;
} else { } else {
@ -1925,7 +1933,7 @@ static int qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder,
int nh = 0, vh = 0; int nh = 0, vh = 0;
nhlen = nghttp3_qpack_huffman_encode_count(nv->name, nv->namelen); nhlen = nghttp3_qpack_huffman_encode_count(nv->name, nv->namelen);
if (nhlen * 4 < nv->namelen * 3) { if (nhlen < nv->namelen) {
nh = 1; nh = 1;
len = nghttp3_qpack_put_varint_len(nhlen, prefix) + nhlen; len = nghttp3_qpack_put_varint_len(nhlen, prefix) + nhlen;
} else { } else {
@ -1933,7 +1941,7 @@ static int qpack_encoder_write_literal(nghttp3_qpack_encoder *encoder,
} }
vhlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen); vhlen = nghttp3_qpack_huffman_encode_count(nv->value, nv->valuelen);
if (vhlen * 4 < nv->valuelen * 3) { if (vhlen < nv->valuelen) {
vh = 1; vh = 1;
len += nghttp3_qpack_put_varint_len(vhlen, 7) + vhlen; len += nghttp3_qpack_put_varint_len(vhlen, 7) + vhlen;
} else { } else {
@ -2083,8 +2091,9 @@ int nghttp3_qpack_context_dtable_add(nghttp3_qpack_context *ctx,
hash); hash);
if (nghttp3_ringbuf_full(&ctx->dtable)) { if (nghttp3_ringbuf_full(&ctx->dtable)) {
rv = nghttp3_ringbuf_reserve(&ctx->dtable, rv = nghttp3_ringbuf_reserve(
nghttp3_ringbuf_len(&ctx->dtable) * 2); &ctx->dtable,
nghttp3_max_size(128, nghttp3_ringbuf_len(&ctx->dtable) * 2));
if (rv != 0) { if (rv != 0) {
goto fail; goto fail;
} }
@ -2259,10 +2268,11 @@ void nghttp3_qpack_entry_free(nghttp3_qpack_entry *ent) {
int nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder *encoder, int nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder *encoder,
nghttp3_qpack_stream *stream) { nghttp3_qpack_stream *stream) {
nghttp3_blocked_streams_key bsk = { nghttp3_blocked_streams_key bsk = {
nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts), .max_cnt = nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts),
nghttp3_qpack_header_block_ref, max_cnts_pe) nghttp3_qpack_header_block_ref, max_cnts_pe)
->max_cnt, ->max_cnt,
(uint64_t)stream->stream_id}; .id = (uint64_t)stream->stream_id,
};
return nghttp3_ksl_insert(&encoder->blocked_streams, NULL, &bsk, stream); return nghttp3_ksl_insert(&encoder->blocked_streams, NULL, &bsk, stream);
} }
@ -2270,10 +2280,11 @@ int nghttp3_qpack_encoder_block_stream(nghttp3_qpack_encoder *encoder,
void nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder *encoder, void nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder *encoder,
nghttp3_qpack_stream *stream) { nghttp3_qpack_stream *stream) {
nghttp3_blocked_streams_key bsk = { nghttp3_blocked_streams_key bsk = {
nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts), .max_cnt = nghttp3_struct_of(nghttp3_pq_top(&stream->max_cnts),
nghttp3_qpack_header_block_ref, max_cnts_pe) nghttp3_qpack_header_block_ref, max_cnts_pe)
->max_cnt, ->max_cnt,
(uint64_t)stream->stream_id}; .id = (uint64_t)stream->stream_id,
};
nghttp3_ksl_it it; nghttp3_ksl_it it;
/* This is purely debugging purpose only */ /* This is purely debugging purpose only */
@ -2287,7 +2298,9 @@ void nghttp3_qpack_encoder_unblock_stream(nghttp3_qpack_encoder *encoder,
void nghttp3_qpack_encoder_unblock(nghttp3_qpack_encoder *encoder, void nghttp3_qpack_encoder_unblock(nghttp3_qpack_encoder *encoder,
uint64_t max_cnt) { uint64_t max_cnt) {
nghttp3_blocked_streams_key bsk = {max_cnt, 0}; nghttp3_blocked_streams_key bsk = {
.max_cnt = max_cnt,
};
nghttp3_ksl_it it; nghttp3_ksl_it it;
it = nghttp3_ksl_lower_bound(&encoder->blocked_streams, &bsk); it = nghttp3_ksl_lower_bound(&encoder->blocked_streams, &bsk);
@ -2667,17 +2680,12 @@ void nghttp3_qpack_read_state_reset(nghttp3_qpack_read_state *rstate) {
rstate->huffman_encoded = 0; rstate->huffman_encoded = 0;
} }
int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder, void nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder,
size_t hard_max_dtable_capacity, size_t hard_max_dtable_capacity,
size_t max_blocked_streams, size_t max_blocked_streams,
const nghttp3_mem *mem) { const nghttp3_mem *mem) {
int rv; qpack_context_init(&decoder->ctx, hard_max_dtable_capacity,
max_blocked_streams, mem);
rv = qpack_context_init(&decoder->ctx, hard_max_dtable_capacity,
max_blocked_streams, mem);
if (rv != 0) {
return rv;
}
decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE; decoder->state = NGHTTP3_QPACK_ES_STATE_OPCODE;
decoder->opcode = 0; decoder->opcode = 0;
@ -2687,8 +2695,6 @@ int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder,
nghttp3_qpack_read_state_reset(&decoder->rstate); nghttp3_qpack_read_state_reset(&decoder->rstate);
nghttp3_buf_init(&decoder->dbuf); nghttp3_buf_init(&decoder->dbuf);
return 0;
} }
void nghttp3_qpack_decoder_free(nghttp3_qpack_decoder *decoder) { void nghttp3_qpack_decoder_free(nghttp3_qpack_decoder *decoder) {
@ -3171,6 +3177,7 @@ int nghttp3_qpack_decoder_dtable_static_add(nghttp3_qpack_decoder *decoder) {
rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0); rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
nghttp3_rcbuf_decref(qnv.value); nghttp3_rcbuf_decref(qnv.value);
decoder->rstate.value = NULL;
return rv; return rv;
} }
@ -3197,6 +3204,7 @@ int nghttp3_qpack_decoder_dtable_dynamic_add(nghttp3_qpack_decoder *decoder) {
rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0); rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
nghttp3_rcbuf_decref(qnv.value); nghttp3_rcbuf_decref(qnv.value);
decoder->rstate.value = NULL;
nghttp3_rcbuf_decref(qnv.name); nghttp3_rcbuf_decref(qnv.name);
return rv; return rv;
@ -3250,7 +3258,9 @@ int nghttp3_qpack_decoder_dtable_literal_add(nghttp3_qpack_decoder *decoder) {
rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0); rv = nghttp3_qpack_context_dtable_add(&decoder->ctx, &qnv, NULL, 0);
nghttp3_rcbuf_decref(qnv.value); nghttp3_rcbuf_decref(qnv.value);
decoder->rstate.value = NULL;
nghttp3_rcbuf_decref(qnv.name); nghttp3_rcbuf_decref(qnv.name);
decoder->rstate.name = NULL;
return rv; return rv;
} }
@ -3818,6 +3828,9 @@ int nghttp3_qpack_decoder_cancel_stream(nghttp3_qpack_decoder *decoder,
uint8_t *p; uint8_t *p;
int rv; int rv;
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
if (qpack_decoder_dbuf_overflow(decoder)) { if (qpack_decoder_dbuf_overflow(decoder)) {
return NGHTTP3_ERR_QPACK_FATAL; return NGHTTP3_ERR_QPACK_FATAL;
} }
@ -4062,7 +4075,6 @@ void nghttp3_qpack_decoder_emit_literal(nghttp3_qpack_decoder *decoder,
int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder, int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder,
size_t hard_max_dtable_capacity, size_t hard_max_dtable_capacity,
const nghttp3_mem *mem) { const nghttp3_mem *mem) {
int rv;
nghttp3_qpack_encoder *p; nghttp3_qpack_encoder *p;
p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_encoder)); p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_encoder));
@ -4070,10 +4082,7 @@ int nghttp3_qpack_encoder_new(nghttp3_qpack_encoder **pencoder,
return NGHTTP3_ERR_NOMEM; return NGHTTP3_ERR_NOMEM;
} }
rv = nghttp3_qpack_encoder_init(p, hard_max_dtable_capacity, mem); nghttp3_qpack_encoder_init(p, hard_max_dtable_capacity, mem);
if (rv != 0) {
return rv;
}
*pencoder = p; *pencoder = p;
@ -4098,6 +4107,9 @@ int nghttp3_qpack_stream_context_new(nghttp3_qpack_stream_context **psctx,
const nghttp3_mem *mem) { const nghttp3_mem *mem) {
nghttp3_qpack_stream_context *p; nghttp3_qpack_stream_context *p;
assert(stream_id >= 0);
assert(stream_id <= (int64_t)NGHTTP3_MAX_VARINT);
p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream_context)); p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_stream_context));
if (p == NULL) { if (p == NULL) {
return NGHTTP3_ERR_NOMEM; return NGHTTP3_ERR_NOMEM;
@ -4127,7 +4139,6 @@ int nghttp3_qpack_decoder_new(nghttp3_qpack_decoder **pdecoder,
size_t hard_max_dtable_capacity, size_t hard_max_dtable_capacity,
size_t max_blocked_streams, size_t max_blocked_streams,
const nghttp3_mem *mem) { const nghttp3_mem *mem) {
int rv;
nghttp3_qpack_decoder *p; nghttp3_qpack_decoder *p;
p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_decoder)); p = nghttp3_mem_malloc(mem, sizeof(nghttp3_qpack_decoder));
@ -4135,11 +4146,8 @@ int nghttp3_qpack_decoder_new(nghttp3_qpack_decoder **pdecoder,
return NGHTTP3_ERR_NOMEM; return NGHTTP3_ERR_NOMEM;
} }
rv = nghttp3_qpack_decoder_init(p, hard_max_dtable_capacity, nghttp3_qpack_decoder_init(p, hard_max_dtable_capacity, max_blocked_streams,
max_blocked_streams, mem); mem);
if (rv != 0) {
return rv;
}
*pdecoder = p; *pdecoder = p;

View File

@ -270,16 +270,10 @@ struct nghttp3_qpack_encoder {
* nghttp3_qpack_encoder_init initializes |encoder|. * nghttp3_qpack_encoder_init initializes |encoder|.
* |hard_max_dtable_capacity| is the upper bound of the dynamic table * |hard_max_dtable_capacity| is the upper bound of the dynamic table
* capacity. |mem| is a memory allocator. * capacity. |mem| is a memory allocator.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP3_ERR_NOMEM
* Out of memory.
*/ */
int nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder, void nghttp3_qpack_encoder_init(nghttp3_qpack_encoder *encoder,
size_t hard_max_dtable_capacity, size_t hard_max_dtable_capacity,
const nghttp3_mem *mem); const nghttp3_mem *mem);
/* /*
* nghttp3_qpack_encoder_free frees memory allocated for |encoder|. * nghttp3_qpack_encoder_free frees memory allocated for |encoder|.
@ -800,17 +794,11 @@ struct nghttp3_qpack_decoder {
* |hard_max_dtable_capacity| is the upper bound of the dynamic table * |hard_max_dtable_capacity| is the upper bound of the dynamic table
* capacity. |max_blocked_streams| is the maximum number of stream * capacity. |max_blocked_streams| is the maximum number of stream
* which can be blocked. |mem| is a memory allocator. * which can be blocked. |mem| is a memory allocator.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* NGHTTP3_ERR_NOMEM
* Out of memory.
*/ */
int nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder, void nghttp3_qpack_decoder_init(nghttp3_qpack_decoder *decoder,
size_t hard_max_dtable_capacity, size_t hard_max_dtable_capacity,
size_t max_blocked_streams, size_t max_blocked_streams,
const nghttp3_mem *mem); const nghttp3_mem *mem);
/* /*
* nghttp3_qpack_decoder_free frees memory allocated for |decoder|. * nghttp3_qpack_decoder_free frees memory allocated for |decoder|.

View File

@ -88,7 +88,9 @@ nghttp3_qpack_huffman_decode(nghttp3_qpack_huffman_decode_context *ctx,
int fin) { int fin) {
uint8_t *p = dest; uint8_t *p = dest;
const uint8_t *end = src + srclen; const uint8_t *end = src + srclen;
nghttp3_qpack_huffman_decode_node node = {ctx->fstate, 0}; nghttp3_qpack_huffman_decode_node node = {
.fstate = ctx->fstate,
};
const nghttp3_qpack_huffman_decode_node *t = &node; const nghttp3_qpack_huffman_decode_node *t = &node;
uint8_t c; uint8_t c;

View File

@ -33,7 +33,7 @@ void nghttp3_range_init(nghttp3_range *r, uint64_t begin, uint64_t end) {
nghttp3_range nghttp3_range_intersect(const nghttp3_range *a, nghttp3_range nghttp3_range_intersect(const nghttp3_range *a,
const nghttp3_range *b) { const nghttp3_range *b) {
nghttp3_range r = {0, 0}; nghttp3_range r = {0};
uint64_t begin = nghttp3_max_uint64(a->begin, b->begin); uint64_t begin = nghttp3_max_uint64(a->begin, b->begin);
uint64_t end = nghttp3_min_uint64(a->end, b->end); uint64_t end = nghttp3_min_uint64(a->end, b->end);

View File

@ -33,18 +33,21 @@
#include "nghttp3_macro.h" #include "nghttp3_macro.h"
#ifndef NDEBUG
static int ispow2(size_t n) { static int ispow2(size_t n) {
#if defined(_MSC_VER) && !defined(__clang__) && \ # if defined(DISABLE_POPCNT) || \
(defined(_M_ARM) || (defined(_M_ARM64) && _MSC_VER < 1941)) (defined(_MSC_VER) && !defined(__clang__) && \
(defined(_M_ARM) || (defined(_M_ARM64) && _MSC_VER < 1941)))
return n && !(n & (n - 1)); return n && !(n & (n - 1));
#elif defined(WIN32) # elif defined(WIN32)
return 1 == __popcnt((unsigned int)n); return 1 == __popcnt((unsigned int)n);
#else /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \ # else /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \
(defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */ (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
return 1 == __builtin_popcount((unsigned int)n); return 1 == __builtin_popcount((unsigned int)n);
#endif /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \ # endif /* !((defined(_MSC_VER) && !defined(__clang__) && (defined(_M_ARM) || \
(defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */ (defined(_M_ARM64) && _MSC_VER < 1941))) || defined(WIN32)) */
} }
#endif /* !defined(NDEBUG) */
int nghttp3_ringbuf_init(nghttp3_ringbuf *rb, size_t nmemb, size_t size, int nghttp3_ringbuf_init(nghttp3_ringbuf *rb, size_t nmemb, size_t size,
const nghttp3_mem *mem) { const nghttp3_mem *mem) {

View File

@ -44,7 +44,7 @@
/* NGHTTP3_MIN_RBLEN is the minimum length of nghttp3_ringbuf */ /* NGHTTP3_MIN_RBLEN is the minimum length of nghttp3_ringbuf */
#define NGHTTP3_MIN_RBLEN 4 #define NGHTTP3_MIN_RBLEN 4
nghttp3_objalloc_def(stream, nghttp3_stream, oplent); nghttp3_objalloc_def(stream, nghttp3_stream, oplent)
int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id, int nghttp3_stream_new(nghttp3_stream **pstream, int64_t stream_id,
const nghttp3_stream_callbacks *callbacks, const nghttp3_stream_callbacks *callbacks,
@ -181,42 +181,45 @@ void nghttp3_stream_read_state_reset(nghttp3_stream_read_state *rstate) {
nghttp3_ssize nghttp3_read_varint(nghttp3_varint_read_state *rvint, nghttp3_ssize nghttp3_read_varint(nghttp3_varint_read_state *rvint,
const uint8_t *begin, const uint8_t *end, const uint8_t *begin, const uint8_t *end,
int fin) { int fin) {
const uint8_t *orig_begin = begin; size_t len, vlen;
size_t len; uint8_t *p;
assert(begin != end); assert(begin != end);
if (rvint->left == 0) { if (rvint->left == 0) {
assert(rvint->acc == 0); assert(rvint->acc == 0);
len = nghttp3_get_varintlen(begin); vlen = nghttp3_get_varintlen(begin);
if (len <= (size_t)(end - begin)) { len = nghttp3_min_size(vlen, (size_t)(end - begin));
if (vlen <= len) {
nghttp3_get_varint(&rvint->acc, begin); nghttp3_get_varint(&rvint->acc, begin);
return (nghttp3_ssize)len; return (nghttp3_ssize)vlen;
} }
if (fin) { if (fin) {
return NGHTTP3_ERR_INVALID_ARGUMENT; return NGHTTP3_ERR_INVALID_ARGUMENT;
} }
rvint->acc = nghttp3_get_varint_fb(begin++); p = (uint8_t *)&rvint->acc + (sizeof(rvint->acc) - vlen);
rvint->left = len - 1; memcpy(p, begin, len);
*p &= 0x3f;
rvint->left = vlen - len;
return (nghttp3_ssize)len;
} }
len = nghttp3_min_size(rvint->left, (size_t)(end - begin)); len = nghttp3_min_size(rvint->left, (size_t)(end - begin));
end = begin + len; p = (uint8_t *)&rvint->acc + (sizeof(rvint->acc) - rvint->left);
memcpy(p, begin, len);
for (; begin != end;) {
rvint->acc = (rvint->acc << 8) + *begin++;
}
rvint->left -= len; rvint->left -= len;
if (fin && rvint->left) { if (rvint->left == 0) {
rvint->acc = (int64_t)nghttp3_ntohl64((uint64_t)rvint->acc);
} else if (fin) {
return NGHTTP3_ERR_INVALID_ARGUMENT; return NGHTTP3_ERR_INVALID_ARGUMENT;
} }
return (nghttp3_ssize)(begin - orig_begin); return (nghttp3_ssize)len;
} }
int nghttp3_stream_frq_add(nghttp3_stream *stream, int nghttp3_stream_frq_add(nghttp3_stream *stream,
@ -301,12 +304,6 @@ int nghttp3_stream_fill_outq(nghttp3_stream *stream) {
return 0; return 0;
} }
static void typed_buf_shared_init(nghttp3_typed_buf *tbuf,
const nghttp3_buf *chunk) {
nghttp3_typed_buf_init(tbuf, chunk, NGHTTP3_BUF_TYPE_SHARED);
tbuf->buf.pos = tbuf->buf.last;
}
int nghttp3_stream_write_stream_type(nghttp3_stream *stream) { int nghttp3_stream_write_stream_type(nghttp3_stream *stream) {
size_t len = nghttp3_put_varintlen((int64_t)stream->type); size_t len = nghttp3_put_varintlen((int64_t)stream->type);
nghttp3_buf *chunk; nghttp3_buf *chunk;
@ -319,7 +316,7 @@ int nghttp3_stream_write_stream_type(nghttp3_stream *stream) {
} }
chunk = nghttp3_stream_get_chunk(stream); chunk = nghttp3_stream_get_chunk(stream);
typed_buf_shared_init(&tbuf, chunk); nghttp3_typed_buf_shared_init(&tbuf, chunk);
chunk->last = nghttp3_put_varint(chunk->last, (int64_t)stream->type); chunk->last = nghttp3_put_varint(chunk->last, (int64_t)stream->type);
tbuf.buf.last = chunk->last; tbuf.buf.last = chunk->last;
@ -336,12 +333,19 @@ int nghttp3_stream_write_settings(nghttp3_stream *stream,
struct { struct {
nghttp3_frame_settings settings; nghttp3_frame_settings settings;
nghttp3_settings_entry iv[15]; nghttp3_settings_entry iv[15];
} fr; } fr = {
.settings =
{
.hd =
{
.type = NGHTTP3_FRAME_SETTINGS,
},
.niv = 3,
},
};
nghttp3_settings_entry *iv; nghttp3_settings_entry *iv;
nghttp3_settings *local_settings = frent->aux.settings.local_settings; nghttp3_settings *local_settings = frent->aux.settings.local_settings;
fr.settings.hd.type = NGHTTP3_FRAME_SETTINGS;
fr.settings.niv = 3;
iv = &fr.settings.iv[0]; iv = &fr.settings.iv[0];
iv[0].id = NGHTTP3_SETTINGS_ID_MAX_FIELD_SECTION_SIZE; iv[0].id = NGHTTP3_SETTINGS_ID_MAX_FIELD_SECTION_SIZE;
@ -373,7 +377,7 @@ int nghttp3_stream_write_settings(nghttp3_stream *stream,
} }
chunk = nghttp3_stream_get_chunk(stream); chunk = nghttp3_stream_get_chunk(stream);
typed_buf_shared_init(&tbuf, chunk); nghttp3_typed_buf_shared_init(&tbuf, chunk);
chunk->last = nghttp3_frame_write_settings(chunk->last, &fr.settings); chunk->last = nghttp3_frame_write_settings(chunk->last, &fr.settings);
@ -398,7 +402,7 @@ int nghttp3_stream_write_goaway(nghttp3_stream *stream,
} }
chunk = nghttp3_stream_get_chunk(stream); chunk = nghttp3_stream_get_chunk(stream);
typed_buf_shared_init(&tbuf, chunk); nghttp3_typed_buf_shared_init(&tbuf, chunk);
chunk->last = nghttp3_frame_write_goaway(chunk->last, fr); chunk->last = nghttp3_frame_write_goaway(chunk->last, fr);
@ -423,7 +427,7 @@ int nghttp3_stream_write_priority_update(nghttp3_stream *stream,
} }
chunk = nghttp3_stream_get_chunk(stream); chunk = nghttp3_stream_get_chunk(stream);
typed_buf_shared_init(&tbuf, chunk); nghttp3_typed_buf_shared_init(&tbuf, chunk);
chunk->last = nghttp3_frame_write_priority_update(chunk->last, fr); chunk->last = nghttp3_frame_write_priority_update(chunk->last, fr);
@ -464,7 +468,7 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream,
rv = nghttp3_qpack_encoder_encode(qenc, &pbuf, rbuf, ebuf, stream->node.id, rv = nghttp3_qpack_encoder_encode(qenc, &pbuf, rbuf, ebuf, stream->node.id,
nva, nvlen); nva, nvlen);
if (rv != 0) { if (rv != 0) {
goto fail; return rv;
} }
pbuflen = nghttp3_buf_len(&pbuf); pbuflen = nghttp3_buf_len(&pbuf);
@ -482,11 +486,11 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream,
rv = nghttp3_stream_ensure_chunk(stream, len); rv = nghttp3_stream_ensure_chunk(stream, len);
if (rv != 0) { if (rv != 0) {
goto fail; return rv;
} }
chunk = nghttp3_stream_get_chunk(stream); chunk = nghttp3_stream_get_chunk(stream);
typed_buf_shared_init(&tbuf, chunk); nghttp3_typed_buf_shared_init(&tbuf, chunk);
chunk->last = nghttp3_frame_write_hd(chunk->last, &hd); chunk->last = nghttp3_frame_write_hd(chunk->last, &hd);
@ -498,13 +502,13 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream,
rv = nghttp3_stream_outq_add(stream, &tbuf); rv = nghttp3_stream_outq_add(stream, &tbuf);
if (rv != 0) { if (rv != 0) {
goto fail; return rv;
} }
nghttp3_typed_buf_init(&tbuf, rbuf, NGHTTP3_BUF_TYPE_PRIVATE); nghttp3_typed_buf_init(&tbuf, rbuf, NGHTTP3_BUF_TYPE_PRIVATE);
rv = nghttp3_stream_outq_add(stream, &tbuf); rv = nghttp3_stream_outq_add(stream, &tbuf);
if (rv != 0) { if (rv != 0) {
goto fail; return rv;
} }
nghttp3_buf_init(rbuf); nghttp3_buf_init(rbuf);
} else if (rbuflen) { } else if (rbuflen) {
@ -513,7 +517,7 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream,
rv = nghttp3_stream_outq_add(stream, &tbuf); rv = nghttp3_stream_outq_add(stream, &tbuf);
if (rv != 0) { if (rv != 0) {
goto fail; return rv;
} }
nghttp3_buf_reset(rbuf); nghttp3_buf_reset(rbuf);
} }
@ -532,18 +536,18 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream,
rv = nghttp3_stream_ensure_chunk(qenc_stream, ebuflen); rv = nghttp3_stream_ensure_chunk(qenc_stream, ebuflen);
if (rv != 0) { if (rv != 0) {
goto fail; return rv;
} }
chunk = nghttp3_stream_get_chunk(qenc_stream); chunk = nghttp3_stream_get_chunk(qenc_stream);
typed_buf_shared_init(&tbuf, chunk); nghttp3_typed_buf_shared_init(&tbuf, chunk);
chunk->last = nghttp3_cpymem(chunk->last, ebuf->pos, ebuflen); chunk->last = nghttp3_cpymem(chunk->last, ebuf->pos, ebuflen);
tbuf.buf.last = chunk->last; tbuf.buf.last = chunk->last;
rv = nghttp3_stream_outq_add(qenc_stream, &tbuf); rv = nghttp3_stream_outq_add(qenc_stream, &tbuf);
if (rv != 0) { if (rv != 0) {
goto fail; return rv;
} }
nghttp3_buf_reset(ebuf); nghttp3_buf_reset(ebuf);
} }
@ -553,10 +557,6 @@ int nghttp3_stream_write_header_block(nghttp3_stream *stream,
assert(0 == nghttp3_buf_len(ebuf)); assert(0 == nghttp3_buf_len(ebuf));
return 0; return 0;
fail:
return rv;
} }
int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof, int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof,
@ -635,7 +635,7 @@ int nghttp3_stream_write_data(nghttp3_stream *stream, int *peof,
} }
chunk = nghttp3_stream_get_chunk(stream); chunk = nghttp3_stream_get_chunk(stream);
typed_buf_shared_init(&tbuf, chunk); nghttp3_typed_buf_shared_init(&tbuf, chunk);
chunk->last = nghttp3_frame_write_hd(chunk->last, &hd); chunk->last = nghttp3_frame_write_hd(chunk->last, &hd);
@ -690,7 +690,7 @@ int nghttp3_stream_write_qpack_decoder_stream(nghttp3_stream *stream) {
} }
chunk = nghttp3_stream_get_chunk(stream); chunk = nghttp3_stream_get_chunk(stream);
typed_buf_shared_init(&tbuf, chunk); nghttp3_typed_buf_shared_init(&tbuf, chunk);
nghttp3_qpack_decoder_write_decoder(qdec, chunk); nghttp3_qpack_decoder_write_decoder(qdec, chunk);
@ -717,17 +717,16 @@ int nghttp3_stream_outq_add(nghttp3_stream *stream,
if (len) { if (len) {
dest = nghttp3_ringbuf_get(outq, len - 1); dest = nghttp3_ringbuf_get(outq, len - 1);
if (dest->type == tbuf->type && dest->type == NGHTTP3_BUF_TYPE_SHARED && if (dest->type == tbuf->type && dest->type == NGHTTP3_BUF_TYPE_SHARED &&
dest->buf.begin == tbuf->buf.begin && dest->buf.last == tbuf->buf.pos) { dest->buf.end == tbuf->buf.end && dest->buf.last == tbuf->buf.pos) {
/* If we have already written last entry, adjust outq_idx and /* If we have already written last entry, adjust outq_idx and
offset so that this entry is eligible to send. */ offset so that this entry is eligible to send. */
if (len == stream->outq_idx) { if (len == stream->outq_idx) {
--stream->outq_idx; --stream->outq_idx;
stream->outq_offset = nghttp3_buf_len(&dest->buf);
} }
dest->buf.last = tbuf->buf.last; dest->buf.last = tbuf->buf.last;
/* TODO Is this required? */
dest->buf.end = tbuf->buf.end; assert(dest->buf.end == tbuf->buf.end);
return 0; return 0;
} }
@ -817,34 +816,24 @@ size_t nghttp3_stream_writev(nghttp3_stream *stream, int *pfin,
nghttp3_ringbuf *outq = &stream->outq; nghttp3_ringbuf *outq = &stream->outq;
size_t len = nghttp3_ringbuf_len(outq); size_t len = nghttp3_ringbuf_len(outq);
size_t i = stream->outq_idx; size_t i = stream->outq_idx;
uint64_t offset = stream->outq_offset;
size_t buflen; size_t buflen;
nghttp3_vec *vbegin = vec, *vend = vec + veccnt; nghttp3_vec *vbegin = vec, *vend = vec + veccnt;
nghttp3_typed_buf *tbuf; nghttp3_typed_buf *tbuf;
assert(veccnt > 0); assert(veccnt > 0);
if (i < len) { for (; i < len && vec != vend; ++i) {
tbuf = nghttp3_ringbuf_get(outq, i); tbuf = nghttp3_ringbuf_get(outq, i);
buflen = nghttp3_buf_len(&tbuf->buf); buflen = nghttp3_buf_len(&tbuf->buf);
if (offset < buflen) { if (buflen == 0) {
vec->base = tbuf->buf.pos + offset; continue;
vec->len = (size_t)(buflen - offset);
++vec;
} else {
/* This is the only case that satisfies offset >= buflen */
assert(0 == offset);
assert(0 == buflen);
} }
++i; vec->base = tbuf->buf.pos;
vec->len = buflen;
for (; i < len && vec != vend; ++i, ++vec) { ++vec;
tbuf = nghttp3_ringbuf_get(outq, i);
vec->base = tbuf->buf.pos;
vec->len = nghttp3_buf_len(&tbuf->buf);
}
} }
/* TODO Rework this if we have finished implementing HTTP /* TODO Rework this if we have finished implementing HTTP
@ -859,26 +848,27 @@ void nghttp3_stream_add_outq_offset(nghttp3_stream *stream, size_t n) {
nghttp3_ringbuf *outq = &stream->outq; nghttp3_ringbuf *outq = &stream->outq;
size_t i; size_t i;
size_t len = nghttp3_ringbuf_len(outq); size_t len = nghttp3_ringbuf_len(outq);
uint64_t offset = stream->outq_offset + n;
size_t buflen; size_t buflen;
nghttp3_typed_buf *tbuf; nghttp3_typed_buf *tbuf;
stream->unsent_bytes -= n;
for (i = stream->outq_idx; i < len; ++i) { for (i = stream->outq_idx; i < len; ++i) {
tbuf = nghttp3_ringbuf_get(outq, i); tbuf = nghttp3_ringbuf_get(outq, i);
buflen = nghttp3_buf_len(&tbuf->buf); buflen = nghttp3_buf_len(&tbuf->buf);
if (offset >= buflen) { if (n < buflen) {
offset -= buflen; tbuf->buf.pos += n;
continue;
break;
} }
break; tbuf->buf.pos = tbuf->buf.last;
n -= buflen;
} }
assert(i < len || offset == 0); assert(i < len || n == 0);
stream->unsent_bytes -= n;
stream->outq_idx = i; stream->outq_idx = i;
stream->outq_offset = offset;
} }
int nghttp3_stream_outq_write_done(nghttp3_stream *stream) { int nghttp3_stream_outq_write_done(nghttp3_stream *stream) {
@ -904,7 +894,6 @@ static void stream_pop_outq_entry(nghttp3_stream *stream,
chunk = nghttp3_ringbuf_get(chunks, 0); chunk = nghttp3_ringbuf_get(chunks, 0);
assert(chunk->begin == tbuf->buf.begin);
assert(chunk->end == tbuf->buf.end); assert(chunk->end == tbuf->buf.end);
if (chunk->last == tbuf->buf.last) { if (chunk->last == tbuf->buf.last) {
@ -927,14 +916,13 @@ static void stream_pop_outq_entry(nghttp3_stream *stream,
int nghttp3_stream_update_ack_offset(nghttp3_stream *stream, uint64_t offset) { int nghttp3_stream_update_ack_offset(nghttp3_stream *stream, uint64_t offset) {
nghttp3_ringbuf *outq = &stream->outq; nghttp3_ringbuf *outq = &stream->outq;
size_t buflen; size_t buflen;
size_t npopped = 0;
uint64_t nack; uint64_t nack;
nghttp3_typed_buf *tbuf; nghttp3_typed_buf *tbuf;
int rv; int rv;
for (; nghttp3_ringbuf_len(outq);) { for (; nghttp3_ringbuf_len(outq);) {
tbuf = nghttp3_ringbuf_get(outq, 0); tbuf = nghttp3_ringbuf_get(outq, 0);
buflen = nghttp3_buf_len(&tbuf->buf); buflen = (size_t)(tbuf->buf.last - tbuf->buf.begin);
/* For NGHTTP3_BUF_TYPE_ALIEN, we never add 0 length buffer. */ /* For NGHTTP3_BUF_TYPE_ALIEN, we never add 0 length buffer. */
if (tbuf->type == NGHTTP3_BUF_TYPE_ALIEN && stream->ack_offset < offset && if (tbuf->type == NGHTTP3_BUF_TYPE_ALIEN && stream->ack_offset < offset &&
@ -949,17 +937,13 @@ int nghttp3_stream_update_ack_offset(nghttp3_stream *stream, uint64_t offset) {
} }
} }
if (offset >= stream->ack_base + buflen) { if (stream->outq_idx > 0 && offset >= stream->ack_base + buflen) {
stream_pop_outq_entry(stream, tbuf); stream_pop_outq_entry(stream, tbuf);
stream->ack_base += buflen; stream->ack_base += buflen;
stream->ack_offset = stream->ack_base; stream->ack_offset = stream->ack_base;
++npopped;
if (stream->outq_idx + 1 == npopped) { --stream->outq_idx;
stream->outq_offset = 0;
break;
}
continue; continue;
} }
@ -967,13 +951,6 @@ int nghttp3_stream_update_ack_offset(nghttp3_stream *stream, uint64_t offset) {
break; break;
} }
assert(stream->outq_idx + 1 >= npopped);
if (stream->outq_idx >= npopped) {
stream->outq_idx -= npopped;
} else {
stream->outq_idx = 0;
}
stream->ack_offset = offset; stream->ack_offset = offset;
return 0; return 0;
@ -1045,19 +1022,17 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
switch (stream->rx.hstate) { switch (stream->rx.hstate) {
case NGHTTP3_HTTP_STATE_NONE: case NGHTTP3_HTTP_STATE_NONE:
return NGHTTP3_ERR_H3_INTERNAL_ERROR; nghttp3_unreachable();
case NGHTTP3_HTTP_STATE_REQ_INITIAL: case NGHTTP3_HTTP_STATE_REQ_INITIAL:
switch (event) { if (event != NGHTTP3_HTTP_EVENT_HEADERS_BEGIN) {
case NGHTTP3_HTTP_EVENT_HEADERS_BEGIN:
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN;
return 0;
default:
return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
} }
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN;
return 0;
case NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN: case NGHTTP3_HTTP_STATE_REQ_HEADERS_BEGIN:
if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) { assert(NGHTTP3_HTTP_EVENT_HEADERS_END == event);
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
}
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_HEADERS_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_HEADERS_END;
return 0; return 0;
case NGHTTP3_HTTP_STATE_REQ_HEADERS_END: case NGHTTP3_HTTP_STATE_REQ_HEADERS_END:
@ -1080,12 +1055,10 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END;
return 0; return 0;
default: default:
return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; nghttp3_unreachable();
} }
case NGHTTP3_HTTP_STATE_REQ_DATA_BEGIN: case NGHTTP3_HTTP_STATE_REQ_DATA_BEGIN:
if (event != NGHTTP3_HTTP_EVENT_DATA_END) { assert(NGHTTP3_HTTP_EVENT_DATA_END == event);
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
}
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_DATA_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_DATA_END;
return 0; return 0;
case NGHTTP3_HTTP_STATE_REQ_DATA_END: case NGHTTP3_HTTP_STATE_REQ_DATA_END:
@ -1108,12 +1081,10 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END;
return 0; return 0;
default: default:
return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; nghttp3_unreachable();
} }
case NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN: case NGHTTP3_HTTP_STATE_REQ_TRAILERS_BEGIN:
if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) { assert(NGHTTP3_HTTP_EVENT_HEADERS_END == event);
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
}
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_TRAILERS_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_TRAILERS_END;
return 0; return 0;
case NGHTTP3_HTTP_STATE_REQ_TRAILERS_END: case NGHTTP3_HTTP_STATE_REQ_TRAILERS_END:
@ -1129,7 +1100,7 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_REQ_END;
return 0; return 0;
case NGHTTP3_HTTP_STATE_REQ_END: case NGHTTP3_HTTP_STATE_REQ_END:
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
case NGHTTP3_HTTP_STATE_RESP_INITIAL: case NGHTTP3_HTTP_STATE_RESP_INITIAL:
if (event != NGHTTP3_HTTP_EVENT_HEADERS_BEGIN) { if (event != NGHTTP3_HTTP_EVENT_HEADERS_BEGIN) {
return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
@ -1137,9 +1108,7 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN; stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN;
return 0; return 0;
case NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN: case NGHTTP3_HTTP_STATE_RESP_HEADERS_BEGIN:
if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) { assert(NGHTTP3_HTTP_EVENT_HEADERS_END == event);
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
}
stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_HEADERS_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_HEADERS_END;
return 0; return 0;
case NGHTTP3_HTTP_STATE_RESP_HEADERS_END: case NGHTTP3_HTTP_STATE_RESP_HEADERS_END:
@ -1169,12 +1138,10 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END;
return 0; return 0;
default: default:
return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; nghttp3_unreachable();
} }
case NGHTTP3_HTTP_STATE_RESP_DATA_BEGIN: case NGHTTP3_HTTP_STATE_RESP_DATA_BEGIN:
if (event != NGHTTP3_HTTP_EVENT_DATA_END) { assert(NGHTTP3_HTTP_EVENT_DATA_END == event);
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
}
stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_DATA_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_DATA_END;
return 0; return 0;
case NGHTTP3_HTTP_STATE_RESP_DATA_END: case NGHTTP3_HTTP_STATE_RESP_DATA_END:
@ -1197,17 +1164,15 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END;
return 0; return 0;
default: default:
return NGHTTP3_ERR_H3_FRAME_UNEXPECTED; nghttp3_unreachable();
} }
case NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN: case NGHTTP3_HTTP_STATE_RESP_TRAILERS_BEGIN:
if (event != NGHTTP3_HTTP_EVENT_HEADERS_END) { assert(NGHTTP3_HTTP_EVENT_HEADERS_END == event);
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING;
}
stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_TRAILERS_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_TRAILERS_END;
return 0; return 0;
case NGHTTP3_HTTP_STATE_RESP_TRAILERS_END: case NGHTTP3_HTTP_STATE_RESP_TRAILERS_END:
if (event != NGHTTP3_HTTP_EVENT_MSG_END) { if (event != NGHTTP3_HTTP_EVENT_MSG_END) {
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
} }
rv = nghttp3_http_on_remote_end_stream(stream); rv = nghttp3_http_on_remote_end_stream(stream);
if (rv != 0) { if (rv != 0) {
@ -1216,7 +1181,7 @@ int nghttp3_stream_transit_rx_http_state(nghttp3_stream *stream,
stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END; stream->rx.hstate = NGHTTP3_HTTP_STATE_RESP_END;
return 0; return 0;
case NGHTTP3_HTTP_STATE_RESP_END: case NGHTTP3_HTTP_STATE_RESP_END:
return NGHTTP3_ERR_MALFORMED_HTTP_MESSAGING; return NGHTTP3_ERR_H3_FRAME_UNEXPECTED;
default: default:
nghttp3_unreachable(); nghttp3_unreachable();
} }

View File

@ -223,9 +223,6 @@ struct nghttp3_stream {
uint64_t unsent_bytes; uint64_t unsent_bytes;
/* outq_idx is an index into outq where next write is made. */ /* outq_idx is an index into outq where next write is made. */
size_t outq_idx; size_t outq_idx;
/* outq_offset is write offset relative to the element at outq_idx
in outq. */
uint64_t outq_offset;
/* ack_base is the number of bytes acknowledged by a remote /* ack_base is the number of bytes acknowledged by a remote
endpoint where the first element in outq is positioned at. */ endpoint where the first element in outq is positioned at. */
uint64_t ack_base; uint64_t ack_base;
@ -255,7 +252,7 @@ struct nghttp3_stream {
}; };
}; };
nghttp3_objalloc_decl(stream, nghttp3_stream, oplent); nghttp3_objalloc_decl(stream, nghttp3_stream, oplent)
typedef struct nghttp3_frame_entry { typedef struct nghttp3_frame_entry {
nghttp3_frame fr; nghttp3_frame fr;

View File

@ -28,8 +28,11 @@
#include <nghttp3/nghttp3.h> #include <nghttp3/nghttp3.h>
static nghttp3_info version = {NGHTTP3_VERSION_AGE, NGHTTP3_VERSION_NUM, static nghttp3_info version = {
NGHTTP3_VERSION}; .age = NGHTTP3_VERSION_AGE,
.version_num = NGHTTP3_VERSION_NUM,
.version_str = NGHTTP3_VERSION,
};
const nghttp3_info *nghttp3_version(int least_version) { const nghttp3_info *nghttp3_version(int least_version) {
if (least_version > NGHTTP3_VERSION_NUM) { if (least_version > NGHTTP3_VERSION_NUM) {

File diff suppressed because it is too large Load Diff

View File

@ -31,90 +31,90 @@
libcurl) */ libcurl) */
#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
# define WIN32 # define WIN32
#endif #endif /* (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif /* defined(__cplusplus) */
#if defined(_MSC_VER) && (_MSC_VER < 1800) #if defined(_MSC_VER) && (_MSC_VER < 1800)
/* MSVC < 2013 does not have inttypes.h because it is not C99 /* MSVC < 2013 does not have inttypes.h because it is not C99
compliant. See compiler macros and version number in compliant. See compiler macros and version number in
https://sourceforge.net/p/predef/wiki/Compilers/ */ https://sourceforge.net/p/predef/wiki/Compilers/ */
# include <stdint.h> # include <stdint.h>
#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ #else /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */
# include <inttypes.h> # include <inttypes.h>
#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */ #endif /* !(defined(_MSC_VER) && (_MSC_VER < 1800)) */
#include <sys/types.h> #include <sys/types.h>
#include <stddef.h> #include <stddef.h>
/** /**
* @enum * @enum
* *
* :type:`sf_type` defines value type. * :type:`sfparse_type` defines value type.
*/ */
typedef enum sf_type { typedef enum sfparse_type {
/** /**
* :enum:`SF_TYPE_BOOLEAN` indicates boolean type. * :enum:`SFPARSE_TYPE_BOOLEAN` indicates boolean type.
*/ */
SF_TYPE_BOOLEAN, SFPARSE_TYPE_BOOLEAN,
/** /**
* :enum:`SF_TYPE_INTEGER` indicates integer type. * :enum:`SFPARSE_TYPE_INTEGER` indicates integer type.
*/ */
SF_TYPE_INTEGER, SFPARSE_TYPE_INTEGER,
/** /**
* :enum:`SF_TYPE_DECIMAL` indicates decimal type. * :enum:`SFPARSE_TYPE_DECIMAL` indicates decimal type.
*/ */
SF_TYPE_DECIMAL, SFPARSE_TYPE_DECIMAL,
/** /**
* :enum:`SF_TYPE_STRING` indicates string type. * :enum:`SFPARSE_TYPE_STRING` indicates string type.
*/ */
SF_TYPE_STRING, SFPARSE_TYPE_STRING,
/** /**
* :enum:`SF_TYPE_TOKEN` indicates token type. * :enum:`SFPARSE_TYPE_TOKEN` indicates token type.
*/ */
SF_TYPE_TOKEN, SFPARSE_TYPE_TOKEN,
/** /**
* :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type. * :enum:`SFPARSE_TYPE_BYTESEQ` indicates byte sequence type.
*/ */
SF_TYPE_BYTESEQ, SFPARSE_TYPE_BYTESEQ,
/** /**
* :enum:`SF_TYPE_INNER_LIST` indicates inner list type. * :enum:`SFPARSE_TYPE_INNER_LIST` indicates inner list type.
*/ */
SF_TYPE_INNER_LIST, SFPARSE_TYPE_INNER_LIST,
/** /**
* :enum:`SF_TYPE_DATE` indicates date type. * :enum:`SFPARSE_TYPE_DATE` indicates date type.
*/ */
SF_TYPE_DATE, SFPARSE_TYPE_DATE,
/** /**
* :enum:`SF_TYPE_DISPSTRING` indicates display string type. * :enum:`SFPARSE_TYPE_DISPSTRING` indicates display string type.
*/ */
SF_TYPE_DISPSTRING SFPARSE_TYPE_DISPSTRING
} sf_type; } sfparse_type;
/** /**
* @macro * @macro
* *
* :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has * :macro:`SFPARSE_ERR_PARSE` indicates fatal parse error has
* occurred, and it is not possible to continue the processing. * occurred, and it is not possible to continue the processing.
*/ */
#define SF_ERR_PARSE_ERROR -1 #define SFPARSE_ERR_PARSE -1
/** /**
* @macro * @macro
* *
* :macro:`SF_ERR_EOF` indicates that there is nothing left to read. * :macro:`SFPARSE_ERR_EOF` indicates that there is nothing left to
* The context of this error varies depending on the function that * read. The context of this error varies depending on the function
* returns this error code. * that returns this error code.
*/ */
#define SF_ERR_EOF -2 #define SFPARSE_ERR_EOF -2
/** /**
* @struct * @struct
* *
* :type:`sf_vec` stores sequence of bytes. * :type:`sfparse_vec` stores sequence of bytes.
*/ */
typedef struct sf_vec { typedef struct sfparse_vec {
/** /**
* :member:`base` points to the beginning of the sequence of bytes. * :member:`base` points to the beginning of the sequence of bytes.
*/ */
@ -123,29 +123,29 @@ typedef struct sf_vec {
* :member:`len` is the number of bytes contained in this sequence. * :member:`len` is the number of bytes contained in this sequence.
*/ */
size_t len; size_t len;
} sf_vec; } sfparse_vec;
/** /**
* @macro * @macro
* *
* :macro:`SF_VALUE_FLAG_NONE` indicates no flag set. * :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set.
*/ */
#define SF_VALUE_FLAG_NONE 0x0u #define SFPARSE_VALUE_FLAG_NONE 0x0u
/** /**
* @macro * @macro
* *
* :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` indicates that a string
* contains escaped character(s). * contains escaped character(s).
*/ */
#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u #define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1u
/** /**
* @struct * @struct
* *
* :type:`sf_decimal` contains decimal value. * :type:`sfparse_decimal` contains decimal value.
*/ */
typedef struct sf_decimal { typedef struct sfparse_decimal {
/** /**
* :member:`numer` contains numerator of the decimal value. * :member:`numer` contains numerator of the decimal value.
*/ */
@ -154,275 +154,289 @@ typedef struct sf_decimal {
* :member:`denom` contains denominator of the decimal value. * :member:`denom` contains denominator of the decimal value.
*/ */
int64_t denom; int64_t denom;
} sf_decimal; } sfparse_decimal;
/** /**
* @struct * @struct
* *
* :type:`sf_value` stores a Structured Field item. For Inner List, * :type:`sfparse_value` stores a Structured Field item. For Inner
* only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order * List, only type is set to
* to read the items contained in an inner list, call * :enum:`sfparse_type.SFPARSE_TYPE_INNER_LIST`. In order to read the
* `sf_parser_inner_list`. * items contained in an inner list, call `sfparse_parser_inner_list`.
*/ */
typedef struct sf_value { typedef struct sfparse_value {
/** /**
* :member:`type` is the type of the value contained in this * :member:`type` is the type of the value contained in this
* particular object. * particular object.
*/ */
sf_type type; sfparse_type type;
/** /**
* :member:`flags` is bitwise OR of one or more of * :member:`flags` is bitwise OR of one or more of
* :macro:`SF_VALUE_FLAG_* <SF_VALUE_FLAG_NONE>`. * :macro:`SFPARSE_VALUE_FLAG_* <SFPARSE_VALUE_FLAG_NONE>`.
*/ */
uint32_t flags; uint32_t flags;
/** /**
* @anonunion_start * @anonunion_start
* *
* @sf_value_value * @sfparse_value_value
*/ */
union { union {
/** /**
* :member:`boolean` contains boolean value if :member:`type` == * :member:`boolean` contains boolean value if :member:`type` ==
* :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0 * :enum:`sfparse_type.SFPARSE_TYPE_BOOLEAN`. 1 indicates true,
* indicates false. * and 0 indicates false.
*/ */
int boolean; int boolean;
/** /**
* :member:`integer` contains integer value if :member:`type` is * :member:`integer` contains integer value if :member:`type` is
* either :enum:`sf_type.SF_TYPE_INTEGER` or * either :enum:`sfparse_type.SFPARSE_TYPE_INTEGER` or
* :enum:`sf_type.SF_TYPE_DATE`. * :enum:`sfparse_type.SFPARSE_TYPE_DATE`.
*/ */
int64_t integer; int64_t integer;
/** /**
* :member:`decimal` contains decimal value if :member:`type` == * :member:`decimal` contains decimal value if :member:`type` ==
* :enum:`sf_type.SF_TYPE_DECIMAL`. * :enum:`sfparse_type.SFPARSE_TYPE_DECIMAL`.
*/ */
sf_decimal decimal; sfparse_decimal decimal;
/** /**
* :member:`vec` contains sequence of bytes if :member:`type` is * :member:`vec` contains sequence of bytes if :member:`type` is
* either :enum:`sf_type.SF_TYPE_STRING`, * either :enum:`sfparse_type.SFPARSE_TYPE_STRING`,
* :enum:`sf_type.SF_TYPE_TOKEN`, :enum:`sf_type.SF_TYPE_BYTESEQ`, * :enum:`sfparse_type.SFPARSE_TYPE_TOKEN`,
* or :enum:`sf_type.SF_TYPE_DISPSTRING`. * :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, or
* :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`.
* *
* For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or * For :enum:`sfparse_type.SFPARSE_TYPE_STRING`, this field
* more escaped characters if :member:`flags` has * contains one or more escaped characters if :member:`flags` has
* :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` set. To unescape
* string, use `sf_unescape`. * the string, use `sfparse_unescape`.
* *
* For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64 * For :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, this field
* encoded string. To decode this byte string, use * contains base64 encoded string. To decode this byte string,
* `sf_base64decode`. * use `sfparse_base64decode`.
* *
* For :enum:`sf_type.SF_TYPE_DISPSTRING`, this field may contain * For :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`, this field
* percent-encoded UTF-8 byte sequences. To decode it, use * may contain percent-encoded UTF-8 byte sequences. To decode
* `sf_pctdecode`. * it, use `sfparse_pctdecode`.
* *
* If :member:`vec.len <sf_vec.len>` == 0, :member:`vec.base * If :member:`vec.len <sfparse_vec.len>` == 0, :member:`vec.base
* <sf_vec.base>` is guaranteed to be NULL. * <sfparse_vec.base>` is guaranteed to be NULL.
*/ */
sf_vec vec; sfparse_vec vec;
/** /**
* @anonunion_end * @anonunion_end
*/ */
}; };
} sf_value; } sfparse_value;
/** /**
* @struct * @struct
* *
* :type:`sf_parser` is the Structured Field Values parser. Use * :type:`sfparse_parser` is the Structured Field Values parser. Use
* `sf_parser_init` to initialize it. * `sfparse_parser_init` to initialize it.
*/ */
typedef struct sf_parser { typedef struct sfparse_parser {
/* all fields are private */ /* all fields are private */
const uint8_t *pos; const uint8_t *pos;
const uint8_t *end; const uint8_t *end;
uint32_t state; uint32_t state;
} sf_parser; } sfparse_parser;
/** /**
* @function * @function
* *
* `sf_parser_init` initializes |sfp| with the given buffer pointed by * `sfparse_parser_init` initializes |sfp| with the given data encoded
* |data| of length |datalen|. * in Structured Field Values pointed by |data| of length |datalen|.
*/ */
void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen); void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data,
size_t datalen);
/** /**
* @function * @function
* *
* `sf_parser_param` reads a parameter. If this function returns 0, * `sfparse_parser_param` reads a parameter. If this function returns
* it stores parameter key and value in |dest_key| and |dest_value| * 0, it stores parameter key and value in |dest_key| and |dest_value|
* respectively, if they are not NULL. * respectively, if they are not NULL.
* *
* This function does no effort to find duplicated keys. Same key may * This function does no effort to find duplicated keys. Same key may
* be reported more than once. * be reported more than once.
* *
* Caller should keep calling this function until it returns negative * Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SF_ERR_EOF`, all parameters have * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all parameters
* read, and caller can continue to read rest of the values. If it * have read, and caller can continue to read rest of the values. If
* returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error * it returns :macro:`SFPARSE_ERR_PARSE`, it encountered fatal error
* while parsing field value. * while parsing field value.
*/ */
int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key,
sfparse_value *dest_value);
/** /**
* @function * @function
* *
* `sf_parser_dict` reads the next dictionary key and value pair. If * `sfparse_parser_dict` reads the next dictionary key and value pair.
* this function returns 0, it stores the key and value in |dest_key| * If this function returns 0, it stores the key and value in
* and |dest_value| respectively, if they are not NULL. * |dest_key| and |dest_value| respectively, if they are not NULL.
* *
* Caller can optionally read parameters attached to the pair by * Caller can optionally read parameters attached to the pair by
* calling `sf_parser_param`. * calling `sfparse_parser_param`.
* *
* This function does no effort to find duplicated keys. Same key may * This function does no effort to find duplicated keys. Same key may
* be reported more than once. * be reported more than once.
* *
* Caller should keep calling this function until it returns negative * Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SF_ERR_EOF`, all key and value * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all key and
* pairs have been read, and there is nothing left to read. * value pairs have been read, and there is nothing left to read.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* :macro:`SF_ERR_EOF` * :macro:`SFPARSE_ERR_EOF`
* All values in the dictionary have read. * All values in the dictionary have read.
* :macro:`SF_ERR_PARSE_ERROR` * :macro:`SFPARSE_ERR_PARSE`
* It encountered fatal error while parsing field value. * It encountered fatal error while parsing field value.
*/ */
int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value); int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key,
sfparse_value *dest_value);
/** /**
* @function * @function
* *
* `sf_parser_list` reads the next list item. If this function * `sfparse_parser_list` reads the next list item. If this function
* returns 0, it stores the item in |dest| if it is not NULL. * returns 0, it stores the item in |dest| if it is not NULL.
* *
* Caller can optionally read parameters attached to the item by * Caller can optionally read parameters attached to the item by
* calling `sf_parser_param`. * calling `sfparse_parser_param`.
* *
* Caller should keep calling this function until it returns negative * Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SF_ERR_EOF`, all values in the * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in
* list have been read, and there is nothing left to read. * the list have been read, and there is nothing left to read.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* :macro:`SF_ERR_EOF` * :macro:`SFPARSE_ERR_EOF`
* All values in the list have read. * All values in the list have read.
* :macro:`SF_ERR_PARSE_ERROR` * :macro:`SFPARSE_ERR_PARSE`
* It encountered fatal error while parsing field value. * It encountered fatal error while parsing field value.
*/ */
int sf_parser_list(sf_parser *sfp, sf_value *dest); int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest);
/** /**
* @function * @function
* *
* `sf_parser_item` reads a single item. If this function returns 0, * `sfparse_parser_item` reads a single item. If this function
* it stores the item in |dest| if it is not NULL. * returns 0, it stores the item in |dest| if it is not NULL.
* *
* This function is only used for the field value that consists of a * This function is only used for the field value that consists of a
* single item. * single item.
* *
* Caller can optionally read parameters attached to the item by * Caller can optionally read parameters attached to the item by
* calling `sf_parser_param`. * calling `sfparse_parser_param`.
* *
* Caller should call this function again to make sure that there is * Caller should call this function again to make sure that there is
* nothing left to read. If this 2nd function call returns * nothing left to read. If this 2nd function call returns
* :macro:`SF_ERR_EOF`, all data have been processed successfully. * :macro:`SFPARSE_ERR_EOF`, all data have been processed
* successfully.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* :macro:`SF_ERR_EOF` * :macro:`SFPARSE_ERR_EOF`
* There is nothing left to read. * There is nothing left to read.
* :macro:`SF_ERR_PARSE_ERROR` * :macro:`SFPARSE_ERR_PARSE`
* It encountered fatal error while parsing field value. * It encountered fatal error while parsing field value.
*/ */
int sf_parser_item(sf_parser *sfp, sf_value *dest); int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest);
/** /**
* @function * @function
* *
* `sf_parser_inner_list` reads the next inner list item. If this * `sfparse_parser_inner_list` reads the next inner list item. If
* function returns 0, it stores the item in |dest| if it is not NULL. * this function returns 0, it stores the item in |dest| if it is not
* NULL.
* *
* Caller can optionally read parameters attached to the item by * Caller can optionally read parameters attached to the item by
* calling `sf_parser_param`. * calling `sfparse_parser_param`.
* *
* Caller should keep calling this function until it returns negative * Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SF_ERR_EOF`, all values in this * error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in
* inner list have been read, and caller can optionally read * this inner list have been read, and caller can optionally read
* parameters attached to this inner list by calling * parameters attached to this inner list by calling
* `sf_parser_param`. Then caller can continue to read rest of the * `sfparse_parser_param`. Then caller can continue to read rest of
* values. * the values.
* *
* This function returns 0 if it succeeds, or one of the following * This function returns 0 if it succeeds, or one of the following
* negative error codes: * negative error codes:
* *
* :macro:`SF_ERR_EOF` * :macro:`SFPARSE_ERR_EOF`
* All values in the inner list have read. * All values in the inner list have read.
* :macro:`SF_ERR_PARSE_ERROR` * :macro:`SFPARSE_ERR_PARSE`
* It encountered fatal error while parsing field value. * It encountered fatal error while parsing field value.
*/ */
int sf_parser_inner_list(sf_parser *sfp, sf_value *dest); int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest);
/** /**
* @function * @function
* *
* `sf_unescape` copies |src| to |dest| by removing escapes (``\``). * `sfparse_unescape` copies |src| to |dest| by removing escapes
* |src| should be the pointer to :member:`sf_value.vec` of type * (``\``). |src| should be the pointer to
* :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`, * :member:`sfparse_value.vec` of type
* `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or * :enum:`sfparse_type.SFPARSE_TYPE_STRING` produced by either
* `sf_parser_param`, otherwise the behavior is undefined. * `sfparse_parser_dict`, `sfparse_parser_list`,
* `sfparse_parser_inner_list`, `sfparse_parser_item`, or
* `sfparse_parser_param`, otherwise the behavior is undefined.
* *
* :member:`dest->base <sf_vec.base>` must point to the buffer that * :member:`dest->base <sfparse_vec.base>` must point to the buffer
* has sufficient space to store the unescaped string. * that has sufficient space to store the unescaped string. The
* memory areas pointed by :member:`dest->base <sfparse_vec.base>` and
* :member:`src->base <sfparse_vec.base>` must not overlap.
* *
* This function sets the length of unescaped string to * This function sets the length of unescaped string to
* :member:`dest->len <sf_vec.len>`. * :member:`dest->len <sfparse_vec.len>`.
*/ */
void sf_unescape(sf_vec *dest, const sf_vec *src); void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src);
/** /**
* @function * @function
* *
* `sf_base64decode` decodes Base64 encoded string |src| and writes * `sfparse_base64decode` decodes Base64 encoded string |src| and
* writes the result into |dest|. |src| should be the pointer to
* :member:`sfparse_value.vec` of type
* :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ` produced by either
* `sfparse_parser_dict`, `sfparse_parser_list`,
* `sfparse_parser_inner_list`, `sfparse_parser_item`, or
* `sfparse_parser_param`, otherwise the behavior is undefined.
*
* :member:`dest->base <sfparse_vec.base>` must point to the buffer
* that has sufficient space to store the decoded byte string.
*
* This function sets the length of decoded byte string to
* :member:`dest->len <sfparse_vec.len>`.
*/
void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src);
/**
* @function
*
* `sfparse_pctdecode` decodes percent-encoded string |src| and writes
* the result into |dest|. |src| should be the pointer to * the result into |dest|. |src| should be the pointer to
* :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ` * :member:`sfparse_value.vec` of type
* produced by either `sf_parser_dict`, `sf_parser_list`, * :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING` produced by either
* `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`, * `sfparse_parser_dict`, `sfparse_parser_list`,
* otherwise the behavior is undefined. * `sfparse_parser_inner_list`, `sfparse_parser_item`, or
* `sfparse_parser_param`, otherwise the behavior is undefined.
* *
* :member:`dest->base <sf_vec.base>` must point to the buffer that * :member:`dest->base <sfparse_vec.base>` must point to the buffer
* has sufficient space to store the decoded byte string. * that has sufficient space to store the decoded byte string. The
* memory areas pointed by :member:`dest->base <sfparse_vec.base>` and
* :member:`src->base <sfparse_vec.base>` must not overlap.
* *
* This function sets the length of decoded byte string to * This function sets the length of decoded byte string to
* :member:`dest->len <sf_vec.len>`. * :member:`dest->len <sfparse_vec.len>`.
*/ */
void sf_base64decode(sf_vec *dest, const sf_vec *src); void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src);
/**
* @function
*
* `sf_pctdecode` decodes percent-encoded string |src| and writes the
* result into |dest|. |src| should be the pointer to
* :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_DISPSTRING`
* produced by either `sf_parser_dict`, `sf_parser_list`,
* `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`,
* otherwise the behavior is undefined.
*
* :member:`dest->base <sf_vec.base>` must point to the buffer that
* has sufficient space to store the decoded byte string.
*
* This function sets the length of decoded byte string to
* :member:`dest->len <sf_vec.len>`.
*/
void sf_pctdecode(sf_vec *dest, const sf_vec *src);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif /* defined(__cplusplus) */
#endif /* SFPARSE_H */ #endif /* !defined(SFPARSE_H) */