Implement SETTINGS_MAX_FRAME_SIZE and SETTINGS_MAX_HEADER_LIST_SIZE
This commit is contained in:
parent
c4be7d48a0
commit
77374ac6e2
|
@ -510,7 +510,15 @@ typedef enum {
|
||||||
/**
|
/**
|
||||||
* SETTINGS_INITIAL_WINDOW_SIZE
|
* SETTINGS_INITIAL_WINDOW_SIZE
|
||||||
*/
|
*/
|
||||||
NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 0x04
|
NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 0x04,
|
||||||
|
/**
|
||||||
|
* SETTINGS_MAX_FRAME_SIZE
|
||||||
|
*/
|
||||||
|
NGHTTP2_SETTINGS_MAX_FRAME_SIZE = 0x05,
|
||||||
|
/**
|
||||||
|
* SETTINGS_MAX_HEADER_SET_SIZE
|
||||||
|
*/
|
||||||
|
NGHTTP2_SETTINGS_MAX_HEADER_SET_SIZE = 0x06
|
||||||
} nghttp2_settings_id;
|
} nghttp2_settings_id;
|
||||||
/* Note: If we add SETTINGS, update the capacity of
|
/* Note: If we add SETTINGS, update the capacity of
|
||||||
NGHTTP2_INBOUND_NUM_IV as well */
|
NGHTTP2_INBOUND_NUM_IV as well */
|
||||||
|
|
|
@ -1037,6 +1037,14 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
|
||||||
|
if(iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
|
||||||
|
iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NGHTTP2_SETTINGS_MAX_HEADER_SET_SIZE:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include "nghttp2_hd.h"
|
#include "nghttp2_hd.h"
|
||||||
#include "nghttp2_buf.h"
|
#include "nghttp2_buf.h"
|
||||||
|
|
||||||
#define NGHTTP2_FRAME_LENGTH_MASK ((1 << 24) - 1)
|
|
||||||
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
|
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
|
||||||
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
|
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
|
||||||
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
|
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
|
||||||
|
@ -43,6 +42,9 @@
|
||||||
/* The number of bytes of frame header. */
|
/* The number of bytes of frame header. */
|
||||||
#define NGHTTP2_FRAME_HDLEN 9
|
#define NGHTTP2_FRAME_HDLEN 9
|
||||||
|
|
||||||
|
#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1)
|
||||||
|
#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 tranmission. 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
|
||||||
|
|
|
@ -292,6 +292,8 @@ static void init_settings(nghttp2_settings_storage *settings)
|
||||||
settings->enable_push = 1;
|
settings->enable_push = 1;
|
||||||
settings->max_concurrent_streams = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
|
settings->max_concurrent_streams = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
|
||||||
settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
|
settings->initial_window_size = NGHTTP2_INITIAL_WINDOW_SIZE;
|
||||||
|
settings->max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MIN;
|
||||||
|
settings->max_header_set_size = UINT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void active_outbound_item_reset(nghttp2_active_outbound_item *aob)
|
static void active_outbound_item_reset(nghttp2_active_outbound_item *aob)
|
||||||
|
@ -3273,6 +3275,12 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
|
||||||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||||
session->local_settings.initial_window_size = iv[i].value;
|
session->local_settings.initial_window_size = iv[i].value;
|
||||||
break;
|
break;
|
||||||
|
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
|
||||||
|
session->local_settings.max_frame_size = iv[i].value;
|
||||||
|
break;
|
||||||
|
case NGHTTP2_SETTINGS_MAX_HEADER_SET_SIZE:
|
||||||
|
session->local_settings.max_header_set_size = iv[i].value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3393,6 +3401,23 @@ int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||||
|
|
||||||
session->remote_settings.initial_window_size = entry->value;
|
session->remote_settings.initial_window_size = entry->value;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
|
||||||
|
|
||||||
|
if(entry->value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
|
||||||
|
entry->value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
|
||||||
|
return session_handle_invalid_connection
|
||||||
|
(session, frame, NGHTTP2_PROTOCOL_ERROR,
|
||||||
|
"SETTINGS: invalid SETTINGS_MAX_FRAME_SIZE");
|
||||||
|
}
|
||||||
|
|
||||||
|
session->remote_settings.max_frame_size = entry->value;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case NGHTTP2_SETTINGS_MAX_HEADER_SET_SIZE:
|
||||||
|
|
||||||
|
session->remote_settings.max_header_set_size = entry->value;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4141,6 +4166,8 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe)
|
||||||
case NGHTTP2_SETTINGS_ENABLE_PUSH:
|
case NGHTTP2_SETTINGS_ENABLE_PUSH:
|
||||||
case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
|
case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
|
||||||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||||
|
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
|
||||||
|
case NGHTTP2_SETTINGS_MAX_HEADER_SET_SIZE:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DEBUGF(fprintf(stderr, "recv: ignore unknown settings id=0x%02x\n",
|
DEBUGF(fprintf(stderr, "recv: ignore unknown settings id=0x%02x\n",
|
||||||
|
@ -4273,6 +4300,26 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||||
iframe->frame.hd.flags,
|
iframe->frame.hd.flags,
|
||||||
iframe->frame.hd.stream_id));
|
iframe->frame.hd.stream_id));
|
||||||
|
|
||||||
|
if(iframe->frame.hd.length > session->local_settings.max_frame_size) {
|
||||||
|
DEBUGF(fprintf(stderr,
|
||||||
|
"recv: legnth is too large %u > %u\n",
|
||||||
|
iframe->frame.hd.length,
|
||||||
|
session->local_settings.max_frame_size));
|
||||||
|
|
||||||
|
busy = 1;
|
||||||
|
|
||||||
|
iframe->state = NGHTTP2_IB_IGN_PAYLOAD;
|
||||||
|
|
||||||
|
rv = nghttp2_session_terminate_session_with_reason
|
||||||
|
(session, NGHTTP2_PROTOCOL_ERROR, "too large frame size");
|
||||||
|
|
||||||
|
if(nghttp2_is_fatal(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch(iframe->frame.hd.type) {
|
switch(iframe->frame.hd.type) {
|
||||||
case NGHTTP2_DATA: {
|
case NGHTTP2_DATA: {
|
||||||
DEBUGF(fprintf(stderr, "recv: DATA\n"));
|
DEBUGF(fprintf(stderr, "recv: DATA\n"));
|
||||||
|
@ -5688,6 +5735,10 @@ uint32_t nghttp2_session_get_remote_settings(nghttp2_session *session,
|
||||||
return session->remote_settings.max_concurrent_streams;
|
return session->remote_settings.max_concurrent_streams;
|
||||||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||||
return session->remote_settings.initial_window_size;
|
return session->remote_settings.initial_window_size;
|
||||||
|
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
|
||||||
|
return session->remote_settings.max_frame_size;
|
||||||
|
case NGHTTP2_SETTINGS_MAX_HEADER_SET_SIZE:
|
||||||
|
return session->remote_settings.max_header_set_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(0);
|
assert(0);
|
||||||
|
|
|
@ -80,7 +80,7 @@ typedef enum {
|
||||||
NGHTTP2_IB_IGN_DATA
|
NGHTTP2_IB_IGN_DATA
|
||||||
} nghttp2_inbound_state;
|
} nghttp2_inbound_state;
|
||||||
|
|
||||||
#define NGHTTP2_INBOUND_NUM_IV 5
|
#define NGHTTP2_INBOUND_NUM_IV 7
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
nghttp2_frame frame;
|
nghttp2_frame frame;
|
||||||
|
@ -113,6 +113,8 @@ typedef struct {
|
||||||
uint32_t enable_push;
|
uint32_t enable_push;
|
||||||
uint32_t max_concurrent_streams;
|
uint32_t max_concurrent_streams;
|
||||||
uint32_t initial_window_size;
|
uint32_t initial_window_size;
|
||||||
|
uint32_t max_frame_size;
|
||||||
|
uint32_t max_header_set_size;
|
||||||
} nghttp2_settings_storage;
|
} nghttp2_settings_storage;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -95,6 +95,8 @@ int main(int argc, char* argv[])
|
||||||
test_nghttp2_session_recv_unexpected_continuation) ||
|
test_nghttp2_session_recv_unexpected_continuation) ||
|
||||||
!CU_add_test(pSuite, "session_recv_settings_header_table_size",
|
!CU_add_test(pSuite, "session_recv_settings_header_table_size",
|
||||||
test_nghttp2_session_recv_settings_header_table_size) ||
|
test_nghttp2_session_recv_settings_header_table_size) ||
|
||||||
|
!CU_add_test(pSuite, "session_recv_too_large_frame_length",
|
||||||
|
test_nghttp2_session_recv_too_large_frame_length) ||
|
||||||
!CU_add_test(pSuite, "session_continue", test_nghttp2_session_continue) ||
|
!CU_add_test(pSuite, "session_continue", test_nghttp2_session_continue) ||
|
||||||
!CU_add_test(pSuite, "session_add_frame",
|
!CU_add_test(pSuite, "session_add_frame",
|
||||||
test_nghttp2_session_add_frame) ||
|
test_nghttp2_session_add_frame) ||
|
||||||
|
|
|
@ -709,4 +709,21 @@ void test_nghttp2_iv_check(void)
|
||||||
iv[1].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
iv[1].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
|
||||||
iv[1].value = UINT32_MAX;
|
iv[1].value = UINT32_MAX;
|
||||||
CU_ASSERT(!nghttp2_iv_check(iv, 2));
|
CU_ASSERT(!nghttp2_iv_check(iv, 2));
|
||||||
|
|
||||||
|
/* Too small SETTINGS_MAX_FRAME_SIZE */
|
||||||
|
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE;
|
||||||
|
iv[0].value = NGHTTP2_MAX_FRAME_SIZE_MIN - 1;
|
||||||
|
CU_ASSERT(!nghttp2_iv_check(iv, 1));
|
||||||
|
|
||||||
|
/* Too large SETTINGS_MAX_FRAME_SIZE */
|
||||||
|
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE;
|
||||||
|
iv[0].value = NGHTTP2_MAX_FRAME_SIZE_MAX + 1;
|
||||||
|
CU_ASSERT(!nghttp2_iv_check(iv, 1));
|
||||||
|
|
||||||
|
/* Max and min SETTINGS_MAX_FRAME_SIZE */
|
||||||
|
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE;
|
||||||
|
iv[0].value = NGHTTP2_MAX_FRAME_SIZE_MIN;
|
||||||
|
iv[1].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE;
|
||||||
|
iv[1].value = NGHTTP2_MAX_FRAME_SIZE_MAX;
|
||||||
|
CU_ASSERT(nghttp2_iv_check(iv, 2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1410,6 +1410,36 @@ void test_nghttp2_session_recv_settings_header_table_size(void)
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_nghttp2_session_recv_too_large_frame_length(void)
|
||||||
|
{
|
||||||
|
nghttp2_session *session;
|
||||||
|
nghttp2_session_callbacks callbacks;
|
||||||
|
uint8_t buf[NGHTTP2_FRAME_HDLEN];
|
||||||
|
nghttp2_outbound_item *item;
|
||||||
|
nghttp2_frame_hd hd = {
|
||||||
|
/* Initial max frame size is NGHTTP2_MAX_FRAME_SIZE_MIN */
|
||||||
|
NGHTTP2_MAX_FRAME_SIZE_MIN + 1,
|
||||||
|
1,
|
||||||
|
NGHTTP2_HEADERS,
|
||||||
|
NGHTTP2_FLAG_NONE
|
||||||
|
};
|
||||||
|
memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
|
||||||
|
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
|
nghttp2_frame_pack_frame_hd(buf, &hd);
|
||||||
|
|
||||||
|
CU_ASSERT(sizeof(buf) ==
|
||||||
|
nghttp2_session_mem_recv(session, buf, sizeof(buf)));
|
||||||
|
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
|
||||||
|
CU_ASSERT(item != NULL);
|
||||||
|
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||||
|
|
||||||
|
nghttp2_session_del(session);
|
||||||
|
}
|
||||||
|
|
||||||
void test_nghttp2_session_continue(void)
|
void test_nghttp2_session_continue(void)
|
||||||
{
|
{
|
||||||
nghttp2_session *session;
|
nghttp2_session *session;
|
||||||
|
@ -2162,6 +2192,25 @@ void test_nghttp2_session_on_settings_received(void)
|
||||||
|
|
||||||
nghttp2_frame_settings_free(&frame.settings);
|
nghttp2_frame_settings_free(&frame.settings);
|
||||||
nghttp2_session_del(session);
|
nghttp2_session_del(session);
|
||||||
|
|
||||||
|
/* Check too large SETTINGS_MAX_FRAME_SIZE */
|
||||||
|
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||||
|
|
||||||
|
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE;
|
||||||
|
iv[0].value = NGHTTP2_MAX_FRAME_SIZE_MAX + 1;
|
||||||
|
|
||||||
|
nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE,
|
||||||
|
dup_iv(iv, 1), 1);
|
||||||
|
|
||||||
|
CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
|
||||||
|
|
||||||
|
item = nghttp2_session_get_next_ob_item(session);
|
||||||
|
|
||||||
|
CU_ASSERT(item != NULL);
|
||||||
|
CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item));
|
||||||
|
|
||||||
|
nghttp2_frame_settings_free(&frame.settings);
|
||||||
|
nghttp2_session_del(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_nghttp2_session_on_push_promise_received(void)
|
void test_nghttp2_session_on_push_promise_received(void)
|
||||||
|
|
|
@ -37,6 +37,7 @@ void test_nghttp2_session_recv_altsvc(void);
|
||||||
void test_nghttp2_session_recv_unknown_frame(void);
|
void test_nghttp2_session_recv_unknown_frame(void);
|
||||||
void test_nghttp2_session_recv_unexpected_continuation(void);
|
void test_nghttp2_session_recv_unexpected_continuation(void);
|
||||||
void test_nghttp2_session_recv_settings_header_table_size(void);
|
void test_nghttp2_session_recv_settings_header_table_size(void);
|
||||||
|
void test_nghttp2_session_recv_too_large_frame_length(void);
|
||||||
void test_nghttp2_session_continue(void);
|
void test_nghttp2_session_continue(void);
|
||||||
void test_nghttp2_session_add_frame(void);
|
void test_nghttp2_session_add_frame(void);
|
||||||
void test_nghttp2_session_on_request_headers_received(void);
|
void test_nghttp2_session_on_request_headers_received(void);
|
||||||
|
|
Loading…
Reference in New Issue