mirror of
https://github.com/nodejs/node.git
synced 2026-10-28 10:15:07 +08:00
deps: update nghttp2 to 1.69.0
PR-URL: https://github.com/nodejs/node/pull/62891 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Stephen Belanger <admin@stephenbelanger.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
1 parent
61db2609e3
commit
5320a1b96f
20 files changed
+4558
-4323
No files matched your search
Vendored
+1
-1
@@ -51,7 +51,7 @@ set(NGHTTP2_GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||
set(NGHTTP2_VERSION_CONFIG "${NGHTTP2_GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
|
||||
set(NGHTTP2_PROJECT_CONFIG "${NGHTTP2_GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
|
||||
set(NGHTTP2_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||
set(NGHTTP2_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
||||
set(NGHTTP2_CONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
|
||||
set(NGHTTP2_NAMESPACE "${PROJECT_NAME}::")
|
||||
set(NGHTTP2_VERSION ${PROJECT_VERSION})
|
||||
|
||||
|
||||
+1
-1
@@ -3252,7 +3252,7 @@ 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,
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@
|
||||
* @macro
|
||||
* Version number of the nghttp2 library release
|
||||
*/
|
||||
#define NGHTTP2_VERSION "1.68.0"
|
||||
#define NGHTTP2_VERSION "1.69.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 0x014500
|
||||
|
||||
#endif /* NGHTTP2VER_H */
|
||||
Vendored
+3
-1
@@ -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) {
|
||||
|
||||
Vendored
+10
@@ -750,6 +750,16 @@ void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
uint8_t *p;
|
||||
|
||||
altsvc = frame->payload;
|
||||
|
||||
if (payloadlen == 0) {
|
||||
altsvc->origin = NULL;
|
||||
altsvc->origin_len = 0;
|
||||
altsvc->field_value = NULL;
|
||||
altsvc->field_value_len = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
p = payload;
|
||||
|
||||
altsvc->origin = p;
|
||||
|
||||
Vendored
-3
@@ -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
|
||||
|
||||
Vendored
+10
-7
@@ -35,9 +35,10 @@
|
||||
/* 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}, \
|
||||
{NULL, NULL, (uint8_t *)(N), nghttp2_strlen_lit((N)), -1}, \
|
||||
{NULL, NULL, (uint8_t *)(V), nghttp2_strlen_lit((V)), -1}, \
|
||||
{(uint8_t *)(N), (uint8_t *)(V), nghttp2_strlen_lit((N)), \
|
||||
nghttp2_strlen_lit((V)), 0}, \
|
||||
T, \
|
||||
H, \
|
||||
}
|
||||
@@ -2058,8 +2059,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 +2145,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;
|
||||
|
||||
|
||||
+12
-11
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+12
-2
@@ -34,9 +34,9 @@
|
||||
typedef enum {
|
||||
/* FSA accepts this state as the end of huffman encoding
|
||||
sequence. */
|
||||
NGHTTP2_HUFF_ACCEPTED = 1 << 14,
|
||||
NGHTTP2_HUFF_ACCEPTED = 1,
|
||||
/* This state emits symbol */
|
||||
NGHTTP2_HUFF_SYM = 1 << 15,
|
||||
NGHTTP2_HUFF_SYM = 1 << 1,
|
||||
} nghttp2_huff_decode_flag;
|
||||
|
||||
typedef struct {
|
||||
@@ -48,6 +48,7 @@ typedef struct {
|
||||
a special node and it is a terminal state that means decoding
|
||||
failed. */
|
||||
uint16_t fstate;
|
||||
uint8_t flags;
|
||||
/* symbol if NGHTTP2_HUFF_SYM flag set */
|
||||
uint8_t sym;
|
||||
} nghttp2_huff_decode;
|
||||
@@ -57,6 +58,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 +71,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) */
|
||||
+4112
-4112
File diff suppressed because it is too large.
Load diff
Vendored
+9
-1
@@ -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)))
|
||||
|
||||
Vendored
+2
-1
@@ -49,7 +49,8 @@ static int memieq(const void *a, const void *b, size_t n) {
|
||||
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 int64_t parse_uint(const uint8_t *s, size_t len) {
|
||||
int64_t n = 0;
|
||||
|
||||
Vendored
+5
-2
@@ -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,
|
||||
/*
|
||||
@@ -52,7 +51,11 @@ typedef enum {
|
||||
* Unlike NGHTTP2_ERR_IGN_HTTP_HEADER, this does not invoke
|
||||
* nghttp2_on_invalid_header_callback.
|
||||
*/
|
||||
NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106
|
||||
NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106,
|
||||
/*
|
||||
* Cancel pushed stream.
|
||||
*/
|
||||
NGHTTP2_ERR_PUSH_CANCEL = -107,
|
||||
} nghttp2_internal_error;
|
||||
|
||||
#endif /* !defined(NGHTTP2_INT_H) */
|
||||
Vendored
+158
-109
@@ -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,175 +74,230 @@ 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));
|
||||
}
|
||||
/* Hasher from
|
||||
https://github.com/rust-lang/rustc-hash/blob/dc5c33f1283de2da64d8d7a06401d91aded03ad4/src/lib.rs
|
||||
to maximize the output's sensitivity to all input bits. */
|
||||
#define NGHTTP2_MAP_HASHER 0xf1357aea2e62a9c5ull
|
||||
/* 64-bit Fibonacci hashing constant, Golden Ratio constant, to get
|
||||
the high bits with the good distribution. */
|
||||
#define NGHTTP2_MAP_FIBO 0x9e3779b97f4a7c15ull
|
||||
|
||||
static void map_bucket_swap(nghttp2_map_bucket *a, nghttp2_map_bucket *b) {
|
||||
nghttp2_map_bucket c = *a;
|
||||
static size_t map_index(const nghttp2_map *map, nghttp2_map_key_type key32) {
|
||||
uint64_t key = (uint64_t)key32;
|
||||
|
||||
*a = *b;
|
||||
*b = c;
|
||||
key += map->seed;
|
||||
key *= NGHTTP2_MAP_HASHER;
|
||||
return (size_t)((key * NGHTTP2_MAP_FIBO) >> (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=%d base=%zu distance=%u\n", i, map->keys[i], idx,
|
||||
map->psl[i] - 1);
|
||||
}
|
||||
}
|
||||
#endif /* !defined(WIN32) */
|
||||
|
||||
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;
|
||||
static void map_set_entry(nghttp2_map *map, size_t idx,
|
||||
nghttp2_map_key_type key, void *data, size_t psl) {
|
||||
map->keys[idx] = key;
|
||||
map->data[idx] = data;
|
||||
map->psl[idx] = (uint8_t)psl;
|
||||
}
|
||||
|
||||
#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|, and returns the index
|
||||
* where the pair is stored if it succeeds. Otherwise, it returns one
|
||||
* of the following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The another data associated to |key| is already present.
|
||||
*/
|
||||
static nghttp2_ssize map_insert(nghttp2_map *map, nghttp2_map_key_type key,
|
||||
void *data) {
|
||||
size_t idx = map_index(map, key);
|
||||
size_t mask = ((size_t)1 << map->hashbits) - 1;
|
||||
size_t psl = 1;
|
||||
size_t kpsl;
|
||||
|
||||
for (;;) {
|
||||
bkt = &map->table[idx];
|
||||
kpsl = map->psl[idx];
|
||||
|
||||
if (bkt->data == NULL) {
|
||||
*bkt = b;
|
||||
if (kpsl == 0) {
|
||||
map_set_entry(map, idx, key, data, psl);
|
||||
++map->size;
|
||||
return 0;
|
||||
|
||||
return (nghttp2_ssize)idx;
|
||||
}
|
||||
|
||||
if (b.psl > bkt->psl) {
|
||||
map_bucket_swap(bkt, &b);
|
||||
} else if (bkt->key == key) {
|
||||
/* TODO This check is just a waste after first swap or if this
|
||||
function is called from map_resize. That said, there is no
|
||||
difference with or without this conditional in performance
|
||||
wise. */
|
||||
if (psl > kpsl) {
|
||||
NGHTTP2_SWAP(nghttp2_map_key_type, &key, &map->keys[idx]);
|
||||
NGHTTP2_SWAP(void *, &data, &map->data[idx]);
|
||||
NGHTTP2_SWAP(uint8_t, &psl, &map->psl[idx]);
|
||||
} else if (map->keys[idx] == key) {
|
||||
/* This check ensures that no duplicate keys are inserted. But
|
||||
it is just a waste after first swap or if this function is
|
||||
called from map_resize. That said, there is no difference
|
||||
with or without this conditional in performance wise. */
|
||||
return 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_ssize idx;
|
||||
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)rv;
|
||||
void *buf;
|
||||
(void)idx;
|
||||
|
||||
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(void *) +
|
||||
sizeof(uint8_t));
|
||||
if (buf == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
new_map.keys = buf;
|
||||
new_map.data =
|
||||
(void *)((uint8_t *)new_map.keys + tablelen * sizeof(nghttp2_map_key_type));
|
||||
new_map.psl = (uint8_t *)new_map.data + tablelen * sizeof(void *);
|
||||
|
||||
if (map->size) {
|
||||
tablelen = 1u << map->hashbits;
|
||||
tablelen = (size_t)1 << map->hashbits;
|
||||
|
||||
for (i = 0; i < tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
if (bkt->data == NULL) {
|
||||
if (map->psl[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = map_insert(&new_map, bkt->key, bkt->data);
|
||||
idx = map_insert(&new_map, map->keys[i], map->data[i]);
|
||||
|
||||
assert(0 == rv);
|
||||
/* map_insert must not fail because all keys are unique during
|
||||
resize. */
|
||||
assert(idx >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
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->data = new_map.data;
|
||||
map->psl = new_map.psl;
|
||||
map->hashbits = new_hashbits;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NGHTTP2_MAX_PSL_RESIZE_THRESH is the maximum psl threshold. If
|
||||
reached, resize the table. */
|
||||
#define NGHTTP2_MAX_PSL_RESIZE_THRESH 128
|
||||
|
||||
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
|
||||
int rv;
|
||||
size_t tablelen;
|
||||
nghttp2_ssize idx;
|
||||
|
||||
assert(data);
|
||||
|
||||
/* Load factor is 7/8 */
|
||||
/* Under the very initial condition, that is map->size == 0 and
|
||||
map->hashbits == 0, 8 > 7 still holds nicely. */
|
||||
if ((map->size + 1) * 8 > (1u << map->hashbits) * 7) {
|
||||
if (map->hashbits) {
|
||||
rv = map_resize(map, map->hashbits + 1);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
rv = map_resize(map, 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;
|
||||
}
|
||||
|
||||
idx = map_insert(map, key, data);
|
||||
if (idx < 0) {
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = map_insert(map, key, data);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
idx = map_insert(map, key, data);
|
||||
if (idx < 0) {
|
||||
return (int)idx;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/* Resize if psl reaches really large value which is almost
|
||||
improbable, but just in case. */
|
||||
if (map->psl[idx] - 1 < NGHTTP2_MAX_PSL_RESIZE_THRESH) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return map_resize(map, map->hashbits + 1);
|
||||
}
|
||||
|
||||
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 +307,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], map->data[idx], kpsl - 1);
|
||||
|
||||
dest = idx;
|
||||
|
||||
idx = (idx + 1) & mask;
|
||||
}
|
||||
@@ -307,7 +356,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;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+8
-9
@@ -38,16 +38,15 @@
|
||||
|
||||
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 struct nghttp2_map {
|
||||
nghttp2_map_bucket *table;
|
||||
nghttp2_map_key_type *keys;
|
||||
void **data;
|
||||
/* psl is the Probe Sequence Length. 0 has special meaning that the
|
||||
element is not stored at i-th position if psl[i] == 0. Because
|
||||
of this, the actual psl value is psl[i] - 1 if psl[i] > 0. */
|
||||
uint8_t *psl;
|
||||
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|.
|
||||
|
||||
+12
@@ -53,6 +53,18 @@ nghttp2_data_provider_wrap_v2(nghttp2_data_provider_wrap *dpw,
|
||||
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;
|
||||
|
||||
+12
-4
@@ -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;
|
||||
|
||||
|
||||
Vendored
+184
-52
@@ -438,7 +438,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();
|
||||
@@ -1051,7 +1051,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 +1188,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);
|
||||
@@ -2141,6 +2144,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: {
|
||||
@@ -2584,7 +2593,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 +2624,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 +2804,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) {
|
||||
@@ -2853,8 +2865,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);
|
||||
@@ -3272,7 +3288,9 @@ static int session_call_on_invalid_header(nghttp2_session *session,
|
||||
session, frame, nv->name->base, nv->name->len, nv->value->base,
|
||||
nv->value->len, nv->flags, session->user_data);
|
||||
} else {
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
/* If both callbacks are not set, the invalid field nv is
|
||||
ignored. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rv == NGHTTP2_ERR_PAUSE || rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
@@ -3357,6 +3375,10 @@ static uint32_t get_error_code_from_lib_error_code(int lib_error_code) {
|
||||
case NGHTTP2_ERR_HTTP_HEADER:
|
||||
case NGHTTP2_ERR_HTTP_MESSAGING:
|
||||
return NGHTTP2_PROTOCOL_ERROR;
|
||||
case NGHTTP2_ERR_INTERNAL:
|
||||
return NGHTTP2_INTERNAL_ERROR;
|
||||
case NGHTTP2_ERR_PUSH_CANCEL:
|
||||
return NGHTTP2_CANCEL;
|
||||
default:
|
||||
return NGHTTP2_INTERNAL_ERROR;
|
||||
}
|
||||
@@ -3408,7 +3430,7 @@ static int session_handle_invalid_stream2(nghttp2_session *session,
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
if (session->callbacks.on_invalid_frame_recv_callback) {
|
||||
if (frame && session->callbacks.on_invalid_frame_recv_callback) {
|
||||
if (session->callbacks.on_invalid_frame_recv_callback(
|
||||
session, frame, lib_error_code, session->user_data) != 0) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
@@ -3495,6 +3517,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;
|
||||
@@ -3563,7 +3586,29 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
|
||||
|
||||
rv2 = session_call_on_invalid_header(session, frame, &nv);
|
||||
if (rv2 == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
rv = NGHTTP2_ERR_HTTP_HEADER;
|
||||
DEBUGF("recv: HTTP error: type=%u, id=%d, header %.*s: %.*s\n",
|
||||
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
||||
nv.name->base, (int)nv.value->len, nv.value->base);
|
||||
|
||||
rv = session_call_error_callback(
|
||||
session, NGHTTP2_ERR_HTTP_HEADER,
|
||||
"Invalid HTTP header field was received: frame type: "
|
||||
"%u, stream: %d, name: [%.*s], value: [%.*s]",
|
||||
frame->hd.type, frame->hd.stream_id, (int)nv.name->len,
|
||||
nv.name->base, (int)nv.value->len, nv.value->base);
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = session_handle_invalid_stream2(
|
||||
session, subject_stream->stream_id, frame,
|
||||
NGHTTP2_ERR_HTTP_HEADER);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
} else {
|
||||
if (rv2 != 0) {
|
||||
return rv2;
|
||||
@@ -3609,6 +3654,16 @@ static int inflate_header_block(nghttp2_session *session, nghttp2_frame *frame,
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -3678,6 +3733,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
|
||||
@@ -3736,12 +3792,22 @@ static int session_after_header_block_received(nghttp2_session *session) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -4078,8 +4144,7 @@ static int update_remote_initial_window_size_func(void *entry, void *ptr) {
|
||||
rv = nghttp2_stream_update_remote_initial_window_size(
|
||||
stream, arg->new_window_size, arg->old_window_size);
|
||||
if (rv != 0) {
|
||||
return nghttp2_session_add_rst_stream(arg->session, stream->stream_id,
|
||||
NGHTTP2_FLOW_CONTROL_ERROR);
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
|
||||
/* If window size gets positive, push deferred DATA frame to
|
||||
@@ -4105,6 +4170,8 @@ static int update_remote_initial_window_size_func(void *entry, void *ptr) {
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FLOW_CONTROL
|
||||
* Window size gets out of range.
|
||||
*/
|
||||
static int
|
||||
session_update_remote_initial_window_size(nghttp2_session *session,
|
||||
@@ -4128,8 +4195,7 @@ static int update_local_initial_window_size_func(void *entry, void *ptr) {
|
||||
rv = nghttp2_stream_update_local_initial_window_size(
|
||||
stream, arg->new_window_size, arg->old_window_size);
|
||||
if (rv != 0) {
|
||||
return nghttp2_session_add_rst_stream(arg->session, stream->stream_id,
|
||||
NGHTTP2_FLOW_CONTROL_ERROR);
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
|
||||
if (stream->window_update_queued) {
|
||||
@@ -4163,6 +4229,8 @@ static int update_local_initial_window_size_func(void *entry, void *ptr) {
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FLOW_CONTROL
|
||||
* Window size gets out of range.
|
||||
*/
|
||||
static int
|
||||
session_update_local_initial_window_size(nghttp2_session *session,
|
||||
@@ -4549,9 +4617,9 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||
session->max_incoming_reserved_streams) {
|
||||
/* Currently, client does not retain closed stream, so we don't
|
||||
check NGHTTP2_SHUT_RD condition here. */
|
||||
|
||||
rv = nghttp2_session_add_rst_stream(
|
||||
session, frame->push_promise.promised_stream_id, NGHTTP2_CANCEL);
|
||||
rv = session_handle_invalid_stream2(session,
|
||||
frame->push_promise.promised_stream_id,
|
||||
NULL, NGHTTP2_ERR_PUSH_CANCEL);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
@@ -4708,8 +4776,9 @@ static int session_on_stream_window_update_received(nghttp2_session *session,
|
||||
}
|
||||
if (NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment <
|
||||
stream->remote_window_size) {
|
||||
return session_handle_invalid_stream(session, frame,
|
||||
NGHTTP2_ERR_FLOW_CONTROL);
|
||||
return session_handle_invalid_connection(
|
||||
session, frame, NGHTTP2_ERR_FLOW_CONTROL,
|
||||
"WINDOW_UPDATE: window size overflow");
|
||||
}
|
||||
stream->remote_window_size += frame->window_update.window_size_increment;
|
||||
|
||||
@@ -4925,6 +4994,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. */
|
||||
@@ -4939,15 +5009,26 @@ 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) {
|
||||
rv = nghttp2_session_add_rst_stream(session, stream->stream_id,
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -5006,8 +5087,8 @@ int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
|
||||
rv = adjust_recv_window_size(&stream->recv_window_size, delta_size,
|
||||
stream->local_window_size);
|
||||
if (rv != 0) {
|
||||
return nghttp2_session_add_rst_stream(session, stream->stream_id,
|
||||
NGHTTP2_FLOW_CONTROL_ERROR);
|
||||
return nghttp2_session_terminate_session(session,
|
||||
NGHTTP2_FLOW_CONTROL_ERROR);
|
||||
}
|
||||
/* We don't have to send WINDOW_UPDATE if the data received is the
|
||||
last chunk in the incoming stream. */
|
||||
@@ -5469,6 +5550,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;
|
||||
}
|
||||
@@ -5476,23 +5561,10 @@ 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) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
|
||||
iframe->state = NGHTTP2_IB_IGN_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
|
||||
if (rv < 0) {
|
||||
rv = nghttp2_session_terminate_session_with_reason(
|
||||
@@ -5576,6 +5648,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);
|
||||
@@ -5590,8 +5666,8 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
}
|
||||
|
||||
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
rv = nghttp2_session_add_rst_stream(
|
||||
session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR);
|
||||
rv = session_handle_invalid_stream2(
|
||||
session, iframe->frame.hd.stream_id, NULL, NGHTTP2_ERR_INTERNAL);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@@ -6044,6 +6120,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6107,8 +6187,8 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
}
|
||||
|
||||
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
rv = nghttp2_session_add_rst_stream(
|
||||
session, iframe->frame.hd.stream_id, NGHTTP2_INTERNAL_ERROR);
|
||||
rv = session_handle_invalid_stream2(
|
||||
session, iframe->frame.hd.stream_id, NULL, NGHTTP2_ERR_INTERNAL);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@@ -6191,9 +6271,9 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
}
|
||||
|
||||
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
|
||||
rv = nghttp2_session_add_rst_stream(
|
||||
session, iframe->frame.push_promise.promised_stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
rv = session_handle_invalid_stream2(
|
||||
session, iframe->frame.push_promise.promised_stream_id, NULL,
|
||||
NGHTTP2_ERR_INTERNAL);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@@ -6296,6 +6376,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;
|
||||
@@ -6371,12 +6455,12 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
iframe->payloadleft -= hd_proclen;
|
||||
|
||||
/* Use promised stream ID for PUSH_PROMISE */
|
||||
rv = nghttp2_session_add_rst_stream(
|
||||
rv = session_handle_invalid_stream2(
|
||||
session,
|
||||
iframe->frame.hd.type == NGHTTP2_PUSH_PROMISE
|
||||
? iframe->frame.push_promise.promised_stream_id
|
||||
: iframe->frame.hd.stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
NULL, NGHTTP2_ERR_INTERNAL);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
@@ -6423,6 +6507,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;
|
||||
}
|
||||
}
|
||||
session_inbound_frame_reset(session);
|
||||
|
||||
@@ -6598,6 +6686,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;
|
||||
}
|
||||
@@ -6648,6 +6740,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;
|
||||
}
|
||||
}
|
||||
|
||||
busy = 1;
|
||||
@@ -6720,6 +6816,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
|
||||
data_readlen =
|
||||
inbound_frame_effective_readlen(iframe, iframe->payloadleft, readlen);
|
||||
|
||||
@@ -6763,13 +6863,25 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
}
|
||||
}
|
||||
|
||||
rv = nghttp2_session_add_rst_stream(
|
||||
session, iframe->frame.hd.stream_id, NGHTTP2_PROTOCOL_ERROR);
|
||||
rv = session_handle_invalid_stream2(
|
||||
session, iframe->frame.hd.stream_id, &iframe->frame,
|
||||
NGHTTP2_ERR_PROTO);
|
||||
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 (nghttp2_ssize)inlen;
|
||||
}
|
||||
|
||||
busy = 1;
|
||||
iframe->state = NGHTTP2_IB_IGN_DATA;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -6777,13 +6889,17 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6797,6 +6913,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;
|
||||
@@ -6863,6 +6983,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;
|
||||
|
||||
@@ -6881,6 +7005,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;
|
||||
@@ -6909,6 +7037,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;
|
||||
@@ -7372,13 +7504,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:
|
||||
|
||||
Vendored
+2
-2
@@ -107,8 +107,8 @@ typedef struct {
|
||||
#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. */
|
||||
|
||||
Vendored
+3
-3
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user