Pass unknown SETTINGS values to nghttp2_on_frame_recv_callback
This commit is contained in:
parent
d88f962565
commit
40f3779eb1
|
@ -463,25 +463,11 @@ size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
|
||||||
return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv;
|
return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
||||||
nghttp2_settings_entry *iv,
|
nghttp2_settings_entry *iv,
|
||||||
size_t niv, nghttp2_mem *mem) {
|
size_t niv) {
|
||||||
size_t payloadlen = niv * sizeof(nghttp2_settings_entry);
|
frame->iv = iv;
|
||||||
|
|
||||||
if (niv == 0) {
|
|
||||||
frame->iv = NULL;
|
|
||||||
} else {
|
|
||||||
frame->iv = nghttp2_mem_malloc(mem, payloadlen);
|
|
||||||
|
|
||||||
if (frame->iv == NULL) {
|
|
||||||
return NGHTTP2_ERR_NOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(frame->iv, iv, payloadlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
frame->niv = niv;
|
frame->niv = niv;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
|
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
|
||||||
|
|
|
@ -215,18 +215,12 @@ void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
|
||||||
const uint8_t *payload);
|
const uint8_t *payload);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Makes a copy of |iv| in frame->settings.iv. The |niv| is assigned
|
* Initializes payload of frame->settings. The |frame| takes
|
||||||
* to frame->settings.niv.
|
* ownership of |iv|.
|
||||||
*
|
|
||||||
* This function returns 0 if it succeeds or one of the following
|
|
||||||
* negative error codes:
|
|
||||||
*
|
|
||||||
* NGHTTP2_ERR_NOMEM
|
|
||||||
* Out of memory.
|
|
||||||
*/
|
*/
|
||||||
int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
||||||
nghttp2_settings_entry *iv,
|
nghttp2_settings_entry *iv,
|
||||||
size_t niv, nghttp2_mem *mem);
|
size_t niv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
|
* Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
|
||||||
|
|
|
@ -305,6 +305,13 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_SETTINGS:
|
case NGHTTP2_SETTINGS:
|
||||||
nghttp2_frame_settings_free(&iframe->frame.settings, mem);
|
nghttp2_frame_settings_free(&iframe->frame.settings, mem);
|
||||||
|
|
||||||
|
nghttp2_mem_free(mem, iframe->iv);
|
||||||
|
|
||||||
|
iframe->iv = NULL;
|
||||||
|
iframe->niv = 0;
|
||||||
|
iframe->max_niv = 0;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case NGHTTP2_PUSH_PROMISE:
|
case NGHTTP2_PUSH_PROMISE:
|
||||||
nghttp2_frame_push_promise_free(&iframe->frame.push_promise, mem);
|
nghttp2_frame_push_promise_free(&iframe->frame.push_promise, mem);
|
||||||
|
@ -351,12 +358,8 @@ static void session_inbound_frame_reset(nghttp2_session *session) {
|
||||||
|
|
||||||
iframe->raw_lbuf = NULL;
|
iframe->raw_lbuf = NULL;
|
||||||
|
|
||||||
iframe->niv = 0;
|
|
||||||
iframe->payloadleft = 0;
|
iframe->payloadleft = 0;
|
||||||
iframe->padlen = 0;
|
iframe->padlen = 0;
|
||||||
iframe->iv[NGHTTP2_INBOUND_NUM_IV - 1].settings_id =
|
|
||||||
NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
|
||||||
iframe->iv[NGHTTP2_INBOUND_NUM_IV - 1].value = UINT32_MAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_settings(nghttp2_settings_storage *settings) {
|
static void init_settings(nghttp2_settings_storage *settings) {
|
||||||
|
@ -4365,39 +4368,39 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int session_process_settings_frame(nghttp2_session *session) {
|
static int session_process_settings_frame(nghttp2_session *session) {
|
||||||
int rv;
|
|
||||||
nghttp2_inbound_frame *iframe = &session->iframe;
|
nghttp2_inbound_frame *iframe = &session->iframe;
|
||||||
nghttp2_frame *frame = &iframe->frame;
|
nghttp2_frame *frame = &iframe->frame;
|
||||||
size_t i;
|
size_t i;
|
||||||
nghttp2_settings_entry min_header_size_entry;
|
nghttp2_settings_entry min_header_size_entry;
|
||||||
nghttp2_mem *mem;
|
|
||||||
|
|
||||||
mem = &session->mem;
|
if (iframe->max_niv) {
|
||||||
min_header_size_entry = iframe->iv[NGHTTP2_INBOUND_NUM_IV - 1];
|
min_header_size_entry = iframe->iv[iframe->max_niv - 1];
|
||||||
|
|
||||||
if (min_header_size_entry.value < UINT32_MAX) {
|
if (min_header_size_entry.value < UINT32_MAX) {
|
||||||
/* If we have less value, then we must have
|
/* If we have less value, then we must have
|
||||||
SETTINGS_HEADER_TABLE_SIZE in i < iframe->niv */
|
SETTINGS_HEADER_TABLE_SIZE in i < iframe->niv */
|
||||||
for (i = 0; i < iframe->niv; ++i) {
|
for (i = 0; i < iframe->niv; ++i) {
|
||||||
if (iframe->iv[i].settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) {
|
if (iframe->iv[i].settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(i < iframe->niv);
|
||||||
|
|
||||||
|
if (min_header_size_entry.value != iframe->iv[i].value) {
|
||||||
|
iframe->iv[iframe->niv++] = iframe->iv[i];
|
||||||
|
iframe->iv[i] = min_header_size_entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(i < iframe->niv);
|
|
||||||
|
|
||||||
if (min_header_size_entry.value != iframe->iv[i].value) {
|
|
||||||
iframe->iv[iframe->niv++] = iframe->iv[i];
|
|
||||||
iframe->iv[i] = min_header_size_entry;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = nghttp2_frame_unpack_settings_payload(&frame->settings, iframe->iv,
|
nghttp2_frame_unpack_settings_payload(&frame->settings, iframe->iv,
|
||||||
iframe->niv, mem);
|
iframe->niv);
|
||||||
if (rv != 0) {
|
|
||||||
assert(nghttp2_is_fatal(rv));
|
iframe->iv = NULL;
|
||||||
return rv;
|
iframe->niv = 0;
|
||||||
}
|
iframe->max_niv = 0;
|
||||||
|
|
||||||
return nghttp2_session_on_settings_received(session, frame, 0 /* ACK */);
|
return nghttp2_session_on_settings_received(session, frame, 0 /* ACK */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5053,6 +5056,7 @@ static size_t inbound_frame_buf_read(nghttp2_inbound_frame *iframe,
|
||||||
*/
|
*/
|
||||||
static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) {
|
static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) {
|
||||||
nghttp2_settings_entry iv;
|
nghttp2_settings_entry iv;
|
||||||
|
nghttp2_settings_entry *min_header_table_size_entry;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
nghttp2_frame_unpack_settings_entry(&iv, iframe->sbuf.pos);
|
nghttp2_frame_unpack_settings_entry(&iv, iframe->sbuf.pos);
|
||||||
|
@ -5066,8 +5070,11 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) {
|
||||||
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
|
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DEBUGF(fprintf(stderr, "recv: ignore unknown settings id=0x%02x\n",
|
DEBUGF(
|
||||||
iv.settings_id));
|
fprintf(stderr, "recv: unknown settings id=0x%02x\n", iv.settings_id));
|
||||||
|
|
||||||
|
iframe->iv[iframe->niv++] = iv;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5082,10 +5089,13 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) {
|
||||||
iframe->iv[iframe->niv++] = iv;
|
iframe->iv[iframe->niv++] = iv;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iv.settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE &&
|
if (iv.settings_id == NGHTTP2_SETTINGS_HEADER_TABLE_SIZE) {
|
||||||
iv.value < iframe->iv[NGHTTP2_INBOUND_NUM_IV - 1].value) {
|
/* Keep track of minimum value of SETTINGS_HEADER_TABLE_SIZE */
|
||||||
|
min_header_table_size_entry = &iframe->iv[iframe->max_niv - 1];
|
||||||
|
|
||||||
iframe->iv[NGHTTP2_INBOUND_NUM_IV - 1] = iv;
|
if (iv.value < min_header_table_size_entry->value) {
|
||||||
|
min_header_table_size_entry->value = iv.value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5458,6 +5468,25 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
||||||
iframe->state = NGHTTP2_IB_READ_SETTINGS;
|
iframe->state = NGHTTP2_IB_READ_SETTINGS;
|
||||||
|
|
||||||
if (iframe->payloadleft) {
|
if (iframe->payloadleft) {
|
||||||
|
nghttp2_settings_entry *min_header_table_size_entry;
|
||||||
|
|
||||||
|
/* We allocate iv with addtional one entry, to store the
|
||||||
|
minimum header table size. */
|
||||||
|
iframe->max_niv =
|
||||||
|
iframe->frame.hd.length / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH + 1;
|
||||||
|
|
||||||
|
iframe->iv = nghttp2_mem_malloc(mem, sizeof(nghttp2_settings_entry) *
|
||||||
|
iframe->max_niv);
|
||||||
|
|
||||||
|
if (!iframe->iv) {
|
||||||
|
return NGHTTP2_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
min_header_table_size_entry = &iframe->iv[iframe->max_niv - 1];
|
||||||
|
min_header_table_size_entry->settings_id =
|
||||||
|
NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||||
|
min_header_table_size_entry->value = UINT32_MAX;
|
||||||
|
|
||||||
inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH);
|
inbound_frame_set_mark(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,18 +120,16 @@ typedef enum {
|
||||||
NGHTTP2_IB_READ_EXTENSION_PAYLOAD
|
NGHTTP2_IB_READ_EXTENSION_PAYLOAD
|
||||||
} nghttp2_inbound_state;
|
} nghttp2_inbound_state;
|
||||||
|
|
||||||
#define NGHTTP2_INBOUND_NUM_IV 7
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nghttp2_frame frame;
|
nghttp2_frame frame;
|
||||||
/* Storage for extension frame payload. frame->ext.payload points
|
/* Storage for extension frame payload. frame->ext.payload points
|
||||||
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;
|
||||||
/* The received SETTINGS entry. The protocol says that we only cares
|
/* The received SETTINGS entry. For the standard settings entries,
|
||||||
about the defined settings ID. If unknown ID is received, it is
|
we only keep the last seen value. For
|
||||||
ignored. We use last entry to hold minimum header table size if
|
SETTINGS_HEADER_TABLE_SIZE, we also keep minimum value in the
|
||||||
same settings are multiple times. */
|
last index. */
|
||||||
nghttp2_settings_entry iv[NGHTTP2_INBOUND_NUM_IV];
|
nghttp2_settings_entry *iv;
|
||||||
/* buffer pointers to small buffer, raw_sbuf */
|
/* buffer pointers to small buffer, raw_sbuf */
|
||||||
nghttp2_buf sbuf;
|
nghttp2_buf sbuf;
|
||||||
/* buffer pointers to large buffer, raw_lbuf */
|
/* buffer pointers to large buffer, raw_lbuf */
|
||||||
|
@ -140,6 +138,8 @@ typedef struct {
|
||||||
uint8_t *raw_lbuf;
|
uint8_t *raw_lbuf;
|
||||||
/* The number of entry filled in |iv| */
|
/* The number of entry filled in |iv| */
|
||||||
size_t niv;
|
size_t niv;
|
||||||
|
/* The number of entries |iv| can store. */
|
||||||
|
size_t max_niv;
|
||||||
/* How many bytes we still need to receive for current frame */
|
/* How many bytes we still need to receive for current frame */
|
||||||
size_t payloadleft;
|
size_t payloadleft;
|
||||||
/* padding length for the current frame */
|
/* padding length for the current frame */
|
||||||
|
|
Loading…
Reference in New Issue