nghttp2 2026-11-02 (80dcb814)

Code extracted from:

    https://github.com/nghttp2/nghttp2.git

at commit 80dcb8140af050fac91a7e6af4fc6dd013404bd1 (v1.71.0).
This commit is contained in:
nghttp2 upstream authored and Brad King committed 2026-11-02 16:39:23 -05:00
1 parent 797e3062b7
commit 0fea265ee6
38 files changed
+5736 -5929

No files matched your search

+39 -18
View File
@@ -465,10 +465,10 @@ typedef enum {
/**
* Possible flooding by peer was detected in this HTTP/2 session.
* Flooding is measured by how many PING and SETTINGS frames with
* ACK flag set are queued for transmission. These frames are
* response for the peer initiated frames, and peer can cause memory
* exhaustion on server side to send these frames forever and does
* not read network.
* ACK flag set are queued for transmission, and the size of the
* outbound queue. These frames are response for the peer initiated
* frames, and peer can cause memory exhaustion on server side to
* send these frames forever and does not read network.
*/
NGHTTP2_ERR_FLOODED = -904,
/**
@@ -664,12 +664,12 @@ typedef enum {
* The ALTSVC frame, which is defined in `RFC 7383
* <https://tools.ietf.org/html/rfc7838#section-4>`_.
*/
NGHTTP2_ALTSVC = 0x0a,
NGHTTP2_ALTSVC = 0x0A,
/**
* The ORIGIN frame, which is defined by `RFC 8336
* <https://tools.ietf.org/html/rfc8336>`_.
*/
NGHTTP2_ORIGIN = 0x0c,
NGHTTP2_ORIGIN = 0x0C,
/**
* The PRIORITY_UPDATE frame, which is defined by :rfc:`9218`.
*/
@@ -756,7 +756,7 @@ typedef enum {
*
* .. warning::
*
* Deprecated. The initial max concurrent streams is 0xffffffffu.
* Deprecated. The initial max concurrent streams is 0xFFFFFFFFU.
*
* Default maximum number of incoming concurrent streams. Use
* `nghttp2_submit_settings()` with
@@ -818,19 +818,19 @@ typedef enum {
/**
* CONNECT_ERROR
*/
NGHTTP2_CONNECT_ERROR = 0x0a,
NGHTTP2_CONNECT_ERROR = 0x0A,
/**
* ENHANCE_YOUR_CALM
*/
NGHTTP2_ENHANCE_YOUR_CALM = 0x0b,
NGHTTP2_ENHANCE_YOUR_CALM = 0x0B,
/**
* INADEQUATE_SECURITY
*/
NGHTTP2_INADEQUATE_SECURITY = 0x0c,
NGHTTP2_INADEQUATE_SECURITY = 0x0C,
/**
* HTTP_1_1_REQUIRED
*/
NGHTTP2_HTTP_1_1_REQUIRED = 0x0d
NGHTTP2_HTTP_1_1_REQUIRED = 0x0D
} nghttp2_error_code;
/**
@@ -3252,12 +3252,27 @@ NGHTTP2_EXTERN void nghttp2_option_set_max_continuations(nghttp2_option *option,
* regenerated per second. When a suspicious activity is detected,
* some amount of tokens are consumed. If there is no token
* available, GOAWAY is sent to tear down the connection. |burst| and
* |rate| default to 1000 and 33 respectively.
* |rate| default to 10000 and 330 respectively.
*/
NGHTTP2_EXTERN void nghttp2_option_set_glitch_rate_limit(nghttp2_option *option,
uint64_t burst,
uint64_t rate);
/**
* @function
*
* This function sets the maximum number of frames allowed in the
* outbound queue. The limit is checked after
* `nghttp2_session_mem_recv2()` and `nghttp2_session_recv()`. The
* current queue size (excluding deferred DATA frames) can be obtained
* by `nghttp2_session_get_outbound_queue_size()`. If it exceeds
* |val|, `nghttp2_session_mem_recv2()` and `nghttp2_session_recv()`
* return :enum:`nghttp2_error.NGHTTP2_ERR_FLOODED`. The default
* value is 5000.
*/
NGHTTP2_EXTERN void
nghttp2_option_set_max_outbound_queue_size(nghttp2_option *option, size_t val);
/**
* @function
*
@@ -4581,6 +4596,8 @@ NGHTTP2_EXTERN int32_t nghttp2_submit_request(
* reached.
* :enum:`nghttp2_error.NGHTTP2_ERR_PROTO`
* The |session| is server session.
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The required memory for |nva| of length |nvlen| is too large.
*
* .. warning::
*
@@ -4724,7 +4741,8 @@ nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
* :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
* The |stream_id| is 0; The required memory for |nva| of length
* |nvlen| is too large.
* :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet. Normally, this does not happen, but when
@@ -4794,7 +4812,8 @@ nghttp2_submit_response2(nghttp2_session *session, int32_t stream_id,
* :enum:`nghttp2_error.NGHTTP2_ERR_NOMEM`
* Out of memory.
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
* The |stream_id| is 0; The required memory for |nva| of length
* |nvlen| is too large.
*/
NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
int32_t stream_id,
@@ -4860,7 +4879,8 @@ NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
* No stream ID is available because maximum stream ID was
* reached.
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0.
* The |stream_id| is 0; The required memory for |nva| of length
* |nvlen| is too large.
* :enum:`nghttp2_error.NGHTTP2_ERR_DATA_EXIST`
* DATA or HEADERS has been already submitted and not fully
* processed yet. This happens if stream denoted by |stream_id|
@@ -5087,8 +5107,8 @@ NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
* copies all the elements in the |iv|.
*
* While updating individual stream's local window size, if the window
* size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
* RST_STREAM is issued against such a stream.
* size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE, GOAWAY
* frame is submitted and the connection will be terminated.
*
* SETTINGS with :enum:`nghttp2_flag.NGHTTP2_FLAG_ACK` is
* automatically submitted by the library and application could not
@@ -5162,7 +5182,8 @@ NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
* reached.
* :enum:`nghttp2_error.NGHTTP2_ERR_INVALID_ARGUMENT`
* The |stream_id| is 0; The |stream_id| does not designate stream
* that peer initiated.
* that peer initiated; The required memory for |nva| of length
* |nvlen| is too large.
* :enum:`nghttp2_error.NGHTTP2_ERR_STREAM_CLOSED`
* The stream was already closed; or the |stream_id| is invalid.
*
+2 -2
View File
@@ -29,7 +29,7 @@
* @macro
* Version number of the nghttp2 library release
*/
#define NGHTTP2_VERSION "1.68.0"
#define NGHTTP2_VERSION "1.71.0"
/**
* @macro
@@ -37,6 +37,6 @@
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
#define NGHTTP2_VERSION_NUM 0x014400
#define NGHTTP2_VERSION_NUM 0x014700
#endif /* NGHTTP2VER_H */
+3 -1
View File
@@ -26,6 +26,8 @@
#include <string.h>
#include "nghttp2_helper.h"
static int select_alpn(const unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen,
const char *key, unsigned int keylen) {
@@ -41,7 +43,7 @@ static int select_alpn(const unsigned char **out, unsigned char *outlen,
}
#define NGHTTP2_HTTP_1_1_ALPN "\x8http/1.1"
#define NGHTTP2_HTTP_1_1_ALPN_LEN (sizeof(NGHTTP2_HTTP_1_1_ALPN) - 1)
#define NGHTTP2_HTTP_1_1_ALPN_LEN nghttp2_strlen_lit(NGHTTP2_HTTP_1_1_ALPN)
int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
const unsigned char *in, unsigned int inlen) {
+19 -28
View File
@@ -29,13 +29,7 @@
#include "nghttp2_helper.h"
#include "nghttp2_debug.h"
void nghttp2_buf_init(nghttp2_buf *buf) {
buf->begin = NULL;
buf->end = NULL;
buf->pos = NULL;
buf->last = NULL;
buf->mark = NULL;
}
void nghttp2_buf_init(nghttp2_buf *buf) { *buf = (nghttp2_buf){0}; }
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem) {
nghttp2_buf_init(buf);
@@ -212,16 +206,15 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
nghttp2_buf_wrap_init(&chain->buf, begin, len);
bufs->mem = mem;
bufs->offset = 0;
bufs->head = chain;
bufs->cur = bufs->head;
bufs->chunk_length = len;
bufs->chunk_used = 1;
bufs->max_chunk = 1;
bufs->chunk_keep = 1;
*bufs = (nghttp2_bufs){
.head = chain,
.cur = chain,
.mem = mem,
.chunk_length = len,
.max_chunk = 1,
.chunk_used = 1,
.chunk_keep = 1,
};
return 0;
}
@@ -251,17 +244,15 @@ int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec,
dst_chain = &cur_chain->next;
}
bufs->mem = mem;
bufs->offset = 0;
bufs->head = head_chain;
bufs->cur = bufs->head;
/* We don't use chunk_length since no allocation is expected. */
bufs->chunk_length = 0;
bufs->chunk_used = veclen;
bufs->max_chunk = veclen;
bufs->chunk_keep = veclen;
*bufs = (nghttp2_bufs){
.head = head_chain,
.cur = head_chain,
.mem = mem,
/* We don't use chunk_length since no allocation is expected. */
.max_chunk = veclen,
.chunk_used = veclen,
.chunk_keep = veclen,
};
return 0;
}
+4 -2
View File
@@ -31,8 +31,10 @@ uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri) {
}
void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri) {
extpri->urgency = nghttp2_extpri_uint8_urgency(u8extpri);
extpri->inc = nghttp2_extpri_uint8_inc(u8extpri);
*extpri = (nghttp2_extpri){
.urgency = nghttp2_extpri_uint8_urgency(u8extpri),
.inc = nghttp2_extpri_uint8_inc(u8extpri),
};
}
int nghttp2_extpri_parse_priority(nghttp2_extpri *extpri, const uint8_t *value,
+1 -1
View File
@@ -36,7 +36,7 @@
* NGHTTP2_EXTPRI_INC_MASK is a bit mask to retrieve incremental bit
* from a value produced by nghttp2_extpri_to_uint8.
*/
#define NGHTTP2_EXTPRI_INC_MASK (1 << 7)
#define NGHTTP2_EXTPRI_INC_MASK 0x80U
/*
* nghttp2_extpri_to_uint8 encodes |pri| into uint8_t variable.
+66 -39
View File
@@ -43,20 +43,22 @@ void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd) {
}
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf) {
hd->length = nghttp2_get_uint32(&buf[0]) >> 8;
hd->type = buf[3];
hd->flags = buf[4];
hd->stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK;
hd->reserved = 0;
*hd = (nghttp2_frame_hd){
.length = nghttp2_get_uint32(&buf[0]) >> 8,
.stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK,
.type = buf[3],
.flags = buf[4],
};
}
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
uint8_t flags, int32_t stream_id) {
hd->length = length;
hd->type = type;
hd->flags = flags;
hd->stream_id = stream_id;
hd->reserved = 0;
*hd = (nghttp2_frame_hd){
.length = length,
.stream_id = stream_id,
.type = type,
.flags = flags,
};
}
void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
@@ -199,16 +201,15 @@ void nghttp2_frame_extension_free(nghttp2_extension *frame) { (void)frame; }
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
uint8_t *origin, size_t origin_len,
uint8_t *field_value, size_t field_value_len) {
nghttp2_ext_altsvc *altsvc;
nghttp2_frame_hd_init(&frame->hd, 2 + origin_len + field_value_len,
NGHTTP2_ALTSVC, NGHTTP2_FLAG_NONE, stream_id);
altsvc = frame->payload;
altsvc->origin = origin;
altsvc->origin_len = origin_len;
altsvc->field_value = field_value;
altsvc->field_value_len = field_value_len;
*(nghttp2_ext_altsvc *)frame->payload = (nghttp2_ext_altsvc){
.origin = origin,
.origin_len = origin_len,
.field_value = field_value,
.field_value_len = field_value_len,
};
}
void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem) {
@@ -225,7 +226,6 @@ void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem) {
void nghttp2_frame_origin_init(nghttp2_extension *frame,
nghttp2_origin_entry *ov, size_t nov) {
nghttp2_ext_origin *origin;
size_t payloadlen = 0;
size_t i;
@@ -236,9 +236,10 @@ void nghttp2_frame_origin_init(nghttp2_extension *frame,
nghttp2_frame_hd_init(&frame->hd, payloadlen, NGHTTP2_ORIGIN,
NGHTTP2_FLAG_NONE, 0);
origin = frame->payload;
origin->ov = ov;
origin->nov = nov;
*(nghttp2_ext_origin *)frame->payload = (nghttp2_ext_origin){
.ov = ov,
.nov = nov,
};
}
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
@@ -256,15 +257,15 @@ void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
int32_t stream_id, uint8_t *field_value,
size_t field_value_len) {
nghttp2_ext_priority_update *priority_update;
nghttp2_frame_hd_init(&frame->hd, 4 + field_value_len,
NGHTTP2_PRIORITY_UPDATE, NGHTTP2_FLAG_NONE, 0);
priority_update = frame->payload;
priority_update->stream_id = stream_id;
priority_update->field_value = field_value;
priority_update->field_value_len = field_value_len;
*(nghttp2_ext_priority_update *)frame->payload =
(nghttp2_ext_priority_update){
.stream_id = stream_id,
.field_value = field_value,
.field_value_len = field_value_len,
};
}
void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
@@ -517,8 +518,10 @@ void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
const uint8_t *payload) {
iv->settings_id = nghttp2_get_uint16(&payload[0]);
iv->value = nghttp2_get_uint32(&payload[2]);
*iv = (nghttp2_settings_entry){
.settings_id = nghttp2_get_uint16(&payload[0]),
.value = nghttp2_get_uint32(&payload[2]),
};
}
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
@@ -750,6 +753,13 @@ void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
uint8_t *p;
altsvc = frame->payload;
if (payloadlen == 0) {
*altsvc = (nghttp2_ext_altsvc){0};
return;
}
p = payload;
altsvc->origin = p;
@@ -852,8 +862,7 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
}
if (nov == 0) {
origin->ov = NULL;
origin->nov = 0;
*origin = (nghttp2_ext_origin){0};
return 0;
}
@@ -865,8 +874,10 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
return NGHTTP2_ERR_NOMEM;
}
origin->ov = ov;
origin->nov = nov;
*origin = (nghttp2_ext_origin){
.nov = nov,
.ov = ov,
};
dst = (uint8_t *)ov + nov * sizeof(nghttp2_origin_entry);
p = payload;
@@ -877,8 +888,10 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
if (originlen == 0) {
continue;
}
ov->origin = dst;
ov->origin_len = originlen;
*ov = (nghttp2_origin_entry){
.origin = dst,
.origin_len = originlen,
};
dst = nghttp2_cpymem(dst, p, originlen);
*dst++ = '\0';
p += originlen;
@@ -1035,8 +1048,8 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen) {
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
size_t nvlen, nghttp2_mem *mem) {
size_t i;
uint8_t *data = NULL;
size_t buflen = 0;
uint8_t *data;
size_t buflen;
nghttp2_nv *p;
if (nvlen == 0) {
@@ -1045,18 +1058,32 @@ int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
return 0;
}
if (sizeof(nghttp2_nv) > SIZE_MAX / nvlen) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
buflen = sizeof(nghttp2_nv) * nvlen;
for (i = 0; i < nvlen; ++i) {
/* + 1 for null-termination */
if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) == 0) {
if (nva[i].namelen == SIZE_MAX ||
buflen > SIZE_MAX - nva[i].namelen - 1) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
buflen += nva[i].namelen + 1;
}
if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) == 0) {
if (nva[i].valuelen == SIZE_MAX ||
buflen > SIZE_MAX - nva[i].valuelen - 1) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
buflen += nva[i].valuelen + 1;
}
}
buflen += sizeof(nghttp2_nv) * nvlen;
*nva_ptr = nghttp2_mem_malloc(mem, buflen);
if (*nva_ptr == NULL) {
+2 -3
View File
@@ -34,10 +34,7 @@
#include "nghttp2_buf.h"
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
/* The number of bytes of frame header. */
#define NGHTTP2_FRAME_HDLEN 9
@@ -600,6 +597,8 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
*
* NGHTTP2_ERR_NOMEM
* Out of memory.
* NGHTTP2_ERR_INVALID_ARGUMENT
* The required memory for |nva| of length |nvlen| is too large.
*/
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
size_t nvlen, nghttp2_mem *mem);
+65 -44
View File
@@ -35,11 +35,27 @@
/* Make scalar initialization form of nghttp2_hd_entry */
#define MAKE_STATIC_ENT(N, V, T, H) \
{ \
{NULL, NULL, (uint8_t *)(N), sizeof((N)) - 1, -1}, \
{NULL, NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, \
{(uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0}, \
T, \
H, \
.name = \
{ \
.base = (uint8_t *)(N), \
.len = nghttp2_strlen_lit((N)), \
.ref = -1, \
}, \
.value = \
{ \
.base = (uint8_t *)(V), \
.len = nghttp2_strlen_lit((V)), \
.ref = -1, \
}, \
.cnv = \
{ \
.name = (uint8_t *)(N), \
.value = (uint8_t *)(V), \
.namelen = nghttp2_strlen_lit((N)), \
.valuelen = nghttp2_strlen_lit((V)), \
}, \
.token = T, \
.hash = H, \
}
/* Generated by mkstatictbl.py */
@@ -486,14 +502,17 @@ static int32_t lookup_token(const uint8_t *name, size_t namelen) {
}
void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv) {
ent->nv = *nv;
ent->cnv.name = nv->name->base;
ent->cnv.namelen = nv->name->len;
ent->cnv.value = nv->value->base;
ent->cnv.valuelen = nv->value->len;
ent->cnv.flags = nv->flags;
ent->next = NULL;
ent->hash = 0;
*ent = (nghttp2_hd_entry){
.nv = *nv,
.cnv =
{
.name = nv->name->base,
.value = nv->value->base,
.namelen = nv->name->len,
.valuelen = nv->value->len,
.flags = nv->flags,
},
};
nghttp2_rcbuf_incref(ent->nv.name);
nghttp2_rcbuf_incref(ent->nv.value);
@@ -527,9 +546,7 @@ static uint32_t name_hash(const nghttp2_nv *nv) {
return h;
}
static void hd_map_init(nghttp2_hd_map *map) {
memset(map, 0, sizeof(nghttp2_hd_map));
}
static void hd_map_init(nghttp2_hd_map *map) { *map = (nghttp2_hd_map){0}; }
static void hd_map_insert(nghttp2_hd_map *map, nghttp2_hd_entry *ent) {
nghttp2_hd_entry **bucket;
@@ -837,7 +854,7 @@ static size_t encode_length(uint8_t *buf, size_t n, size_t prefix) {
n -= k;
for (; n >= 128; n >>= 7) {
*buf++ = (uint8_t)((1 << 7) | (n & 0x7f));
*buf++ = (uint8_t)((1 << 7) | (n & 0x7F));
}
*buf++ = (uint8_t)n;
@@ -889,7 +906,7 @@ static nghttp2_ssize decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
}
for (; in != last; ++in, shift += 7) {
uint32_t add = *in & 0x7f;
uint32_t add = *in & 0x7F;
if (shift >= 32) {
DEBUGF("inflate: shift exponent overflow\n");
@@ -943,7 +960,7 @@ static int emit_table_size(nghttp2_bufs *bufs, size_t table_size) {
bufp = sb;
*bufp = 0x20u;
*bufp = 0x20U;
encode_length(bufp, table_size, 5);
@@ -970,7 +987,7 @@ static int emit_indexed_block(nghttp2_bufs *bufs, size_t idx) {
}
bufp = sb;
*bufp = 0x80u;
*bufp = 0x80U;
encode_length(bufp, idx + 1, 7);
rv = nghttp2_bufs_add(bufs, sb, blocklen);
@@ -1029,11 +1046,11 @@ static int emit_string(nghttp2_bufs *bufs, const uint8_t *str, size_t len) {
static uint8_t pack_first_byte(int indexing_mode) {
switch (indexing_mode) {
case NGHTTP2_HD_WITH_INDEXING:
return 0x40u;
return 0x40U;
case NGHTTP2_HD_WITHOUT_INDEXING:
return 0;
case NGHTTP2_HD_NEVER_INDEXING:
return 0x10u;
return 0x10U;
default:
assert(0);
}
@@ -1317,10 +1334,12 @@ nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) {
->nv;
} else {
const nghttp2_hd_static_entry *ent = &static_table[idx];
nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name,
(nghttp2_rcbuf *)&ent->value, ent->token,
NGHTTP2_NV_FLAG_NONE};
return nv;
return (nghttp2_hd_nv){
.name = (nghttp2_rcbuf *)&ent->name,
.value = (nghttp2_rcbuf *)&ent->value,
.token = ent->token,
.flags = NGHTTP2_NV_FLAG_NONE,
};
}
}
@@ -1885,13 +1904,13 @@ nghttp2_ssize nghttp2_hd_inflate_hd3(nghttp2_hd_inflater *inflater,
}
if (*inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
nv_out->name = hd_nv.name->base;
nv_out->namelen = hd_nv.name->len;
nv_out->value = hd_nv.value->base;
nv_out->valuelen = hd_nv.value->len;
nv_out->flags = hd_nv.flags;
*nv_out = (nghttp2_nv){
.name = hd_nv.name->base,
.value = hd_nv.value->base,
.namelen = hd_nv.name->len,
.valuelen = hd_nv.value->len,
.flags = hd_nv.flags,
};
}
return rv;
@@ -1921,7 +1940,7 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
busy = 0;
switch (inflater->state) {
case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE:
if ((*in & 0xe0u) != 0x20u) {
if ((*in & 0xE0U) != 0x20U) {
DEBUGF("inflatehd: header table size change was expected, but saw "
"0x%02x as first byte",
*in);
@@ -1931,7 +1950,7 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
/* fall through */
case NGHTTP2_HD_STATE_INFLATE_START:
case NGHTTP2_HD_STATE_OPCODE:
if ((*in & 0xe0u) == 0x20u) {
if ((*in & 0xE0U) == 0x20U) {
DEBUGF("inflatehd: header table size change\n");
if (inflater->state == NGHTTP2_HD_STATE_OPCODE) {
DEBUGF("inflatehd: header table size change must appear at the head "
@@ -1941,12 +1960,12 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
}
inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
inflater->state = NGHTTP2_HD_STATE_READ_TABLE_SIZE;
} else if (*in & 0x80u) {
} else if (*in & 0x80U) {
DEBUGF("inflatehd: indexed repr\n");
inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
} else {
if (*in == 0x40u || *in == 0 || *in == 0x10u) {
if (*in == 0x40U || *in == 0 || *in == 0x10U) {
DEBUGF("inflatehd: literal header repr - new name\n");
inflater->opcode = NGHTTP2_HD_OPCODE_NEWNAME;
inflater->state = NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN;
@@ -1956,7 +1975,7 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
}
inflater->index_required = (*in & 0x40) != 0;
inflater->no_index = (*in & 0xf0u) == 0x10u;
inflater->no_index = (*in & 0xF0U) == 0x10U;
DEBUGF("inflatehd: indexing required=%d, no_index=%d\n",
inflater->index_required, inflater->no_index);
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
@@ -2058,8 +2077,9 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF;
rv =
nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left * 2 + 1, mem);
rv = nghttp2_rcbuf_new(
&inflater->namercbuf,
nghttp2_huff_estimate_decode_length(inflater->left) + 1, mem);
} else {
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME;
rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left + 1, mem);
@@ -2143,8 +2163,9 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF;
rv =
nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left * 2 + 1, mem);
rv = nghttp2_rcbuf_new(
&inflater->valuercbuf,
nghttp2_huff_estimate_decode_length(inflater->left) + 1, mem);
} else {
inflater->state = NGHTTP2_HD_STATE_READ_VALUE;
@@ -2314,11 +2335,11 @@ void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater) {
}
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx,
nghttp2_nv *nv, int indexing_mode) {
const nghttp2_nv *nv, int indexing_mode) {
return emit_indname_block(bufs, idx, nv, indexing_mode);
}
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
int indexing_mode) {
return emit_newname_block(bufs, nv, indexing_mode);
}
+2 -2
View File
@@ -364,10 +364,10 @@ nghttp2_ssize nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
/* For unittesting purpose */
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
nghttp2_nv *nv, int indexing_mode);
const nghttp2_nv *nv, int indexing_mode);
/* For unittesting purpose */
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
int indexing_mode);
/* For unittesting purpose */
+12 -11
View File
@@ -104,15 +104,15 @@ int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
}
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
ctx->fstate = NGHTTP2_HUFF_ACCEPTED;
ctx->fstate = 0;
ctx->flags = NGHTTP2_HUFF_ACCEPTED;
}
nghttp2_ssize nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
nghttp2_buf *buf, const uint8_t *src,
size_t srclen, int final) {
const uint8_t *end = src + srclen;
nghttp2_huff_decode node = {ctx->fstate, 0};
const nghttp2_huff_decode *t = &node;
nghttp2_huff_decode t = {ctx->fstate, ctx->flags, 0};
uint8_t c;
/* We use the decoding algorithm described in
@@ -121,20 +121,21 @@ nghttp2_ssize nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
- https://github.com/nghttp2/nghttp2/files/15141264/Prefix.pdf */
for (; src != end;) {
c = *src++;
t = &huff_decode_table[t->fstate & 0x1ff][c >> 4];
if (t->fstate & NGHTTP2_HUFF_SYM) {
*buf->last++ = t->sym;
t = huff_decode_table[t.fstate][c >> 4];
if (t.flags & NGHTTP2_HUFF_SYM) {
*buf->last++ = t.sym;
}
t = &huff_decode_table[t->fstate & 0x1ff][c & 0xf];
if (t->fstate & NGHTTP2_HUFF_SYM) {
*buf->last++ = t->sym;
t = huff_decode_table[t.fstate][c & 0xF];
if (t.flags & NGHTTP2_HUFF_SYM) {
*buf->last++ = t.sym;
}
}
ctx->fstate = t->fstate;
ctx->fstate = t.fstate;
ctx->flags = t.flags;
if (final && !(ctx->fstate & NGHTTP2_HUFF_ACCEPTED)) {
if (final && !(ctx->flags & NGHTTP2_HUFF_ACCEPTED)) {
return NGHTTP2_ERR_HEADER_COMP;
}
+21 -13
View File
@@ -31,23 +31,22 @@
#include <nghttp2/nghttp2.h>
typedef enum {
/* FSA accepts this state as the end of huffman encoding
sequence. */
NGHTTP2_HUFF_ACCEPTED = 1 << 14,
/* This state emits symbol */
NGHTTP2_HUFF_SYM = 1 << 15,
} nghttp2_huff_decode_flag;
/* FSA accepts this state as the end of huffman encoding sequence. */
#define NGHTTP2_HUFF_ACCEPTED 0x01U
/* This state emits symbol */
#define NGHTTP2_HUFF_SYM 0x02U
typedef struct {
/* fstate is the current huffman decoding state, which is actually
the node ID of internal huffman tree with
nghttp2_huff_decode_flag OR-ed. We have 257 leaf nodes, but they
are identical to root node other than emitting a symbol, so we
have 256 internal nodes [1..255], inclusive. The node ID 256 is
a special node and it is a terminal state that means decoding
failed. */
the node ID of internal huffman tree. We have 257 leaf nodes,
but they are identical to root node other than emitting a symbol,
so we have 256 internal nodes [1..255], inclusive. The node ID
256 is a special node and it is a terminal state that means
decoding failed. */
uint16_t fstate;
/* flags is the bitwise OR of zero or more of NGHTTP2_HUFF_*
values. */
uint8_t flags;
/* symbol if NGHTTP2_HUFF_SYM flag set */
uint8_t sym;
} nghttp2_huff_decode;
@@ -57,6 +56,7 @@ typedef nghttp2_huff_decode huff_decode_table_type[16];
typedef struct {
/* fstate is the current huffman decoding state. */
uint16_t fstate;
uint8_t flags;
} nghttp2_hd_huff_decode_context;
typedef struct {
@@ -69,4 +69,12 @@ typedef struct {
extern const nghttp2_huff_sym huff_sym_table[];
extern const nghttp2_huff_decode huff_decode_table[][16];
/*
* nghttp2_huff_estimate_decode_length returns the estimated decoded
* length of the huffman encoded string of length |len|.
*/
static inline size_t nghttp2_huff_estimate_decode_length(size_t len) {
return len * 8 / 5;
}
#endif /* !defined(NGHTTP2_HD_HUFFMAN_H) */
+4177 -4177
View File
File diff suppressed because it is too large. Load diff
+197 -398
View File
@@ -52,77 +52,77 @@ uint32_t nghttp2_get_uint32(const uint8_t *data) {
}
/* Generated by gendowncasetbl.py */
static const uint8_t DOWNCASE_TBL[] = {
0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */,
4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */,
8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */,
12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */,
16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */,
20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */,
24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */,
28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */,
32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */,
36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */,
40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */,
44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */,
48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */,
52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */,
60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */,
64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */,
100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */,
104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */,
108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */,
112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */,
116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */,
120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */,
92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */,
96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */,
100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */,
124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */,
128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */,
132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */,
136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */,
140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */,
144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */,
148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */,
152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */,
156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */,
160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */,
164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */,
168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */,
172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */,
176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */,
180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */,
184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */,
188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */,
192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */,
196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */,
200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */,
204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */,
208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */,
212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */,
216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */,
220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */,
224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */,
228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */,
232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */,
236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */,
240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */,
244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */,
248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */,
252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */,
const uint8_t nghttp2_downcase_tbl[] = {
0x00 /* NUL */, 0x01 /* SOH */, 0x02 /* STX */, 0x03 /* ETX */,
0x04 /* EOT */, 0x05 /* ENQ */, 0x06 /* ACK */, 0x07 /* BEL */,
0x08 /* BS */, 0x09 /* HT */, 0x0A /* LF */, 0x0B /* VT */,
0x0C /* FF */, 0x0D /* CR */, 0x0E /* SO */, 0x0F /* SI */,
0x10 /* DLE */, 0x11 /* DC1 */, 0x12 /* DC2 */, 0x13 /* DC3 */,
0x14 /* DC4 */, 0x15 /* NAK */, 0x16 /* SYN */, 0x17 /* ETB */,
0x18 /* CAN */, 0x19 /* EM */, 0x1A /* SUB */, 0x1B /* ESC */,
0x1C /* FS */, 0x1D /* GS */, 0x1E /* RS */, 0x1F /* US */,
0x20 /* SPC */, 0x21 /* ! */, 0x22 /* " */, 0x23 /* # */,
0x24 /* $ */, 0x25 /* % */, 0x26 /* & */, 0x27 /* ' */,
0x28 /* ( */, 0x29 /* ) */, 0x2A /* * */, 0x2B /* + */,
0x2C /* , */, 0x2D /* - */, 0x2E /* . */, 0x2F /* / */,
0x30 /* 0 */, 0x31 /* 1 */, 0x32 /* 2 */, 0x33 /* 3 */,
0x34 /* 4 */, 0x35 /* 5 */, 0x36 /* 6 */, 0x37 /* 7 */,
0x38 /* 8 */, 0x39 /* 9 */, 0x3A /* : */, 0x3B /* ; */,
0x3C /* < */, 0x3D /* = */, 0x3E /* > */, 0x3F /* ? */,
0x40 /* @ */, 0x61 /* A */, 0x62 /* B */, 0x63 /* C */,
0x64 /* D */, 0x65 /* E */, 0x66 /* F */, 0x67 /* G */,
0x68 /* H */, 0x69 /* I */, 0x6A /* J */, 0x6B /* K */,
0x6C /* L */, 0x6D /* M */, 0x6E /* N */, 0x6F /* O */,
0x70 /* P */, 0x71 /* Q */, 0x72 /* R */, 0x73 /* S */,
0x74 /* T */, 0x75 /* U */, 0x76 /* V */, 0x77 /* W */,
0x78 /* X */, 0x79 /* Y */, 0x7A /* Z */, 0x5B /* [ */,
0x5C /* \ */, 0x5D /* ] */, 0x5E /* ^ */, 0x5F /* _ */,
0x60 /* ` */, 0x61 /* a */, 0x62 /* b */, 0x63 /* c */,
0x64 /* d */, 0x65 /* e */, 0x66 /* f */, 0x67 /* g */,
0x68 /* h */, 0x69 /* i */, 0x6A /* j */, 0x6B /* k */,
0x6C /* l */, 0x6D /* m */, 0x6E /* n */, 0x6F /* o */,
0x70 /* p */, 0x71 /* q */, 0x72 /* r */, 0x73 /* s */,
0x74 /* t */, 0x75 /* u */, 0x76 /* v */, 0x77 /* w */,
0x78 /* x */, 0x79 /* y */, 0x7A /* z */, 0x7B /* { */,
0x7C /* | */, 0x7D /* } */, 0x7E /* ~ */, 0x7F /* DEL */,
0x80 /* 0x80 */, 0x81 /* 0x81 */, 0x82 /* 0x82 */, 0x83 /* 0x83 */,
0x84 /* 0x84 */, 0x85 /* 0x85 */, 0x86 /* 0x86 */, 0x87 /* 0x87 */,
0x88 /* 0x88 */, 0x89 /* 0x89 */, 0x8A /* 0x8A */, 0x8B /* 0x8B */,
0x8C /* 0x8C */, 0x8D /* 0x8D */, 0x8E /* 0x8E */, 0x8F /* 0x8F */,
0x90 /* 0x90 */, 0x91 /* 0x91 */, 0x92 /* 0x92 */, 0x93 /* 0x93 */,
0x94 /* 0x94 */, 0x95 /* 0x95 */, 0x96 /* 0x96 */, 0x97 /* 0x97 */,
0x98 /* 0x98 */, 0x99 /* 0x99 */, 0x9A /* 0x9A */, 0x9B /* 0x9B */,
0x9C /* 0x9C */, 0x9D /* 0x9D */, 0x9E /* 0x9E */, 0x9F /* 0x9F */,
0xA0 /* 0xA0 */, 0xA1 /* 0xA1 */, 0xA2 /* 0xA2 */, 0xA3 /* 0xA3 */,
0xA4 /* 0xA4 */, 0xA5 /* 0xA5 */, 0xA6 /* 0xA6 */, 0xA7 /* 0xA7 */,
0xA8 /* 0xA8 */, 0xA9 /* 0xA9 */, 0xAA /* 0xAA */, 0xAB /* 0xAB */,
0xAC /* 0xAC */, 0xAD /* 0xAD */, 0xAE /* 0xAE */, 0xAF /* 0xAF */,
0xB0 /* 0xB0 */, 0xB1 /* 0xB1 */, 0xB2 /* 0xB2 */, 0xB3 /* 0xB3 */,
0xB4 /* 0xB4 */, 0xB5 /* 0xB5 */, 0xB6 /* 0xB6 */, 0xB7 /* 0xB7 */,
0xB8 /* 0xB8 */, 0xB9 /* 0xB9 */, 0xBA /* 0xBA */, 0xBB /* 0xBB */,
0xBC /* 0xBC */, 0xBD /* 0xBD */, 0xBE /* 0xBE */, 0xBF /* 0xBF */,
0xC0 /* 0xC0 */, 0xC1 /* 0xC1 */, 0xC2 /* 0xC2 */, 0xC3 /* 0xC3 */,
0xC4 /* 0xC4 */, 0xC5 /* 0xC5 */, 0xC6 /* 0xC6 */, 0xC7 /* 0xC7 */,
0xC8 /* 0xC8 */, 0xC9 /* 0xC9 */, 0xCA /* 0xCA */, 0xCB /* 0xCB */,
0xCC /* 0xCC */, 0xCD /* 0xCD */, 0xCE /* 0xCE */, 0xCF /* 0xCF */,
0xD0 /* 0xD0 */, 0xD1 /* 0xD1 */, 0xD2 /* 0xD2 */, 0xD3 /* 0xD3 */,
0xD4 /* 0xD4 */, 0xD5 /* 0xD5 */, 0xD6 /* 0xD6 */, 0xD7 /* 0xD7 */,
0xD8 /* 0xD8 */, 0xD9 /* 0xD9 */, 0xDA /* 0xDA */, 0xDB /* 0xDB */,
0xDC /* 0xDC */, 0xDD /* 0xDD */, 0xDE /* 0xDE */, 0xDF /* 0xDF */,
0xE0 /* 0xE0 */, 0xE1 /* 0xE1 */, 0xE2 /* 0xE2 */, 0xE3 /* 0xE3 */,
0xE4 /* 0xE4 */, 0xE5 /* 0xE5 */, 0xE6 /* 0xE6 */, 0xE7 /* 0xE7 */,
0xE8 /* 0xE8 */, 0xE9 /* 0xE9 */, 0xEA /* 0xEA */, 0xEB /* 0xEB */,
0xEC /* 0xEC */, 0xED /* 0xED */, 0xEE /* 0xEE */, 0xEF /* 0xEF */,
0xF0 /* 0xF0 */, 0xF1 /* 0xF1 */, 0xF2 /* 0xF2 */, 0xF3 /* 0xF3 */,
0xF4 /* 0xF4 */, 0xF5 /* 0xF5 */, 0xF6 /* 0xF6 */, 0xF7 /* 0xF7 */,
0xF8 /* 0xF8 */, 0xF9 /* 0xF9 */, 0xFA /* 0xFA */, 0xFB /* 0xFB */,
0xFC /* 0xFC */, 0xFD /* 0xFD */, 0xFE /* 0xFE */, 0xFF /* 0xFF */,
};
void nghttp2_downcase(uint8_t *s, size_t len) {
size_t i;
for (i = 0; i < len; ++i) {
s[i] = DOWNCASE_TBL[s[i]];
s[i] = nghttp2_downcase_byte(s[i]);
}
}
@@ -247,7 +247,8 @@ int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
int nghttp2_should_send_window_update(int32_t local_window_size,
int32_t recv_window_size) {
return recv_window_size > 0 && recv_window_size >= local_window_size / 2;
return recv_window_size > 0 && local_window_size > 0 &&
recv_window_size >= local_window_size / 2;
}
const char *nghttp2_strerror(int error_code) {
@@ -343,72 +344,18 @@ const char *nghttp2_strerror(int error_code) {
}
}
/* Generated by gennmchartbl.py */
static const int VALID_HD_NAME_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */,
0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */,
0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */,
0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */,
0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */,
0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */,
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
static const uint8_t VALID_HD_NAME_CHARS[256] = {
['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['*'] = 1,
['+'] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, ['A'] = 2,
['B'] = 2, ['C'] = 2, ['D'] = 2, ['E'] = 2, ['F'] = 2, ['G'] = 2, ['H'] = 2,
['I'] = 2, ['J'] = 2, ['K'] = 2, ['L'] = 2, ['M'] = 2, ['N'] = 2, ['O'] = 2,
['P'] = 2, ['Q'] = 2, ['R'] = 2, ['S'] = 2, ['T'] = 2, ['U'] = 2, ['V'] = 2,
['W'] = 2, ['X'] = 2, ['Y'] = 2, ['Z'] = 2, ['^'] = 1, ['_'] = 1, ['`'] = 1,
['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1,
['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1,
['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['|'] = 1, ['~'] = 1,
};
int nghttp2_check_header_name(const uint8_t *name, size_t len) {
@@ -424,79 +371,66 @@ int nghttp2_check_header_name(const uint8_t *name, size_t len) {
--len;
}
for (last = name + len; name != last; ++name) {
if (!VALID_HD_NAME_CHARS[*name]) {
if (VALID_HD_NAME_CHARS[*name] != 1) {
return 0;
}
}
return 1;
}
/* Generated by genvchartbl.py */
static const int VALID_HD_VALUE_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
int nghttp2_check_nonempty_header_name(const uint8_t *name, size_t len) {
const uint8_t *last;
int rv;
for (last = name + len; name != last; ++name) {
rv = VALID_HD_NAME_CHARS[*name];
if (rv != 1) {
return rv;
}
}
return 1;
}
static const uint8_t VALID_HD_VALUE_CHARS[256] = {
['\t'] = 1, [' '] = 1, ['!'] = 1, ['"'] = 1, ['#'] = 1, ['$'] = 1,
['%'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1, [')'] = 1, ['*'] = 1,
['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1, ['/'] = 1, ['0'] = 1,
['1'] = 1, ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1,
['7'] = 1, ['8'] = 1, ['9'] = 1, [':'] = 1, [';'] = 1, ['<'] = 1,
['='] = 1, ['>'] = 1, ['?'] = 1, ['@'] = 1, ['A'] = 1, ['B'] = 1,
['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1,
['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1,
['O'] = 1, ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1,
['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1,
['['] = 1, ['\\'] = 1, [']'] = 1, ['^'] = 1, ['_'] = 1, ['`'] = 1,
['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1,
['g'] = 1, ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1,
['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1,
['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1,
['y'] = 1, ['z'] = 1, ['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1,
[0x80] = 1, [0x81] = 1, [0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1,
[0x86] = 1, [0x87] = 1, [0x88] = 1, [0x89] = 1, [0x8A] = 1, [0x8B] = 1,
[0x8C] = 1, [0x8D] = 1, [0x8E] = 1, [0x8F] = 1, [0x90] = 1, [0x91] = 1,
[0x92] = 1, [0x93] = 1, [0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1,
[0x98] = 1, [0x99] = 1, [0x9A] = 1, [0x9B] = 1, [0x9C] = 1, [0x9D] = 1,
[0x9E] = 1, [0x9F] = 1, [0xA0] = 1, [0xA1] = 1, [0xA2] = 1, [0xA3] = 1,
[0xA4] = 1, [0xA5] = 1, [0xA6] = 1, [0xA7] = 1, [0xA8] = 1, [0xA9] = 1,
[0xAA] = 1, [0xAB] = 1, [0xAC] = 1, [0xAD] = 1, [0xAE] = 1, [0xAF] = 1,
[0xB0] = 1, [0xB1] = 1, [0xB2] = 1, [0xB3] = 1, [0xB4] = 1, [0xB5] = 1,
[0xB6] = 1, [0xB7] = 1, [0xB8] = 1, [0xB9] = 1, [0xBA] = 1, [0xBB] = 1,
[0xBC] = 1, [0xBD] = 1, [0xBE] = 1, [0xBF] = 1, [0xC0] = 1, [0xC1] = 1,
[0xC2] = 1, [0xC3] = 1, [0xC4] = 1, [0xC5] = 1, [0xC6] = 1, [0xC7] = 1,
[0xC8] = 1, [0xC9] = 1, [0xCA] = 1, [0xCB] = 1, [0xCC] = 1, [0xCD] = 1,
[0xCE] = 1, [0xCF] = 1, [0xD0] = 1, [0xD1] = 1, [0xD2] = 1, [0xD3] = 1,
[0xD4] = 1, [0xD5] = 1, [0xD6] = 1, [0xD7] = 1, [0xD8] = 1, [0xD9] = 1,
[0xDA] = 1, [0xDB] = 1, [0xDC] = 1, [0xDD] = 1, [0xDE] = 1, [0xDF] = 1,
[0xE0] = 1, [0xE1] = 1, [0xE2] = 1, [0xE3] = 1, [0xE4] = 1, [0xE5] = 1,
[0xE6] = 1, [0xE7] = 1, [0xE8] = 1, [0xE9] = 1, [0xEA] = 1, [0xEB] = 1,
[0xEC] = 1, [0xED] = 1, [0xEE] = 1, [0xEF] = 1, [0xF0] = 1, [0xF1] = 1,
[0xF2] = 1, [0xF3] = 1, [0xF4] = 1, [0xF5] = 1, [0xF6] = 1, [0xF7] = 1,
[0xF8] = 1, [0xF9] = 1, [0xFA] = 1, [0xFB] = 1, [0xFC] = 1, [0xFD] = 1,
[0xFE] = 1, [0xFF] = 1,
};
int nghttp2_check_header_value(const uint8_t *value, size_t len) {
@@ -522,72 +456,18 @@ int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) {
return nghttp2_check_header_value(value, len);
}
/* Generated by genmethodchartbl.py */
static char VALID_METHOD_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 0 /* [ */,
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
static const uint8_t VALID_METHOD_CHARS[256] = {
['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['*'] = 1,
['+'] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1, ['3'] = 1,
['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1, ['A'] = 1,
['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1,
['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1,
['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1,
['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['^'] = 1, ['_'] = 1, ['`'] = 1,
['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1,
['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1,
['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1,
['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['|'] = 1, ['~'] = 1,
};
int nghttp2_check_method(const uint8_t *value, size_t len) {
@@ -603,72 +483,44 @@ int nghttp2_check_method(const uint8_t *value, size_t len) {
return 1;
}
/* Generated by genpathchartbl.py */
static char VALID_PATH_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
static const uint8_t VALID_PATH_CHARS[256] = {
['!'] = 1, ['"'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1,
['\''] = 1, ['('] = 1, [')'] = 1, ['*'] = 1, ['+'] = 1, [','] = 1,
['-'] = 1, ['.'] = 1, ['/'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1,
['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1,
['9'] = 1, [':'] = 1, [';'] = 1, ['<'] = 1, ['='] = 1, ['>'] = 1,
['?'] = 1, ['@'] = 1, ['A'] = 1, ['B'] = 1, ['C'] = 1, ['D'] = 1,
['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1,
['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1,
['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1,
['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 1, ['\\'] = 1,
[']'] = 1, ['^'] = 1, ['_'] = 1, ['`'] = 1, ['a'] = 1, ['b'] = 1,
['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1,
['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1,
['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1,
['u'] = 1, ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1,
['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1, [0x80] = 1, [0x81] = 1,
[0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1, [0x86] = 1, [0x87] = 1,
[0x88] = 1, [0x89] = 1, [0x8A] = 1, [0x8B] = 1, [0x8C] = 1, [0x8D] = 1,
[0x8E] = 1, [0x8F] = 1, [0x90] = 1, [0x91] = 1, [0x92] = 1, [0x93] = 1,
[0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1, [0x98] = 1, [0x99] = 1,
[0x9A] = 1, [0x9B] = 1, [0x9C] = 1, [0x9D] = 1, [0x9E] = 1, [0x9F] = 1,
[0xA0] = 1, [0xA1] = 1, [0xA2] = 1, [0xA3] = 1, [0xA4] = 1, [0xA5] = 1,
[0xA6] = 1, [0xA7] = 1, [0xA8] = 1, [0xA9] = 1, [0xAA] = 1, [0xAB] = 1,
[0xAC] = 1, [0xAD] = 1, [0xAE] = 1, [0xAF] = 1, [0xB0] = 1, [0xB1] = 1,
[0xB2] = 1, [0xB3] = 1, [0xB4] = 1, [0xB5] = 1, [0xB6] = 1, [0xB7] = 1,
[0xB8] = 1, [0xB9] = 1, [0xBA] = 1, [0xBB] = 1, [0xBC] = 1, [0xBD] = 1,
[0xBE] = 1, [0xBF] = 1, [0xC0] = 1, [0xC1] = 1, [0xC2] = 1, [0xC3] = 1,
[0xC4] = 1, [0xC5] = 1, [0xC6] = 1, [0xC7] = 1, [0xC8] = 1, [0xC9] = 1,
[0xCA] = 1, [0xCB] = 1, [0xCC] = 1, [0xCD] = 1, [0xCE] = 1, [0xCF] = 1,
[0xD0] = 1, [0xD1] = 1, [0xD2] = 1, [0xD3] = 1, [0xD4] = 1, [0xD5] = 1,
[0xD6] = 1, [0xD7] = 1, [0xD8] = 1, [0xD9] = 1, [0xDA] = 1, [0xDB] = 1,
[0xDC] = 1, [0xDD] = 1, [0xDE] = 1, [0xDF] = 1, [0xE0] = 1, [0xE1] = 1,
[0xE2] = 1, [0xE3] = 1, [0xE4] = 1, [0xE5] = 1, [0xE6] = 1, [0xE7] = 1,
[0xE8] = 1, [0xE9] = 1, [0xEA] = 1, [0xEB] = 1, [0xEC] = 1, [0xED] = 1,
[0xEE] = 1, [0xEF] = 1, [0xF0] = 1, [0xF1] = 1, [0xF2] = 1, [0xF3] = 1,
[0xF4] = 1, [0xF5] = 1, [0xF6] = 1, [0xF7] = 1, [0xF8] = 1, [0xF9] = 1,
[0xFA] = 1, [0xFB] = 1, [0xFC] = 1, [0xFD] = 1, [0xFE] = 1, [0xFF] = 1,
};
int nghttp2_check_path(const uint8_t *value, size_t len) {
@@ -681,72 +533,19 @@ int nghttp2_check_path(const uint8_t *value, size_t len) {
return 1;
}
/* Generated by genauthoritychartbl.py */
static char VALID_AUTHORITY_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */,
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */,
0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
static const uint8_t VALID_AUTHORITY_CHARS[256] = {
['!'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1, [')'] = 1,
['*'] = 1, ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1,
['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1,
['9'] = 1, [':'] = 1, [';'] = 1, ['='] = 1, ['@'] = 1, ['A'] = 1, ['B'] = 1,
['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1,
['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1,
['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1,
['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 1, [']'] = 1, ['_'] = 1, ['a'] = 1,
['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1,
['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1,
['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1,
['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['~'] = 1,
};
int nghttp2_check_authority(const uint8_t *value, size_t len) {
+27 -1
View File
@@ -61,7 +61,15 @@ nghttp2_min_def(uint32, uint32_t)
nghttp2_min_def(uint64, uint64_t)
nghttp2_min_def(size, size_t)
#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
/*
* nghttp2_strlen_lit returns the length of string literal |S|. This
* macro assumes |S| is NULL-terminated string literal. It must not
* be used with pointers.
*/
#define nghttp2_strlen_lit(S) (sizeof(S) - 1)
#define lstreq(A, B, N) \
(nghttp2_strlen_lit((A)) == (N) && memcmp((A), (B), (N)) == 0)
#define nghttp2_struct_of(ptr, type, member) \
((type *)(void *)((char *)(ptr) - offsetof(type, member)))
@@ -92,6 +100,16 @@ uint32_t nghttp2_get_uint32(const uint8_t *data);
void nghttp2_downcase(uint8_t *s, size_t len);
extern const uint8_t nghttp2_downcase_tbl[];
/*
* nghttp2_downcase_byte returns the lower case version of |c| if 'A'
* <= |c| && |c| <= 'Z'. Otherwise, it returns |c|.
*/
static inline uint8_t nghttp2_downcase_byte(uint8_t c) {
return nghttp2_downcase_tbl[c];
}
/*
* Adjusts |*local_window_size_ptr|, |*recv_window_size_ptr|,
* |*recv_reduction_ptr| with |*delta_ptr| which is the
@@ -142,4 +160,12 @@ int nghttp2_should_send_window_update(int32_t local_window_size,
*/
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
/*
* nghttp2_check_nonempty_header_name validates regular header name
* pointed by |name| of length |len|. |len| must be greater than
* zero. This function returns 1 if it succeeds, or 2 if the name
* contains a character in [A-Z], otherwise 0.
*/
int nghttp2_check_nonempty_header_name(const uint8_t *name, size_t len);
#endif /* !defined(NGHTTP2_HELPER_H) */
+162 -234
View File
@@ -33,45 +33,59 @@
#include "nghttp2_extpri.h"
#include "sfparse.h"
static uint8_t downcase(uint8_t c) {
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
}
/*
* memieq returns nonzero if the data pointed by |a| of length |n|
* equals to |b| of the same length in case-insensitive manner. The
* data pointed by |a| must not include upper cased letters (A-Z).
*/
static int memieq(const void *a, const void *b, size_t n) {
size_t i;
const uint8_t *aa = a, *bb = b;
for (i = 0; i < n; ++i) {
if (downcase(aa[i]) != downcase(bb[i])) {
if (aa[i] != nghttp2_downcase_byte(bb[i])) {
return 0;
}
}
return 1;
}
#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
#define lstrieq(A, B, N) \
(nghttp2_strlen_lit((A)) == (N) && memieq((A), (B), (N)))
static int32_t parse_status_code(const uint8_t *s, size_t len) {
if (len != 3 || '1' > s[0] || s[0] > '9' || '0' > s[1] || s[1] > '9' ||
'0' > s[2] || s[2] > '9') {
return -1;
}
return (s[0] - '0') * 100 + (s[1] - '0') * 10 + (s[2] - '0');
}
static int64_t parse_uint(const uint8_t *s, size_t len) {
int64_t n = 0;
uint64_t n = 0;
uint32_t c;
size_t i;
if (len == 0) {
return -1;
}
for (i = 0; i < len; ++i) {
if ('0' <= s[i] && s[i] <= '9') {
if (n > INT64_MAX / 10) {
return -1;
}
n *= 10;
if (n > INT64_MAX - (s[i] - '0')) {
return -1;
}
n += s[i] - '0';
continue;
if ('0' > s[i] || s[i] > '9') {
return -1;
}
return -1;
c = s[i] - '0';
if (n > ((uint64_t)INT64_MAX - c) / 10) {
return -1;
}
n = n * 10 + c;
}
return n;
return (int64_t)n;
}
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
@@ -101,25 +115,90 @@ static int check_path(nghttp2_stream *stream) {
(stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK)));
}
static int check_scheme(const uint8_t *value, size_t len) {
const uint8_t *last;
if (len == 0) {
return 0;
}
if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) {
return 0;
}
last = value + len;
++value;
for (; value != last; ++value) {
if (!(('A' <= *value && *value <= 'Z') ||
('a' <= *value && *value <= 'z') ||
('0' <= *value && *value <= '9') || *value == '+' || *value == '-' ||
*value == '.')) {
return 0;
}
}
return 1;
}
static int lws(const uint8_t *s, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
if (s[i] != ' ' && s[i] != '\t') {
return 0;
}
}
return 1;
}
/* Same as the array in nghttp2_helper.c, but '@' is not allowed */
static const uint8_t VALID_AUTHORITY_CHARS[256] = {
['!'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1, [')'] = 1,
['*'] = 1, ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1,
['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1,
['9'] = 1, [':'] = 1, [';'] = 1, ['='] = 1, ['A'] = 1, ['B'] = 1, ['C'] = 1,
['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1, ['H'] = 1, ['I'] = 1, ['J'] = 1,
['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1, ['O'] = 1, ['P'] = 1, ['Q'] = 1,
['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1, ['V'] = 1, ['W'] = 1, ['X'] = 1,
['Y'] = 1, ['Z'] = 1, ['['] = 1, [']'] = 1, ['_'] = 1, ['a'] = 1, ['b'] = 1,
['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, ['h'] = 1, ['i'] = 1,
['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, ['o'] = 1, ['p'] = 1,
['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, ['v'] = 1, ['w'] = 1,
['x'] = 1, ['y'] = 1, ['z'] = 1, ['~'] = 1,
};
static int check_authority(const uint8_t *value, size_t len) {
const uint8_t *last;
for (last = value + len; value != last; ++value) {
if (!VALID_AUTHORITY_CHARS[*value]) {
return 0;
}
}
return 1;
}
static int check_header_value(const nghttp2_stream *stream,
const nghttp2_rcbuf *value) {
if (stream->flags &
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
return nghttp2_check_header_value(value->base, value->len);
}
return nghttp2_check_header_value_rfc9113(value->base, value->len);
}
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
int trailer, int connect_protocol) {
nghttp2_extpri extpri;
if (nv->name->base[0] == ':') {
if (trailer ||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
}
switch (nv->token) {
case NGHTTP2_TOKEN__AUTHORITY:
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
if (!check_authority(nv->value->base, nv->value->len) ||
!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
break;
case NGHTTP2_TOKEN__METHOD:
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
if (!nghttp2_check_method(nv->value->base, nv->value->len) ||
!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
switch (nv->value->len) {
@@ -149,7 +228,8 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
}
break;
case NGHTTP2_TOKEN__PATH:
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
if (!nghttp2_check_path(nv->value->base, nv->value->len) ||
!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if (nv->value->base[0] == '/') {
@@ -159,7 +239,8 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
}
break;
case NGHTTP2_TOKEN__SCHEME:
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
if (!check_scheme(nv->value->base, nv->value->len) ||
!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if ((nv->value->len == 4 && memieq("http", nv->value->base, 4)) ||
@@ -168,15 +249,28 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
}
break;
case NGHTTP2_TOKEN__PROTOCOL:
if (!connect_protocol) {
if (!connect_protocol ||
!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PROTOCOL)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PROTOCOL)) {
if (stream->flags &
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
/* Check the value consists of just white spaces, which was done
in check_pseudo_header before
nghttp2_check_header_value_rfc9113 has been introduced. */
if (lws(nv->value->base, nv->value->len) ||
!nghttp2_check_header_value(nv->value->base, nv->value->len)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
} else if (!nghttp2_check_header_value_rfc9113(nv->value->base,
nv->value->len)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
break;
case NGHTTP2_TOKEN_HOST:
if (!check_authority(nv->value->base, nv->value->len)) {
return NGHTTP2_ERR_IGN_HTTP_HEADER;
}
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
@@ -204,6 +298,13 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
}
break;
case NGHTTP2_TOKEN_PRIORITY:
if (!check_header_value(stream, nv->value)) {
stream->http_flags &= ~NGHTTP2_HTTP_FLAG_PRIORITY;
stream->http_flags |= NGHTTP2_HTTP_FLAG_BAD_PRIORITY;
return NGHTTP2_ERR_IGN_HTTP_HEADER;
}
if (!trailer &&
/* Do not parse the header field in PUSH_PROMISE. */
(stream->stream_id & 1) &&
@@ -214,7 +315,7 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
stream->http_extpri = nghttp2_extpri_to_uint8(&extpri);
stream->http_flags |= NGHTTP2_HTTP_FLAG_PRIORITY;
} else {
stream->http_flags &= (uint32_t)~NGHTTP2_HTTP_FLAG_PRIORITY;
stream->http_flags &= ~NGHTTP2_HTTP_FLAG_PRIORITY;
stream->http_flags |= NGHTTP2_HTTP_FLAG_BAD_PRIORITY;
}
}
@@ -223,33 +324,22 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
if (nv->name->base[0] == ':') {
return NGHTTP2_ERR_HTTP_HEADER;
}
}
if (nv->name->base[0] != ':') {
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
if (!check_header_value(stream, nv->value)) {
return NGHTTP2_ERR_IGN_HTTP_HEADER;
}
}
return 0;
}
static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
int trailer) {
if (nv->name->base[0] == ':') {
if (trailer ||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
}
static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv) {
switch (nv->token) {
case NGHTTP2_TOKEN__STATUS: {
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
if (nv->value->len != 3) {
return NGHTTP2_ERR_HTTP_HEADER;
}
stream->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len);
stream->status_code = parse_status_code(nv->value->base, nv->value->len);
if (stream->status_code == -1 || stream->status_code == 101) {
return NGHTTP2_ERR_HTTP_HEADER;
}
@@ -303,132 +393,18 @@ static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
if (nv->name->base[0] == ':') {
return NGHTTP2_ERR_HTTP_HEADER;
}
}
if (nv->name->base[0] != ':') {
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
if (!check_header_value(stream, nv->value)) {
return NGHTTP2_ERR_IGN_HTTP_HEADER;
}
}
return 0;
}
static int check_scheme(const uint8_t *value, size_t len) {
const uint8_t *last;
if (len == 0) {
return 0;
}
if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) {
return 0;
}
last = value + len;
++value;
for (; value != last; ++value) {
if (!(('A' <= *value && *value <= 'Z') ||
('a' <= *value && *value <= 'z') ||
('0' <= *value && *value <= '9') || *value == '+' || *value == '-' ||
*value == '.')) {
return 0;
}
}
return 1;
}
static int lws(const uint8_t *s, size_t n) {
size_t i;
for (i = 0; i < n; ++i) {
if (s[i] != ' ' && s[i] != '\t') {
return 0;
}
}
return 1;
}
/* Generated by genauthoritychartbl.py, but '@' is not allowed */
static char VALID_AUTHORITY_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */,
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */,
0 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */,
0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
};
static int check_authority(const uint8_t *value, size_t len) {
const uint8_t *last;
for (last = value + len; value != last; ++value) {
if (!VALID_AUTHORITY_CHARS[*value]) {
return 0;
}
}
return 1;
}
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
nghttp2_frame *frame, nghttp2_hd_nv *nv,
const nghttp2_frame *frame, nghttp2_hd_nv *nv,
int trailer) {
int rv;
/* We are strict for pseudo header field. One bad character should
lead to fail. OTOH, we should be a bit forgiving for regular
headers, since existing public internet has so much illegal
@@ -436,78 +412,30 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
this, we may disrupt many web sites and/or libraries. So we
become conservative here, and just ignore those illegal regular
headers. */
if (!nghttp2_check_header_name(nv->name->base, nv->name->len)) {
size_t i;
if (nv->name->len > 0 && nv->name->base[0] == ':') {
return NGHTTP2_ERR_HTTP_HEADER;
}
/* header field name must be lower-cased without exception */
for (i = 0; i < nv->name->len; ++i) {
uint8_t c = nv->name->base[i];
if ('A' <= c && c <= 'Z') {
return NGHTTP2_ERR_HTTP_HEADER;
}
}
/* When ignoring regular headers, we set this flag so that we
still enforce header field ordering rule for pseudo header
fields. */
if (nv->name->len == 0) {
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
return NGHTTP2_ERR_IGN_HTTP_HEADER;
}
switch (nv->token) {
case NGHTTP2_TOKEN__METHOD:
rv = nghttp2_check_method(nv->value->base, nv->value->len);
break;
case NGHTTP2_TOKEN__PATH:
rv = nghttp2_check_path(nv->value->base, nv->value->len);
break;
case NGHTTP2_TOKEN__AUTHORITY:
case NGHTTP2_TOKEN_HOST:
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
rv = check_authority(nv->value->base, nv->value->len);
} else if (
stream->flags &
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
} else {
rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
if (nv->name->base[0] == ':') {
/* pseudo header must have a valid token. */
if (nv->token == -1 || trailer ||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
return NGHTTP2_ERR_HTTP_HEADER;
}
break;
case NGHTTP2_TOKEN__SCHEME:
rv = check_scheme(nv->value->base, nv->value->len);
break;
case NGHTTP2_TOKEN__PROTOCOL:
/* Check the value consists of just white spaces, which was done
in check_pseudo_header before
nghttp2_check_header_value_rfc9113 has been introduced. */
if ((stream->flags &
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
lws(nv->value->base, nv->value->len)) {
rv = 0;
break;
}
/* fall through */
default:
if (stream->flags &
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
} else {
rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
} else {
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
switch (nghttp2_check_nonempty_header_name(nv->name->base, nv->name->len)) {
case 0:
return NGHTTP2_ERR_IGN_HTTP_HEADER;
case 2:
/* header field name must be lower-cased without exception */
return NGHTTP2_ERR_HTTP_HEADER;
}
}
if (rv == 0) {
assert(nv->name->len > 0);
if (nv->name->base[0] == ':') {
return NGHTTP2_ERR_HTTP_HEADER;
}
/* When ignoring regular headers, we set this flag so that we
still enforce header field ordering rule for pseudo header
fields. */
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
return NGHTTP2_ERR_IGN_HTTP_HEADER;
}
assert(nv->name->len > 0);
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
return http_request_on_header(stream, nv, trailer,
@@ -515,7 +443,7 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
session->pending_enable_connect_protocol);
}
return http_response_on_header(stream, nv, trailer);
return http_response_on_header(stream, nv);
}
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
@@ -570,7 +498,7 @@ int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
}
stream->http_flags =
stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
stream->http_flags & ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
if (!expect_response_body(stream)) {
stream->content_length = 0;
+1 -1
View File
@@ -48,7 +48,7 @@
* if it was not received because of compatibility reasons.
*/
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
nghttp2_frame *frame, nghttp2_hd_nv *nv,
const nghttp2_frame *frame, nghttp2_hd_nv *nv,
int trailer);
/*
-1
View File
@@ -39,7 +39,6 @@ typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
/* Internal error code. They must be in the range [-499, -100],
inclusive. */
typedef enum {
NGHTTP2_ERR_CREDENTIAL_PENDING = -101,
NGHTTP2_ERR_IGN_HEADER_BLOCK = -103,
NGHTTP2_ERR_IGN_PAYLOAD = -104,
/*
+133 -108
View File
@@ -33,12 +33,11 @@
#define NGHTTP2_INITIAL_HASHBITS 4
void nghttp2_map_init(nghttp2_map *map, uint32_t seed, nghttp2_mem *mem) {
map->mem = mem;
map->hashbits = 0;
map->table = NULL;
map->seed = seed;
map->size = 0;
void nghttp2_map_init(nghttp2_map *map, uint64_t seed, nghttp2_mem *mem) {
*map = (nghttp2_map){
.mem = mem,
.seed = seed,
};
}
void nghttp2_map_free(nghttp2_map *map) {
@@ -46,30 +45,27 @@ void nghttp2_map_free(nghttp2_map *map) {
return;
}
nghttp2_mem_free(map->mem, map->table);
nghttp2_mem_free(map->mem, map->keys);
}
int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr),
void *ptr) {
int rv;
size_t i;
nghttp2_map_bucket *bkt;
size_t tablelen;
if (map->size == 0) {
return 0;
}
tablelen = 1u << map->hashbits;
tablelen = (size_t)1 << map->hashbits;
for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
if (map->psl[i] == 0) {
continue;
}
rv = func(bkt->data, ptr);
rv = func(map->data[i], ptr);
if (rv != 0) {
return rv;
}
@@ -78,118 +74,158 @@ int nghttp2_map_each(const nghttp2_map *map, int (*func)(void *data, void *ptr),
return 0;
}
static size_t map_hash(const nghttp2_map *map, nghttp2_map_key_type key) {
/* hasher from
https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
We do not perform finalization here because we use top bits
anyway. */
uint32_t h = ((uint32_t)key + map->seed) * 0x93d765dd;
return (size_t)((h * 2654435769u) >> (32 - map->hashbits));
}
/* 64-bit finalizer (fmix64) from MurmurHash3 to maximize the output's
sensitivity to all input bits. */
#define NGHTTP2_MAP_HASHER1 0xFF51AFD7ED558CCDULL
#define NGHTTP2_MAP_HASHER2 0xC4CEB9FE1A85EC53ULL
static void map_bucket_swap(nghttp2_map_bucket *a, nghttp2_map_bucket *b) {
nghttp2_map_bucket c = *a;
*a = *b;
*b = c;
static size_t map_index(const nghttp2_map *map, nghttp2_map_key_type key) {
key ^= map->seed;
key ^= key >> 33;
key *= NGHTTP2_MAP_HASHER1;
key ^= key >> 33;
key *= NGHTTP2_MAP_HASHER2;
key ^= key >> 33;
return (size_t)(key >> (64 - map->hashbits));
}
#ifndef WIN32
void nghttp2_map_print_distance(const nghttp2_map *map) {
size_t i;
size_t idx;
nghttp2_map_bucket *bkt;
size_t tablelen;
if (map->size == 0) {
return;
}
tablelen = 1u << map->hashbits;
tablelen = (size_t)1 << map->hashbits;
for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
if (map->psl[i] == 0) {
fprintf(stderr, "@%zu <EMPTY>\n", i);
continue;
}
idx = map_hash(map, bkt->key);
fprintf(stderr, "@%zu hash=%zu key=%d base=%zu distance=%u\n", i,
map_hash(map, bkt->key), bkt->key, idx, bkt->psl);
idx = map_index(map, map->keys[i]);
fprintf(stderr, "@%zu key=%" PRIu64 " base=%zu distance=%zu\n", i,
map->keys[i], idx, map->psl[i] - 1);
}
}
#endif /* !defined(WIN32) */
static void map_set_entry(nghttp2_map *map, size_t idx,
nghttp2_map_key_type key, size_t psl, void *data) {
map->keys[idx] = key;
map->psl[idx] = psl;
map->data[idx] = data;
}
#define NGHTTP2_SWAP(TYPE, A, B) \
do { \
TYPE t = (TYPE) * (A); \
\
*(A) = *(B); \
*(B) = t; \
} while (0)
/*
* map_insert inserts |key| and |data| to |map|.
*
* It returns 0 if it succeeds, or one of the following negative error
* codes:
*
* NGHTTP2_ERR_INVALID_ARGUMENT
* The another data associated to |key| is already present.
*/
static int map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
size_t idx = map_hash(map, key);
nghttp2_map_bucket b = {
.key = key,
.data = data,
};
nghttp2_map_bucket *bkt;
size_t mask = (1u << map->hashbits) - 1;
size_t idx = map_index(map, key);
size_t mask = ((size_t)1 << map->hashbits) - 1;
size_t psl = 1;
size_t kpsl;
for (;;) {
bkt = &map->table[idx];
kpsl = map->psl[idx];
if (bkt->data == NULL) {
*bkt = b;
if (kpsl == 0) {
map_set_entry(map, idx, key, psl, data);
++map->size;
return 0;
}
if (b.psl > bkt->psl) {
map_bucket_swap(bkt, &b);
} else if (bkt->key == key) {
/* TODO This check is just a waste after first swap or if this
function is called from map_resize. That said, there is no
difference with or without this conditional in performance
wise. */
if (psl > kpsl) {
NGHTTP2_SWAP(nghttp2_map_key_type, &key, &map->keys[idx]);
NGHTTP2_SWAP(size_t, &psl, &map->psl[idx]);
NGHTTP2_SWAP(void *, &data, &map->data[idx]);
} else if (map->keys[idx] == key) {
/* This check ensures that no duplicate keys are inserted. But
it is just a waste after first swap or if this function is
called from map_resize. That said, there is no difference
with or without this conditional in performance wise. */
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
++b.psl;
++psl;
idx = (idx + 1) & mask;
}
}
/* NGHTTP2_MAP_MAX_HASHBITS is the maximum number of bits used for
hash table. The theoretical limit of the maximum number of keys
that can be stored is 1 << NGHTTP2_MAP_MAX_HASHBITS. */
#define NGHTTP2_MAP_MAX_HASHBITS (sizeof(size_t) * 8 - 1)
static int map_resize(nghttp2_map *map, size_t new_hashbits) {
size_t i;
nghttp2_map_bucket *bkt;
size_t tablelen;
int rv;
nghttp2_map new_map = {
.table = nghttp2_mem_calloc(map->mem, 1u << new_hashbits,
sizeof(nghttp2_map_bucket)),
.mem = map->mem,
.seed = map->seed,
.hashbits = new_hashbits,
};
void *buf;
int rv;
(void)rv;
if (new_map.table == NULL) {
if (new_hashbits > NGHTTP2_MAP_MAX_HASHBITS) {
return NGHTTP2_ERR_NOMEM;
}
tablelen = (size_t)1 << new_hashbits;
buf = nghttp2_mem_calloc(map->mem, tablelen,
sizeof(nghttp2_map_key_type) + sizeof(size_t) +
sizeof(void *));
if (!buf) {
return NGHTTP2_ERR_NOMEM;
}
new_map.keys = buf;
new_map.psl = (size_t *)(void *)((uint8_t *)new_map.keys +
tablelen * sizeof(nghttp2_map_key_type));
new_map.data = (void *)((uint8_t *)new_map.psl + tablelen * sizeof(size_t));
if (map->size) {
tablelen = 1u << map->hashbits;
tablelen = (size_t)1 << map->hashbits;
for (i = 0; i < tablelen; ++i) {
bkt = &map->table[i];
if (bkt->data == NULL) {
if (map->psl[i] == 0) {
continue;
}
rv = map_insert(&new_map, bkt->key, bkt->data);
rv = map_insert(&new_map, map->keys[i], map->data[i]);
/* map_insert must not fail because all keys are unique during
resize. */
assert(0 == rv);
}
}
nghttp2_mem_free(map->mem, map->table);
map->table = new_map.table;
nghttp2_mem_free(map->mem, map->keys);
map->keys = new_map.keys;
map->psl = new_map.psl;
map->data = new_map.data;
map->hashbits = new_hashbits;
return 0;
@@ -197,56 +233,47 @@ static int map_resize(nghttp2_map *map, size_t new_hashbits) {
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
int rv;
size_t tablelen;
assert(data);
/* Load factor is 7/8 */
/* Under the very initial condition, that is map->size == 0 and
map->hashbits == 0, 8 > 7 still holds nicely. */
if ((map->size + 1) * 8 > (1u << map->hashbits) * 7) {
if (map->hashbits) {
rv = map_resize(map, map->hashbits + 1);
if (rv != 0) {
return rv;
}
} else {
rv = map_resize(map, NGHTTP2_INITIAL_HASHBITS);
if (rv != 0) {
return rv;
}
/* tablelen is incorrect if map->hashbits == 0 which leads to
tablelen = 1, but it is only used to check the load factor, and
it works in this special case. */
tablelen = (size_t)1 << map->hashbits;
/* Load factor is 7 / 8. Because tablelen is power of 2, (tablelen
- (tablelen >> 3)) computes tablelen * 7 / 8. */
if (map->size + 1 >= (tablelen - (tablelen >> 3))) {
rv = map_resize(map, map->hashbits ? map->hashbits + 1
: NGHTTP2_INITIAL_HASHBITS);
if (rv != 0) {
return rv;
}
}
rv = map_insert(map, key, data);
if (rv != 0) {
return rv;
}
return 0;
return map_insert(map, key, data);
}
void *nghttp2_map_find(const nghttp2_map *map, nghttp2_map_key_type key) {
size_t idx;
nghttp2_map_bucket *bkt;
size_t psl = 0;
size_t psl = 1;
size_t mask;
if (map->size == 0) {
return NULL;
}
idx = map_hash(map, key);
mask = (1u << map->hashbits) - 1;
idx = map_index(map, key);
mask = ((size_t)1 << map->hashbits) - 1;
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL || psl > bkt->psl) {
if (psl > map->psl[idx]) {
return NULL;
}
if (bkt->key == key) {
return bkt->data;
if (map->keys[idx] == key) {
return map->data[idx];
}
++psl;
@@ -256,38 +283,36 @@ void *nghttp2_map_find(const nghttp2_map *map, nghttp2_map_key_type key) {
int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
size_t idx;
nghttp2_map_bucket *b, *bkt;
size_t psl = 0;
size_t dest;
size_t psl = 1, kpsl;
size_t mask;
if (map->size == 0) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
idx = map_hash(map, key);
mask = (1u << map->hashbits) - 1;
idx = map_index(map, key);
mask = ((size_t)1 << map->hashbits) - 1;
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL || psl > bkt->psl) {
if (psl > map->psl[idx]) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
if (bkt->key == key) {
b = bkt;
if (map->keys[idx] == key) {
dest = idx;
idx = (idx + 1) & mask;
for (;;) {
bkt = &map->table[idx];
if (bkt->data == NULL || bkt->psl == 0) {
b->data = NULL;
kpsl = map->psl[idx];
if (kpsl <= 1) {
map->psl[dest] = 0;
break;
}
--bkt->psl;
*b = *bkt;
b = bkt;
map_set_entry(map, dest, map->keys[idx], kpsl - 1, map->data[idx]);
dest = idx;
idx = (idx + 1) & mask;
}
@@ -307,7 +332,7 @@ void nghttp2_map_clear(nghttp2_map *map) {
return;
}
memset(map->table, 0, sizeof(*map->table) * (1u << map->hashbits));
memset(map->psl, 0, sizeof(*map->psl) * ((size_t)1 << map->hashbits));
map->size = 0;
}
+9 -10
View File
@@ -36,18 +36,17 @@
/* Implementation of unordered map */
typedef int32_t nghttp2_map_key_type;
typedef struct nghttp2_map_bucket {
uint32_t psl;
nghttp2_map_key_type key;
void *data;
} nghttp2_map_bucket;
typedef uint64_t nghttp2_map_key_type;
typedef struct nghttp2_map {
nghttp2_map_bucket *table;
nghttp2_map_key_type *keys;
/* psl is the Probe Sequence Length. 0 has special meaning that the
element is not stored at i-th position if psl[i] == 0. Because
of this, the actual psl value is psl[i] - 1 if psl[i] > 0. */
size_t *psl;
void **data;
nghttp2_mem *mem;
uint32_t seed;
uint64_t seed;
size_t size;
size_t hashbits;
} nghttp2_map;
@@ -55,7 +54,7 @@ typedef struct nghttp2_map {
/*
* nghttp2_map_init initializes the map |map|.
*/
void nghttp2_map_init(nghttp2_map *map, uint32_t seed, nghttp2_mem *mem);
void nghttp2_map_init(nghttp2_map *map, uint64_t seed, nghttp2_mem *mem);
/*
* nghttp2_map_free deallocates any resources allocated for |map|.
+6 -2
View File
@@ -48,8 +48,12 @@ static void *default_realloc(void *ptr, size_t size, void *mem_user_data) {
return realloc(ptr, size);
}
static nghttp2_mem mem_default = {NULL, default_malloc, default_free,
default_calloc, default_realloc};
static nghttp2_mem mem_default = {
.malloc = default_malloc,
.free = default_free,
.calloc = default_calloc,
.realloc = default_realloc,
};
nghttp2_mem *nghttp2_mem_default(void) { return &mem_default; }
+8 -46
View File
@@ -40,52 +40,14 @@
#include <nghttp2/nghttp2.h>
#ifdef WIN32
/* Windows requires ws2_32 library for ntonl family functions. We
define inline functions for those function so that we don't have
dependency on that lib. */
# ifdef _MSC_VER
# define STIN static __inline
# else /* !defined(_MSC_VER) */
# define STIN static inline
# endif /* !defined(_MSC_VER) */
STIN uint32_t htonl(uint32_t hostlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&res;
*p++ = (unsigned char)(hostlong >> 24);
*p++ = (hostlong >> 16) & 0xffu;
*p++ = (hostlong >> 8) & 0xffu;
*p = hostlong & 0xffu;
return res;
}
STIN uint16_t htons(uint16_t hostshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&res;
*p++ = (unsigned char)(hostshort >> 8);
*p = hostshort & 0xffu;
return res;
}
STIN uint32_t ntohl(uint32_t netlong) {
uint32_t res;
unsigned char *p = (unsigned char *)&netlong;
res = (uint32_t)(*p++ << 24);
res += (uint32_t)(*p++ << 16);
res += (uint32_t)(*p++ << 8);
res += *p;
return res;
}
STIN uint16_t ntohs(uint16_t netshort) {
uint16_t res;
unsigned char *p = (unsigned char *)&netshort;
res = (uint16_t)(*p++ << 8);
res += *p;
return res;
}
/* Windows requires ws2_32 library for ntonl family of functions.
Instead of using them, use _byteswap_* functions. This is fine
because all platforms that can run Windows these days are little
endian. */
# define htonl(N) _byteswap_ulong(N)
# define htons(N) _byteswap_ushort(N)
# define ntohl(N) _byteswap_ulong(N)
# define ntohs(N) _byteswap_ushort(N)
#endif /* defined(WIN32) */
#endif /* !defined(NGHTTP2_NET_H) */
+6
View File
@@ -162,3 +162,9 @@ void nghttp2_option_set_glitch_rate_limit(nghttp2_option *option,
option->glitch_burst = burst;
option->glitch_rate = rate;
}
void nghttp2_option_set_max_outbound_queue_size(nghttp2_option *option,
size_t val) {
option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_QUEUE_SIZE;
option->max_outbound_queue_size = val;
}
+46 -42
View File
@@ -34,46 +34,46 @@
/**
* Configuration options
*/
typedef enum {
/**
* This option prevents the library from sending WINDOW_UPDATE for a
* connection automatically. If this option is set to nonzero, the
* library won't send WINDOW_UPDATE for DATA until application calls
* nghttp2_session_consume() to indicate the amount of consumed
* DATA. By default, this option is set to zero.
*/
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1,
/**
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
* remote endpoint as if it is received in SETTINGS frame. Without
* specifying this option, before the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
* endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may
* cause problem if local endpoint submits lots of requests
* initially and sending them at once to the remote peer may lead to
* the rejection of some requests. Specifying this option to the
* sensible value, say 100, may avoid this kind of issue. This value
* will be overwritten if the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
*/
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5,
NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6,
NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7,
NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8,
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 13,
NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 14,
NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT = 1 << 15,
NGHTTP2_OPT_MAX_CONTINUATIONS = 1 << 16,
NGHTTP2_OPT_GLITCH_RATE_LIMIT = 1 << 17,
} nghttp2_option_flag;
/**
* This option prevents the library from sending WINDOW_UPDATE for a
* connection automatically. If this option is set to nonzero, the
* library won't send WINDOW_UPDATE for DATA until application calls
* nghttp2_session_consume() to indicate the amount of consumed DATA.
* By default, this option is set to zero.
*/
#define NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE 0x01U
/**
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
* remote endpoint as if it is received in SETTINGS frame. Without
* specifying this option, before the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
* endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may
* cause problem if local endpoint submits lots of requests initially
* and sending them at once to the remote peer may lead to the
* rejection of some requests. Specifying this option to the sensible
* value, say 100, may avoid this kind of issue. This value will be
* overwritten if the local endpoint receives
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
*/
#define NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS 0x02U
#define NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC 0x04U
#define NGHTTP2_OPT_NO_HTTP_MESSAGING 0x08U
#define NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS 0x10U
#define NGHTTP2_OPT_USER_RECV_EXT_TYPES 0x20U
#define NGHTTP2_OPT_NO_AUTO_PING_ACK 0x40U
#define NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES 0x80U
#define NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH 0x0100U
#define NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE 0x0200U
#define NGHTTP2_OPT_NO_CLOSED_STREAMS 0x0400U
#define NGHTTP2_OPT_MAX_OUTBOUND_ACK 0x0800U
#define NGHTTP2_OPT_MAX_SETTINGS 0x1000U
#define NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES 0x2000U
#define NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION 0x4000U
#define NGHTTP2_OPT_STREAM_RESET_RATE_LIMIT 0x8000U
#define NGHTTP2_OPT_MAX_CONTINUATIONS 0x010000U
#define NGHTTP2_OPT_GLITCH_RATE_LIMIT 0x020000U
#define NGHTTP2_OPT_MAX_OUTBOUND_QUEUE_SIZE 0x040000U
/**
* Struct to store option values for nghttp2_session.
@@ -110,8 +110,12 @@ struct nghttp2_option {
*/
size_t max_continuations;
/**
* Bitwise OR of nghttp2_option_flag to determine that which fields
* are specified.
* NGHTTP2_OPT_MAX_OUTBOUND_QUEUE_SIZE
*/
size_t max_outbound_queue_size;
/**
* Bitwise OR of NGHTTP2_OPT_* values to determine which fields are
* specified.
*/
uint32_t opt_set_mask;
/**
+21 -6
View File
@@ -34,8 +34,10 @@ nghttp2_data_provider_wrap_v1(nghttp2_data_provider_wrap *dpw,
return NULL;
}
dpw->version = NGHTTP2_DATA_PROVIDER_V1;
dpw->data_prd.v1 = *data_prd;
*dpw = (nghttp2_data_provider_wrap){
.version = NGHTTP2_DATA_PROVIDER_V1,
.data_prd.v1 = *data_prd,
};
return dpw;
}
@@ -47,12 +49,26 @@ nghttp2_data_provider_wrap_v2(nghttp2_data_provider_wrap *dpw,
return NULL;
}
dpw->version = NGHTTP2_DATA_PROVIDER_V2;
dpw->data_prd.v2 = *data_prd;
*dpw = (nghttp2_data_provider_wrap){
.version = NGHTTP2_DATA_PROVIDER_V2,
.data_prd.v2 = *data_prd,
};
return dpw;
}
int nghttp2_data_provider_wrap_contains_read_callback(
const nghttp2_data_provider_wrap *dpw) {
switch (dpw->version) {
case NGHTTP2_DATA_PROVIDER_V1:
return dpw->data_prd.v1.read_callback != NULL;
case NGHTTP2_DATA_PROVIDER_V2:
return dpw->data_prd.v2.read_callback != NULL;
default:
return 0;
}
}
void nghttp2_outbound_item_init(nghttp2_outbound_item *item) {
item->cycle = 0;
item->qnext = NULL;
@@ -127,8 +143,7 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
}
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q) {
q->head = q->tail = NULL;
q->n = 0;
*q = (nghttp2_outbound_queue){0};
}
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
+12 -4
View File
@@ -39,10 +39,6 @@
typedef struct nghttp2_data_provider_wrap {
int version;
union {
struct {
nghttp2_data_source source;
void *read_callback;
};
nghttp2_data_provider v1;
nghttp2_data_provider2 v2;
} data_prd;
@@ -56,6 +52,11 @@ nghttp2_data_provider_wrap *
nghttp2_data_provider_wrap_v2(nghttp2_data_provider_wrap *dpw,
const nghttp2_data_provider2 *data_prd);
/* nghttp2_data_provider_wrap_contains_read_callback returns nonzero
if |dpw| contains read_callback in either version. */
int nghttp2_data_provider_wrap_contains_read_callback(
const nghttp2_data_provider_wrap *dpw);
/* struct used for HEADERS and PUSH_PROMISE frame */
typedef struct {
nghttp2_data_provider_wrap dpw;
@@ -110,6 +111,12 @@ typedef struct {
uint8_t flags;
} nghttp2_goaway_aux_data;
typedef struct {
/* nonzero if RST_STREAM should be sent even if stream is not
found. */
uint8_t continue_without_stream;
} nghttp2_rst_stream_aux_data;
/* struct used for extension frame */
typedef struct {
/* nonzero if this extension frame is serialized by library
@@ -122,6 +129,7 @@ typedef union {
nghttp2_data_aux_data data;
nghttp2_headers_aux_data headers;
nghttp2_goaway_aux_data goaway;
nghttp2_rst_stream_aux_data rst_stream;
nghttp2_ext_aux_data ext;
} nghttp2_aux_data;
+4 -5
View File
@@ -30,11 +30,10 @@
#include "nghttp2_helper.h"
void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
pq->mem = mem;
pq->capacity = 0;
pq->q = NULL;
pq->length = 0;
pq->less = less;
*pq = (nghttp2_pq){
.mem = mem,
.less = less,
};
}
void nghttp2_pq_free(nghttp2_pq *pq) {
+8 -6
View File
@@ -27,15 +27,17 @@
void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
int32_t stream_id, int32_t weight,
int exclusive) {
pri_spec->stream_id = stream_id;
pri_spec->weight = weight;
pri_spec->exclusive = exclusive != 0;
*pri_spec = (nghttp2_priority_spec){
.stream_id = stream_id,
.weight = weight,
.exclusive = exclusive != 0,
};
}
void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec) {
pri_spec->stream_id = 0;
pri_spec->weight = NGHTTP2_DEFAULT_WEIGHT;
pri_spec->exclusive = 0;
*pri_spec = (nghttp2_priority_spec){
.weight = NGHTTP2_DEFAULT_WEIGHT,
};
}
int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec) {
+4 -5
View File
@@ -27,9 +27,7 @@
#include <string.h>
#include <assert.h>
void nghttp2_queue_init(nghttp2_queue *queue) {
queue->front = queue->back = NULL;
}
void nghttp2_queue_init(nghttp2_queue *queue) { *queue = (nghttp2_queue){0}; }
void nghttp2_queue_free(nghttp2_queue *queue) {
if (!queue) {
@@ -50,8 +48,9 @@ int nghttp2_queue_push(nghttp2_queue *queue, void *data) {
if (!new_cell) {
return NGHTTP2_ERR_NOMEM;
}
new_cell->data = data;
new_cell->next = NULL;
*new_cell = (nghttp2_queue_cell){
.data = data,
};
if (queue->back) {
queue->back->next = new_cell;
queue->back = new_cell;
+5 -3
View File
@@ -26,9 +26,11 @@
#include "nghttp2_helper.h"
void nghttp2_ratelim_init(nghttp2_ratelim *rl, uint64_t burst, uint64_t rate) {
rl->val = rl->burst = burst;
rl->rate = rate;
rl->tstamp = 0;
*rl = (nghttp2_ratelim){
.burst = burst,
.rate = rate,
.val = burst,
};
}
void nghttp2_ratelim_update(nghttp2_ratelim *rl, uint64_t tstamp) {
+7 -5
View File
@@ -41,11 +41,13 @@ int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size,
*rcbuf_ptr = (void *)p;
(*rcbuf_ptr)->mem_user_data = mem->mem_user_data;
(*rcbuf_ptr)->free = mem->free;
(*rcbuf_ptr)->base = p + sizeof(nghttp2_rcbuf);
(*rcbuf_ptr)->len = size;
(*rcbuf_ptr)->ref = 1;
**rcbuf_ptr = (nghttp2_rcbuf){
.mem_user_data = mem->mem_user_data,
.free = mem->free,
.base = p + sizeof(nghttp2_rcbuf),
.len = size,
.ref = 1,
};
return 0;
}
+368 -125
View File
@@ -285,7 +285,8 @@ nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
int32_t stream_id) {
nghttp2_stream *stream;
stream = (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id);
stream = (nghttp2_stream *)nghttp2_map_find(&session->streams,
(nghttp2_map_key_type)stream_id);
if (stream == NULL || (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) ||
stream->state == NGHTTP2_STREAM_IDLE) {
@@ -297,7 +298,8 @@ nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
int32_t stream_id) {
return (nghttp2_stream *)nghttp2_map_find(&session->streams, stream_id);
return (nghttp2_stream *)nghttp2_map_find(&session->streams,
(nghttp2_map_key_type)stream_id);
}
static void session_inbound_frame_reset(nghttp2_session *session) {
@@ -392,13 +394,15 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
}
static void init_settings(nghttp2_settings_storage *settings) {
settings->header_table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
settings->enable_push = 1;
settings->max_concurrent_streams = NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS;
settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN;
settings->max_header_list_size = UINT32_MAX;
settings->no_rfc7540_priorities = UINT32_MAX;
*settings = (nghttp2_settings_storage){
.header_table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE,
.enable_push = 1,
.max_concurrent_streams = NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS,
.initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE,
.max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN,
.max_header_list_size = UINT32_MAX,
.no_rfc7540_priorities = UINT32_MAX,
};
}
static void active_outbound_item_reset(nghttp2_active_outbound_item *aob,
@@ -438,7 +442,7 @@ static int session_new(nghttp2_session **session_ptr,
size_t max_deflate_dynamic_table_size =
NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
size_t i;
uint32_t map_seed;
uint64_t map_seed;
if (mem == NULL) {
mem = nghttp2_mem_default();
@@ -496,6 +500,8 @@ static int session_new(nghttp2_session **session_ptr,
(*session_ptr)->max_outbound_ack = NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM;
(*session_ptr)->max_settings = NGHTTP2_DEFAULT_MAX_SETTINGS;
(*session_ptr)->max_continuations = NGHTTP2_DEFAULT_MAX_CONTINUATIONS;
(*session_ptr)->max_outbound_queue_size =
NGHTTP2_DEFAULT_MAX_OUTBOUND_QUEUE_SIZE;
if (option) {
if ((option->opt_set_mask & NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE) &&
@@ -576,6 +582,10 @@ static int session_new(nghttp2_session **session_ptr,
nghttp2_ratelim_init(&(*session_ptr)->glitch_ratelim,
option->glitch_burst, option->glitch_rate);
}
if (option->opt_set_mask & NGHTTP2_OPT_MAX_OUTBOUND_QUEUE_SIZE) {
(*session_ptr)->max_outbound_queue_size = option->max_outbound_queue_size;
}
}
rv = nghttp2_hd_deflate_init2(&(*session_ptr)->hd_deflater,
@@ -1051,7 +1061,6 @@ int nghttp2_session_add_item(nghttp2_session *session,
nghttp2_outbound_queue_push(&session->ob_syn, item);
item->queued = 1;
return 0;
;
}
nghttp2_outbound_queue_push(&session->ob_reg, item);
@@ -1189,6 +1198,10 @@ int nghttp2_session_add_rst_stream_continue(nghttp2_session *session,
frame = &item->frame;
nghttp2_frame_rst_stream_init(&frame->rst_stream, stream_id, error_code);
item->aux_data.rst_stream.continue_without_stream =
(uint8_t)(continue_without_stream != 0);
rv = nghttp2_session_add_item(session, item);
if (rv != 0) {
nghttp2_frame_rst_stream_free(&frame->rst_stream);
@@ -1240,7 +1253,8 @@ nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
stream_user_data);
stream->seq = session->stream_seq++;
rv = nghttp2_map_insert(&session->streams, stream_id, stream);
rv = nghttp2_map_insert(&session->streams, (nghttp2_map_key_type)stream_id,
stream);
if (rv != 0) {
nghttp2_stream_free(stream);
nghttp2_mem_free(mem, stream);
@@ -1361,7 +1375,8 @@ void nghttp2_session_destroy_stream(nghttp2_session *session,
session_ob_data_remove(session, stream);
}
nghttp2_map_remove(&session->streams, stream->stream_id);
nghttp2_map_remove(&session->streams,
(nghttp2_map_key_type)stream->stream_id);
nghttp2_stream_free(stream);
nghttp2_mem_free(mem, stream);
}
@@ -1976,9 +1991,9 @@ static int session_prep_frame(nghttp2_session *session,
rv = nghttp2_session_predicate_data_send(session, stream);
if (rv != 0) {
// If stream was already closed, nghttp2_session_get_stream()
// returns NULL, but item is still attached to the stream.
// Search stream including closed again.
/* If stream was already closed, nghttp2_session_get_stream()
returns NULL, but item is still attached to the stream.
Search stream including closed again. */
stream = nghttp2_session_get_stream_raw(session, frame->hd.stream_id);
if (stream) {
session_detach_stream_item(session, stream);
@@ -2141,6 +2156,12 @@ static int session_prep_frame(nghttp2_session *session,
if (session_is_closing(session)) {
return NGHTTP2_ERR_SESSION_CLOSING;
}
if (!item->aux_data.rst_stream.continue_without_stream &&
!nghttp2_session_get_stream(session, frame->rst_stream.hd.stream_id)) {
return NGHTTP2_ERR_STREAM_CLOSED;
}
nghttp2_frame_pack_rst_stream(&session->aob.framebufs, &frame->rst_stream);
return 0;
case NGHTTP2_SETTINGS: {
@@ -2499,13 +2520,6 @@ static int session_after_frame_sent1(nghttp2_session *session) {
aux_data = &item->aux_data.data;
stream = nghttp2_session_get_stream(session, frame->hd.stream_id);
/* We update flow control window after a frame was completely
sent. This is possible because we choose payload length not to
exceed the window */
session->remote_window_size -= (int32_t)frame->hd.length;
if (stream) {
stream->remote_window_size -= (int32_t)frame->hd.length;
}
if (stream && aux_data->eof) {
session_detach_stream_item(session, stream);
@@ -2584,7 +2598,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
}
/* We assume aux_data is a pointer to nghttp2_headers_aux_data */
aux_data = &item->aux_data.headers;
if (aux_data->dpw.data_prd.read_callback) {
if (nghttp2_data_provider_wrap_contains_read_callback(&aux_data->dpw)) {
/* nghttp2_submit_data_shared() makes a copy of
aux_data->dpw */
rv = nghttp2_submit_data_shared(session, NGHTTP2_FLAG_END_STREAM,
@@ -2615,7 +2629,7 @@ static int session_after_frame_sent1(nghttp2_session *session) {
}
/* We assume aux_data is a pointer to nghttp2_headers_aux_data */
aux_data = &item->aux_data.headers;
if (aux_data->dpw.data_prd.read_callback) {
if (nghttp2_data_provider_wrap_contains_read_callback(&aux_data->dpw)) {
rv = nghttp2_submit_data_shared(session, NGHTTP2_FLAG_END_STREAM,
frame->hd.stream_id, &aux_data->dpw);
if (nghttp2_is_fatal(rv)) {
@@ -2795,7 +2809,10 @@ static int session_call_send_data(nghttp2_session *session,
aux_data = &item->aux_data.data;
rv = session->callbacks.send_data_callback(session, frame, buf->pos, length,
&aux_data->dpw.data_prd.source,
/* This is fine because
of Common Initial
Sequence rule. */
&aux_data->dpw.data_prd.v2.source,
session->user_data);
switch (rv) {
@@ -2809,6 +2826,20 @@ static int session_call_send_data(nghttp2_session *session,
}
}
static void session_update_remote_window(nghttp2_session *session,
int32_t stream_id, size_t datalen) {
nghttp2_stream *stream;
session->remote_window_size -= (int32_t)datalen;
stream = nghttp2_session_get_stream(session, stream_id);
if (!stream) {
return;
}
stream->remote_window_size -= (int32_t)datalen;
}
static nghttp2_ssize nghttp2_session_mem_send_internal(nghttp2_session *session,
const uint8_t **data_ptr,
int fast_cb) {
@@ -2853,8 +2884,12 @@ static nghttp2_ssize nghttp2_session_mem_send_internal(nghttp2_session *session,
nghttp2_frame *frame = &item->frame;
/* The library is responsible for the transmission of
WINDOW_UPDATE frame, so we don't call error callback for
it. */
it. As for RST_STREAM, if it is not sent due to missing
stream, we also do not call error callback because it may
cause a lot of noises.*/
if (frame->hd.type != NGHTTP2_WINDOW_UPDATE &&
(frame->hd.type != NGHTTP2_RST_STREAM ||
rv != NGHTTP2_ERR_STREAM_CLOSED) &&
session->callbacks.on_frame_not_send_callback(
session, frame, rv, session->user_data) != 0) {
nghttp2_outbound_item_free(item, mem);
@@ -3063,6 +3098,9 @@ static nghttp2_ssize nghttp2_session_mem_send_internal(nghttp2_session *session,
return 0;
}
session_update_remote_window(session, frame->hd.stream_id,
frame->hd.length);
pause = (rv == NGHTTP2_ERR_PAUSE);
rv = session_after_frame_sent1(session);
@@ -3112,6 +3150,7 @@ nghttp2_ssize nghttp2_session_mem_send2(nghttp2_session *session,
const uint8_t **data_ptr) {
int rv;
nghttp2_ssize len;
const nghttp2_frame *frame;
*data_ptr = NULL;
@@ -3121,6 +3160,14 @@ nghttp2_ssize nghttp2_session_mem_send2(nghttp2_session *session,
}
if (session->aob.item) {
frame = &session->aob.item->frame;
if (frame->hd.type == NGHTTP2_DATA &&
(size_t)len == NGHTTP2_FRAME_HDLEN + frame->hd.length) {
session_update_remote_window(session, frame->hd.stream_id,
frame->hd.length);
}
/* We have to call session_after_frame_sent1 here to handle stream
closure upon transmission of frames. Otherwise, END_STREAM may
be reached to client before we call nghttp2_session_mem_send
@@ -3140,6 +3187,7 @@ int nghttp2_session_send(nghttp2_session *session) {
nghttp2_ssize datalen;
nghttp2_ssize sentlen;
nghttp2_bufs *framebufs;
const nghttp2_frame *frame;
framebufs = &session->aob.framebufs;
@@ -3164,6 +3212,17 @@ int nghttp2_session_send(nghttp2_session *session) {
}
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
if (sentlen > 0 && session->aob.item) {
frame = &session->aob.item->frame;
if (frame->hd.type == NGHTTP2_DATA &&
(size_t)datalen == NGHTTP2_FRAME_HDLEN + frame->hd.length) {
session_update_remote_window(session, frame->hd.stream_id,
frame->hd.length);
}
}
/* Rewind the offset to the amount of unsent bytes */
framebufs->cur->buf.pos -= datalen - sentlen;
}
@@ -3501,6 +3560,7 @@ static int session_inflate_handle_invalid_connection(nghttp2_session *session,
static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
size_t *readlen_ptr, uint8_t *in, size_t inlen,
int final, int call_header_cb) {
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_ssize proclen;
int rv;
int inflate_flags;
@@ -3631,8 +3691,23 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
return rv;
}
return nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR);
rv =
session_handle_invalid_stream2(session, subject_stream->stream_id,
frame, NGHTTP2_ERR_HTTP_HEADER);
if (nghttp2_is_fatal(rv)) {
return rv;
}
rv = session_update_glitch_ratelim(session);
if (rv != 0) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return 0;
}
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
}
if (rv == 0) {
@@ -3701,6 +3776,7 @@ static int session_end_stream_headers_received(nghttp2_session *session,
static int session_after_header_block_received(nghttp2_session *session) {
int rv = 0;
nghttp2_frame *frame = &session->iframe.frame;
nghttp2_inbound_frame *iframe = &session->iframe;
nghttp2_stream *stream;
/* We don't call on_frame_recv_callback if stream has been closed
@@ -3745,7 +3821,37 @@ static int session_after_header_block_received(nghttp2_session *session) {
}
}
if (rv != 0) {
return nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR);
int32_t stream_id;
if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
stream_id = frame->push_promise.promised_stream_id;
} else {
stream_id = frame->hd.stream_id;
}
rv = session_handle_invalid_stream2(session, stream_id, frame,
NGHTTP2_ERR_HTTP_MESSAGING);
if (nghttp2_is_fatal(rv)) {
return rv;
}
rv = session_update_glitch_ratelim(session);
if (rv != 0) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return 0;
}
if (frame->hd.type == NGHTTP2_HEADERS &&
(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) {
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
/* Don't call nghttp2_session_close_stream_if_shut_rdwr
because RST_STREAM has been submitted. */
}
return 0;
}
}
@@ -3957,6 +4063,22 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_ERR_STREAM_CLOSED, "HEADERS: stream closed");
}
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) &&
(session->server || stream->status_code / 100 == 2)) {
rv = session_update_glitch_ratelim(session);
if (rv != 0) {
return rv;
}
if (session->iframe.state == NGHTTP2_IB_IGN_ALL) {
return 0;
}
return session_inflate_handle_invalid_stream(session, frame,
NGHTTP2_ERR_PROTO);
}
if (nghttp2_session_is_my_stream_id(session, frame->hd.stream_id)) {
if (stream->state == NGHTTP2_STREAM_OPENED) {
rv = session_call_on_begin_headers(session, frame);
@@ -4113,14 +4235,13 @@ static int update_remote_initial_window_size_func(void *entry, void *ptr) {
static int
session_update_remote_initial_window_size(nghttp2_session *session,
int32_t new_initial_window_size) {
nghttp2_update_window_size_arg arg;
arg.session = session;
arg.new_window_size = new_initial_window_size;
arg.old_window_size = (int32_t)session->remote_settings.initial_window_size;
return nghttp2_map_each(&session->streams,
update_remote_initial_window_size_func, &arg);
return nghttp2_map_each(
&session->streams, update_remote_initial_window_size_func,
&(nghttp2_update_window_size_arg){
.session = session,
.new_window_size = new_initial_window_size,
.old_window_size = (int32_t)session->remote_settings.initial_window_size,
});
}
static int update_local_initial_window_size_func(void *entry, void *ptr) {
@@ -4135,6 +4256,11 @@ static int update_local_initial_window_size_func(void *entry, void *ptr) {
return NGHTTP2_ERR_FLOW_CONTROL;
}
if ((int64_t)stream->local_window_size - (int64_t)stream->recv_window_size >
NGHTTP2_MAX_WINDOW_SIZE) {
return NGHTTP2_ERR_FLOW_CONTROL;
}
if (stream->window_update_queued) {
return 0;
}
@@ -4173,12 +4299,13 @@ static int
session_update_local_initial_window_size(nghttp2_session *session,
int32_t new_initial_window_size,
int32_t old_initial_window_size) {
nghttp2_update_window_size_arg arg;
arg.session = session;
arg.new_window_size = new_initial_window_size;
arg.old_window_size = old_initial_window_size;
return nghttp2_map_each(&session->streams,
update_local_initial_window_size_func, &arg);
update_local_initial_window_size_func,
&(nghttp2_update_window_size_arg){
.session = session,
.new_window_size = new_initial_window_size,
.old_window_size = old_initial_window_size,
});
}
/*
@@ -4568,6 +4695,13 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
session, frame, NGHTTP2_ERR_STREAM_CLOSED, "PUSH_PROMISE: stream closed");
}
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) &&
stream->status_code / 100 == 2) {
return session_inflate_handle_invalid_connection(
session, frame, NGHTTP2_ERR_PROTO,
"PUSH_PROMISE: not allowed in CONNECT stream");
}
promised_stream = nghttp2_session_open_stream(
session, frame->push_promise.promised_stream_id, NGHTTP2_STREAM_FLAG_NONE,
NGHTTP2_STREAM_RESERVED, NULL);
@@ -4834,6 +4968,12 @@ int nghttp2_session_on_priority_update_received(nghttp2_session *session,
"PRIORITY_UPDATE: max concurrent streams exceeded");
}
if (session->num_idle_streams + session->num_incoming_streams >=
session->pending_local_max_concurrent_stream) {
/* Ignore priority hints for excessive streams. */
return session_call_on_frame_received(session, frame);
}
stream =
nghttp2_session_open_stream(session, priority_update->stream_id,
NGHTTP2_FLAG_NONE, NGHTTP2_STREAM_IDLE, NULL);
@@ -4931,6 +5071,7 @@ int nghttp2_session_on_data_received(nghttp2_session *session,
nghttp2_frame *frame) {
int rv = 0;
nghttp2_stream *stream;
nghttp2_inbound_frame *iframe = &session->iframe;
/* We don't call on_frame_recv_callback if stream has been closed
already or being closed. */
@@ -4945,7 +5086,27 @@ int nghttp2_session_on_data_received(nghttp2_session *session,
if (session_enforce_http_messaging(session) &&
(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) {
if (nghttp2_http_on_remote_end_stream(stream) != 0) {
return nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR);
rv = session_handle_invalid_stream2(session, stream->stream_id, frame,
NGHTTP2_ERR_HTTP_MESSAGING);
if (nghttp2_is_fatal(rv)) {
return rv;
}
rv = session_update_glitch_ratelim(session);
if (rv != 0) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return 0;
}
nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
/* Don't call nghttp2_session_close_stream_if_shut_rdwr because
RST_STREAM has been submitted. */
return 0;
}
}
@@ -5061,7 +5222,8 @@ static int session_update_consumed_size(nghttp2_session *session,
int32_t recv_size;
int rv;
if ((size_t)*consumed_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta_size) {
if (delta_size > NGHTTP2_MAX_WINDOW_SIZE ||
(size_t)*consumed_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta_size) {
return nghttp2_session_terminate_session(session,
NGHTTP2_FLOW_CONTROL_ERROR);
}
@@ -5330,6 +5492,42 @@ inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe,
return (nghttp2_ssize)(readlen);
}
static int session_update_recv_window_on_data_hd(nghttp2_session *session) {
const nghttp2_inbound_frame *iframe = &session->iframe;
int32_t stream_id = iframe->frame.hd.stream_id;
size_t datalen = iframe->frame.hd.length;
nghttp2_stream *stream;
int rv;
if (datalen == 0) {
return 0;
}
rv = nghttp2_session_update_recv_connection_window_size(session, datalen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return 0;
}
stream = nghttp2_session_get_stream(session, stream_id);
if (!stream) {
return 0;
}
rv = nghttp2_session_update_recv_stream_window_size(
session, stream, datalen,
!(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) &&
stream->state != NGHTTP2_STREAM_CLOSING);
if (nghttp2_is_fatal(rv)) {
return rv;
}
return 0;
}
static const uint8_t static_in[] = {0};
ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
@@ -5337,8 +5535,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
return (ssize_t)nghttp2_session_mem_recv2(session, in, inlen);
}
nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
const uint8_t *in, size_t inlen) {
static nghttp2_ssize session_mem_recv(nghttp2_session *session,
const uint8_t *in, size_t inlen) {
const uint8_t *first, *last;
nghttp2_inbound_frame *iframe = &session->iframe;
size_t readlen;
@@ -5466,6 +5664,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
busy = 1;
rv = session_on_data_received_fail_fast(session);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
@@ -5473,8 +5675,8 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
DEBUGF("recv: DATA not allowed stream_id=%d\n",
iframe->frame.hd.stream_id);
rv = session_update_glitch_ratelim(session);
if (rv != 0) {
rv = session_update_recv_window_on_data_hd(session);
if (nghttp2_is_fatal(rv)) {
return rv;
}
@@ -5486,10 +5688,15 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
break;
}
rv = session_update_recv_window_on_data_hd(session);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
if (rv < 0) {
rv = nghttp2_session_terminate_session_with_reason(
@@ -5573,6 +5780,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
on_begin_frame_called = 1;
rv = session_process_headers_frame(session);
@@ -5909,7 +6120,7 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
iframe->frame.ext.payload = &iframe->ext_frame_payload.origin;
if (session->server || iframe->frame.hd.stream_id ||
(iframe->frame.hd.flags & 0xf0)) {
(iframe->frame.hd.flags & 0xF0)) {
/* Receiving too frequent invalid frames is
suspicious. */
rv = session_update_glitch_ratelim(session);
@@ -6041,6 +6252,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
}
}
@@ -6293,6 +6508,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
session_inbound_frame_reset(session);
break;
@@ -6549,10 +6768,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
}
#endif /* defined(DEBUGBUILD) */
if (++session->num_continuations > session->max_continuations) {
return NGHTTP2_ERR_TOO_MANY_CONTINUATIONS;
}
readlen = inbound_frame_buf_read(iframe, in, last);
in += readlen;
@@ -6582,6 +6797,23 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return (nghttp2_ssize)inlen;
}
if (++session->num_continuations > session->max_continuations) {
return NGHTTP2_ERR_TOO_MANY_CONTINUATIONS;
}
if (cont_hd.length > session->local_settings.max_frame_size) {
DEBUGF("recv: length is too large %zu > %u\n", cont_hd.length,
session->local_settings.max_frame_size);
rv = nghttp2_session_terminate_session_with_reason(
session, NGHTTP2_FRAME_SIZE_ERROR, "too large frame size");
if (nghttp2_is_fatal(rv)) {
return rv;
}
return (nghttp2_ssize)inlen;
}
/* CONTINUATION won't bear NGHTTP2_PADDED flag */
iframe->frame.hd.flags =
@@ -6599,6 +6831,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
} else {
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
}
@@ -6618,16 +6854,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return (nghttp2_ssize)(in - first);
}
/* Pad Length field is subject to flow control */
rv = nghttp2_session_update_recv_connection_window_size(session, readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
/* Pad Length field is consumed immediately */
rv =
nghttp2_session_consume(session, iframe->frame.hd.stream_id, readlen);
@@ -6640,21 +6866,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return (nghttp2_ssize)inlen;
}
stream = nghttp2_session_get_stream(session, iframe->frame.hd.stream_id);
if (stream) {
rv = nghttp2_session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
}
busy = 1;
padlen = inbound_frame_compute_pad(iframe);
@@ -6707,28 +6918,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
if (readlen > 0) {
nghttp2_ssize data_readlen;
rv =
nghttp2_session_update_recv_connection_window_size(session, readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
rv = nghttp2_session_update_recv_stream_window_size(
session, stream, readlen,
iframe->payloadleft ||
(iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
data_readlen =
inbound_frame_effective_readlen(iframe, iframe->payloadleft, readlen);
@@ -6758,26 +6947,57 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
if (data_readlen > 0) {
if (session_enforce_http_messaging(session)) {
if (nghttp2_http_on_data_chunk(stream, (size_t)data_readlen) != 0) {
rv = nghttp2_session_terminate_session(session,
NGHTTP2_PROTOCOL_ERROR);
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
/* Consume all data for connection immediately here */
rv = session_update_connection_consumed_size(
session, (size_t)data_readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_DATA) {
return (nghttp2_ssize)inlen;
}
}
rv = session_handle_invalid_stream2(
session, iframe->frame.hd.stream_id, &iframe->frame,
NGHTTP2_ERR_PROTO);
if (nghttp2_is_fatal(rv)) {
return rv;
}
return (nghttp2_ssize)inlen;
rv = session_update_glitch_ratelim(session);
if (rv != 0) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
busy = 1;
iframe->state = NGHTTP2_IB_IGN_DATA;
break;
}
}
if (session->callbacks.on_data_chunk_recv_callback) {
rv = session->callbacks.on_data_chunk_recv_callback(
session, iframe->frame.hd.flags, iframe->frame.hd.stream_id,
in - readlen, (size_t)data_readlen, session->user_data);
if (rv == NGHTTP2_ERR_PAUSE) {
return (nghttp2_ssize)(in - first);
}
if (nghttp2_is_fatal(rv)) {
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
if (rv == NGHTTP2_ERR_PAUSE) {
return (nghttp2_ssize)(in - first);
}
}
}
}
@@ -6809,18 +7029,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
iframe->payloadleft);
if (readlen > 0) {
/* Update connection-level flow control window for ignored
DATA frame too */
rv =
nghttp2_session_update_recv_connection_window_size(session, readlen);
if (nghttp2_is_fatal(rv)) {
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
if (session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE) {
/* Ignored DATA is considered as "consumed" immediately. */
rv = session_update_connection_consumed_size(session, readlen);
@@ -6861,6 +7069,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
if (rv != 0) {
busy = 1;
@@ -6879,6 +7091,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
session_inbound_frame_reset(session);
break;
@@ -6907,6 +7123,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return rv;
}
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
return (nghttp2_ssize)inlen;
}
session_inbound_frame_reset(session);
break;
@@ -6958,6 +7178,23 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
return (nghttp2_ssize)(in - first);
}
nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
const uint8_t *in, size_t inlen) {
nghttp2_ssize nread;
nread = session_mem_recv(session, in, inlen);
if (nread < 0 && nghttp2_is_fatal((int)nread)) {
return nread;
}
if (nghttp2_session_get_outbound_queue_size(session) >
session->max_outbound_queue_size) {
return NGHTTP2_ERR_FLOODED;
}
return nread;
}
int nghttp2_session_recv(nghttp2_session *session) {
uint8_t buf[NGHTTP2_INBOUND_BUFFER_LENGTH];
while (1) {
@@ -7370,13 +7607,13 @@ int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
case NGHTTP2_DATA_PROVIDER_V1:
payloadlen = (nghttp2_ssize)aux_data->dpw.data_prd.v1.read_callback(
session, frame->hd.stream_id, buf->pos, datamax, &data_flags,
&aux_data->dpw.data_prd.source, session->user_data);
&aux_data->dpw.data_prd.v1.source, session->user_data);
break;
case NGHTTP2_DATA_PROVIDER_V2:
payloadlen = aux_data->dpw.data_prd.v2.read_callback(
session, frame->hd.stream_id, buf->pos, datamax, &data_flags,
&aux_data->dpw.data_prd.source, session->user_data);
&aux_data->dpw.data_prd.v2.source, session->user_data);
break;
default:
@@ -7560,13 +7797,13 @@ nghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session,
int32_t nghttp2_session_get_stream_local_window_size(nghttp2_session *session,
int32_t stream_id) {
nghttp2_stream *stream;
int32_t size;
int64_t size;
stream = nghttp2_session_get_stream(session, stream_id);
if (stream == NULL) {
return -1;
}
size = stream->local_window_size - stream->recv_window_size;
size = (int64_t)stream->local_window_size - (int64_t)stream->recv_window_size;
/* size could be negative if local endpoint reduced
SETTINGS_INITIAL_WINDOW_SIZE */
@@ -7574,7 +7811,13 @@ int32_t nghttp2_session_get_stream_local_window_size(nghttp2_session *session,
return 0;
}
return size;
/* In this case, GOAWAY with NGHTTP2_FLOW_CONTROL_ERROR has already
been queued or sent */
if (size > NGHTTP2_MAX_WINDOW_SIZE) {
return NGHTTP2_MAX_WINDOW_SIZE;
}
return (int32_t)size;
}
int32_t
+40 -38
View File
@@ -50,24 +50,20 @@ extern nghttp2_stream nghttp2_stream_root;
/*
* Option flags.
*/
typedef enum {
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6,
} nghttp2_optmask;
#define NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE 0x01U
#define NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC 0x02U
#define NGHTTP2_OPTMASK_NO_HTTP_MESSAGING 0x04U
#define NGHTTP2_OPTMASK_NO_AUTO_PING_ACK 0x08U
#define NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION 0x40U
/*
* bitmask for built-in type to enable the default handling for that
* type of the frame.
*/
typedef enum {
NGHTTP2_TYPEMASK_NONE = 0,
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
NGHTTP2_TYPEMASK_ORIGIN = 1 << 1,
NGHTTP2_TYPEMASK_PRIORITY_UPDATE = 1 << 2
} nghttp2_typemask;
#define NGHTTP2_TYPEMASK_NONE 0x00U
#define NGHTTP2_TYPEMASK_ALTSVC 0x01U
#define NGHTTP2_TYPEMASK_ORIGIN 0x02U
#define NGHTTP2_TYPEMASK_PRIORITY_UPDATE 0x04U
typedef enum {
NGHTTP2_OB_POP_ITEM,
@@ -100,20 +96,23 @@ typedef struct {
#define NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM 1000
/* The default value of maximum number of concurrent streams. */
#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xFFFFFFFFU
/* The default values for stream reset rate limiter. */
#define NGHTTP2_DEFAULT_STREAM_RESET_BURST 1000
#define NGHTTP2_DEFAULT_STREAM_RESET_RATE 33
/* The default values for glitch rate limiter. */
#define NGHTTP2_DEFAULT_GLITCH_BURST 1000
#define NGHTTP2_DEFAULT_GLITCH_RATE 33
#define NGHTTP2_DEFAULT_GLITCH_BURST 10000
#define NGHTTP2_DEFAULT_GLITCH_RATE 330
/* The default max number of CONTINUATION frames following an incoming
HEADER frame. */
#define NGHTTP2_DEFAULT_MAX_CONTINUATIONS 8
/* The default maximum size of the outbound queue. */
#define NGHTTP2_DEFAULT_MAX_OUTBOUND_QUEUE_SIZE 5000
/* Internal state when receiving incoming frame */
typedef enum {
/* Receiving frame header */
@@ -178,19 +177,18 @@ typedef struct {
uint32_t no_rfc7540_priorities;
} nghttp2_settings_storage;
typedef enum {
NGHTTP2_GOAWAY_NONE = 0,
/* Flag means that connection should be terminated after sending GOAWAY. */
NGHTTP2_GOAWAY_TERM_ON_SEND = 0x1,
/* Flag means GOAWAY to terminate session has been sent */
NGHTTP2_GOAWAY_TERM_SENT = 0x2,
/* Flag means GOAWAY was sent */
NGHTTP2_GOAWAY_SENT = 0x4,
/* Flag means GOAWAY was received */
NGHTTP2_GOAWAY_RECV = 0x8,
/* Flag means GOAWAY has been submitted at least once */
NGHTTP2_GOAWAY_SUBMITTED = 0x10
} nghttp2_goaway_flag;
#define NGHTTP2_GOAWAY_NONE 0x00U
/* Flag means that connection should be terminated after sending
GOAWAY. */
#define NGHTTP2_GOAWAY_TERM_ON_SEND 0x01U
/* Flag means GOAWAY to terminate session has been sent */
#define NGHTTP2_GOAWAY_TERM_SENT 0x02U
/* Flag means GOAWAY was sent */
#define NGHTTP2_GOAWAY_SENT 0x04U
/* Flag means GOAWAY was received */
#define NGHTTP2_GOAWAY_RECV 0x08U
/* Flag means GOAWAY has been submitted at least once */
#define NGHTTP2_GOAWAY_SUBMITTED 0x10U
/* nghttp2_inflight_settings stores the SETTINGS entries which local
endpoint has sent to the remote endpoint, and has not received ACK
@@ -285,6 +283,8 @@ struct nghttp2_session {
/* The number of CONTINUATION frames following an incoming HEADER
frame. This variable is reset when END_HEADERS flag is seen. */
size_t num_continuations;
/* The maximum size of the outbound queue. */
size_t max_outbound_queue_size;
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
uint32_t next_stream_id;
/* The last stream ID this session initiated. For client session,
@@ -330,13 +330,15 @@ struct nghttp2_session {
nghttp2_settings_storage remote_settings;
/* Settings value of the local endpoint. */
nghttp2_settings_storage local_settings;
/* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */
/* Option flags. This is bitwise-OR of 0 or more of
NGHTTP2_OPTMASK_* values. */
uint32_t opt_flags;
/* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
to refuse the incoming stream if it exceeds this value. */
uint32_t pending_local_max_concurrent_stream;
/* The bitwise OR of zero or more of nghttp2_typemask to indicate
that the default handling of extension frame is enabled. */
/* The bitwise OR of zero or more of NGHTTP2_TYPEMASK_* values to
indicate that the default handling of extension frame is
enabled. */
uint32_t builtin_recv_ext_types;
/* Unacked local ENABLE_PUSH value. We use this to refuse
PUSH_PROMISE before SETTINGS ACK is received. */
@@ -350,7 +352,7 @@ struct nghttp2_session {
/* Nonzero if the session is server side. */
uint8_t server;
/* Flags indicating GOAWAY is sent and/or received. The flags are
composed by bitwise OR-ing nghttp2_goaway_flag. */
composed by bitwise OR-ing NGHTTP2_GOAWAY_* values. */
uint8_t goaway_flags;
/* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
this session. The nonzero does not necessarily mean
@@ -510,11 +512,11 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
/*
* Creates new stream in |session| with stream ID |stream_id|,
* priority |pri_spec| and flags |flags|. The |flags| is bitwise OR
* of nghttp2_stream_flag. Since this function is called when initial
* HEADERS is sent or received, these flags are taken from it. The
* state of stream is set to |initial_state|. The |stream_user_data|
* is a pointer to the arbitrary user supplied data to be associated
* to this stream.
* of NGHTTP2_STREAM_FLAG_* values. Since this function is called
* when initial HEADERS is sent or received, these flags are taken
* from it. The state of stream is set to |initial_state|. The
* |stream_user_data| is a pointer to the arbitrary user supplied data
* to be associated to this stream.
*
* If |initial_state| is NGHTTP2_STREAM_RESERVED, this function sets
* NGHTTP2_STREAM_FLAG_PUSH flag set.
+15 -28
View File
@@ -36,38 +36,25 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
int32_t remote_initial_window_size,
int32_t local_initial_window_size,
void *stream_user_data) {
stream->stream_id = stream_id;
stream->flags = flags;
stream->state = initial_state;
stream->shut_flags = NGHTTP2_SHUT_NONE;
stream->stream_user_data = stream_user_data;
stream->item = NULL;
stream->remote_window_size = remote_initial_window_size;
stream->local_window_size = local_initial_window_size;
stream->recv_window_size = 0;
stream->consumed_size = 0;
stream->recv_reduction = 0;
stream->window_update_queued = 0;
stream->closed_next = NULL;
stream->http_flags = NGHTTP2_HTTP_FLAG_NONE;
stream->content_length = -1;
stream->recv_content_length = 0;
stream->status_code = -1;
stream->queued = 0;
stream->cycle = 0;
stream->pending_penalty = 0;
stream->seq = 0;
stream->last_writelen = 0;
stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
*stream = (nghttp2_stream){
.state = initial_state,
.content_length = -1,
.stream_user_data = stream_user_data,
.stream_id = stream_id,
.remote_window_size = remote_initial_window_size,
.local_window_size = local_initial_window_size,
.status_code = -1,
.http_flags = NGHTTP2_HTTP_FLAG_NONE,
.flags = flags,
.shut_flags = NGHTTP2_SHUT_NONE,
.extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY,
.http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY,
};
}
void nghttp2_stream_free(nghttp2_stream *stream) { (void)stream; }
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
void nghttp2_stream_shutdown(nghttp2_stream *stream, uint8_t flag) {
stream->shut_flags = (uint8_t)(stream->shut_flags | flag);
}
+74 -78
View File
@@ -66,81 +66,76 @@ typedef enum {
NGHTTP2_STREAM_IDLE
} nghttp2_stream_state;
typedef enum {
NGHTTP2_SHUT_NONE = 0,
/* Indicates further receptions will be disallowed. */
NGHTTP2_SHUT_RD = 0x01,
/* Indicates further transmissions will be disallowed. */
NGHTTP2_SHUT_WR = 0x02,
/* Indicates both further receptions and transmissions will be
disallowed. */
NGHTTP2_SHUT_RDWR = NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR
} nghttp2_shut_flag;
#define NGHTTP2_SHUT_NONE 0x00U
/* Indicates further receptions will be disallowed. */
#define NGHTTP2_SHUT_RD 0x01U
/* Indicates further transmissions will be disallowed. */
#define NGHTTP2_SHUT_WR 0x02U
/* Indicates both further receptions and transmissions will be
disallowed. */
#define NGHTTP2_SHUT_RDWR (NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR)
typedef enum {
NGHTTP2_STREAM_FLAG_NONE = 0,
/* Indicates that this stream is pushed stream and not opened
yet. */
NGHTTP2_STREAM_FLAG_PUSH = 0x01,
/* Indicates that this stream was closed */
NGHTTP2_STREAM_FLAG_CLOSED = 0x02,
/* Indicates the item is deferred due to flow control. */
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL = 0x04,
/* Indicates the item is deferred by user callback */
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c,
/* Ignore client RFC 9218 priority signal. */
NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES = 0x20,
/* Indicates that RFC 9113 leading and trailing white spaces
validation against a field value is not performed. */
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 0x40,
} nghttp2_stream_flag;
#define NGHTTP2_STREAM_FLAG_NONE 0x00U
/* Indicates that this stream is pushed stream and not opened yet. */
#define NGHTTP2_STREAM_FLAG_PUSH 0x01U
/* Indicates that this stream was closed */
#define NGHTTP2_STREAM_FLAG_CLOSED 0x02U
/* Indicates the item is deferred due to flow control. */
#define NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL 0x04U
/* Indicates the item is deferred by user callback */
#define NGHTTP2_STREAM_FLAG_DEFERRED_USER 0x08U
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
#define NGHTTP2_STREAM_FLAG_DEFERRED_ALL \
(NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL | \
NGHTTP2_STREAM_FLAG_DEFERRED_USER)
/* Ignore client RFC 9218 priority signal. */
#define NGHTTP2_STREAM_FLAG_IGNORE_CLIENT_PRIORITIES 0x20U
/* Indicates that RFC 9113 leading and trailing white spaces
validation against a field value is not performed. */
#define NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION 0x40U
/* HTTP related flags to enforce HTTP semantics */
typedef enum {
NGHTTP2_HTTP_FLAG_NONE = 0,
/* header field seen so far */
NGHTTP2_HTTP_FLAG__AUTHORITY = 1,
NGHTTP2_HTTP_FLAG__PATH = 1 << 1,
NGHTTP2_HTTP_FLAG__METHOD = 1 << 2,
NGHTTP2_HTTP_FLAG__SCHEME = 1 << 3,
/* host is not pseudo header, but we require either host or
:authority */
NGHTTP2_HTTP_FLAG_HOST = 1 << 4,
NGHTTP2_HTTP_FLAG__STATUS = 1 << 5,
/* required header fields for HTTP request except for CONNECT
method. */
NGHTTP2_HTTP_FLAG_REQ_HEADERS = NGHTTP2_HTTP_FLAG__METHOD |
NGHTTP2_HTTP_FLAG__PATH |
NGHTTP2_HTTP_FLAG__SCHEME,
NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED = 1 << 6,
/* HTTP method flags */
NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10,
NGHTTP2_HTTP_FLAG_METH_ALL =
NGHTTP2_HTTP_FLAG_METH_CONNECT | NGHTTP2_HTTP_FLAG_METH_HEAD |
NGHTTP2_HTTP_FLAG_METH_OPTIONS | NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND,
/* :path category */
/* path starts with "/" */
NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11,
/* path "*" */
NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 12,
/* scheme */
/* "http" or "https" scheme */
NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13,
/* set if final response is expected */
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15,
/* set if priority header field is received */
NGHTTP2_HTTP_FLAG_PRIORITY = 1 << 16,
/* set if an error is encountered while parsing priority header
field */
NGHTTP2_HTTP_FLAG_BAD_PRIORITY = 1 << 17,
} nghttp2_http_flag;
#define NGHTTP2_HTTP_FLAG_NONE 0x00U
/* header field seen so far */
#define NGHTTP2_HTTP_FLAG__AUTHORITY 0x01U
#define NGHTTP2_HTTP_FLAG__PATH 0x02U
#define NGHTTP2_HTTP_FLAG__METHOD 0x04U
#define NGHTTP2_HTTP_FLAG__SCHEME 0x08U
/* host is not pseudo header, but we require either host or
:authority */
#define NGHTTP2_HTTP_FLAG_HOST 0x10U
#define NGHTTP2_HTTP_FLAG__STATUS 0x20U
/* required header fields for HTTP request except for CONNECT
method. */
#define NGHTTP2_HTTP_FLAG_REQ_HEADERS \
(NGHTTP2_HTTP_FLAG__METHOD | NGHTTP2_HTTP_FLAG__PATH | \
NGHTTP2_HTTP_FLAG__SCHEME)
#define NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED 0x40U
/* HTTP method flags */
#define NGHTTP2_HTTP_FLAG_METH_CONNECT 0x80U
#define NGHTTP2_HTTP_FLAG_METH_HEAD 0x0100U
#define NGHTTP2_HTTP_FLAG_METH_OPTIONS 0x0200U
#define NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND 0x0400U
#define NGHTTP2_HTTP_FLAG_METH_ALL \
(NGHTTP2_HTTP_FLAG_METH_CONNECT | NGHTTP2_HTTP_FLAG_METH_HEAD | \
NGHTTP2_HTTP_FLAG_METH_OPTIONS | NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND)
/* :path category */
/* path starts with "/" */
#define NGHTTP2_HTTP_FLAG_PATH_REGULAR 0x0800U
/* path "*" */
#define NGHTTP2_HTTP_FLAG_PATH_ASTERISK 0x1000U
/* scheme */
/* "http" or "https" scheme */
#define NGHTTP2_HTTP_FLAG_SCHEME_HTTP 0x2000U
/* set if final response is expected */
#define NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE 0x4000U
#define NGHTTP2_HTTP_FLAG__PROTOCOL 0x8000U
/* set if priority header field is received */
#define NGHTTP2_HTTP_FLAG_PRIORITY 0x010000U
/* set if an error is encountered while parsing priority header
field */
#define NGHTTP2_HTTP_FLAG_BAD_PRIORITY 0x020000U
struct nghttp2_stream {
nghttp2_stream_state state;
@@ -184,12 +179,13 @@ struct nghttp2_stream {
/* This is unpaid penalty (offset) when calculating cycle. */
uint32_t pending_penalty;
/* status code from remote server */
int16_t status_code;
/* Bitwise OR of zero or more nghttp2_http_flag values */
int32_t status_code;
/* Bitwise OR of zero or more NGHTTP2_HTTP_FLAG_* values */
uint32_t http_flags;
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
/* This is bitwise-OR of 0 or more of NGHTTP2_STREAM_FLAG_*
values. */
uint8_t flags;
/* Bitwise OR of zero or more nghttp2_shut_flag values */
/* Bitwise OR of zero or more NGHTTP2_SHUT_* values. */
uint8_t shut_flags;
/* Nonzero if this stream has been queued to stream pointed by
dep_prev. We maintain the invariant that if a stream is queued,
@@ -218,9 +214,9 @@ void nghttp2_stream_free(nghttp2_stream *stream);
/*
* Disallow either further receptions or transmissions, or both.
* |flag| is bitwise OR of one or more of nghttp2_shut_flag.
* |flag| is bitwise OR of one or more of NGHTTP2_SHUT_* values.
*/
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
void nghttp2_stream_shutdown(nghttp2_stream *stream, uint8_t flag);
/*
* Defer |stream->item|. We won't call this function in the situation
+7 -8
View File
@@ -57,7 +57,7 @@ static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
nghttp2_outbound_item_init(item);
if (dpw != NULL && dpw->data_prd.read_callback != NULL) {
if (dpw != NULL && nghttp2_data_provider_wrap_contains_read_callback(dpw)) {
item->aux_data.headers.dpw = *dpw;
}
@@ -649,7 +649,7 @@ fail_item_malloc:
static uint8_t set_request_flags(const nghttp2_data_provider_wrap *dpw) {
uint8_t flags = NGHTTP2_FLAG_NONE;
if (dpw == NULL || dpw->data_prd.read_callback == NULL) {
if (dpw == NULL || !nghttp2_data_provider_wrap_contains_read_callback(dpw)) {
flags |= NGHTTP2_FLAG_END_STREAM;
}
@@ -700,7 +700,7 @@ int32_t nghttp2_submit_request2(nghttp2_session *session,
static uint8_t set_response_flags(const nghttp2_data_provider_wrap *dpw) {
uint8_t flags = NGHTTP2_FLAG_NONE;
if (dpw == NULL || dpw->data_prd.read_callback == NULL) {
if (dpw == NULL || !nghttp2_data_provider_wrap_contains_read_callback(dpw)) {
flags |= NGHTTP2_FLAG_END_STREAM;
}
return flags;
@@ -748,7 +748,6 @@ int nghttp2_submit_data_shared(nghttp2_session *session, uint8_t flags,
int rv;
nghttp2_outbound_item *item;
nghttp2_frame *frame;
nghttp2_data_aux_data *aux_data;
uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM;
nghttp2_mem *mem;
@@ -766,10 +765,10 @@ int nghttp2_submit_data_shared(nghttp2_session *session, uint8_t flags,
nghttp2_outbound_item_init(item);
frame = &item->frame;
aux_data = &item->aux_data.data;
aux_data->dpw = *dpw;
aux_data->eof = 0;
aux_data->flags = nflags;
item->aux_data.data = (nghttp2_data_aux_data){
.dpw = *dpw,
.flags = nflags,
};
/* flags are sent on transmission */
nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id);
+161 -432
View File
@@ -34,18 +34,18 @@
# include <immintrin.h>
#endif /* __AVX2__ */
#define SFPARSE_STATE_DICT 0x08u
#define SFPARSE_STATE_LIST 0x10u
#define SFPARSE_STATE_ITEM 0x18u
#define SFPARSE_STATE_DICT 0x08U
#define SFPARSE_STATE_LIST 0x10U
#define SFPARSE_STATE_ITEM 0x18U
#define SFPARSE_STATE_INNER_LIST 0x04u
#define SFPARSE_STATE_INNER_LIST 0x04U
#define SFPARSE_STATE_BEFORE 0x00u
#define SFPARSE_STATE_BEFORE_PARAMS 0x01u
#define SFPARSE_STATE_PARAMS 0x02u
#define SFPARSE_STATE_AFTER 0x03u
#define SFPARSE_STATE_BEFORE 0x00U
#define SFPARSE_STATE_BEFORE_PARAMS 0x01U
#define SFPARSE_STATE_PARAMS 0x02U
#define SFPARSE_STATE_AFTER 0x03U
#define SFPARSE_STATE_OP_MASK 0x03u
#define SFPARSE_STATE_OP_MASK 0x03U
#define SFPARSE_SET_STATE_AFTER(NAME) \
(SFPARSE_STATE_##NAME | SFPARSE_STATE_AFTER)
@@ -69,314 +69,33 @@
#define SFPARSE_STATE_ITEM_INNER_LIST_BEFORE \
SFPARSE_SET_STATE_INNER_LIST_BEFORE(ITEM)
#define SFPARSE_STATE_INITIAL 0x00u
#define SFPARSE_STATE_INITIAL 0x00U
#define DIGIT_CASES \
case '0': \
case '1': \
case '2': \
case '3': \
case '4': \
case '5': \
case '6': \
case '7': \
case '8': \
case '9'
#define LCALPHAS \
['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, \
['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1, ['n'] = 1, \
['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1, ['u'] = 1, \
['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1
#define LCALPHA_CASES \
case 'a': \
case 'b': \
case 'c': \
case 'd': \
case 'e': \
case 'f': \
case 'g': \
case 'h': \
case 'i': \
case 'j': \
case 'k': \
case 'l': \
case 'm': \
case 'n': \
case 'o': \
case 'p': \
case 'q': \
case 'r': \
case 's': \
case 't': \
case 'u': \
case 'v': \
case 'w': \
case 'x': \
case 'y': \
case 'z'
#define ALPHAS(N) \
['A'] = (N), ['B'] = (N), ['C'] = (N), ['D'] = (N), ['E'] = (N), \
['F'] = (N), ['G'] = (N), ['H'] = (N), ['I'] = (N), ['J'] = (N), \
['K'] = (N), ['L'] = (N), ['M'] = (N), ['N'] = (N), ['O'] = (N), \
['P'] = (N), ['Q'] = (N), ['R'] = (N), ['S'] = (N), ['T'] = (N), \
['U'] = (N), ['V'] = (N), ['W'] = (N), ['X'] = (N), ['Y'] = (N), \
['Z'] = (N), ['a'] = (N), ['b'] = (N), ['c'] = (N), ['d'] = (N), \
['e'] = (N), ['f'] = (N), ['g'] = (N), ['h'] = (N), ['i'] = (N), \
['j'] = (N), ['k'] = (N), ['l'] = (N), ['m'] = (N), ['n'] = (N), \
['o'] = (N), ['p'] = (N), ['q'] = (N), ['r'] = (N), ['s'] = (N), \
['t'] = (N), ['u'] = (N), ['v'] = (N), ['w'] = (N), ['x'] = (N), \
['y'] = (N), ['z'] = (N)
#define UCALPHA_CASES \
case 'A': \
case 'B': \
case 'C': \
case 'D': \
case 'E': \
case 'F': \
case 'G': \
case 'H': \
case 'I': \
case 'J': \
case 'K': \
case 'L': \
case 'M': \
case 'N': \
case 'O': \
case 'P': \
case 'Q': \
case 'R': \
case 'S': \
case 'T': \
case 'U': \
case 'V': \
case 'W': \
case 'X': \
case 'Y': \
case 'Z'
#define DIGITS(N) \
['0'] = (N), ['1'] = (N), ['2'] = (N), ['3'] = (N), ['4'] = (N), \
['5'] = (N), ['6'] = (N), ['7'] = (N), ['8'] = (N), ['9'] = (N)
#define ALPHA_CASES \
UCALPHA_CASES: \
LCALPHA_CASES
#define TOKEN_CASES \
case '!': \
case '#': \
case '$': \
case '%': \
case '&': \
case '\'': \
case '*': \
case '+': \
case '-': \
case '.': \
case '/': \
DIGIT_CASES: \
case ':': \
UCALPHA_CASES: \
case '^': \
case '_': \
case '`': \
LCALPHA_CASES: \
case '|': \
case '~'
#define LCHEXALPHA_CASES \
case 'a': \
case 'b': \
case 'c': \
case 'd': \
case 'e': \
case 'f'
#define X00_1F_CASES \
case 0x00: \
case 0x01: \
case 0x02: \
case 0x03: \
case 0x04: \
case 0x05: \
case 0x06: \
case 0x07: \
case 0x08: \
case 0x09: \
case 0x0a: \
case 0x0b: \
case 0x0c: \
case 0x0d: \
case 0x0e: \
case 0x0f: \
case 0x10: \
case 0x11: \
case 0x12: \
case 0x13: \
case 0x14: \
case 0x15: \
case 0x16: \
case 0x17: \
case 0x18: \
case 0x19: \
case 0x1a: \
case 0x1b: \
case 0x1c: \
case 0x1d: \
case 0x1e: \
case 0x1f
#define X20_21_CASES \
case ' ': \
case '!'
#define X23_5B_CASES \
case '#': \
case '$': \
case '%': \
case '&': \
case '\'': \
case '(': \
case ')': \
case '*': \
case '+': \
case ',': \
case '-': \
case '.': \
case '/': \
DIGIT_CASES: \
case ':': \
case ';': \
case '<': \
case '=': \
case '>': \
case '?': \
case '@': \
UCALPHA_CASES: \
case '['
#define X5D_7E_CASES \
case ']': \
case '^': \
case '_': \
case '`': \
LCALPHA_CASES: \
case '{': \
case '|': \
case '}': \
case '~'
#define X7F_FF_CASES \
case 0x7f: \
case 0x80: \
case 0x81: \
case 0x82: \
case 0x83: \
case 0x84: \
case 0x85: \
case 0x86: \
case 0x87: \
case 0x88: \
case 0x89: \
case 0x8a: \
case 0x8b: \
case 0x8c: \
case 0x8d: \
case 0x8e: \
case 0x8f: \
case 0x90: \
case 0x91: \
case 0x92: \
case 0x93: \
case 0x94: \
case 0x95: \
case 0x96: \
case 0x97: \
case 0x98: \
case 0x99: \
case 0x9a: \
case 0x9b: \
case 0x9c: \
case 0x9d: \
case 0x9e: \
case 0x9f: \
case 0xa0: \
case 0xa1: \
case 0xa2: \
case 0xa3: \
case 0xa4: \
case 0xa5: \
case 0xa6: \
case 0xa7: \
case 0xa8: \
case 0xa9: \
case 0xaa: \
case 0xab: \
case 0xac: \
case 0xad: \
case 0xae: \
case 0xaf: \
case 0xb0: \
case 0xb1: \
case 0xb2: \
case 0xb3: \
case 0xb4: \
case 0xb5: \
case 0xb6: \
case 0xb7: \
case 0xb8: \
case 0xb9: \
case 0xba: \
case 0xbb: \
case 0xbc: \
case 0xbd: \
case 0xbe: \
case 0xbf: \
case 0xc0: \
case 0xc1: \
case 0xc2: \
case 0xc3: \
case 0xc4: \
case 0xc5: \
case 0xc6: \
case 0xc7: \
case 0xc8: \
case 0xc9: \
case 0xca: \
case 0xcb: \
case 0xcc: \
case 0xcd: \
case 0xce: \
case 0xcf: \
case 0xd0: \
case 0xd1: \
case 0xd2: \
case 0xd3: \
case 0xd4: \
case 0xd5: \
case 0xd6: \
case 0xd7: \
case 0xd8: \
case 0xd9: \
case 0xda: \
case 0xdb: \
case 0xdc: \
case 0xdd: \
case 0xde: \
case 0xdf: \
case 0xe0: \
case 0xe1: \
case 0xe2: \
case 0xe3: \
case 0xe4: \
case 0xe5: \
case 0xe6: \
case 0xe7: \
case 0xe8: \
case 0xe9: \
case 0xea: \
case 0xeb: \
case 0xec: \
case 0xed: \
case 0xee: \
case 0xef: \
case 0xf0: \
case 0xf1: \
case 0xf2: \
case 0xf3: \
case 0xf4: \
case 0xf5: \
case 0xf6: \
case 0xf7: \
case 0xf8: \
case 0xf9: \
case 0xfa: \
case 0xfb: \
case 0xfc: \
case 0xfd: \
case 0xfe: \
case 0xff
#define HEXALPHAS(N) \
['a'] = (N), ['b'] = (N), ['c'] = (N), ['d'] = (N), ['e'] = (N), ['f'] = (N)
static int is_ws(uint8_t c) {
switch (c) {
@@ -463,17 +182,17 @@ static const uint8_t *find_char_key(const uint8_t *first, const uint8_t *last) {
}
#endif /* __AVX2__ */
static const uint8_t key_tbl[256] = {
['*'] = 1, LCALPHAS, ['_'] = 2, ['-'] = 2, ['.'] = 2, DIGITS(2),
};
static int parser_key(sfparse_parser *sfp, sfparse_vec *dest) {
const uint8_t *base;
#ifdef __AVX2__
const uint8_t *last;
#endif /* __AVX2__ */
switch (*sfp->pos) {
case '*':
LCALPHA_CASES:
break;
default:
if (key_tbl[*sfp->pos] != 1) {
return SFPARSE_ERR_PARSE;
}
@@ -481,7 +200,7 @@ static int parser_key(sfparse_parser *sfp, sfparse_vec *dest) {
#ifdef __AVX2__
if (sfp->end - sfp->pos >= 32) {
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu);
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU);
sfp->pos = find_char_key(sfp->pos, last);
if (sfp->pos != last) {
@@ -490,19 +209,8 @@ static int parser_key(sfparse_parser *sfp, sfparse_vec *dest) {
}
#endif /* __AVX2__ */
for (; !parser_eof(sfp); ++sfp->pos) {
switch (*sfp->pos) {
case '_':
case '-':
case '.':
case '*':
DIGIT_CASES:
LCALPHA_CASES:
continue;
}
break;
}
for (; !parser_eof(sfp) && key_tbl[*sfp->pos]; ++sfp->pos)
;
#ifdef __AVX2__
fin:
@@ -515,6 +223,10 @@ fin:
return 0;
}
static const uint8_t number_tbl[256] = {
DIGITS(1),
};
static int parser_number(sfparse_parser *sfp, sfparse_value *dest) {
int sign = 1;
int64_t value = 0;
@@ -532,20 +244,13 @@ static int parser_number(sfparse_parser *sfp, sfparse_value *dest) {
assert(!parser_eof(sfp));
for (; !parser_eof(sfp); ++sfp->pos) {
switch (*sfp->pos) {
DIGIT_CASES:
if (++len > 15) {
return SFPARSE_ERR_PARSE;
}
value *= 10;
value += *sfp->pos - '0';
continue;
for (; !parser_eof(sfp) && number_tbl[*sfp->pos]; ++sfp->pos) {
if (++len > 15) {
return SFPARSE_ERR_PARSE;
}
break;
value *= 10;
value += *sfp->pos - '0';
}
if (len == 0) {
@@ -572,20 +277,13 @@ static int parser_number(sfparse_parser *sfp, sfparse_value *dest) {
++sfp->pos;
for (; !parser_eof(sfp); ++sfp->pos) {
switch (*sfp->pos) {
DIGIT_CASES:
if (++len > 15) {
return SFPARSE_ERR_PARSE;
}
value *= 10;
value += *sfp->pos - '0';
continue;
for (; !parser_eof(sfp) && number_tbl[*sfp->pos]; ++sfp->pos) {
if (++len > 15) {
return SFPARSE_ERR_PARSE;
}
break;
value *= 10;
value += *sfp->pos - '0';
}
if (fpos == len || len - fpos > 3) {
@@ -651,7 +349,7 @@ static const uint8_t *find_char_string(const uint8_t *first,
const uint8_t *last) {
const __m256i bs = _mm256_set1_epi8('\\');
const __m256i dq = _mm256_set1_epi8('"');
const __m256i del = _mm256_set1_epi8(0x7f);
const __m256i del = _mm256_set1_epi8(0x7F);
const __m256i sp = _mm256_set1_epi8(' ');
__m256i s, x;
uint32_t m;
@@ -674,6 +372,14 @@ static const uint8_t *find_char_string(const uint8_t *first,
}
#endif /* __AVX2__ */
static const uint8_t string_tbl[256] = {
[' '] = 1, ['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1,
['('] = 1, [')'] = 1, ['*'] = 1, ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1,
['/'] = 1, DIGITS(1), [':'] = 1, [';'] = 1, ['<'] = 1, ['='] = 1, ['>'] = 1,
['?'] = 1, ['@'] = 1, ALPHAS(1), ['['] = 1, [']'] = 1, ['^'] = 1, ['_'] = 1,
['`'] = 1, ['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1, ['\\'] = 2, ['"'] = 3,
};
static int parser_string(sfparse_parser *sfp, sfparse_value *dest) {
const uint8_t *base;
#ifdef __AVX2__
@@ -688,7 +394,7 @@ static int parser_string(sfparse_parser *sfp, sfparse_value *dest) {
#ifdef __AVX2__
for (; sfp->end - sfp->pos >= 32; ++sfp->pos) {
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu);
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU);
sfp->pos = find_char_string(sfp->pos, last);
if (sfp->pos == last) {
@@ -722,12 +428,12 @@ static int parser_string(sfparse_parser *sfp, sfparse_value *dest) {
#endif /* __AVX2__ */
for (; !parser_eof(sfp); ++sfp->pos) {
switch (*sfp->pos) {
X20_21_CASES:
X23_5B_CASES:
X5D_7E_CASES:
switch (string_tbl[*sfp->pos]) {
case 0:
return SFPARSE_ERR_PARSE;
case 1:
break;
case '\\':
case 2:
++sfp->pos;
if (parser_eof(sfp)) {
return SFPARSE_ERR_PARSE;
@@ -744,10 +450,8 @@ static int parser_string(sfparse_parser *sfp, sfparse_value *dest) {
}
break;
case '"':
case 3:
goto fin;
default:
return SFPARSE_ERR_PARSE;
}
}
@@ -820,6 +524,12 @@ static const uint8_t *find_char_token(const uint8_t *first,
}
#endif /* __AVX2__ */
static const uint8_t token_tbl[256] = {
['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['*'] = 1,
['+'] = 1, ['-'] = 1, ['.'] = 1, ['/'] = 1, DIGITS(1), [':'] = 1, ALPHAS(1),
['^'] = 1, ['_'] = 1, ['`'] = 1, ['|'] = 1, ['~'] = 1,
};
static int parser_token(sfparse_parser *sfp, sfparse_value *dest) {
const uint8_t *base;
#ifdef __AVX2__
@@ -831,7 +541,7 @@ static int parser_token(sfparse_parser *sfp, sfparse_value *dest) {
#ifdef __AVX2__
if (sfp->end - sfp->pos >= 32) {
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu);
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU);
sfp->pos = find_char_token(sfp->pos, last);
if (sfp->pos != last) {
@@ -840,14 +550,8 @@ static int parser_token(sfparse_parser *sfp, sfparse_value *dest) {
}
#endif /* __AVX2__ */
for (; !parser_eof(sfp); ++sfp->pos) {
switch (*sfp->pos) {
TOKEN_CASES:
continue;
}
break;
}
for (; !parser_eof(sfp) && token_tbl[*sfp->pos]; ++sfp->pos)
;
#ifdef __AVX2__
fin:
@@ -901,6 +605,10 @@ static const uint8_t *find_char_byteseq(const uint8_t *first,
}
#endif /* __AVX2__ */
static const uint8_t byteseq_tbl[256] = {
['+'] = 1, ['/'] = 1, DIGITS(1), ALPHAS(1), ['='] = 2, [':'] = 3,
};
static int parser_byteseq(sfparse_parser *sfp, sfparse_value *dest) {
const uint8_t *base;
#ifdef __AVX2__
@@ -914,19 +622,18 @@ static int parser_byteseq(sfparse_parser *sfp, sfparse_value *dest) {
#ifdef __AVX2__
if (sfp->end - sfp->pos >= 32) {
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu);
last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU);
sfp->pos = find_char_byteseq(sfp->pos, last);
}
#endif /* __AVX2__ */
for (; !parser_eof(sfp); ++sfp->pos) {
switch (*sfp->pos) {
case '+':
case '/':
DIGIT_CASES:
ALPHA_CASES:
switch (byteseq_tbl[*sfp->pos]) {
case 0:
return SFPARSE_ERR_PARSE;
case 1:
continue;
case '=':
case 2:
switch ((sfp->pos - base) & 0x3) {
case 0:
case 1:
@@ -954,14 +661,12 @@ static int parser_byteseq(sfparse_parser *sfp, sfparse_value *dest) {
}
goto fin;
case ':':
case 3:
if (((sfp->pos - base) & 0x3) == 1) {
return SFPARSE_ERR_PARSE;
}
goto fin;
default:
return SFPARSE_ERR_PARSE;
}
}
@@ -1016,35 +721,43 @@ static int parser_boolean(sfparse_parser *sfp, sfparse_value *dest) {
return 0;
}
static const uint8_t pct_tbl[256] = {
DIGITS(1),
HEXALPHAS(2),
};
static int pctdecode(uint8_t *pc, const uint8_t **ppos) {
uint8_t c, b = **ppos;
switch (b) {
DIGIT_CASES:
switch (pct_tbl[b]) {
case 0:
return -1;
case 1:
c = (uint8_t)((b - '0') << 4);
break;
LCHEXALPHA_CASES:
case 2:
c = (uint8_t)((b - 'a' + 10) << 4);
break;
default:
return -1;
assert(0);
abort();
}
b = *++*ppos;
switch (b) {
DIGIT_CASES:
switch (pct_tbl[b]) {
case 0:
return -1;
case 1:
c |= (uint8_t)(b - '0');
break;
LCHEXALPHA_CASES:
case 2:
c |= (uint8_t)(b - 'a' + 10);
break;
default:
return -1;
}
*pc = c;
@@ -1115,6 +828,14 @@ static void utf8_decode(uint32_t *state, uint8_t byte) {
/* End of utf8 dfa */
static const uint8_t dispstring_tbl[256] = {
[' '] = 1, ['!'] = 1, ['#'] = 1, ['$'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1,
[')'] = 1, ['*'] = 1, ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1, ['/'] = 1,
DIGITS(1), [':'] = 1, [';'] = 1, ['<'] = 1, ['='] = 1, ['>'] = 1, ['?'] = 1,
['@'] = 1, ALPHAS(1), ['['] = 1, ['\\'] = 1, [']'] = 1, ['^'] = 1, ['_'] = 1,
['`'] = 1, ['{'] = 1, ['|'] = 1, ['}'] = 1, ['~'] = 1, ['%'] = 2, ['"'] = 3,
};
static int parser_dispstring(sfparse_parser *sfp, sfparse_value *dest) {
const uint8_t *base;
uint8_t c;
@@ -1131,31 +852,39 @@ static int parser_dispstring(sfparse_parser *sfp, sfparse_value *dest) {
base = ++sfp->pos;
for (; !parser_eof(sfp);) {
switch (*sfp->pos) {
X00_1F_CASES:
X7F_FF_CASES:
switch (dispstring_tbl[*sfp->pos]) {
case 0:
return SFPARSE_ERR_PARSE;
case '%':
case 1:
++sfp->pos;
if (sfp->pos + 2 > sfp->end) {
return SFPARSE_ERR_PARSE;
}
break;
case 2:
for (;;) {
++sfp->pos;
if (pctdecode(&c, &sfp->pos) != 0) {
return SFPARSE_ERR_PARSE;
}
if (sfp->pos + 2 > sfp->end || pctdecode(&c, &sfp->pos) != 0) {
return SFPARSE_ERR_PARSE;
}
utf8_decode(&utf8state, c);
if (utf8state == UTF8_REJECT) {
return SFPARSE_ERR_PARSE;
utf8_decode(&utf8state, c);
if (utf8state == UTF8_ACCEPT) {
if (sfp->pos != sfp->end && *sfp->pos == '%') {
continue;
}
break;
}
if (utf8state == UTF8_REJECT || sfp->pos + 1 > sfp->end ||
*sfp->pos != '%') {
return SFPARSE_ERR_PARSE;
}
}
break;
case '"':
if (utf8state != UTF8_ACCEPT) {
return SFPARSE_ERR_PARSE;
}
case 3:
assert(utf8state == UTF8_ACCEPT);
if (dest) {
dest->type = SFPARSE_TYPE_DISPSTRING;
@@ -1167,38 +896,38 @@ static int parser_dispstring(sfparse_parser *sfp, sfparse_value *dest) {
++sfp->pos;
return 0;
default:
if (utf8state != UTF8_ACCEPT) {
return SFPARSE_ERR_PARSE;
}
++sfp->pos;
}
}
return SFPARSE_ERR_PARSE;
}
static const uint8_t bare_item_tbl[256] = {
['"'] = 1, ['-'] = 2, DIGITS(2), ['@'] = 3, [':'] = 4,
['?'] = 5, ['*'] = 6, ALPHAS(6), ['%'] = 7,
};
static int parser_bare_item(sfparse_parser *sfp, sfparse_value *dest) {
switch (*sfp->pos) {
case '"':
switch (bare_item_tbl[*sfp->pos]) {
case 0:
return SFPARSE_ERR_PARSE;
case 1:
return parser_string(sfp, dest);
case '-':
DIGIT_CASES:
case 2:
return parser_number(sfp, dest);
case '@':
case 3:
return parser_date(sfp, dest);
case ':':
case 4:
return parser_byteseq(sfp, dest);
case '?':
case 5:
return parser_boolean(sfp, dest);
case '*':
ALPHA_CASES:
case 6:
return parser_token(sfp, dest);
case '%':
case 7:
return parser_dispstring(sfp, dest);
default:
return SFPARSE_ERR_PARSE;
assert(0);
abort();
}
}
@@ -1700,8 +1429,8 @@ void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src) {
}
*o++ = (uint8_t)(n >> 16);
*o++ = (n >> 8) & 0xffu;
*o++ = n & 0xffu;
*o++ = (n >> 8) & 0xFFU;
*o++ = n & 0xFFU;
}
switch (left) {
@@ -1738,8 +1467,8 @@ void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src) {
n = (uint32_t)(index_tbl[*p++] << 10);
n += (uint32_t)(index_tbl[*p++] << 4);
n += (uint32_t)(index_tbl[*p++] >> 2);
*o++ = (n >> 8) & 0xffu;
*o++ = n & 0xffu;
*o++ = (n >> 8) & 0xFFU;
*o++ = n & 0xFFU;
break;
}
+2 -2
View File
@@ -130,7 +130,7 @@ typedef struct sfparse_vec {
*
* :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set.
*/
#define SFPARSE_VALUE_FLAG_NONE 0x0u
#define SFPARSE_VALUE_FLAG_NONE 0x0U
/**
* @macro
@@ -138,7 +138,7 @@ typedef struct sfparse_vec {
* :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` indicates that a string
* contains escaped character(s).
*/
#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1u
#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1U
/**
* @struct