Implement SETTINGS_MAX_FRAME_SIZE and SETTINGS_MAX_HEADER_LIST_SIZE

This commit is contained in:
Tatsuhiro Tsujikawa 2014-07-27 16:58:04 +09:00
parent c4be7d48a0
commit 77374ac6e2
9 changed files with 143 additions and 3 deletions

View File

@ -510,7 +510,15 @@ typedef enum {
/**
* 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;
/* Note: If we add SETTINGS, update the capacity of
NGHTTP2_INBOUND_NUM_IV as well */

View File

@ -1037,6 +1037,14 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
return 0;
}
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:
return 0;
}

View File

@ -33,7 +33,6 @@
#include "nghttp2_hd.h"
#include "nghttp2_buf.h"
#define NGHTTP2_FRAME_LENGTH_MASK ((1 << 24) - 1)
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
@ -43,6 +42,9 @@
/* The number of bytes of frame header. */
#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
/* The one frame buffer length for tranmission. We may use several of
them to support CONTINUATION. To account for Pad Length field, we

View File

@ -292,6 +292,8 @@ static void init_settings(nghttp2_settings_storage *settings)
settings->enable_push = 1;
settings->max_concurrent_streams = NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
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)
@ -3273,6 +3275,12 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
session->local_settings.initial_window_size = iv[i].value;
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;
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;
}
}
@ -4141,6 +4166,8 @@ static void inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe)
case NGHTTP2_SETTINGS_ENABLE_PUSH:
case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
case NGHTTP2_SETTINGS_MAX_HEADER_SET_SIZE:
break;
default:
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.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) {
case NGHTTP2_DATA: {
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;
case NGHTTP2_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);

View File

@ -80,7 +80,7 @@ typedef enum {
NGHTTP2_IB_IGN_DATA
} nghttp2_inbound_state;
#define NGHTTP2_INBOUND_NUM_IV 5
#define NGHTTP2_INBOUND_NUM_IV 7
typedef struct {
nghttp2_frame frame;
@ -113,6 +113,8 @@ typedef struct {
uint32_t enable_push;
uint32_t max_concurrent_streams;
uint32_t initial_window_size;
uint32_t max_frame_size;
uint32_t max_header_set_size;
} nghttp2_settings_storage;
typedef enum {

View File

@ -95,6 +95,8 @@ int main(int argc, char* argv[])
test_nghttp2_session_recv_unexpected_continuation) ||
!CU_add_test(pSuite, "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_add_frame",
test_nghttp2_session_add_frame) ||

View File

@ -709,4 +709,21 @@ void test_nghttp2_iv_check(void)
iv[1].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
iv[1].value = UINT32_MAX;
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));
}

View File

@ -1410,6 +1410,36 @@ void test_nghttp2_session_recv_settings_header_table_size(void)
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)
{
nghttp2_session *session;
@ -2162,6 +2192,25 @@ void test_nghttp2_session_on_settings_received(void)
nghttp2_frame_settings_free(&frame.settings);
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)

View File

@ -37,6 +37,7 @@ void test_nghttp2_session_recv_altsvc(void);
void test_nghttp2_session_recv_unknown_frame(void);
void test_nghttp2_session_recv_unexpected_continuation(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_add_frame(void);
void test_nghttp2_session_on_request_headers_received(void);