mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-05 21:31:08 -06:00
Merge branch 'upstream-nghttp2' into update-nghttp2
# By nghttp2 upstream * upstream-nghttp2: nghttp2 2022-09-21 (87fef4ab)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -82,8 +82,10 @@ void nghttp2_buf_reset(nghttp2_buf *buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
|
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
|
||||||
buf->begin = buf->pos = buf->last = buf->mark = begin;
|
buf->begin = buf->pos = buf->last = buf->mark = buf->end = begin;
|
||||||
buf->end = begin + len;
|
if (len) {
|
||||||
|
buf->end += len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
|
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);
|
|||||||
* |new_cap|. If extensions took place, buffer pointers in |buf| will
|
* |new_cap|. If extensions took place, buffer pointers in |buf| will
|
||||||
* change.
|
* change.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the followings
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
* negative error codes:
|
* negative error codes:
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
|||||||
35
Utilities/cmnghttp2/lib/nghttp2_extpri.c
Normal file
35
Utilities/cmnghttp2/lib/nghttp2_extpri.c
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 nghttp3 contributors
|
||||||
|
* Copyright (c) 2022 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#include "nghttp2_extpri.h"
|
||||||
|
|
||||||
|
uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri) {
|
||||||
|
return (uint8_t)((uint32_t)extpri->inc << 7 | extpri->urgency);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
65
Utilities/cmnghttp2/lib/nghttp2_extpri.h
Normal file
65
Utilities/cmnghttp2/lib/nghttp2_extpri.h
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* nghttp2 - HTTP/2 C Library
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 nghttp3 contributors
|
||||||
|
* Copyright (c) 2022 nghttp2 contributors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef NGHTTP2_EXTPRI_H
|
||||||
|
#define NGHTTP2_EXTPRI_H
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
|
#include <nghttp2/nghttp2.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_extpri_to_uint8 encodes |pri| into uint8_t variable.
|
||||||
|
*/
|
||||||
|
uint8_t nghttp2_extpri_to_uint8(const nghttp2_extpri *extpri);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_extpri_from_uint8 decodes |u8extpri|, which is produced by
|
||||||
|
* nghttp2_extpri_to_uint8, intto |extpri|.
|
||||||
|
*/
|
||||||
|
void nghttp2_extpri_from_uint8(nghttp2_extpri *extpri, uint8_t u8extpri);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_extpri_uint8_urgency extracts urgency from |PRI| which is
|
||||||
|
* supposed to be constructed by nghttp2_extpri_to_uint8.
|
||||||
|
*/
|
||||||
|
#define nghttp2_extpri_uint8_urgency(PRI) \
|
||||||
|
((uint32_t)((PRI) & ~NGHTTP2_EXTPRI_INC_MASK))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_extpri_uint8_inc extracts inc from |PRI| which is supposed to
|
||||||
|
* be constructed by nghttp2_extpri_to_uint8.
|
||||||
|
*/
|
||||||
|
#define nghttp2_extpri_uint8_inc(PRI) (((PRI)&NGHTTP2_EXTPRI_INC_MASK) != 0)
|
||||||
|
|
||||||
|
#endif /* NGHTTP2_EXTPRI_H */
|
||||||
@@ -253,6 +253,31 @@ void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
|
|||||||
nghttp2_mem_free(mem, origin->ov);
|
nghttp2_mem_free(mem, origin->ov);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
|
||||||
|
nghttp2_mem *mem) {
|
||||||
|
nghttp2_ext_priority_update *priority_update;
|
||||||
|
|
||||||
|
priority_update = frame->payload;
|
||||||
|
if (priority_update == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nghttp2_mem_free(mem, priority_update->field_value);
|
||||||
|
}
|
||||||
|
|
||||||
size_t nghttp2_frame_priority_len(uint8_t flags) {
|
size_t nghttp2_frame_priority_len(uint8_t flags) {
|
||||||
if (flags & NGHTTP2_FLAG_PRIORITY) {
|
if (flags & NGHTTP2_FLAG_PRIORITY) {
|
||||||
return NGHTTP2_PRIORITY_SPECLEN;
|
return NGHTTP2_PRIORITY_SPECLEN;
|
||||||
@@ -654,8 +679,6 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
|||||||
var_gift_payloadlen = 0;
|
var_gift_payloadlen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
payloadlen -= var_gift_payloadlen;
|
|
||||||
|
|
||||||
if (!var_gift_payloadlen) {
|
if (!var_gift_payloadlen) {
|
||||||
var_gift_payload = NULL;
|
var_gift_payload = NULL;
|
||||||
} else {
|
} else {
|
||||||
@@ -818,8 +841,10 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
|
|||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
||||||
origin = frame->payload;
|
origin = frame->payload;
|
||||||
p = payload;
|
p = end = payload;
|
||||||
end = p + payloadlen;
|
if (payloadlen) {
|
||||||
|
end += payloadlen;
|
||||||
|
}
|
||||||
|
|
||||||
for (; p != end;) {
|
for (; p != end;) {
|
||||||
if (end - p < 2) {
|
if (end - p < 2) {
|
||||||
@@ -876,6 +901,57 @@ int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
|
||||||
|
nghttp2_extension *frame) {
|
||||||
|
int rv;
|
||||||
|
nghttp2_buf *buf;
|
||||||
|
nghttp2_ext_priority_update *priority_update;
|
||||||
|
|
||||||
|
/* This is required with --disable-assert. */
|
||||||
|
(void)rv;
|
||||||
|
|
||||||
|
priority_update = frame->payload;
|
||||||
|
|
||||||
|
buf = &bufs->head->buf;
|
||||||
|
|
||||||
|
assert(nghttp2_buf_avail(buf) >= 4 + priority_update->field_value_len);
|
||||||
|
|
||||||
|
buf->pos -= NGHTTP2_FRAME_HDLEN;
|
||||||
|
|
||||||
|
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
|
||||||
|
|
||||||
|
nghttp2_put_uint32be(buf->last, (uint32_t)priority_update->stream_id);
|
||||||
|
buf->last += 4;
|
||||||
|
|
||||||
|
rv = nghttp2_bufs_add(bufs, priority_update->field_value,
|
||||||
|
priority_update->field_value_len);
|
||||||
|
|
||||||
|
assert(rv == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
|
||||||
|
uint8_t *payload,
|
||||||
|
size_t payloadlen) {
|
||||||
|
nghttp2_ext_priority_update *priority_update;
|
||||||
|
|
||||||
|
assert(payloadlen >= 4);
|
||||||
|
|
||||||
|
priority_update = frame->payload;
|
||||||
|
|
||||||
|
priority_update->stream_id =
|
||||||
|
nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
|
||||||
|
|
||||||
|
if (payloadlen > 4) {
|
||||||
|
priority_update->field_value = payload + 4;
|
||||||
|
priority_update->field_value_len = payloadlen - 4;
|
||||||
|
} else {
|
||||||
|
priority_update->field_value = NULL;
|
||||||
|
priority_update->field_value_len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
||||||
size_t niv, nghttp2_mem *mem) {
|
size_t niv, nghttp2_mem *mem) {
|
||||||
nghttp2_settings_entry *iv_copy;
|
nghttp2_settings_entry *iv_copy;
|
||||||
@@ -897,9 +973,25 @@ nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) {
|
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) {
|
||||||
return a->namelen == b->namelen && a->valuelen == b->valuelen &&
|
if (a->namelen != b->namelen || a->valuelen != b->valuelen) {
|
||||||
memcmp(a->name, b->name, a->namelen) == 0 &&
|
return 0;
|
||||||
memcmp(a->value, b->value, a->valuelen) == 0;
|
}
|
||||||
|
|
||||||
|
if (a->name == NULL || b->name == NULL) {
|
||||||
|
assert(a->namelen == 0);
|
||||||
|
assert(b->namelen == 0);
|
||||||
|
} else if (memcmp(a->name, b->name, a->namelen) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->value == NULL || b->value == NULL) {
|
||||||
|
assert(a->valuelen == 0);
|
||||||
|
assert(b->valuelen == 0);
|
||||||
|
} else if (memcmp(a->value, b->value, a->valuelen) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) {
|
void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) {
|
||||||
@@ -1055,6 +1147,11 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES:
|
||||||
|
if (iv[i].value != 0 && iv[i].value != 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
|
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
|
||||||
|
|
||||||
#define NGHTTP2_MAX_PAYLOADLEN 16384
|
#define NGHTTP2_MAX_PAYLOADLEN 16384
|
||||||
/* The one frame buffer length for tranmission. We may use several of
|
/* The one frame buffer length for transmission. We may use several of
|
||||||
them to support CONTINUATION. To account for Pad Length field, we
|
them to support CONTINUATION. To account for Pad Length field, we
|
||||||
allocate extra 1 byte, which saves extra large memcopying. */
|
allocate extra 1 byte, which saves extra large memcopying. */
|
||||||
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
|
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
/* Maximum headers block size to send, calculated using
|
/* Maximum headers block size to send, calculated using
|
||||||
nghttp2_hd_deflate_bound(). This is the default value, and can be
|
nghttp2_hd_deflate_bound(). This is the default value, and can be
|
||||||
overridden by nghttp2_option_set_max_send_header_block_size(). */
|
overridden by nghttp2_option_set_max_send_header_block_length(). */
|
||||||
#define NGHTTP2_MAX_HEADERSLEN 65536
|
#define NGHTTP2_MAX_HEADERSLEN 65536
|
||||||
|
|
||||||
/* The number of bytes for each SETTINGS entry */
|
/* The number of bytes for each SETTINGS entry */
|
||||||
@@ -73,6 +73,7 @@
|
|||||||
typedef union {
|
typedef union {
|
||||||
nghttp2_ext_altsvc altsvc;
|
nghttp2_ext_altsvc altsvc;
|
||||||
nghttp2_ext_origin origin;
|
nghttp2_ext_origin origin;
|
||||||
|
nghttp2_ext_priority_update priority_update;
|
||||||
} nghttp2_ext_frame_payload;
|
} nghttp2_ext_frame_payload;
|
||||||
|
|
||||||
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
||||||
@@ -423,6 +424,31 @@ int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *ext);
|
|||||||
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
|
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
|
||||||
const uint8_t *payload,
|
const uint8_t *payload,
|
||||||
size_t payloadlen, nghttp2_mem *mem);
|
size_t payloadlen, nghttp2_mem *mem);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packs PRIORITY_UPDATE frame |frame| in wire frame format and store
|
||||||
|
* it in |bufs|.
|
||||||
|
*
|
||||||
|
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||||
|
* before calling this function.
|
||||||
|
*
|
||||||
|
* This function always succeeds and returns 0.
|
||||||
|
*/
|
||||||
|
int nghttp2_frame_pack_priority_update(nghttp2_bufs *bufs,
|
||||||
|
nghttp2_extension *ext);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpacks PRIORITY_UPDATE wire format into |frame|. The |payload| of
|
||||||
|
* |payloadlen| bytes contains frame payload. This function assumes
|
||||||
|
* that frame->payload points to the nghttp2_ext_priority_update
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* This function always succeeds and returns 0.
|
||||||
|
*/
|
||||||
|
void nghttp2_frame_unpack_priority_update_payload(nghttp2_extension *frame,
|
||||||
|
uint8_t *payload,
|
||||||
|
size_t payloadlen);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initializes HEADERS frame |frame| with given values. |frame| takes
|
* Initializes HEADERS frame |frame| with given values. |frame| takes
|
||||||
* ownership of |nva|, so caller must not free it. If |stream_id| is
|
* ownership of |nva|, so caller must not free it. If |stream_id| is
|
||||||
@@ -538,6 +564,25 @@ void nghttp2_frame_origin_init(nghttp2_extension *frame,
|
|||||||
*/
|
*/
|
||||||
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
|
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes PRIORITY_UPDATE frame |frame| with given values. This
|
||||||
|
* function assumes that frame->payload points to
|
||||||
|
* nghttp2_ext_priority_update object. On success, this function
|
||||||
|
* takes ownership of |field_value|, so caller must not free it.
|
||||||
|
*/
|
||||||
|
void nghttp2_frame_priority_update_init(nghttp2_extension *frame,
|
||||||
|
int32_t stream_id, uint8_t *field_value,
|
||||||
|
size_t field_value_len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frees up resources under |frame|. This function does not free
|
||||||
|
* nghttp2_ext_priority_update object pointed by frame->payload. This
|
||||||
|
* function only frees field_value pointed by
|
||||||
|
* nghttp2_ext_priority_update.field_value.
|
||||||
|
*/
|
||||||
|
void nghttp2_frame_priority_update_free(nghttp2_extension *frame,
|
||||||
|
nghttp2_mem *mem);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the number of padding bytes after payload. The total
|
* Returns the number of padding bytes after payload. The total
|
||||||
* padding length is given in the |padlen|. The returned value does
|
* padding length is given in the |padlen|. The returned value does
|
||||||
|
|||||||
@@ -269,6 +269,11 @@ static int32_t lookup_token(const uint8_t *name, size_t namelen) {
|
|||||||
return NGHTTP2_TOKEN_LOCATION;
|
return NGHTTP2_TOKEN_LOCATION;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'y':
|
||||||
|
if (memeq("priorit", name, 7)) {
|
||||||
|
return NGHTTP2_TOKEN_PRIORITY;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
@@ -1263,6 +1268,8 @@ int nghttp2_hd_inflate_change_table_size(
|
|||||||
return NGHTTP2_ERR_INVALID_STATE;
|
return NGHTTP2_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
||||||
|
|
||||||
/* It seems that encoder is not required to send dynamic table size
|
/* It seems that encoder is not required to send dynamic table size
|
||||||
update if the table size is not changed after applying
|
update if the table size is not changed after applying
|
||||||
SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this
|
SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this
|
||||||
@@ -1275,13 +1282,12 @@ int nghttp2_hd_inflate_change_table_size(
|
|||||||
/* Remember minimum value, and validate that encoder sends the
|
/* Remember minimum value, and validate that encoder sends the
|
||||||
value less than or equal to this. */
|
value less than or equal to this. */
|
||||||
inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
||||||
|
|
||||||
|
inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
|
||||||
|
|
||||||
|
hd_context_shrink_table_size(&inflater->ctx, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
|
||||||
|
|
||||||
inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
|
|
||||||
|
|
||||||
hd_context_shrink_table_size(&inflater->ctx, NULL);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ typedef enum {
|
|||||||
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
||||||
NGHTTP2_TOKEN_UPGRADE,
|
NGHTTP2_TOKEN_UPGRADE,
|
||||||
NGHTTP2_TOKEN__PROTOCOL,
|
NGHTTP2_TOKEN__PROTOCOL,
|
||||||
|
NGHTTP2_TOKEN_PRIORITY,
|
||||||
} nghttp2_token;
|
} nghttp2_token;
|
||||||
|
|
||||||
struct nghttp2_hd_entry;
|
struct nghttp2_hd_entry;
|
||||||
|
|||||||
@@ -334,6 +334,8 @@ const char *nghttp2_strerror(int error_code) {
|
|||||||
case NGHTTP2_ERR_FLOODED:
|
case NGHTTP2_ERR_FLOODED:
|
||||||
return "Flooding was detected in this HTTP/2 session, and it must be "
|
return "Flooding was detected in this HTTP/2 session, and it must be "
|
||||||
"closed";
|
"closed";
|
||||||
|
case NGHTTP2_ERR_TOO_MANY_SETTINGS:
|
||||||
|
return "SETTINGS frame contained more than the maximum allowed entries";
|
||||||
default:
|
default:
|
||||||
return "Unknown error code";
|
return "Unknown error code";
|
||||||
}
|
}
|
||||||
@@ -505,7 +507,179 @@ int nghttp2_check_header_value(const uint8_t *value, size_t len) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generated by genauthroitychartbl.py */
|
int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) {
|
||||||
|
if (len == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' ||
|
||||||
|
*(value + len - 1) == '\t') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
||||||
|
};
|
||||||
|
|
||||||
|
int nghttp2_check_method(const uint8_t *value, size_t len) {
|
||||||
|
const uint8_t *last;
|
||||||
|
if (len == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (last = value + len; value != last; ++value) {
|
||||||
|
if (!VALID_METHOD_CHARS[*value]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 */
|
||||||
|
};
|
||||||
|
|
||||||
|
int nghttp2_check_path(const uint8_t *value, size_t len) {
|
||||||
|
const uint8_t *last;
|
||||||
|
for (last = value + len; value != last; ++value) {
|
||||||
|
if (!VALID_PATH_CHARS[*value]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generated by genauthoritychartbl.py */
|
||||||
static char VALID_AUTHORITY_CHARS[] = {
|
static char VALID_AUTHORITY_CHARS[] = {
|
||||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "nghttp2_hd.h"
|
#include "nghttp2_hd.h"
|
||||||
#include "nghttp2_helper.h"
|
#include "nghttp2_helper.h"
|
||||||
|
#include "nghttp2_extpri.h"
|
||||||
|
|
||||||
static uint8_t downcase(uint8_t c) {
|
static uint8_t downcase(uint8_t c) {
|
||||||
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
|
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
|
||||||
@@ -72,25 +73,12 @@ static int64_t parse_uint(const uint8_t *s, size_t len) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
|
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
|
||||||
int flag) {
|
uint32_t flag) {
|
||||||
if (stream->http_flags & flag) {
|
if ((stream->http_flags & flag) || nv->value->len == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (lws(nv->value->base, nv->value->len)) {
|
stream->http_flags = stream->http_flags | flag;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
stream->http_flags = (uint16_t)(stream->http_flags | flag);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +102,8 @@ static int check_path(nghttp2_stream *stream) {
|
|||||||
|
|
||||||
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
||||||
int trailer, int connect_protocol) {
|
int trailer, int connect_protocol) {
|
||||||
|
nghttp2_extpri extpri;
|
||||||
|
|
||||||
if (nv->name->base[0] == ':') {
|
if (nv->name->base[0] == ':') {
|
||||||
if (trailer ||
|
if (trailer ||
|
||||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||||
@@ -212,6 +202,23 @@ static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
|||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_TOKEN_PRIORITY:
|
||||||
|
if (!trailer &&
|
||||||
|
/* Do not parse the header field in PUSH_PROMISE. */
|
||||||
|
(stream->stream_id & 1) &&
|
||||||
|
(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
|
||||||
|
!(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) {
|
||||||
|
nghttp2_extpri_from_uint8(&extpri, stream->http_extpri);
|
||||||
|
if (nghttp2_http_parse_priority(&extpri, nv->value->base,
|
||||||
|
nv->value->len) == 0) {
|
||||||
|
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_BAD_PRIORITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (nv->name->base[0] == ':') {
|
if (nv->name->base[0] == ':') {
|
||||||
return NGHTTP2_ERR_HTTP_HEADER;
|
return NGHTTP2_ERR_HTTP_HEADER;
|
||||||
@@ -329,6 +336,16 @@ static int check_scheme(const uint8_t *value, size_t len) {
|
|||||||
return 1;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||||
nghttp2_frame *frame, nghttp2_hd_nv *nv,
|
nghttp2_frame *frame, nghttp2_hd_nv *nv,
|
||||||
int trailer) {
|
int trailer) {
|
||||||
@@ -360,13 +377,46 @@ int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
|||||||
return NGHTTP2_ERR_IGN_HTTP_HEADER;
|
return NGHTTP2_ERR_IGN_HTTP_HEADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nv->token == NGHTTP2_TOKEN__AUTHORITY ||
|
switch (nv->token) {
|
||||||
nv->token == NGHTTP2_TOKEN_HOST) {
|
case NGHTTP2_TOKEN__METHOD:
|
||||||
rv = nghttp2_check_authority(nv->value->base, nv->value->len);
|
rv = nghttp2_check_method(nv->value->base, nv->value->len);
|
||||||
} else if (nv->token == NGHTTP2_TOKEN__SCHEME) {
|
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 = nghttp2_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);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NGHTTP2_TOKEN__SCHEME:
|
||||||
rv = check_scheme(nv->value->base, nv->value->len);
|
rv = check_scheme(nv->value->base, nv->value->len);
|
||||||
} else {
|
break;
|
||||||
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rv == 0) {
|
if (rv == 0) {
|
||||||
@@ -434,16 +484,15 @@ int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
|
|||||||
|
|
||||||
if (stream->status_code / 100 == 1) {
|
if (stream->status_code / 100 == 1) {
|
||||||
/* non-final response */
|
/* non-final response */
|
||||||
stream->http_flags =
|
stream->http_flags = (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
|
||||||
(uint16_t)((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
|
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
|
||||||
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
|
|
||||||
stream->content_length = -1;
|
stream->content_length = -1;
|
||||||
stream->status_code = -1;
|
stream->status_code = -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->http_flags =
|
stream->http_flags =
|
||||||
(uint16_t)(stream->http_flags & ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
|
stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
|
||||||
|
|
||||||
if (!expect_response_body(stream)) {
|
if (!expect_response_body(stream)) {
|
||||||
stream->content_length = 0;
|
stream->content_length = 0;
|
||||||
@@ -528,3 +577,715 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generated by genchartbl.py */
|
||||||
|
static const int SF_KEY_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||||
|
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
|
||||||
|
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||||
|
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||||
|
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||||
|
0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
|
||||||
|
0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
|
||||||
|
0 /* ( */, 0 /* ) */, 1 /* * */, 0 /* + */, 0 /* , */,
|
||||||
|
1 /* - */, 1 /* . */, 0 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||||
|
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||||
|
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||||
|
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
|
||||||
|
0 /* A */, 0 /* B */, 0 /* C */, 0 /* D */, 0 /* E */,
|
||||||
|
0 /* F */, 0 /* G */, 0 /* H */, 0 /* I */, 0 /* J */,
|
||||||
|
0 /* K */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
|
||||||
|
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* T */,
|
||||||
|
0 /* U */, 0 /* V */, 0 /* W */, 0 /* X */, 0 /* Y */,
|
||||||
|
0 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
|
||||||
|
1 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||||
|
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||||
|
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||||
|
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
|
||||||
|
0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
|
||||||
|
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
|
||||||
|
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||||
|
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
|
||||||
|
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
|
||||||
|
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
|
||||||
|
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||||
|
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
|
||||||
|
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
|
||||||
|
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
|
||||||
|
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||||
|
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
|
||||||
|
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
|
||||||
|
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
|
||||||
|
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||||
|
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
|
||||||
|
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
|
||||||
|
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
|
||||||
|
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||||
|
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
|
||||||
|
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
|
||||||
|
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
|
||||||
|
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||||
|
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
|
||||||
|
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
|
||||||
|
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
|
||||||
|
0 /* 0xff */,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t sf_parse_key(const uint8_t *begin, const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
|
||||||
|
if ((*p < 'a' || 'z' < *p) && *p != '*') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end && SF_KEY_CHARS[*p]; ++p)
|
||||||
|
;
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_integer_or_decimal(nghttp2_sf_value *dest,
|
||||||
|
const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
int sign = 1;
|
||||||
|
int64_t value = 0;
|
||||||
|
int type = NGHTTP2_SF_VALUE_TYPE_INTEGER;
|
||||||
|
size_t len = 0;
|
||||||
|
size_t fpos = 0;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (*p == '-') {
|
||||||
|
if (++p == end) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sign = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p < '0' || '9' < *p) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end; ++p) {
|
||||||
|
switch (*p) {
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
value *= 10;
|
||||||
|
value += *p - '0';
|
||||||
|
|
||||||
|
if (++len > 15) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
if (type != NGHTTP2_SF_VALUE_TYPE_INTEGER) {
|
||||||
|
goto fin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 12) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fpos = len;
|
||||||
|
type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto fin;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fin:
|
||||||
|
switch (type) {
|
||||||
|
case NGHTTP2_SF_VALUE_TYPE_INTEGER:
|
||||||
|
if (dest) {
|
||||||
|
dest->type = (uint8_t)type;
|
||||||
|
dest->i = value * sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
case NGHTTP2_SF_VALUE_TYPE_DECIMAL:
|
||||||
|
if (fpos == len || len - fpos > 3) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->type = (uint8_t)type;
|
||||||
|
dest->d = (double)value;
|
||||||
|
for (i = len - fpos; i > 0; --i) {
|
||||||
|
dest->d /= (double)10;
|
||||||
|
}
|
||||||
|
dest->d *= sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generated by genchartbl.py */
|
||||||
|
static const int SF_DQUOTE_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||||
|
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
|
||||||
|
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||||
|
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||||
|
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||||
|
0 /* RS */, 0 /* US */, 1 /* SPC */, 1 /* ! */, 0 /* " */,
|
||||||
|
1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||||
|
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* , */,
|
||||||
|
1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||||
|
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||||
|
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||||
|
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* @ */,
|
||||||
|
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
|
||||||
|
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
|
||||||
|
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||||
|
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
|
||||||
|
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
|
||||||
|
1 /* Z */, 1 /* [ */, 0 /* \ */, 1 /* ] */, 1 /* ^ */,
|
||||||
|
1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||||
|
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||||
|
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||||
|
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* | */,
|
||||||
|
1 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
|
||||||
|
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
|
||||||
|
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||||
|
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
|
||||||
|
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
|
||||||
|
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
|
||||||
|
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||||
|
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
|
||||||
|
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
|
||||||
|
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
|
||||||
|
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||||
|
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
|
||||||
|
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
|
||||||
|
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
|
||||||
|
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||||
|
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
|
||||||
|
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
|
||||||
|
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
|
||||||
|
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||||
|
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
|
||||||
|
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
|
||||||
|
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
|
||||||
|
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||||
|
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
|
||||||
|
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
|
||||||
|
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
|
||||||
|
0 /* 0xff */,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t sf_parse_string(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
|
||||||
|
if (*p++ != '"') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end; ++p) {
|
||||||
|
switch (*p) {
|
||||||
|
case '\\':
|
||||||
|
if (++p == end) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*p) {
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_STRING;
|
||||||
|
dest->s.base = begin + 1;
|
||||||
|
dest->s.len = (size_t)(p - dest->s.base);
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
default:
|
||||||
|
if (!SF_DQUOTE_CHARS[*p]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generated by genchartbl.py */
|
||||||
|
static const int SF_TOKEN_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||||
|
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
|
||||||
|
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||||
|
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||||
|
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||||
|
0 /* RS */, 0 /* US */, 0 /* SPC */, 1 /* ! */, 0 /* " */,
|
||||||
|
1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||||
|
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* , */,
|
||||||
|
1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||||
|
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||||
|
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 0 /* ; */,
|
||||||
|
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
|
||||||
|
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
|
||||||
|
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
|
||||||
|
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||||
|
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
|
||||||
|
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
|
||||||
|
1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */,
|
||||||
|
1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||||
|
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||||
|
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||||
|
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* | */,
|
||||||
|
0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
|
||||||
|
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
|
||||||
|
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||||
|
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
|
||||||
|
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
|
||||||
|
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
|
||||||
|
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||||
|
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
|
||||||
|
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
|
||||||
|
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
|
||||||
|
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||||
|
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
|
||||||
|
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
|
||||||
|
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
|
||||||
|
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||||
|
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
|
||||||
|
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
|
||||||
|
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
|
||||||
|
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||||
|
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
|
||||||
|
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
|
||||||
|
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
|
||||||
|
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||||
|
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
|
||||||
|
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
|
||||||
|
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
|
||||||
|
0 /* 0xff */,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t sf_parse_token(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
|
||||||
|
if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end && SF_TOKEN_CHARS[*p]; ++p)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_TOKEN;
|
||||||
|
dest->s.base = begin;
|
||||||
|
dest->s.len = (size_t)(p - begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generated by genchartbl.py */
|
||||||
|
static const int SF_BYTESEQ_CHARS[] = {
|
||||||
|
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||||
|
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
|
||||||
|
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||||
|
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||||
|
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||||
|
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||||
|
0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
|
||||||
|
0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
|
||||||
|
0 /* ( */, 0 /* ) */, 0 /* * */, 1 /* + */, 0 /* , */,
|
||||||
|
0 /* - */, 0 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||||
|
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||||
|
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||||
|
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
|
||||||
|
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
|
||||||
|
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
|
||||||
|
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||||
|
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
|
||||||
|
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
|
||||||
|
1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
|
||||||
|
0 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||||
|
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||||
|
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||||
|
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||||
|
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||||
|
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
|
||||||
|
0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
|
||||||
|
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
|
||||||
|
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||||
|
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
|
||||||
|
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
|
||||||
|
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
|
||||||
|
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||||
|
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
|
||||||
|
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
|
||||||
|
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
|
||||||
|
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||||
|
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
|
||||||
|
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
|
||||||
|
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
|
||||||
|
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||||
|
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
|
||||||
|
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
|
||||||
|
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
|
||||||
|
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||||
|
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
|
||||||
|
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
|
||||||
|
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
|
||||||
|
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||||
|
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
|
||||||
|
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
|
||||||
|
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
|
||||||
|
0 /* 0xff */,
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t sf_parse_byteseq(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
|
||||||
|
if (*p++ != ':') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; p != end; ++p) {
|
||||||
|
switch (*p) {
|
||||||
|
case ':':
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_BYTESEQ;
|
||||||
|
dest->s.base = begin + 1;
|
||||||
|
dest->s.len = (size_t)(p - dest->s.base);
|
||||||
|
}
|
||||||
|
|
||||||
|
++p;
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
default:
|
||||||
|
if (!SF_BYTESEQ_CHARS[*p]) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_boolean(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
int b;
|
||||||
|
|
||||||
|
if (*p++ != '?') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p == end) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (*p++) {
|
||||||
|
case '0':
|
||||||
|
b = 0;
|
||||||
|
break;
|
||||||
|
case '1':
|
||||||
|
b = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
|
||||||
|
dest->b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_bare_item(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
switch (*begin) {
|
||||||
|
case '-':
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
return sf_parse_integer_or_decimal(dest, begin, end);
|
||||||
|
case '"':
|
||||||
|
return sf_parse_string(dest, begin, end);
|
||||||
|
case '*':
|
||||||
|
return sf_parse_token(dest, begin, end);
|
||||||
|
case ':':
|
||||||
|
return sf_parse_byteseq(dest, begin, end);
|
||||||
|
case '?':
|
||||||
|
return sf_parse_boolean(dest, begin, end);
|
||||||
|
default:
|
||||||
|
if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) {
|
||||||
|
return sf_parse_token(dest, begin, end);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define sf_discard_sp_end_err(BEGIN, END, ERR) \
|
||||||
|
for (;; ++(BEGIN)) { \
|
||||||
|
if ((BEGIN) == (END)) { \
|
||||||
|
return (ERR); \
|
||||||
|
} \
|
||||||
|
if (*(BEGIN) != ' ') { \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_params(const uint8_t *begin, const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
ssize_t slen;
|
||||||
|
|
||||||
|
for (; p != end && *p == ';';) {
|
||||||
|
++p;
|
||||||
|
|
||||||
|
sf_discard_sp_end_err(p, end, -1);
|
||||||
|
|
||||||
|
slen = sf_parse_key(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (p == end || *p != '=') {
|
||||||
|
/* Boolean true */
|
||||||
|
} else if (++p == end) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
slen = sf_parse_bare_item(NULL, p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
ssize_t slen;
|
||||||
|
|
||||||
|
slen = sf_parse_bare_item(dest, p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
slen = sf_parse_params(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
return sf_parse_item(dest, begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_inner_list(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
const uint8_t *p = begin;
|
||||||
|
ssize_t slen;
|
||||||
|
|
||||||
|
if (*p++ != '(') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
sf_discard_sp_end_err(p, end, -1);
|
||||||
|
|
||||||
|
if (*p == ')') {
|
||||||
|
++p;
|
||||||
|
|
||||||
|
slen = sf_parse_params(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (dest) {
|
||||||
|
dest->type = NGHTTP2_SF_VALUE_TYPE_INNER_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
slen = sf_parse_item(NULL, p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (p == end || (*p != ' ' && *p != ')')) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
|
||||||
|
const uint8_t *begin, const uint8_t *end) {
|
||||||
|
return sf_parse_inner_list(dest, begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t sf_parse_item_or_inner_list(nghttp2_sf_value *dest,
|
||||||
|
const uint8_t *begin,
|
||||||
|
const uint8_t *end) {
|
||||||
|
if (*begin == '(') {
|
||||||
|
return sf_parse_inner_list(dest, begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sf_parse_item(dest, begin, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define sf_discard_ows(BEGIN, END) \
|
||||||
|
for (;; ++(BEGIN)) { \
|
||||||
|
if ((BEGIN) == (END)) { \
|
||||||
|
goto fin; \
|
||||||
|
} \
|
||||||
|
if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define sf_discard_ows_end_err(BEGIN, END, ERR) \
|
||||||
|
for (;; ++(BEGIN)) { \
|
||||||
|
if ((BEGIN) == (END)) { \
|
||||||
|
return (ERR); \
|
||||||
|
} \
|
||||||
|
if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
|
||||||
|
size_t valuelen) {
|
||||||
|
const uint8_t *p = value, *end = value + valuelen;
|
||||||
|
ssize_t slen;
|
||||||
|
nghttp2_sf_value val;
|
||||||
|
nghttp2_extpri pri = *dest;
|
||||||
|
const uint8_t *key;
|
||||||
|
size_t keylen;
|
||||||
|
|
||||||
|
for (; p != end && *p == ' '; ++p)
|
||||||
|
;
|
||||||
|
|
||||||
|
for (; p != end;) {
|
||||||
|
slen = sf_parse_key(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = p;
|
||||||
|
keylen = (size_t)slen;
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (p == end || *p != '=') {
|
||||||
|
/* Boolean true */
|
||||||
|
val.type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
|
||||||
|
val.b = 1;
|
||||||
|
|
||||||
|
slen = sf_parse_params(p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
} else if (++p == end) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
} else {
|
||||||
|
slen = sf_parse_item_or_inner_list(&val, p, end);
|
||||||
|
if (slen < 0) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p += slen;
|
||||||
|
|
||||||
|
if (keylen == 1) {
|
||||||
|
switch (key[0]) {
|
||||||
|
case 'i':
|
||||||
|
if (val.type != NGHTTP2_SF_VALUE_TYPE_BOOLEAN) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pri.inc = val.b;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (val.type != NGHTTP2_SF_VALUE_TYPE_INTEGER ||
|
||||||
|
val.i < NGHTTP2_EXTPRI_URGENCY_HIGH ||
|
||||||
|
NGHTTP2_EXTPRI_URGENCY_LOW < val.i) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
pri.urgency = (uint32_t)val.i;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sf_discard_ows(p, end);
|
||||||
|
|
||||||
|
if (*p++ != ',') {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
fin:
|
||||||
|
*dest = pri;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -94,4 +94,55 @@ int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
|
|||||||
void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RFC 8941 Structured Field Values.
|
||||||
|
*/
|
||||||
|
typedef enum nghttp2_sf_value_type {
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_BOOLEAN,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_INTEGER,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_DECIMAL,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_STRING,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_TOKEN,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_BYTESEQ,
|
||||||
|
NGHTTP2_SF_VALUE_TYPE_INNER_LIST,
|
||||||
|
} nghttp2_sf_value_type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_sf_value stores Structured Field Values item. For Inner
|
||||||
|
* List, only type is set to NGHTTP2_SF_VALUE_TYPE_INNER_LIST.
|
||||||
|
*/
|
||||||
|
typedef struct nghttp2_sf_value {
|
||||||
|
uint8_t type;
|
||||||
|
union {
|
||||||
|
int b;
|
||||||
|
int64_t i;
|
||||||
|
double d;
|
||||||
|
struct {
|
||||||
|
const uint8_t *base;
|
||||||
|
size_t len;
|
||||||
|
} s;
|
||||||
|
};
|
||||||
|
} nghttp2_sf_value;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_sf_parse_item parses the input sequence [|begin|, |end|)
|
||||||
|
* and stores the parsed an Item in |dest|. It returns the number of
|
||||||
|
* bytes consumed if it succeeds, or -1. This function is declared
|
||||||
|
* here for unit tests.
|
||||||
|
*/
|
||||||
|
ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
|
||||||
|
const uint8_t *end);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* nghttp2_sf_parse_inner_list parses the input sequence [|begin|, |end|)
|
||||||
|
* and stores the parsed an Inner List in |dest|. It returns the number of
|
||||||
|
* bytes consumed if it succeeds, or -1. This function is declared
|
||||||
|
* here for unit tests.
|
||||||
|
*/
|
||||||
|
ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
|
||||||
|
const uint8_t *begin, const uint8_t *end);
|
||||||
|
|
||||||
|
int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
|
||||||
|
size_t valuelen);
|
||||||
|
|
||||||
#endif /* NGHTTP2_HTTP_H */
|
#endif /* NGHTTP2_HTTP_H */
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* nghttp2 - HTTP/2 C Library
|
* nghttp2 - HTTP/2 C Library
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
* Copyright (c) 2017 ngtcp2 contributors
|
||||||
|
* Copyright (c) 2012 nghttp2 contributors
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
@@ -25,14 +26,19 @@
|
|||||||
#include "nghttp2_map.h"
|
#include "nghttp2_map.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#define INITIAL_TABLE_LENGTH 256
|
#include "nghttp2_helper.h"
|
||||||
|
|
||||||
|
#define NGHTTP2_INITIAL_TABLE_LENBITS 8
|
||||||
|
|
||||||
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
|
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
|
||||||
map->mem = mem;
|
map->mem = mem;
|
||||||
map->tablelen = INITIAL_TABLE_LENGTH;
|
map->tablelen = 1 << NGHTTP2_INITIAL_TABLE_LENBITS;
|
||||||
|
map->tablelenbits = NGHTTP2_INITIAL_TABLE_LENBITS;
|
||||||
map->table =
|
map->table =
|
||||||
nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_entry *));
|
nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_bucket));
|
||||||
if (map->table == NULL) {
|
if (map->table == NULL) {
|
||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
@@ -43,112 +49,188 @@ int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_map_free(nghttp2_map *map) {
|
void nghttp2_map_free(nghttp2_map *map) {
|
||||||
|
if (!map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nghttp2_mem_free(map->mem, map->table);
|
nghttp2_mem_free(map->mem, map->table);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_map_each_free(nghttp2_map *map,
|
void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
|
||||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
|
||||||
void *ptr) {
|
void *ptr) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
nghttp2_map_bucket *bkt;
|
||||||
|
|
||||||
for (i = 0; i < map->tablelen; ++i) {
|
for (i = 0; i < map->tablelen; ++i) {
|
||||||
nghttp2_map_entry *entry;
|
bkt = &map->table[i];
|
||||||
for (entry = map->table[i]; entry;) {
|
|
||||||
nghttp2_map_entry *next = entry->next;
|
if (bkt->data == NULL) {
|
||||||
func(entry, ptr);
|
continue;
|
||||||
entry = next;
|
|
||||||
}
|
}
|
||||||
map->table[i] = NULL;
|
|
||||||
|
func(bkt->data, ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_map_each(nghttp2_map *map,
|
int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
|
||||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
|
||||||
void *ptr) {
|
void *ptr) {
|
||||||
int rv;
|
int rv;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
nghttp2_map_bucket *bkt;
|
||||||
|
|
||||||
for (i = 0; i < map->tablelen; ++i) {
|
for (i = 0; i < map->tablelen; ++i) {
|
||||||
nghttp2_map_entry *entry;
|
bkt = &map->table[i];
|
||||||
for (entry = map->table[i]; entry; entry = entry->next) {
|
|
||||||
rv = func(entry, ptr);
|
if (bkt->data == NULL) {
|
||||||
if (rv != 0) {
|
continue;
|
||||||
return rv;
|
}
|
||||||
}
|
|
||||||
|
rv = func(bkt->data, ptr);
|
||||||
|
if (rv != 0) {
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) {
|
static uint32_t hash(nghttp2_map_key_type key) {
|
||||||
entry->key = key;
|
return (uint32_t)key * 2654435769u;
|
||||||
entry->next = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Same hash function in android HashMap source code. */
|
static size_t h2idx(uint32_t hash, uint32_t bits) {
|
||||||
/* The |mod| must be power of 2 */
|
return hash >> (32 - bits);
|
||||||
static uint32_t hash(int32_t key, uint32_t mod) {
|
|
||||||
uint32_t h = (uint32_t)key;
|
|
||||||
h ^= (h >> 20) ^ (h >> 12);
|
|
||||||
h ^= (h >> 7) ^ (h >> 4);
|
|
||||||
return h & (mod - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int insert(nghttp2_map_entry **table, uint32_t tablelen,
|
static size_t distance(uint32_t tablelen, uint32_t tablelenbits,
|
||||||
nghttp2_map_entry *entry) {
|
nghttp2_map_bucket *bkt, size_t idx) {
|
||||||
uint32_t h = hash(entry->key, tablelen);
|
return (idx - h2idx(bkt->hash, tablelenbits)) & (tablelen - 1);
|
||||||
if (table[h] == NULL) {
|
|
||||||
table[h] = entry;
|
|
||||||
} else {
|
|
||||||
nghttp2_map_entry *p;
|
|
||||||
/* We won't allow duplicated key, so check it out. */
|
|
||||||
for (p = table[h]; p; p = p->next) {
|
|
||||||
if (p->key == entry->key) {
|
|
||||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
entry->next = table[h];
|
|
||||||
table[h] = entry;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* new_tablelen must be power of 2 */
|
static void map_bucket_swap(nghttp2_map_bucket *bkt, uint32_t *phash,
|
||||||
static int resize(nghttp2_map *map, uint32_t new_tablelen) {
|
nghttp2_map_key_type *pkey, void **pdata) {
|
||||||
|
uint32_t h = bkt->hash;
|
||||||
|
nghttp2_map_key_type key = bkt->key;
|
||||||
|
void *data = bkt->data;
|
||||||
|
|
||||||
|
bkt->hash = *phash;
|
||||||
|
bkt->key = *pkey;
|
||||||
|
bkt->data = *pdata;
|
||||||
|
|
||||||
|
*phash = h;
|
||||||
|
*pkey = key;
|
||||||
|
*pdata = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void map_bucket_set_data(nghttp2_map_bucket *bkt, uint32_t hash,
|
||||||
|
nghttp2_map_key_type key, void *data) {
|
||||||
|
bkt->hash = hash;
|
||||||
|
bkt->key = key;
|
||||||
|
bkt->data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nghttp2_map_print_distance(nghttp2_map *map) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
nghttp2_map_entry **new_table;
|
size_t idx;
|
||||||
|
nghttp2_map_bucket *bkt;
|
||||||
|
|
||||||
|
for (i = 0; i < map->tablelen; ++i) {
|
||||||
|
bkt = &map->table[i];
|
||||||
|
|
||||||
|
if (bkt->data == NULL) {
|
||||||
|
fprintf(stderr, "@%u <EMPTY>\n", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = h2idx(bkt->hash, map->tablelenbits);
|
||||||
|
fprintf(stderr, "@%u hash=%08x key=%d base=%zu distance=%zu\n", i,
|
||||||
|
bkt->hash, bkt->key, idx,
|
||||||
|
distance(map->tablelen, map->tablelenbits, bkt, idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int insert(nghttp2_map_bucket *table, uint32_t tablelen,
|
||||||
|
uint32_t tablelenbits, uint32_t hash,
|
||||||
|
nghttp2_map_key_type key, void *data) {
|
||||||
|
size_t idx = h2idx(hash, tablelenbits);
|
||||||
|
size_t d = 0, dd;
|
||||||
|
nghttp2_map_bucket *bkt;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
bkt = &table[idx];
|
||||||
|
|
||||||
|
if (bkt->data == NULL) {
|
||||||
|
map_bucket_set_data(bkt, hash, key, data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dd = distance(tablelen, tablelenbits, bkt, idx);
|
||||||
|
if (d > dd) {
|
||||||
|
map_bucket_swap(bkt, &hash, &key, &data);
|
||||||
|
d = dd;
|
||||||
|
} 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. */
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
++d;
|
||||||
|
idx = (idx + 1) & (tablelen - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* new_tablelen must be power of 2 and new_tablelen == (1 <<
|
||||||
|
new_tablelenbits) must hold. */
|
||||||
|
static int map_resize(nghttp2_map *map, uint32_t new_tablelen,
|
||||||
|
uint32_t new_tablelenbits) {
|
||||||
|
uint32_t i;
|
||||||
|
nghttp2_map_bucket *new_table;
|
||||||
|
nghttp2_map_bucket *bkt;
|
||||||
|
int rv;
|
||||||
|
(void)rv;
|
||||||
|
|
||||||
new_table =
|
new_table =
|
||||||
nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_entry *));
|
nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_bucket));
|
||||||
if (new_table == NULL) {
|
if (new_table == NULL) {
|
||||||
return NGHTTP2_ERR_NOMEM;
|
return NGHTTP2_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < map->tablelen; ++i) {
|
for (i = 0; i < map->tablelen; ++i) {
|
||||||
nghttp2_map_entry *entry;
|
bkt = &map->table[i];
|
||||||
for (entry = map->table[i]; entry;) {
|
if (bkt->data == NULL) {
|
||||||
nghttp2_map_entry *next = entry->next;
|
continue;
|
||||||
entry->next = NULL;
|
|
||||||
/* This function must succeed */
|
|
||||||
insert(new_table, new_tablelen, entry);
|
|
||||||
entry = next;
|
|
||||||
}
|
}
|
||||||
|
rv = insert(new_table, new_tablelen, new_tablelenbits, bkt->hash, bkt->key,
|
||||||
|
bkt->data);
|
||||||
|
|
||||||
|
assert(0 == rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_mem_free(map->mem, map->table);
|
nghttp2_mem_free(map->mem, map->table);
|
||||||
map->tablelen = new_tablelen;
|
map->tablelen = new_tablelen;
|
||||||
|
map->tablelenbits = new_tablelenbits;
|
||||||
map->table = new_table;
|
map->table = new_table;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
|
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
|
assert(data);
|
||||||
|
|
||||||
/* Load factor is 0.75 */
|
/* Load factor is 0.75 */
|
||||||
if ((map->size + 1) * 4 > map->tablelen * 3) {
|
if ((map->size + 1) * 4 > map->tablelen * 3) {
|
||||||
rv = resize(map, map->tablelen * 2);
|
rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rv = insert(map->table, map->tablelen, new_entry);
|
|
||||||
|
rv = insert(map->table, map->tablelen, map->tablelenbits, hash(key), key,
|
||||||
|
data);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@@ -156,34 +238,76 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) {
|
void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
|
||||||
uint32_t h;
|
uint32_t h = hash(key);
|
||||||
nghttp2_map_entry *entry;
|
size_t idx = h2idx(h, map->tablelenbits);
|
||||||
h = hash(key, map->tablelen);
|
nghttp2_map_bucket *bkt;
|
||||||
for (entry = map->table[h]; entry; entry = entry->next) {
|
size_t d = 0;
|
||||||
if (entry->key == key) {
|
|
||||||
return entry;
|
for (;;) {
|
||||||
|
bkt = &map->table[idx];
|
||||||
|
|
||||||
|
if (bkt->data == NULL ||
|
||||||
|
d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bkt->key == key) {
|
||||||
|
return bkt->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
++d;
|
||||||
|
idx = (idx + 1) & (map->tablelen - 1);
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_map_remove(nghttp2_map *map, key_type key) {
|
int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
|
||||||
uint32_t h;
|
uint32_t h = hash(key);
|
||||||
nghttp2_map_entry **dst;
|
size_t idx = h2idx(h, map->tablelenbits), didx;
|
||||||
|
nghttp2_map_bucket *bkt;
|
||||||
|
size_t d = 0;
|
||||||
|
|
||||||
h = hash(key, map->tablelen);
|
for (;;) {
|
||||||
|
bkt = &map->table[idx];
|
||||||
|
|
||||||
for (dst = &map->table[h]; *dst; dst = &(*dst)->next) {
|
if (bkt->data == NULL ||
|
||||||
if ((*dst)->key != key) {
|
d > distance(map->tablelen, map->tablelenbits, bkt, idx)) {
|
||||||
continue;
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
*dst = (*dst)->next;
|
if (bkt->key == key) {
|
||||||
--map->size;
|
map_bucket_set_data(bkt, 0, 0, NULL);
|
||||||
return 0;
|
|
||||||
|
didx = idx;
|
||||||
|
idx = (idx + 1) & (map->tablelen - 1);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
bkt = &map->table[idx];
|
||||||
|
if (bkt->data == NULL ||
|
||||||
|
distance(map->tablelen, map->tablelenbits, bkt, idx) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
map->table[didx] = *bkt;
|
||||||
|
map_bucket_set_data(bkt, 0, 0, NULL);
|
||||||
|
didx = idx;
|
||||||
|
|
||||||
|
idx = (idx + 1) & (map->tablelen - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
--map->size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
++d;
|
||||||
|
idx = (idx + 1) & (map->tablelen - 1);
|
||||||
}
|
}
|
||||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
}
|
||||||
|
|
||||||
|
void nghttp2_map_clear(nghttp2_map *map) {
|
||||||
|
memset(map->table, 0, sizeof(*map->table) * map->tablelen);
|
||||||
|
map->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nghttp2_map_size(nghttp2_map *map) { return map->size; }
|
size_t nghttp2_map_size(nghttp2_map *map) { return map->size; }
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* nghttp2 - HTTP/2 C Library
|
* nghttp2 - HTTP/2 C Library
|
||||||
*
|
*
|
||||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
* Copyright (c) 2017 ngtcp2 contributors
|
||||||
|
* Copyright (c) 2012 nghttp2 contributors
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
@@ -30,27 +31,25 @@
|
|||||||
#endif /* HAVE_CONFIG_H */
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
#include <nghttp2/nghttp2.h>
|
#include <nghttp2/nghttp2.h>
|
||||||
#include "nghttp2_int.h"
|
|
||||||
#include "nghttp2_mem.h"
|
#include "nghttp2_mem.h"
|
||||||
|
|
||||||
/* Implementation of unordered map */
|
/* Implementation of unordered map */
|
||||||
|
|
||||||
typedef int32_t key_type;
|
typedef int32_t nghttp2_map_key_type;
|
||||||
|
|
||||||
typedef struct nghttp2_map_entry {
|
typedef struct nghttp2_map_bucket {
|
||||||
struct nghttp2_map_entry *next;
|
uint32_t hash;
|
||||||
key_type key;
|
nghttp2_map_key_type key;
|
||||||
#if SIZEOF_INT_P == 4
|
void *data;
|
||||||
/* we requires 8 bytes aligment */
|
} nghttp2_map_bucket;
|
||||||
int64_t pad;
|
|
||||||
#endif
|
|
||||||
} nghttp2_map_entry;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct nghttp2_map {
|
||||||
nghttp2_map_entry **table;
|
nghttp2_map_bucket *table;
|
||||||
nghttp2_mem *mem;
|
nghttp2_mem *mem;
|
||||||
size_t size;
|
size_t size;
|
||||||
uint32_t tablelen;
|
uint32_t tablelen;
|
||||||
|
uint32_t tablelenbits;
|
||||||
} nghttp2_map;
|
} nghttp2_map;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -74,21 +73,14 @@ void nghttp2_map_free(nghttp2_map *map);
|
|||||||
/*
|
/*
|
||||||
* Deallocates each entries using |func| function and any resources
|
* Deallocates each entries using |func| function and any resources
|
||||||
* allocated for |map|. The |func| function is responsible for freeing
|
* allocated for |map|. The |func| function is responsible for freeing
|
||||||
* given the |entry| object. The |ptr| will be passed to the |func| as
|
* given the |data| object. The |ptr| will be passed to the |func| as
|
||||||
* send argument. The return value of the |func| will be ignored.
|
* send argument. The return value of the |func| will be ignored.
|
||||||
*/
|
*/
|
||||||
void nghttp2_map_each_free(nghttp2_map *map,
|
void nghttp2_map_each_free(nghttp2_map *map, int (*func)(void *data, void *ptr),
|
||||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
|
||||||
void *ptr);
|
void *ptr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initializes the |entry| with the |key|. All entries to be inserted
|
* Inserts the new |data| with the |key| to the map |map|.
|
||||||
* to the map must be initialized with this function.
|
|
||||||
*/
|
|
||||||
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inserts the new |entry| with the key |entry->key| to the map |map|.
|
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
* negative error codes:
|
* negative error codes:
|
||||||
@@ -98,25 +90,30 @@ void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
|
|||||||
* NGHTTP2_ERR_NOMEM
|
* NGHTTP2_ERR_NOMEM
|
||||||
* Out of memory
|
* Out of memory
|
||||||
*/
|
*/
|
||||||
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
|
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the entry associated by the key |key|. If there is no such
|
* Returns the data associated by the key |key|. If there is no such
|
||||||
* entry, this function returns NULL.
|
* data, this function returns NULL.
|
||||||
*/
|
*/
|
||||||
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
|
void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Removes the entry associated by the key |key| from the |map|. The
|
* Removes the data associated by the key |key| from the |map|. The
|
||||||
* removed entry is not freed by this function.
|
* removed data is not freed by this function.
|
||||||
*
|
*
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
* negative error codes:
|
* negative error codes:
|
||||||
*
|
*
|
||||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||||
* The entry associated by |key| does not exist.
|
* The data associated by |key| does not exist.
|
||||||
*/
|
*/
|
||||||
int nghttp2_map_remove(nghttp2_map *map, key_type key);
|
int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes all entries from |map|.
|
||||||
|
*/
|
||||||
|
void nghttp2_map_clear(nghttp2_map *map);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the number of items stored in the map |map|.
|
* Returns the number of items stored in the map |map|.
|
||||||
@@ -124,21 +121,22 @@ int nghttp2_map_remove(nghttp2_map *map, key_type key);
|
|||||||
size_t nghttp2_map_size(nghttp2_map *map);
|
size_t nghttp2_map_size(nghttp2_map *map);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Applies the function |func| to each entry in the |map| with the
|
* Applies the function |func| to each data in the |map| with the
|
||||||
* optional user supplied pointer |ptr|.
|
* optional user supplied pointer |ptr|.
|
||||||
*
|
*
|
||||||
* If the |func| returns 0, this function calls the |func| with the
|
* If the |func| returns 0, this function calls the |func| with the
|
||||||
* next entry. If the |func| returns nonzero, it will not call the
|
* next data. If the |func| returns nonzero, it will not call the
|
||||||
* |func| for further entries and return the return value of the
|
* |func| for further entries and return the return value of the
|
||||||
* |func| immediately. Thus, this function returns 0 if all the
|
* |func| immediately. Thus, this function returns 0 if all the
|
||||||
* invocations of the |func| return 0, or nonzero value which the last
|
* invocations of the |func| return 0, or nonzero value which the last
|
||||||
* invocation of |func| returns.
|
* invocation of |func| returns.
|
||||||
*
|
*
|
||||||
* Don't use this function to free each entry. Use
|
* Don't use this function to free each data. Use
|
||||||
* nghttp2_map_each_free() instead.
|
* nghttp2_map_each_free() instead.
|
||||||
*/
|
*/
|
||||||
int nghttp2_map_each(nghttp2_map *map,
|
int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
|
||||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
|
||||||
void *ptr);
|
void *ptr);
|
||||||
|
|
||||||
|
void nghttp2_map_print_distance(nghttp2_map *map);
|
||||||
|
|
||||||
#endif /* NGHTTP2_MAP_H */
|
#endif /* NGHTTP2_MAP_H */
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
#if defined(WIN32)
|
#if defined(WIN32)
|
||||||
/* Windows requires ws2_32 library for ntonl family functions. We
|
/* Windows requires ws2_32 library for ntonl family functions. We
|
||||||
define inline functions for those function so that we don't have
|
define inline functions for those function so that we don't have
|
||||||
dependeny on that lib. */
|
dependency on that lib. */
|
||||||
|
|
||||||
# ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
# define STIN static __inline
|
# define STIN static __inline
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
STIN uint32_t htonl(uint32_t hostlong) {
|
STIN uint32_t htonl(uint32_t hostlong) {
|
||||||
uint32_t res;
|
uint32_t res;
|
||||||
unsigned char *p = (unsigned char *)&res;
|
unsigned char *p = (unsigned char *)&res;
|
||||||
*p++ = hostlong >> 24;
|
*p++ = (unsigned char)(hostlong >> 24);
|
||||||
*p++ = (hostlong >> 16) & 0xffu;
|
*p++ = (hostlong >> 16) & 0xffu;
|
||||||
*p++ = (hostlong >> 8) & 0xffu;
|
*p++ = (hostlong >> 8) & 0xffu;
|
||||||
*p = hostlong & 0xffu;
|
*p = hostlong & 0xffu;
|
||||||
@@ -63,7 +63,7 @@ STIN uint32_t htonl(uint32_t hostlong) {
|
|||||||
STIN uint16_t htons(uint16_t hostshort) {
|
STIN uint16_t htons(uint16_t hostshort) {
|
||||||
uint16_t res;
|
uint16_t res;
|
||||||
unsigned char *p = (unsigned char *)&res;
|
unsigned char *p = (unsigned char *)&res;
|
||||||
*p++ = hostshort >> 8;
|
*p++ = (unsigned char)(hostshort >> 8);
|
||||||
*p = hostshort & 0xffu;
|
*p = hostshort & 0xffu;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
|
|||||||
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||||
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
|
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
|
||||||
return;
|
return;
|
||||||
|
case NGHTTP2_PRIORITY_UPDATE:
|
||||||
|
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||||
|
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_PRIORITY_UPDATE;
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -121,3 +125,21 @@ void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, size_t val) {
|
|||||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
|
option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
|
||||||
option->max_outbound_ack = val;
|
option->max_outbound_ack = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
|
||||||
|
option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
|
||||||
|
option->max_settings = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nghttp2_option_set_server_fallback_rfc7540_priorities(
|
||||||
|
nghttp2_option *option, int val) {
|
||||||
|
option->opt_set_mask |= NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES;
|
||||||
|
option->server_fallback_rfc7540_priorities = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nghttp2_option_set_no_rfc9113_leading_and_trailing_ws_validation(
|
||||||
|
nghttp2_option *option, int val) {
|
||||||
|
option->opt_set_mask |=
|
||||||
|
NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION;
|
||||||
|
option->no_rfc9113_leading_and_trailing_ws_validation = val;
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ typedef enum {
|
|||||||
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
|
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
|
||||||
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
|
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
|
||||||
NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
|
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_option_flag;
|
} nghttp2_option_flag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,6 +88,10 @@ struct nghttp2_option {
|
|||||||
* NGHTTP2_OPT_MAX_OUTBOUND_ACK
|
* NGHTTP2_OPT_MAX_OUTBOUND_ACK
|
||||||
*/
|
*/
|
||||||
size_t max_outbound_ack;
|
size_t max_outbound_ack;
|
||||||
|
/**
|
||||||
|
* NGHTTP2_OPT_MAX_SETTINGS
|
||||||
|
*/
|
||||||
|
size_t max_settings;
|
||||||
/**
|
/**
|
||||||
* Bitwise OR of nghttp2_option_flag to determine that which fields
|
* Bitwise OR of nghttp2_option_flag to determine that which fields
|
||||||
* are specified.
|
* are specified.
|
||||||
@@ -122,6 +129,14 @@ struct nghttp2_option {
|
|||||||
* NGHTTP2_OPT_NO_CLOSED_STREAMS
|
* NGHTTP2_OPT_NO_CLOSED_STREAMS
|
||||||
*/
|
*/
|
||||||
int no_closed_streams;
|
int no_closed_streams;
|
||||||
|
/**
|
||||||
|
* NGHTTP2_OPT_SERVER_FALLBACK_RFC7540_PRIORITIES
|
||||||
|
*/
|
||||||
|
int server_fallback_rfc7540_priorities;
|
||||||
|
/**
|
||||||
|
* NGHTTP2_OPT_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION
|
||||||
|
*/
|
||||||
|
int no_rfc9113_leading_and_trailing_ws_validation;
|
||||||
/**
|
/**
|
||||||
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
|
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
|
|||||||
case NGHTTP2_ORIGIN:
|
case NGHTTP2_ORIGIN:
|
||||||
nghttp2_frame_origin_free(&frame->ext, mem);
|
nghttp2_frame_origin_free(&frame->ext, mem);
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_PRIORITY_UPDATE:
|
||||||
|
nghttp2_frame_priority_update_free(&frame->ext, mem);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ struct nghttp2_outbound_item {
|
|||||||
to this structure to avoid frequent memory allocation. */
|
to this structure to avoid frequent memory allocation. */
|
||||||
nghttp2_ext_frame_payload ext_frame_payload;
|
nghttp2_ext_frame_payload ext_frame_payload;
|
||||||
nghttp2_aux_data aux_data;
|
nghttp2_aux_data aux_data;
|
||||||
/* The priority used in priority comparion. Smaller is served
|
/* The priority used in priority comparison. Smaller is served
|
||||||
earlier. For PING, SETTINGS and non-DATA frames (excluding
|
earlier. For PING, SETTINGS and non-DATA frames (excluding
|
||||||
response HEADERS frame) have dedicated cycle value defined above.
|
response HEADERS frame) have dedicated cycle value defined above.
|
||||||
For DATA frame, cycle is computed by taking into account of
|
For DATA frame, cycle is computed by taking into account of
|
||||||
|
|||||||
@@ -29,13 +29,12 @@
|
|||||||
|
|
||||||
#include "nghttp2_helper.h"
|
#include "nghttp2_helper.h"
|
||||||
|
|
||||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
|
void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
|
||||||
pq->mem = mem;
|
pq->mem = mem;
|
||||||
pq->capacity = 0;
|
pq->capacity = 0;
|
||||||
pq->q = NULL;
|
pq->q = NULL;
|
||||||
pq->length = 0;
|
pq->length = 0;
|
||||||
pq->less = less;
|
pq->less = less;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_pq_free(nghttp2_pq *pq) {
|
void nghttp2_pq_free(nghttp2_pq *pq) {
|
||||||
|
|||||||
@@ -55,14 +55,8 @@ typedef struct {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Initializes priority queue |pq| with compare function |cmp|.
|
* Initializes priority queue |pq| with compare function |cmp|.
|
||||||
*
|
|
||||||
* This function returns 0 if it succeeds, or one of the following
|
|
||||||
* negative error codes:
|
|
||||||
*
|
|
||||||
* NGHTTP2_ERR_NOMEM
|
|
||||||
* Out of memory.
|
|
||||||
*/
|
*/
|
||||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
|
void nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deallocates any resources allocated for |pq|. The stored items are
|
* Deallocates any resources allocated for |pq|. The stored items are
|
||||||
@@ -114,7 +108,7 @@ typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg);
|
|||||||
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
|
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Applys |fun| to each item in |pq|. The |arg| is passed as arg
|
* Applies |fun| to each item in |pq|. The |arg| is passed as arg
|
||||||
* parameter to callback function. This function must not change the
|
* parameter to callback function. This function must not change the
|
||||||
* ordering key. If the return value from callback is nonzero, this
|
* ordering key. If the return value from callback is nonzero, this
|
||||||
* function returns 1 immediately without iterating remaining items.
|
* function returns 1 immediately without iterating remaining items.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,9 @@ typedef enum {
|
|||||||
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
|
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
|
||||||
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
|
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
|
||||||
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
|
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
|
||||||
NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4
|
NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4,
|
||||||
|
NGHTTP2_OPTMASK_SERVER_FALLBACK_RFC7540_PRIORITIES = 1 << 5,
|
||||||
|
NGHTTP2_OPTMASK_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION = 1 << 6,
|
||||||
} nghttp2_optmask;
|
} nghttp2_optmask;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -62,7 +64,8 @@ typedef enum {
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
NGHTTP2_TYPEMASK_NONE = 0,
|
NGHTTP2_TYPEMASK_NONE = 0,
|
||||||
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
|
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
|
||||||
NGHTTP2_TYPEMASK_ORIGIN = 1 << 1
|
NGHTTP2_TYPEMASK_ORIGIN = 1 << 1,
|
||||||
|
NGHTTP2_TYPEMASK_PRIORITY_UPDATE = 1 << 2
|
||||||
} nghttp2_typemask;
|
} nghttp2_typemask;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -151,10 +154,8 @@ typedef struct {
|
|||||||
/* padding length for the current frame */
|
/* padding length for the current frame */
|
||||||
size_t padlen;
|
size_t padlen;
|
||||||
nghttp2_inbound_state state;
|
nghttp2_inbound_state state;
|
||||||
/* Small buffer. Currently the largest contiguous chunk to buffer
|
/* Small fixed sized buffer. */
|
||||||
is frame header. We buffer part of payload, but they are smaller
|
uint8_t raw_sbuf[32];
|
||||||
than frame header. */
|
|
||||||
uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
|
|
||||||
} nghttp2_inbound_frame;
|
} nghttp2_inbound_frame;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -165,6 +166,7 @@ typedef struct {
|
|||||||
uint32_t max_frame_size;
|
uint32_t max_frame_size;
|
||||||
uint32_t max_header_list_size;
|
uint32_t max_header_list_size;
|
||||||
uint32_t enable_connect_protocol;
|
uint32_t enable_connect_protocol;
|
||||||
|
uint32_t no_rfc7540_priorities;
|
||||||
} nghttp2_settings_storage;
|
} nghttp2_settings_storage;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -202,6 +204,12 @@ struct nghttp2_session {
|
|||||||
response) frame, which are subject to
|
response) frame, which are subject to
|
||||||
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
|
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
|
||||||
nghttp2_outbound_queue ob_syn;
|
nghttp2_outbound_queue ob_syn;
|
||||||
|
/* Queues for DATA frames which is used when
|
||||||
|
SETTINGS_NO_RFC7540_PRIORITIES is enabled. This implements RFC
|
||||||
|
9218 extensible prioritization scheme. */
|
||||||
|
struct {
|
||||||
|
nghttp2_pq ob_data;
|
||||||
|
} sched[NGHTTP2_EXTPRI_URGENCY_LEVELS];
|
||||||
nghttp2_active_outbound_item aob;
|
nghttp2_active_outbound_item aob;
|
||||||
nghttp2_inbound_frame iframe;
|
nghttp2_inbound_frame iframe;
|
||||||
nghttp2_hd_deflater hd_deflater;
|
nghttp2_hd_deflater hd_deflater;
|
||||||
@@ -227,6 +235,9 @@ struct nghttp2_session {
|
|||||||
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
|
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
|
||||||
considered as in-flight. */
|
considered as in-flight. */
|
||||||
nghttp2_inflight_settings *inflight_settings_head;
|
nghttp2_inflight_settings *inflight_settings_head;
|
||||||
|
/* Sequential number across all streams to process streams in
|
||||||
|
FIFO. */
|
||||||
|
uint64_t stream_seq;
|
||||||
/* The number of outgoing streams. This will be capped by
|
/* The number of outgoing streams. This will be capped by
|
||||||
remote_settings.max_concurrent_streams. */
|
remote_settings.max_concurrent_streams. */
|
||||||
size_t num_outgoing_streams;
|
size_t num_outgoing_streams;
|
||||||
@@ -267,6 +278,8 @@ struct nghttp2_session {
|
|||||||
/* The maximum length of header block to send. Calculated by the
|
/* The maximum length of header block to send. Calculated by the
|
||||||
same way as nghttp2_hd_deflate_bound() does. */
|
same way as nghttp2_hd_deflate_bound() does. */
|
||||||
size_t max_send_header_block_length;
|
size_t max_send_header_block_length;
|
||||||
|
/* The maximum number of settings accepted per SETTINGS frame. */
|
||||||
|
size_t max_settings;
|
||||||
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
|
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
|
||||||
uint32_t next_stream_id;
|
uint32_t next_stream_id;
|
||||||
/* The last stream ID this session initiated. For client session,
|
/* The last stream ID this session initiated. For client session,
|
||||||
@@ -326,6 +339,11 @@ struct nghttp2_session {
|
|||||||
/* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to
|
/* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to
|
||||||
accept :protocol header field before SETTINGS_ACK is received. */
|
accept :protocol header field before SETTINGS_ACK is received. */
|
||||||
uint8_t pending_enable_connect_protocol;
|
uint8_t pending_enable_connect_protocol;
|
||||||
|
/* Unacked local SETTINGS_NO_RFC7540_PRIORITIES value, which is
|
||||||
|
effective before it is acknowledged. */
|
||||||
|
uint8_t pending_no_rfc7540_priorities;
|
||||||
|
/* Turn on fallback to RFC 7540 priorities; for server use only. */
|
||||||
|
uint8_t fallback_rfc7540_priorities;
|
||||||
/* Nonzero if the session is server side. */
|
/* Nonzero if the session is server side. */
|
||||||
uint8_t server;
|
uint8_t server;
|
||||||
/* Flags indicating GOAWAY is sent and/or received. The flags are
|
/* Flags indicating GOAWAY is sent and/or received. The flags are
|
||||||
@@ -406,7 +424,7 @@ int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
|
|||||||
uint32_t error_code);
|
uint32_t error_code);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adds PING frame. This is a convenient functin built on top of
|
* Adds PING frame. This is a convenient function built on top of
|
||||||
* nghttp2_session_add_frame() to add PING easily.
|
* nghttp2_session_add_frame() to add PING easily.
|
||||||
*
|
*
|
||||||
* If the |opaque_data| is not NULL, it must point to 8 bytes memory
|
* If the |opaque_data| is not NULL, it must point to 8 bytes memory
|
||||||
@@ -771,6 +789,19 @@ int nghttp2_session_on_altsvc_received(nghttp2_session *session,
|
|||||||
int nghttp2_session_on_origin_received(nghttp2_session *session,
|
int nghttp2_session_on_origin_received(nghttp2_session *session,
|
||||||
nghttp2_frame *frame);
|
nghttp2_frame *frame);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when PRIORITY_UPDATE is received, assuming |frame| is
|
||||||
|
* properly initialized.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||||
|
* The callback function failed.
|
||||||
|
*/
|
||||||
|
int nghttp2_session_on_priority_update_received(nghttp2_session *session,
|
||||||
|
nghttp2_frame *frame);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called when DATA is received, assuming |frame| is properly
|
* Called when DATA is received, assuming |frame| is properly
|
||||||
* initialized.
|
* initialized.
|
||||||
@@ -898,4 +929,36 @@ int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
|
|||||||
uint32_t error_code,
|
uint32_t error_code,
|
||||||
const char *reason);
|
const char *reason);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Accumulates received bytes |delta_size| for connection-level flow
|
||||||
|
* control and decides whether to send WINDOW_UPDATE to the
|
||||||
|
* connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
|
||||||
|
* WINDOW_UPDATE will not be sent.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
*/
|
||||||
|
int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
|
||||||
|
size_t delta_size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Accumulates received bytes |delta_size| for stream-level flow
|
||||||
|
* control and decides whether to send WINDOW_UPDATE to that stream.
|
||||||
|
* If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
|
||||||
|
* be sent.
|
||||||
|
*
|
||||||
|
* This function returns 0 if it succeeds, or one of the following
|
||||||
|
* negative error codes:
|
||||||
|
*
|
||||||
|
* NGHTTP2_ERR_NOMEM
|
||||||
|
* Out of memory.
|
||||||
|
*/
|
||||||
|
int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
|
||||||
|
nghttp2_stream *stream,
|
||||||
|
size_t delta_size,
|
||||||
|
int send_window_update);
|
||||||
|
|
||||||
#endif /* NGHTTP2_SESSION_H */
|
#endif /* NGHTTP2_SESSION_H */
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#include "nghttp2_frame.h"
|
#include "nghttp2_frame.h"
|
||||||
|
|
||||||
/* Maximum distance between any two stream's cycle in the same
|
/* Maximum distance between any two stream's cycle in the same
|
||||||
prirority queue. Imagine stream A's cycle is A, and stream B's
|
priority queue. Imagine stream A's cycle is A, and stream B's
|
||||||
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
|
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
|
||||||
may get overflow. Because of how we calculate the next cycle
|
may get overflow. Because of how we calculate the next cycle
|
||||||
value, if B - A is less than or equals to
|
value, if B - A is less than or equals to
|
||||||
@@ -62,7 +62,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
|||||||
int32_t weight, int32_t remote_initial_window_size,
|
int32_t weight, int32_t remote_initial_window_size,
|
||||||
int32_t local_initial_window_size,
|
int32_t local_initial_window_size,
|
||||||
void *stream_user_data, nghttp2_mem *mem) {
|
void *stream_user_data, nghttp2_mem *mem) {
|
||||||
nghttp2_map_entry_init(&stream->map_entry, (key_type)stream_id);
|
|
||||||
nghttp2_pq_init(&stream->obq, stream_less, mem);
|
nghttp2_pq_init(&stream->obq, stream_less, mem);
|
||||||
|
|
||||||
stream->stream_id = stream_id;
|
stream->stream_id = stream_id;
|
||||||
@@ -101,6 +100,8 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
|||||||
stream->descendant_next_seq = 0;
|
stream->descendant_next_seq = 0;
|
||||||
stream->seq = 0;
|
stream->seq = 0;
|
||||||
stream->last_writelen = 0;
|
stream->last_writelen = 0;
|
||||||
|
|
||||||
|
stream->extpri = stream->http_extpri = NGHTTP2_EXTPRI_DEFAULT_URGENCY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_stream_free(nghttp2_stream *stream) {
|
void nghttp2_stream_free(nghttp2_stream *stream) {
|
||||||
@@ -485,6 +486,10 @@ int nghttp2_stream_attach_item(nghttp2_stream *stream,
|
|||||||
|
|
||||||
stream->item = item;
|
stream->item = item;
|
||||||
|
|
||||||
|
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
rv = stream_update_dep_on_attach_item(stream);
|
rv = stream_update_dep_on_attach_item(stream);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
/* This may relave stream->queued == 1, but stream->item == NULL.
|
/* This may relave stream->queued == 1, but stream->item == NULL.
|
||||||
@@ -504,6 +509,10 @@ int nghttp2_stream_detach_item(nghttp2_stream *stream) {
|
|||||||
stream->item = NULL;
|
stream->item = NULL;
|
||||||
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
|
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
|
||||||
|
|
||||||
|
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return stream_update_dep_on_detach_item(stream);
|
return stream_update_dep_on_detach_item(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,6 +524,10 @@ int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
|
|||||||
|
|
||||||
stream->flags |= flags;
|
stream->flags |= flags;
|
||||||
|
|
||||||
|
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return stream_update_dep_on_detach_item(stream);
|
return stream_update_dep_on_detach_item(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,6 +543,10 @@ int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return stream_update_dep_on_attach_item(stream);
|
return stream_update_dep_on_attach_item(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,8 +90,15 @@ typedef enum {
|
|||||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
|
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
|
||||||
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
|
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
|
||||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
|
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
|
||||||
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
|
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c,
|
||||||
|
/* Indicates that this stream is not subject to RFC7540
|
||||||
|
priorities scheme. */
|
||||||
|
NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES = 0x10,
|
||||||
|
/* 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;
|
} nghttp2_stream_flag;
|
||||||
|
|
||||||
/* HTTP related flags to enforce HTTP semantics */
|
/* HTTP related flags to enforce HTTP semantics */
|
||||||
@@ -132,11 +139,14 @@ typedef enum {
|
|||||||
/* set if final response is expected */
|
/* set if final response is expected */
|
||||||
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
|
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
|
||||||
NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15,
|
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;
|
} nghttp2_http_flag;
|
||||||
|
|
||||||
struct nghttp2_stream {
|
struct nghttp2_stream {
|
||||||
/* Intrusive Map */
|
|
||||||
nghttp2_map_entry map_entry;
|
|
||||||
/* Entry for dep_prev->obq */
|
/* Entry for dep_prev->obq */
|
||||||
nghttp2_pq_entry pq_entry;
|
nghttp2_pq_entry pq_entry;
|
||||||
/* Priority Queue storing direct descendant (nghttp2_stream). Only
|
/* Priority Queue storing direct descendant (nghttp2_stream). Only
|
||||||
@@ -206,7 +216,7 @@ struct nghttp2_stream {
|
|||||||
/* status code from remote server */
|
/* status code from remote server */
|
||||||
int16_t status_code;
|
int16_t status_code;
|
||||||
/* Bitwise OR of zero or more nghttp2_http_flag values */
|
/* Bitwise OR of zero or more nghttp2_http_flag values */
|
||||||
uint16_t http_flags;
|
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. */
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
/* Bitwise OR of zero or more nghttp2_shut_flag values */
|
/* Bitwise OR of zero or more nghttp2_shut_flag values */
|
||||||
@@ -220,6 +230,12 @@ struct nghttp2_stream {
|
|||||||
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
|
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
|
||||||
is not queued. */
|
is not queued. */
|
||||||
uint8_t window_update_queued;
|
uint8_t window_update_queued;
|
||||||
|
/* extpri is a stream priority produced by nghttp2_extpri_to_uint8
|
||||||
|
used by RFC 9218 extensible priorities. */
|
||||||
|
uint8_t extpri;
|
||||||
|
/* http_extpri is a stream priority received in HTTP request header
|
||||||
|
fields and produced by nghttp2_extpri_to_uint8. */
|
||||||
|
uint8_t http_extpri;
|
||||||
};
|
};
|
||||||
|
|
||||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||||
|
|||||||
@@ -196,7 +196,8 @@ int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
|
|||||||
|
|
||||||
flags &= NGHTTP2_FLAG_END_STREAM;
|
flags &= NGHTTP2_FLAG_END_STREAM;
|
||||||
|
|
||||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
|
||||||
|
session->remote_settings.no_rfc7540_priorities != 1) {
|
||||||
rv = detect_self_dependency(session, stream_id, pri_spec);
|
rv = detect_self_dependency(session, stream_id, pri_spec);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
@@ -229,6 +230,10 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
|||||||
|
|
||||||
mem = &session->mem;
|
mem = &session->mem;
|
||||||
|
|
||||||
|
if (session->remote_settings.no_rfc7540_priorities == 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (stream_id == 0 || pri_spec == NULL) {
|
if (stream_id == 0 || pri_spec == NULL) {
|
||||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
@@ -450,6 +455,13 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
|||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (window_size_increment > 0) {
|
||||||
|
return nghttp2_session_add_window_update(session, 0, stream_id,
|
||||||
|
window_size_increment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nghttp2_session_update_recv_connection_window_size(session, 0);
|
||||||
} else {
|
} else {
|
||||||
stream = nghttp2_session_get_stream(session, stream_id);
|
stream = nghttp2_session_get_stream(session, stream_id);
|
||||||
|
|
||||||
@@ -476,14 +488,15 @@ int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
|||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (window_size_increment > 0) {
|
if (window_size_increment > 0) {
|
||||||
return nghttp2_session_add_window_update(session, 0, stream_id,
|
return nghttp2_session_add_window_update(session, 0, stream_id,
|
||||||
window_size_increment);
|
window_size_increment);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
|
||||||
|
1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||||
@@ -654,6 +667,78 @@ fail_item_malloc:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags,
|
||||||
|
int32_t stream_id,
|
||||||
|
const uint8_t *field_value,
|
||||||
|
size_t field_value_len) {
|
||||||
|
nghttp2_mem *mem;
|
||||||
|
uint8_t *buf, *p;
|
||||||
|
nghttp2_outbound_item *item;
|
||||||
|
nghttp2_frame *frame;
|
||||||
|
nghttp2_ext_priority_update *priority_update;
|
||||||
|
int rv;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
|
mem = &session->mem;
|
||||||
|
|
||||||
|
if (session->server) {
|
||||||
|
return NGHTTP2_ERR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->remote_settings.no_rfc7540_priorities == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream_id == 0 || 4 + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
|
||||||
|
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_value_len) {
|
||||||
|
buf = nghttp2_mem_malloc(mem, field_value_len + 1);
|
||||||
|
if (buf == NULL) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = nghttp2_cpymem(buf, field_value, field_value_len);
|
||||||
|
*p = '\0';
|
||||||
|
} else {
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||||
|
if (item == NULL) {
|
||||||
|
rv = NGHTTP2_ERR_NOMEM;
|
||||||
|
goto fail_item_malloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
nghttp2_outbound_item_init(item);
|
||||||
|
|
||||||
|
item->aux_data.ext.builtin = 1;
|
||||||
|
|
||||||
|
priority_update = &item->ext_frame_payload.priority_update;
|
||||||
|
|
||||||
|
frame = &item->frame;
|
||||||
|
frame->ext.payload = priority_update;
|
||||||
|
|
||||||
|
nghttp2_frame_priority_update_init(&frame->ext, stream_id, buf,
|
||||||
|
field_value_len);
|
||||||
|
|
||||||
|
rv = nghttp2_session_add_item(session, item);
|
||||||
|
if (rv != 0) {
|
||||||
|
nghttp2_frame_priority_update_free(&frame->ext, mem);
|
||||||
|
nghttp2_mem_free(mem, item);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail_item_malloc:
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
|
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
|
||||||
const nghttp2_data_provider *data_prd) {
|
const nghttp2_data_provider *data_prd) {
|
||||||
uint8_t flags = NGHTTP2_FLAG_NONE;
|
uint8_t flags = NGHTTP2_FLAG_NONE;
|
||||||
@@ -680,7 +765,8 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
|
|||||||
return NGHTTP2_ERR_PROTO;
|
return NGHTTP2_ERR_PROTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
|
||||||
|
session->remote_settings.no_rfc7540_priorities != 1) {
|
||||||
rv = detect_self_dependency(session, -1, pri_spec);
|
rv = detect_self_dependency(session, -1, pri_spec);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return rv;
|
return rv;
|
||||||
|
|||||||
Reference in New Issue
Block a user