From 196406da0e1f4402b4a56fda0aa078f3d9d9c71c Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 5 Feb 2014 23:37:27 +0900 Subject: [PATCH 01/56] Change protocol identifier to h2-10 --- lib/includes/nghttp2/nghttp2.h | 4 ++-- tests/nghttp2_npn_test.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 8563a0a0..0b956a3e 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -40,13 +40,13 @@ extern "C" { * * The protocol version identification of this library supports. */ -#define NGHTTP2_PROTO_VERSION_ID "HTTP-draft-09/2.0" +#define NGHTTP2_PROTO_VERSION_ID "h2-10" /** * @macro * * The length of :macro:`NGHTTP2_PROTO_VERSION_ID`. */ -#define NGHTTP2_PROTO_VERSION_ID_LEN 17 +#define NGHTTP2_PROTO_VERSION_ID_LEN 5 struct nghttp2_session; /** diff --git a/tests/nghttp2_npn_test.c b/tests/nghttp2_npn_test.c index 5bb10fdc..d49865fe 100644 --- a/tests/nghttp2_npn_test.c +++ b/tests/nghttp2_npn_test.c @@ -33,14 +33,13 @@ static void http2(void) { const unsigned char p[] = { 8, 'h', 't', 't', 'p', '/', '1', '.', '1', - 17, 'H', 'T', 'T', 'P', '-', 'd', 'r', 'a', 'f', 't', '-', '0', '9', '/', - '2', '.', '0', + 5, 'h', '2', '-', '1', '0', 6, 's', 'p', 'd', 'y', '/', '3' }; unsigned char outlen; unsigned char* out; CU_ASSERT(1 == nghttp2_select_next_protocol(&out, &outlen, p, sizeof(p))); - CU_ASSERT(17 == outlen); + CU_ASSERT(NGHTTP2_PROTO_VERSION_ID_LEN == outlen); CU_ASSERT(memcmp(NGHTTP2_PROTO_VERSION_ID, out, outlen) == 0); } From c79adf6997bb5e6cdffe35bdb194d72b5082ecea Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 6 Feb 2014 00:23:20 +0900 Subject: [PATCH 02/56] Remove flow control disabling feature --- lib/includes/nghttp2/nghttp2.h | 16 +-- lib/nghttp2_frame.c | 12 +-- lib/nghttp2_frame.h | 6 +- lib/nghttp2_session.c | 181 +++++---------------------------- lib/nghttp2_session.h | 8 -- lib/nghttp2_stream.c | 4 - lib/nghttp2_stream.h | 14 --- lib/nghttp2_submit.c | 10 +- src/HttpServer.cc | 8 +- src/HttpServer.h | 1 - src/app_helper.cc | 2 - src/nghttp.cc | 18 +--- src/nghttpd.cc | 11 +- tests/main.c | 4 - tests/nghttp2_frame_test.c | 20 ++-- tests/nghttp2_session_test.c | 151 ++++----------------------- tests/nghttp2_session_test.h | 2 - 17 files changed, 63 insertions(+), 405 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 0b956a3e..c23a9477 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -425,14 +425,10 @@ typedef enum { * SETTINGS_INITIAL_WINDOW_SIZE */ NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 7, - /** - * SETTINGS_FLOW_CONTROL_OPTIONS - */ - NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS = 10, /** * Maximum ID of :type:`nghttp2_settings_id`. */ - NGHTTP2_SETTINGS_MAX = 10 + NGHTTP2_SETTINGS_MAX = 7 } nghttp2_settings_id; /** @@ -1623,9 +1619,6 @@ size_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session); * window_size_increment with `nghttp2_submit_window_update()`, this * function returns the number of bytes less than actually received. * - * If flow control is disabled for that stream, this function returns - * 0. - * * This function returns -1 if it fails. */ int32_t nghttp2_session_get_stream_effective_recv_data_length @@ -1656,9 +1649,6 @@ int32_t nghttp2_session_get_stream_effective_local_window_size * with `nghttp2_submit_window_update()`, this function returns the * number of bytes less than actually received. * - * If flow control is disabled for a connection, this function returns - * 0. - * * This function returns -1 if it fails. */ int32_t nghttp2_session_get_effective_recv_data_length @@ -2021,8 +2011,8 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags, * negative error codes: * * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` - * The |iv| contains invalid value (e.g., attempting to re-enable - * flow control). + * The |iv| contains invalid value (e.g., initial window size + * strictly greater than (1 << 31) - 1. * :enum:`NGHTTP2_ERR_NOMEM` * Out of memory. */ diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index c70f5ff2..b422327e 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -617,8 +617,7 @@ ssize_t nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, return nvlen; } -int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv, - int32_t flow_control_opt) +int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) { size_t i; for(i = 0; i < niv; ++i) { @@ -628,15 +627,6 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv, return 0; } break; - case NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS: - if(flow_control_opt) { - if((iv[i].value & 0x1) == 0) { - /* Attempt to re-enabling flow-control is error */ - return 0; - } - } else { - flow_control_opt = iv[i].value & 0x1; - } default: break; } diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index 26a29ee4..fe6b995f 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -472,12 +472,10 @@ void nghttp2_nv_array_del(nghttp2_nv *nva); /* * Checks that the |iv|, which includes |niv| entries, does not have - * invalid values. The |flow_control_opt| is current flow control - * option value. + * invalid values. * * This function returns nonzero if it succeeds, or 0. */ -int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv, - int32_t flow_control_opt); +int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); #endif /* NGHTTP2_FRAME_H */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 43c9f737..f5264e0b 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -186,7 +186,6 @@ static void init_settings(uint32_t *settings) NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS; settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] = NGHTTP2_INITIAL_WINDOW_SIZE; - settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS] = 0; } typedef struct { @@ -225,8 +224,6 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE; } - (*session_ptr)->remote_flow_control = 1; - (*session_ptr)->local_flow_control = 1; (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; (*session_ptr)->recv_window_size = 0; (*session_ptr)->recv_reduction = 0; @@ -585,10 +582,6 @@ nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session, return NULL; } nghttp2_stream_init(stream, stream_id, flags, pri, initial_state, - !session->remote_settings - [NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS], - !session->local_settings - [NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS], session->remote_settings [NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], session->local_settings @@ -1016,12 +1009,8 @@ static size_t nghttp2_session_next_data_read(nghttp2_session *session, { int32_t window_size = NGHTTP2_DATA_PAYLOAD_LENGTH; /* Take into account both connection-level flow control here */ - if(session->remote_flow_control) { - window_size = nghttp2_min(window_size, session->remote_window_size); - } - if(stream->remote_flow_control) { - window_size = nghttp2_min(window_size, stream->remote_window_size); - } + window_size = nghttp2_min(window_size, session->remote_window_size); + window_size = nghttp2_min(window_size, stream->remote_window_size); if(window_size > 0) { return window_size; } @@ -1786,12 +1775,10 @@ int nghttp2_session_send(nghttp2_session *session) } frame = nghttp2_outbound_item_get_data_frame(session->aob.item); stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if(stream && stream->remote_flow_control) { + if(stream) { stream->remote_window_size -= len; } - if(session->remote_flow_control) { - session->remote_window_size -= len; - } + session->remote_window_size -= len; } session->aob.framebufoff += sentlen; if(session->aob.framebufoff == session->aob.framebufmark) { @@ -2506,8 +2493,7 @@ static int nghttp2_update_remote_initial_window_size_func if(stream->deferred_data && (stream->deferred_flags & NGHTTP2_DEFERRED_FLOW_CONTROL) && stream->remote_window_size > 0 && - (arg->session->remote_flow_control == 0 || - arg->session->remote_window_size > 0)) { + arg->session->remote_window_size > 0) { rv = nghttp2_pq_push(&arg->session->ob_pq, stream->deferred_data); if(rv != 0) { /* FATAL */ @@ -2552,9 +2538,6 @@ static int nghttp2_update_local_initial_window_size_func nghttp2_stream *stream; arg = (nghttp2_update_window_size_arg*)ptr; stream = (nghttp2_stream*)entry; - if(!stream->local_flow_control) { - return 0; - } rv = nghttp2_stream_update_local_initial_window_size(stream, arg->new_window_size, arg->old_window_size); @@ -2603,70 +2586,6 @@ static int nghttp2_session_update_local_initial_window_size &arg); } -static int nghttp2_disable_remote_flow_control_func(nghttp2_map_entry *entry, - void *ptr) -{ - nghttp2_session *session; - nghttp2_stream *stream; - session = (nghttp2_session*)ptr; - stream = (nghttp2_stream*)entry; - stream->remote_flow_control = 0; - /* If DATA frame is deferred due to flow control, push it back to - outbound queue. */ - if(stream->deferred_data && - (stream->deferred_flags & NGHTTP2_DEFERRED_FLOW_CONTROL)) { - int rv; - rv = nghttp2_pq_push(&session->ob_pq, stream->deferred_data); - if(rv == 0) { - nghttp2_stream_detach_deferred_data(stream); - } else { - /* FATAL */ - assert(rv < NGHTTP2_ERR_FATAL); - return rv; - } - } - return 0; -} - -/* - * Disable remote side connection-level flow control and stream-level - * flow control of existing streams. - * - * This function returns 0 if it succeeds, or one of negative error codes. - * - * The error code is always FATAL. - */ -static int nghttp2_session_disable_remote_flow_control -(nghttp2_session *session) -{ - session->remote_flow_control = 0; - return nghttp2_map_each(&session->streams, - nghttp2_disable_remote_flow_control_func, session); -} - -static int nghttp2_disable_local_flow_control_func(nghttp2_map_entry *entry, - void *ptr) -{ - nghttp2_stream *stream; - stream = (nghttp2_stream*)entry; - stream->local_flow_control = 0; - return 0; -} - -/* - * Disable stream-level flow control in local side of existing - * streams. - */ -static void nghttp2_session_disable_local_flow_control -(nghttp2_session *session) -{ - int rv; - session->local_flow_control = 0; - rv = nghttp2_map_each(&session->streams, - nghttp2_disable_local_flow_control_func, NULL); - assert(rv == 0); -} - /* * Apply SETTINGS values |iv| having |niv| elements to the local * settings. SETTINGS_MAX_CONCURRENT_STREAMS is not applied here @@ -2687,9 +2606,6 @@ int nghttp2_session_update_local_settings(nghttp2_session *session, { int rv; size_t i; - uint8_t old_flow_control = - session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]; - uint8_t new_flow_control = old_flow_control; int32_t new_initial_window_size = -1; int32_t header_table_size = -1; uint8_t header_table_size_seen = 0; @@ -2703,9 +2619,6 @@ int nghttp2_session_update_local_settings(nghttp2_session *session, case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: new_initial_window_size = iv[i].value; break; - case NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS: - new_flow_control = iv[i].value; - break; } } if(header_table_size_seen) { @@ -2719,7 +2632,7 @@ int nghttp2_session_update_local_settings(nghttp2_session *session, return rv; } } - if(!old_flow_control && !new_flow_control && new_initial_window_size != -1) { + if(new_initial_window_size != -1) { rv = nghttp2_session_update_local_initial_window_size (session, new_initial_window_size, @@ -2736,10 +2649,6 @@ int nghttp2_session_update_local_settings(nghttp2_session *session, session->local_settings[iv[i].settings_id] = iv[i].value; } } - if(old_flow_control == 0 && - session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]) { - nghttp2_session_disable_local_flow_control(session); - } return 0; } @@ -2830,23 +2739,6 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, (session, frame, NGHTTP2_PROTOCOL_ERROR); } break; - case NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS: - if(entry->value & 0x1) { - if(session->remote_settings[entry->settings_id] == 0) { - rv = nghttp2_session_disable_remote_flow_control(session); - if(rv != 0) { - /* FATAL */ - assert(rv < NGHTTP2_ERR_FATAL); - return rv; - } - } - } else if(session->remote_settings[entry->settings_id] == 1) { - /* Re-enabling flow control is subject to connection-level - error(?) */ - return nghttp2_session_handle_invalid_connection - (session, frame, NGHTTP2_FLOW_CONTROL_ERROR); - } - break; } session->remote_settings[entry->settings_id] = entry->value; } @@ -3035,7 +2927,7 @@ static int nghttp2_push_back_deferred_data_func(nghttp2_map_entry *entry, outbound queue. */ if(stream->deferred_data && (stream->deferred_flags & NGHTTP2_DEFERRED_FLOW_CONTROL) && - (stream->remote_flow_control == 0 || stream->remote_window_size > 0)) { + stream->remote_window_size > 0) { int rv; rv = nghttp2_pq_push(&session->ob_pq, stream->deferred_data); if(rv == 0) { @@ -3064,13 +2956,6 @@ static int session_on_connection_window_update_received { int rv; /* Handle connection-level flow control */ - if(session->remote_flow_control == 0) { - /* Disabling flow control by sending SETTINGS and receiving - WINDOW_UPDATE are asynchronous, so it is hard to determine - that the peer is misbehaving or not without measuring - RTT. For now, we just ignore such frames. */ - return nghttp2_session_call_on_frame_received(session, frame); - } if(NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < session->remote_window_size) { return nghttp2_session_handle_invalid_connection @@ -3107,10 +2992,6 @@ static int session_on_stream_window_update_received return nghttp2_session_handle_invalid_connection (session, frame, NGHTTP2_PROTOCOL_ERROR); } - if(stream->remote_flow_control == 0) { - /* Same reason with connection-level flow control */ - return nghttp2_session_call_on_frame_received(session, frame); - } if(NGHTTP2_MAX_WINDOW_SIZE - frame->window_update.window_size_increment < stream->remote_window_size) { return nghttp2_session_handle_invalid_stream(session, frame, @@ -3118,8 +2999,7 @@ static int session_on_stream_window_update_received } stream->remote_window_size += frame->window_update.window_size_increment; if(stream->remote_window_size > 0 && - (session->remote_flow_control == 0 || - session->remote_window_size > 0) && + session->remote_window_size > 0 && stream->deferred_data != NULL && (stream->deferred_flags & NGHTTP2_DEFERRED_FLOW_CONTROL)) { rv = nghttp2_pq_push(&session->ob_pq, stream->deferred_data); @@ -3411,7 +3291,6 @@ static int 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_FLOW_CONTROL_OPTIONS: break; default: return -1; @@ -3822,23 +3701,21 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n", readlen, iframe->payloadleft)); if(readlen > 0) { - if(session->local_flow_control) { - rv = nghttp2_session_update_recv_connection_window_size - (session, readlen); - if(nghttp2_is_fatal(rv)) { - return rv; - } - if(iframe->payloadleft || - (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { - nghttp2_stream *stream; - stream = nghttp2_session_get_stream(session, - iframe->frame.hd.stream_id); - if(stream && stream->local_flow_control) { - rv = nghttp2_session_update_recv_stream_window_size - (session, stream, readlen); - if(nghttp2_is_fatal(rv)) { - return rv; - } + rv = nghttp2_session_update_recv_connection_window_size + (session, readlen); + if(nghttp2_is_fatal(rv)) { + return rv; + } + if(iframe->payloadleft || + (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { + nghttp2_stream *stream; + stream = nghttp2_session_get_stream(session, + iframe->frame.hd.stream_id); + if(stream) { + rv = nghttp2_session_update_recv_stream_window_size + (session, stream, readlen); + if(nghttp2_is_fatal(rv)) { + return rv; } } } @@ -3875,7 +3752,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, readlen = inbound_frame_payload_readlen(iframe, in, last); iframe->payloadleft -= readlen; in += readlen; - if(readlen > 0 && session->local_flow_control) { + if(readlen > 0) { /* Update connection-level flow control window for ignored DATA frame too */ rv = nghttp2_session_update_recv_connection_window_size @@ -4033,9 +3910,7 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, nghttp2_frame *frame; nghttp2_settings_entry *iv_copy; int r; - if(!nghttp2_iv_check(iv, niv, - session->local_settings - [NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS])) { + if(!nghttp2_iv_check(iv, niv)) { return NGHTTP2_ERR_INVALID_ARGUMENT; } frame = malloc(sizeof(nghttp2_frame)); @@ -4149,9 +4024,6 @@ int32_t nghttp2_session_get_stream_effective_recv_data_length if(stream == NULL) { return -1; } - if(stream->local_flow_control == 0) { - return 0; - } return stream->recv_window_size < 0 ? 0 : stream->recv_window_size; } @@ -4169,9 +4041,6 @@ int32_t nghttp2_session_get_stream_effective_local_window_size int32_t nghttp2_session_get_effective_recv_data_length (nghttp2_session *session) { - if(session->local_flow_control == 0) { - return 0; - } return session->recv_window_size < 0 ? 0 : session->recv_window_size; } diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 21eb5377..f4f17922 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -189,14 +189,6 @@ struct nghttp2_session { /* Flags indicating GOAWAY is sent and/or recieved. The flags are composed by bitwise OR-ing nghttp2_goaway_flag. */ uint8_t goaway_flags; - /* Non-zero indicates connection-level flow control on remote side - is in effect. This will be disabled when WINDOW_UPDATE with - END_FLOW_CONTROL bit set is received. */ - uint8_t remote_flow_control; - /* Non-zero indicates connection-level flow control on local side is - in effect. This will be disabled when WINDOW_UPDATE with - END_FLOW_CONTROL bit set is sent. */ - uint8_t local_flow_control; }; /* Struct used when updating initial window size of each active diff --git a/lib/nghttp2_stream.c b/lib/nghttp2_stream.c index b212bf4d..f674657c 100644 --- a/lib/nghttp2_stream.c +++ b/lib/nghttp2_stream.c @@ -29,8 +29,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, uint8_t flags, int32_t pri, nghttp2_stream_state initial_state, - uint8_t remote_flow_control, - uint8_t local_flow_control, int32_t remote_initial_window_size, int32_t local_initial_window_size, void *stream_user_data) @@ -44,8 +42,6 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, stream->stream_user_data = stream_user_data; stream->deferred_data = NULL; stream->deferred_flags = NGHTTP2_DEFERRED_NONE; - stream->remote_flow_control = remote_flow_control; - stream->local_flow_control = local_flow_control; stream->remote_window_size = remote_initial_window_size; stream->local_window_size = local_initial_window_size; stream->recv_window_size = 0; diff --git a/lib/nghttp2_stream.h b/lib/nghttp2_stream.h index c3698a34..a0392429 100644 --- a/lib/nghttp2_stream.h +++ b/lib/nghttp2_stream.h @@ -117,25 +117,11 @@ typedef struct { /* The flags for defered DATA. Bitwise OR of zero or more nghttp2_deferred_flag values */ uint8_t deferred_flags; - /* Flag to indicate whether the remote side has flow control - enabled. If it is enabled, we have to enforces flow control to - send data to the other side. This could be disabled when - receiving SETTINGS with flow control options off or receiving - WINDOW_UPDATE with END_FLOW_CONTROL bit set. */ - uint8_t remote_flow_control; - /* Flag to indicate whether the local side has flow control - enabled. If it is enabled, the received data are subject to the - flow control. This could be disabled by sending SETTINGS with - flow control options off or sending WINDOW_UPDATE with - END_FLOW_CONTROL bit set. */ - uint8_t local_flow_control; } nghttp2_stream; void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id, uint8_t flags, int32_t pri, nghttp2_stream_state initial_state, - uint8_t remote_flow_control, - uint8_t local_flow_control, int32_t remote_initial_window_size, int32_t local_initial_window_size, void *stream_user_data); diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index 31e56d72..4096dece 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -219,9 +219,6 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags, } flags = 0; if(stream_id == 0) { - if(!session->local_flow_control) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } rv = nghttp2_adjust_local_window_size(&session->local_window_size, &session->recv_window_size, &session->recv_reduction, @@ -232,9 +229,6 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags, } else { stream = nghttp2_session_get_stream(session, stream_id); if(stream) { - if(!stream->local_flow_control) { - return NGHTTP2_ERR_INVALID_ARGUMENT; - } rv = nghttp2_adjust_local_window_size(&stream->local_window_size, &stream->recv_window_size, &stream->recv_reduction, @@ -325,9 +319,7 @@ ssize_t nghttp2_pack_settings_payload(uint8_t *buf, const nghttp2_settings_entry *iv, size_t niv) { - /* Assume that current flow_control_option is 0 (which means that - flow control is enabled) */ - if(!nghttp2_iv_check(iv, niv, 0)) { + if(!nghttp2_iv_check(iv, niv)) { return NGHTTP2_ERR_INVALID_ARGUMENT; } diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 9d81ccaa..cd3b1999 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -71,8 +71,7 @@ Config::Config() verbose(false), daemon(false), verify_client(false), - no_tls(false), - no_flow_control(false) + no_tls(false) {} Request::Request(int32_t stream_id) @@ -373,11 +372,6 @@ int Http2Handler::on_connect() entry[0].value = 100; entry[1].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; entry[1].value = 0; - if(sessions_->get_config()->no_flow_control) { - entry[niv].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - entry[niv].value = 1; - ++niv; - } if(sessions_->get_config()->header_table_size >= 0) { entry[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; entry[niv].value = sessions_->get_config()->header_table_size; diff --git a/src/HttpServer.h b/src/HttpServer.h index fb7d64c9..3d909263 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -62,7 +62,6 @@ struct Config { bool daemon; bool verify_client; bool no_tls; - bool no_flow_control; Config(); }; diff --git a/src/app_helper.cc b/src/app_helper.cc index 6516af39..ce565202 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -95,8 +95,6 @@ const char* strsettingsid(int32_t id) return "SETTINGS_MAX_CONCURRENT_STREAMS"; case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: return "SETTINGS_INITIAL_WINDOW_SIZE"; - case NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS: - return "SETTINGS_FLOW_CONTROL_OPTIONS"; default: return "UNKNOWN"; } diff --git a/src/nghttp.cc b/src/nghttp.cc index b7865527..04caa96d 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -95,7 +95,6 @@ struct Config { bool verbose; bool get_assets; bool stat; - bool no_flow_control; bool upgrade; Config() : output_upper_thres(1024*1024), @@ -111,7 +110,6 @@ struct Config { verbose(false), get_assets(false), stat(false), - no_flow_control(false), upgrade(false) {} }; @@ -366,11 +364,6 @@ size_t populate_settings(nghttp2_settings_entry *iv) } else { iv[1].value = NGHTTP2_INITIAL_WINDOW_SIZE; } - if(config.no_flow_control) { - iv[niv].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[niv].value = 1; - ++niv; - } if(config.header_table_size >= 0) { iv[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; iv[niv].value = config.header_table_size; @@ -1642,7 +1635,7 @@ int run(char **uris, int n) namespace { void print_usage(std::ostream& out) { - out << "Usage: nghttp [-Oafnsuv] [-t ] [-w ] [-W ]\n" + out << "Usage: nghttp [-Oansuv] [-t ] [-w ] [-W ]\n" << " [--cert=] [--key=] [-d ] [-m ]\n" << " [-p ] [-M ]\n" << " ..." @@ -1686,9 +1679,6 @@ void print_help(std::ostream& out) << " -m, --multiply= Request each URI times. By default, same\n" << " URI is not requested twice. This option\n" << " disables it too.\n" - << " -f, --no-flow-control\n" - << " Disables connection and stream level flow\n" - << " controls.\n" << " -u, --upgrade Perform HTTP Upgrade for HTTP/2.0. This\n" << " option is ignored if the request URI has\n" << " https scheme.\n" @@ -1727,7 +1717,6 @@ int main(int argc, char **argv) {"header", required_argument, nullptr, 'H'}, {"data", required_argument, nullptr, 'd'}, {"multiply", required_argument, nullptr, 'm'}, - {"no-flow-control", no_argument, nullptr, 'f'}, {"upgrade", no_argument, nullptr, 'u'}, {"pri", required_argument, nullptr, 'p'}, {"peer-max-concurrent-streams", required_argument, nullptr, 'M'}, @@ -1738,7 +1727,7 @@ int main(int argc, char **argv) {nullptr, 0, nullptr, 0 } }; int option_index = 0; - int c = getopt_long(argc, argv, "M:Oac:d:fm:np:hH:vst:uw:W:", long_options, + int c = getopt_long(argc, argv, "M:Oac:d:m:np:hH:vst:uw:W:", long_options, &option_index); char *end; if(c == -1) { @@ -1752,9 +1741,6 @@ int main(int argc, char **argv) case 'O': config.remote_name = true; break; - case 'f': - config.no_flow_control = true; - break; case 'h': print_help(std::cout); exit(EXIT_SUCCESS); diff --git a/src/nghttpd.cc b/src/nghttpd.cc index 043c1474..582c457c 100644 --- a/src/nghttpd.cc +++ b/src/nghttpd.cc @@ -75,7 +75,7 @@ int parse_push_config(Config& config, const char *optarg) namespace { void print_usage(std::ostream& out) { - out << "Usage: nghttpd [-DVfhv] [-d ] [--no-tls] [ ]" + out << "Usage: nghttpd [-DVhv] [-d ] [--no-tls] [ ]" << std::endl; } } // namespace @@ -103,9 +103,6 @@ void print_help(std::ostream& out) << " -v, --verbose Print debug information such as reception/\n" << " transmission of frames and name/value pairs.\n" << " --no-tls Disable SSL/TLS.\n" - << " -f, --no-flow-control\n" - << " Disables connection and stream level flow\n" - << " controls.\n" << " -c, --header-table-size=\n" << " Specify decoder header table size.\n" << " --color Force colored log output.\n" @@ -134,7 +131,6 @@ int main(int argc, char **argv) {"help", no_argument, nullptr, 'h'}, {"verbose", no_argument, nullptr, 'v'}, {"verify-client", no_argument, nullptr, 'V'}, - {"no-flow-control", no_argument, nullptr, 'f'}, {"header-table-size", required_argument, nullptr, 'c'}, {"push", required_argument, nullptr, 'p'}, {"no-tls", no_argument, &flag, 1}, @@ -142,7 +138,7 @@ int main(int argc, char **argv) {nullptr, 0, nullptr, 0} }; int option_index = 0; - int c = getopt_long(argc, argv, "DVc:d:fhp:v", long_options, &option_index); + int c = getopt_long(argc, argv, "DVc:d:hp:v", long_options, &option_index); char *end; if(c == -1) { break; @@ -157,9 +153,6 @@ int main(int argc, char **argv) case 'd': config.htdocs = optarg; break; - case 'f': - config.no_flow_control = true; - break; case 'h': print_help(std::cout); exit(EXIT_SUCCESS); diff --git a/tests/main.c b/tests/main.c index 71e681cf..f5df28cf 100644 --- a/tests/main.c +++ b/tests/main.c @@ -177,10 +177,6 @@ int main(int argc, char* argv[]) test_nghttp2_session_defer_data) || !CU_add_test(pSuite, "session_flow_control", test_nghttp2_session_flow_control) || - !CU_add_test(pSuite, "session_flow_control_disable_remote", - test_nghttp2_session_flow_control_disable_remote) || - !CU_add_test(pSuite, "session_flow_control_disable_local", - test_nghttp2_session_flow_control_disable_local) || !CU_add_test(pSuite, "session_flow_control_data_recv", test_nghttp2_session_flow_control_data_recv) || !CU_add_test(pSuite, "session_data_read_temporal_failure", diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 3640f2a4..b28d7d33 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -220,8 +220,8 @@ void test_nghttp2_frame_pack_settings() iv[0].value = 256; iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; iv[1].value = 16384; - iv[2].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[2].value = 1; + iv[2].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; + iv[2].value = 4096; nghttp2_frame_settings_init(&frame, NGHTTP2_FLAG_NONE, nghttp2_frame_iv_copy(iv, 3), 3); @@ -397,22 +397,16 @@ void test_nghttp2_iv_check(void) iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; iv[0].value = 100; - iv[1].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[1].value = 0; - iv[2].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[2].value = 1; + iv[1].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; + iv[1].value = 1024; - CU_ASSERT(nghttp2_iv_check(iv, 2, 0)); - CU_ASSERT(nghttp2_iv_check(iv, 3, 0)); - /* Re-enabling flow-control*/ - CU_ASSERT(0 == nghttp2_iv_check(iv, 2, 1)); - CU_ASSERT(0 == nghttp2_iv_check(iv, 3, 1)); + CU_ASSERT(nghttp2_iv_check(iv, 2)); iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; iv[1].value = NGHTTP2_MAX_WINDOW_SIZE; - CU_ASSERT(nghttp2_iv_check(iv, 2, 0)); + CU_ASSERT(nghttp2_iv_check(iv, 2)); /* Too large window size */ iv[1].value = (uint32_t)NGHTTP2_MAX_WINDOW_SIZE + 1; - CU_ASSERT(0 == nghttp2_iv_check(iv, 2, 0)); + CU_ASSERT(0 == nghttp2_iv_check(iv, 2)); } diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index cb21f8db..cbf31a3e 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -1311,8 +1311,8 @@ void test_nghttp2_session_on_settings_received(void) iv[2].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; iv[2].value = 64*1024; - iv[3].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[3].value = 1; + iv[3].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; + iv[3].value = 1024; /* Unknown settings ID */ iv[4].settings_id = 999; @@ -1341,8 +1341,8 @@ void test_nghttp2_session_on_settings_received(void) session->remote_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]); CU_ASSERT(64*1024 == session->remote_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); - CU_ASSERT(1 == - session->remote_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]); + CU_ASSERT(1024 == + session->remote_settings[NGHTTP2_SETTINGS_HEADER_TABLE_SIZE]); CU_ASSERT(64*1024 == stream1->remote_window_size); CU_ASSERT(0 == stream2->remote_window_size); @@ -1354,10 +1354,6 @@ void test_nghttp2_session_on_settings_received(void) CU_ASSERT(16*1024 == stream1->remote_window_size); CU_ASSERT(-48*1024 == stream2->remote_window_size); - CU_ASSERT(0 == stream1->remote_flow_control); - CU_ASSERT(0 == stream2->remote_flow_control); - CU_ASSERT(0 == session->remote_flow_control); - nghttp2_frame_settings_free(&frame.settings); nghttp2_session_del(session); @@ -2591,18 +2587,14 @@ void test_nghttp2_submit_settings(void) iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; iv[1].value = 16*1024; - iv[2].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[2].value = 1; + iv[2].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; + iv[2].value = 50; - iv[3].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; - iv[3].value = 50; + iv[3].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; + iv[3].value = 0; - iv[4].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; - iv[4].value = 0; - - /* Attempt to re-enable flow-control */ - iv[5].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[5].value = 0; + iv[4].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; + iv[4].value = (uint32_t)NGHTTP2_MAX_WINDOW_SIZE + 1; memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); callbacks.send_callback = null_send_callback; @@ -2610,25 +2602,23 @@ void test_nghttp2_submit_settings(void) nghttp2_session_server_new(&session, &callbacks, &ud); CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == - nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 6)); + nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 5)); /* Make sure that local settings are not changed */ CU_ASSERT(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS == session->local_settings[NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS]); CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE == session->local_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); - CU_ASSERT(0 == - session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]); - /* Now sends without 6th one */ - CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 5)); + /* Now sends without 5th one */ + CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 4)); item = nghttp2_session_get_next_ob_item(session); CU_ASSERT(NGHTTP2_SETTINGS == OB_CTRL_TYPE(item)); frame = item->frame; - CU_ASSERT(5 == frame->settings.niv); + CU_ASSERT(4 == frame->settings.niv); CU_ASSERT(5 == frame->settings.iv[0].value); CU_ASSERT(NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS == frame->settings.iv[0].settings_id); @@ -2651,9 +2641,6 @@ void test_nghttp2_submit_settings(void) CU_ASSERT(16*1024 == session->local_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); - CU_ASSERT(1 == - session->local_settings[NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS]); - CU_ASSERT(0 == session->local_flow_control); CU_ASSERT(0 == session->hd_inflater.ctx.hd_table_bufsize_max); nghttp2_session_del(session); @@ -2673,9 +2660,6 @@ void test_nghttp2_submit_settings_update_local_window_size(void) iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; iv[0].value = 16*1024; - iv[1].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[1].value = 1; - memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); callbacks.send_callback = null_send_callback; @@ -2690,7 +2674,6 @@ void test_nghttp2_submit_settings_update_local_window_size(void) stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE, NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENED, NULL); - stream->local_flow_control = 0; CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1)); CU_ASSERT(0 == nghttp2_session_send(session)); @@ -2701,7 +2684,7 @@ void test_nghttp2_submit_settings_update_local_window_size(void) CU_ASSERT(16*1024 + 100 == stream->local_window_size); stream = nghttp2_session_get_stream(session, 3); - CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE == stream->local_window_size); + CU_ASSERT(16*1024 == stream->local_window_size); item = nghttp2_session_get_next_ob_item(session); CU_ASSERT(NGHTTP2_WINDOW_UPDATE == OB_CTRL_TYPE(item)); @@ -2709,20 +2692,6 @@ void test_nghttp2_submit_settings_update_local_window_size(void) nghttp2_session_del(session); - /* Check flow control disabled case */ - nghttp2_session_server_new(&session, &callbacks, NULL); - stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - NGHTTP2_PRI_DEFAULT, - NGHTTP2_STREAM_OPENED, NULL); - - CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 2)); - CU_ASSERT(0 == nghttp2_session_send(session)); - CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0)); - - CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE == stream->local_window_size); - - nghttp2_session_del(session); - /* Check overflow case */ iv[0].value = 128*1024; nghttp2_session_server_new(&session, &callbacks, NULL); @@ -2817,10 +2786,6 @@ void test_nghttp2_submit_window_update(void) CU_ASSERT(0 == nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2, 0)); - /* Disable local flow control */ - stream->local_flow_control = 0; - CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == - nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2, -1)); /* It is ok if stream is closed or does not exist at the call time */ CU_ASSERT(0 == @@ -3431,84 +3396,6 @@ void test_nghttp2_session_flow_control(void) nghttp2_session_del(session); } -void test_nghttp2_session_flow_control_disable_remote(void) -{ - nghttp2_session *session; - nghttp2_session_callbacks callbacks; - my_user_data ud; - nghttp2_data_provider data_prd; - nghttp2_frame frame; - size_t data_size = 128*1024; - nghttp2_settings_entry iv = { NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS, 0x1 }; - - memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); - callbacks.send_callback = null_send_callback; - callbacks.on_frame_send_callback = on_frame_send_callback; - data_prd.read_callback = fixed_length_data_source_read_callback; - - ud.frame_send_cb_called = 0; - ud.data_source_length = data_size; - - /* Initial window size is 64KiB */ - nghttp2_session_client_new(&session, &callbacks, &ud); - nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, - &data_prd, NULL); - - /* Sends 64KiB data */ - CU_ASSERT(0 == nghttp2_session_send(session)); - CU_ASSERT(data_size - NGHTTP2_INITIAL_WINDOW_SIZE == ud.data_source_length); - - /* Disable flow control entirely */ - nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, - dup_iv(&iv, 1), 1); - nghttp2_session_on_settings_received(session, &frame, 1); - - /* Check both connection and stream-level remote_flow_control is - disabled */ - CU_ASSERT(0 == nghttp2_session_get_stream(session, 1)->remote_flow_control); - CU_ASSERT(0 == session->remote_flow_control); - - /* Sends remaining data */ - CU_ASSERT(0 == nghttp2_session_send(session)); - CU_ASSERT(0 == ud.data_source_length); - - nghttp2_frame_settings_free(&frame.settings); - nghttp2_session_del(session); -} - -void test_nghttp2_session_flow_control_disable_local(void) -{ - nghttp2_session *session; - nghttp2_session_callbacks callbacks; - nghttp2_stream *stream; - nghttp2_settings_entry iv[1]; - nghttp2_frame ack_frame; - - nghttp2_frame_settings_init(&ack_frame.settings, NGHTTP2_FLAG_ACK, NULL, 0); - memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); - callbacks.send_callback = null_send_callback; - - nghttp2_session_client_new(&session, &callbacks, NULL); - - stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, - NGHTTP2_PRI_DEFAULT, - NGHTTP2_STREAM_OPENING, NULL); - - iv[0].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[0].value = 1; - - CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, - ARRLEN(iv))); - CU_ASSERT(0 == nghttp2_session_send(session)); - CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0)); - - CU_ASSERT(0 == stream->local_flow_control); - CU_ASSERT(0 == session->local_flow_control); - - nghttp2_session_del(session); - nghttp2_frame_settings_free(&ack_frame.settings); -} - void test_nghttp2_session_flow_control_data_recv(void) { nghttp2_session *session; @@ -3934,8 +3821,8 @@ void test_nghttp2_pack_settings_payload(void) nghttp2_settings_entry *resiv; size_t resniv; - iv[0].settings_id = NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS; - iv[0].value = 1; + iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; + iv[0].value = 1023; iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; iv[1].value = 4095; @@ -3944,8 +3831,8 @@ void test_nghttp2_pack_settings_payload(void) CU_ASSERT(0 == nghttp2_frame_unpack_settings_payload2(&resiv, &resniv, buf, len)); CU_ASSERT(2 == resniv); - CU_ASSERT(NGHTTP2_SETTINGS_FLOW_CONTROL_OPTIONS == resiv[0].settings_id); - CU_ASSERT(1 == resiv[0].value); + CU_ASSERT(NGHTTP2_SETTINGS_HEADER_TABLE_SIZE == resiv[0].settings_id); + CU_ASSERT(1023 == resiv[0].value); CU_ASSERT(NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE == resiv[1].settings_id); CU_ASSERT(4095 == resiv[1].value); diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index 4b5bfcaf..6b4977f8 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -79,8 +79,6 @@ void test_nghttp2_session_stream_close_on_headers_push(void); void test_nghttp2_session_stop_data_with_rst_stream(void); void test_nghttp2_session_defer_data(void); void test_nghttp2_session_flow_control(void); -void test_nghttp2_session_flow_control_disable_remote(void); -void test_nghttp2_session_flow_control_disable_local(void); void test_nghttp2_session_flow_control_data_recv(void); void test_nghttp2_session_data_read_temporal_failure(void); void test_nghttp2_session_on_stream_close(void); From 112b49cb9ae85025ed8a005a4ae86b07e6a953c4 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 6 Feb 2014 00:26:12 +0900 Subject: [PATCH 03/56] Renumber SETTINGS --- lib/includes/nghttp2/nghttp2.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index c23a9477..1e9da150 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -420,15 +420,15 @@ typedef enum { /** * SETTINGS_MAX_CONCURRENT_STREAMS */ - NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 4, + NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 3, /** * SETTINGS_INITIAL_WINDOW_SIZE */ - NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 7, + NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 4, /** * Maximum ID of :type:`nghttp2_settings_id`. */ - NGHTTP2_SETTINGS_MAX = 7 + NGHTTP2_SETTINGS_MAX = 4 } nghttp2_settings_id; /** From f2c654f8987435863bd033d9abb72fcab38627ac Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 6 Feb 2014 21:38:16 +0900 Subject: [PATCH 04/56] Fix reception of ENABLE_PUSH ignored; strict check for SETTINGS value --- lib/nghttp2_frame.c | 10 ++++++++-- lib/nghttp2_session.c | 30 +++++++++++++++++------------- tests/nghttp2_frame_test.c | 9 +++++++++ tests/nghttp2_session_test.c | 5 +++-- 4 files changed, 37 insertions(+), 17 deletions(-) diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index b422327e..451aea55 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -622,13 +622,19 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) size_t i; for(i = 0; i < niv; ++i) { switch(iv[i].settings_id) { + case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: + case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: + break; + case NGHTTP2_SETTINGS_ENABLE_PUSH: + if(iv[i].value != 0 && iv[i].value != 1) { + return 0; + } + break; case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: if(iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) { return 0; } break; - default: - break; } } return 1; diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index f5264e0b..0108d542 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -2720,23 +2720,27 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, } } break; + case NGHTTP2_SETTINGS_ENABLE_PUSH: + if(entry->value != 0 && entry->value != 1) { + return nghttp2_session_handle_invalid_connection + (session, frame, NGHTTP2_PROTOCOL_ERROR); + } + break; case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: /* Update the initial window size of the all active streams */ /* Check that initial_window_size < (1u << 31) */ - if(entry->value <= NGHTTP2_MAX_WINDOW_SIZE) { - rv = nghttp2_session_update_remote_initial_window_size - (session, entry->value); - if(rv != 0) { - if(nghttp2_is_fatal(rv)) { - return rv; - } else { - return nghttp2_session_handle_invalid_connection - (session, frame, NGHTTP2_FLOW_CONTROL_ERROR); - } - } - } else { + if(entry->value > NGHTTP2_MAX_WINDOW_SIZE) { return nghttp2_session_handle_invalid_connection - (session, frame, NGHTTP2_PROTOCOL_ERROR); + (session, frame, NGHTTP2_FLOW_CONTROL_ERROR); + } + rv = nghttp2_session_update_remote_initial_window_size + (session, entry->value); + if(nghttp2_is_fatal(rv)) { + return rv; + } + if(rv != 0) { + return nghttp2_session_handle_invalid_connection + (session, frame, NGHTTP2_FLOW_CONTROL_ERROR); } break; } diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index b28d7d33..08e7f698 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -409,4 +409,13 @@ void test_nghttp2_iv_check(void) /* Too large window size */ iv[1].value = (uint32_t)NGHTTP2_MAX_WINDOW_SIZE + 1; CU_ASSERT(0 == nghttp2_iv_check(iv, 2)); + + /* ENABLE_PUSH only allows 0 or 1 */ + iv[1].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; + iv[1].value = 0; + CU_ASSERT(nghttp2_iv_check(iv, 2)); + iv[1].value = 1; + CU_ASSERT(nghttp2_iv_check(iv, 2)); + iv[1].value = 3; + CU_ASSERT(!nghttp2_iv_check(iv, 2)); } diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index cbf31a3e..5ec1b04a 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -1314,8 +1314,7 @@ void test_nghttp2_session_on_settings_received(void) iv[3].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE; iv[3].value = 1024; - /* Unknown settings ID */ - iv[4].settings_id = 999; + iv[4].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; iv[4].value = 0; memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); @@ -1343,6 +1342,8 @@ void test_nghttp2_session_on_settings_received(void) session->remote_settings[NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE]); CU_ASSERT(1024 == session->remote_settings[NGHTTP2_SETTINGS_HEADER_TABLE_SIZE]); + CU_ASSERT(0 == + session->remote_settings[NGHTTP2_SETTINGS_ENABLE_PUSH]); CU_ASSERT(64*1024 == stream1->remote_window_size); CU_ASSERT(0 == stream2->remote_window_size); From 40a5756564b3a3316c0f099ec84d38bd82e8eb08 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 6 Feb 2014 21:42:49 +0900 Subject: [PATCH 05/56] Terminate connection if unknown frame type is received --- lib/nghttp2_session.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 0108d542..4432d0fd 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3432,7 +3432,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->left = 8; break; - case NGHTTP2_CONTINUATION: + default: + /* Receiving unknown frame type and CONTINUATION in this state + are subject to connection error of type PROTOCOL_ERROR */ rv = nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR); if(nghttp2_is_fatal(rv)) { @@ -3441,10 +3443,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, busy = 1; iframe->state = NGHTTP2_IB_IGN_PAYLOAD; break; - default: - busy = 1; - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; - break; } break; case NGHTTP2_IB_READ_NBYTE: From d5848886013f7dbac8d03ccf8315deeacb26dfa2 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 6 Feb 2014 21:49:16 +0900 Subject: [PATCH 06/56] Renumber frame types, flags and error codes --- lib/includes/nghttp2/nghttp2.h | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 1e9da150..773b0e2b 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -364,11 +364,11 @@ typedef enum { /** * The WINDOW_UPDATE frame. */ - NGHTTP2_WINDOW_UPDATE = 9, + NGHTTP2_WINDOW_UPDATE = 8, /** * The CONTINUATION frame. */ - NGHTTP2_CONTINUATION = 10 + NGHTTP2_CONTINUATION = 9 } nghttp2_frame_type; /** @@ -401,7 +401,19 @@ typedef enum { /** * The ACK flag. */ - NGHTTP2_FLAG_ACK = 0x1 + NGHTTP2_FLAG_ACK = 0x1, + /** + * The END_SEGMENT flag. + */ + NGHTTP2_FLAG_END_SEGMENT = 0x2, + /** + * The PAD_LOW flag. + */ + NGHTTP2_FLAG_PAD_LOW = 0x4, + /** + * The PAD_HIGH flag. + */ + NGHTTP2_FLAG_PAD_HIGH = 0x8 } nghttp2_flag; /** @@ -489,7 +501,11 @@ typedef enum { /** * ENHANCE_YOUR_CALM */ - NGHTTP2_ENHANCE_YOUR_CALM = 420 + NGHTTP2_ENHANCE_YOUR_CALM = 11, + /** + * INADEQUATE_SECURITY + */ + NGHTTP2_INADEQUATE_SECURITY = 12 } nghttp2_error_code; /** From f26270b5b462ffc535fad30da60d1d628375b4cf Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 6 Feb 2014 22:06:42 +0900 Subject: [PATCH 07/56] Change SETTINGS payload format according to the spec --- lib/nghttp2_frame.c | 20 ++++++++++---------- lib/nghttp2_frame.h | 3 +++ lib/nghttp2_session.c | 8 ++++---- lib/nghttp2_submit.c | 3 ++- tests/nghttp2_frame_test.c | 6 ++++-- tests/nghttp2_session_test.c | 4 ++-- 6 files changed, 25 insertions(+), 19 deletions(-) diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index 451aea55..1b9a4c6b 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -110,7 +110,8 @@ void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags, nghttp2_settings_entry *iv, size_t niv) { memset(frame, 0, sizeof(nghttp2_settings)); - nghttp2_frame_set_hd(&frame->hd, niv*8, NGHTTP2_SETTINGS, flags, 0); + nghttp2_frame_set_hd(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH, + NGHTTP2_SETTINGS, flags, 0); frame->niv = niv; frame->iv = iv; } @@ -341,11 +342,11 @@ size_t nghttp2_frame_pack_settings_payload(uint8_t *buf, size_t niv) { size_t i; - for(i = 0; i < niv; ++i, buf += 8) { - nghttp2_put_uint32be(buf, iv[i].settings_id); - nghttp2_put_uint32be(buf + 4, iv[i].value); + for(i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) { + buf[0] = iv[i].settings_id; + nghttp2_put_uint32be(buf + 1, iv[i].value); } - return 8 * niv; + return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv; } int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame, @@ -366,9 +367,8 @@ int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame, void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv, const uint8_t *payload) { - iv->settings_id = nghttp2_get_uint32(&payload[0]) & - NGHTTP2_SETTINGS_ID_MASK; - iv->value = nghttp2_get_uint32(&payload[4]); + iv->settings_id = payload[0]; + iv->value = nghttp2_get_uint32(&payload[1]); } int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr, @@ -377,13 +377,13 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr, size_t payloadlen) { size_t i; - *niv_ptr = payloadlen / 8; + *niv_ptr = payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; *iv_ptr = malloc((*niv_ptr)*sizeof(nghttp2_settings_entry)); if(*iv_ptr == NULL) { return NGHTTP2_ERR_NOMEM; } for(i = 0; i < *niv_ptr; ++i) { - size_t off = i*8; + size_t off = i * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]); } return 0; diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index fe6b995f..841bce35 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -48,6 +48,9 @@ /* The number of bytes of frame header. */ #define NGHTTP2_FRAME_HEAD_LENGTH 8 +/* The number of bytes for each SETTINGS entry */ +#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 5 + /* Category of frames. */ typedef enum { /* non-DATA frame */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 4432d0fd..7020947a 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3390,7 +3390,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; case NGHTTP2_SETTINGS: DEBUGF(fprintf(stderr, "SETTINGS\n")); - if((iframe->frame.hd.length & 0x7) || + if((iframe->frame.hd.length % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) || ((iframe->frame.hd.flags & NGHTTP2_FLAG_ACK) && iframe->payloadleft > 0)) { busy = 1; @@ -3399,7 +3399,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } iframe->state = NGHTTP2_IB_READ_SETTINGS; if(iframe->payloadleft) { - iframe->left = 8; + iframe->left = NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; break; } busy = 1; @@ -3629,7 +3629,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } } if(iframe->payloadleft) { - iframe->left = 8; + iframe->left = NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; iframe->buflen = 0; break; } @@ -4070,7 +4070,7 @@ int nghttp2_session_upgrade(nghttp2_session *session, (session->server && session->last_recv_stream_id >= 1)) { return NGHTTP2_ERR_PROTO; } - if(settings_payloadlen % 8) { + if(settings_payloadlen % NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) { return NGHTTP2_ERR_INVALID_ARGUMENT; } rv = nghttp2_frame_unpack_settings_payload2(&iv, &niv, settings_payload, diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index 4096dece..3ef60ad4 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -323,8 +323,9 @@ ssize_t nghttp2_pack_settings_payload(uint8_t *buf, return NGHTTP2_ERR_INVALID_ARGUMENT; } - if(buflen < (niv * 8)) + if(buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) { return NGHTTP2_ERR_INSUFF_BUFSIZE; + } return nghttp2_frame_pack_settings_payload(buf, iv, niv); } diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 08e7f698..74d01563 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -226,9 +226,11 @@ void test_nghttp2_frame_pack_settings() nghttp2_frame_settings_init(&frame, NGHTTP2_FLAG_NONE, nghttp2_frame_iv_copy(iv, 3), 3); framelen = nghttp2_frame_pack_settings(&buf, &buflen, &frame); - CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH+3*8 == framelen); + CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH + + 3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH == framelen); CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen)); - check_frame_header(3*8, NGHTTP2_SETTINGS, NGHTTP2_FLAG_NONE, 0, &oframe.hd); + check_frame_header(3 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH, + NGHTTP2_SETTINGS, NGHTTP2_FLAG_NONE, 0, &oframe.hd); CU_ASSERT(3 == oframe.niv); for(i = 0; i < 3; ++i) { CU_ASSERT(iv[i].settings_id == oframe.iv[i].settings_id); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 5ec1b04a..e42529f7 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -3828,7 +3828,7 @@ void test_nghttp2_pack_settings_payload(void) iv[1].value = 4095; len = nghttp2_pack_settings_payload(buf, sizeof(buf), iv, 2); - CU_ASSERT(16 == len); + CU_ASSERT(2 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH == len); CU_ASSERT(0 == nghttp2_frame_unpack_settings_payload2(&resiv, &resniv, buf, len)); CU_ASSERT(2 == resniv); @@ -3839,6 +3839,6 @@ void test_nghttp2_pack_settings_payload(void) free(resiv); - len = nghttp2_pack_settings_payload(buf, 15 /* too small */, iv, 2); + len = nghttp2_pack_settings_payload(buf, 9 /* too small */, iv, 2); CU_ASSERT(NGHTTP2_ERR_INSUFF_BUFSIZE == len); } From 814d0f76f33d50e312569a44a371db160c74c016 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 7 Feb 2014 23:22:17 +0900 Subject: [PATCH 08/56] Implement DATA frame padding --- lib/includes/nghttp2/nghttp2.h | 27 ++++- lib/nghttp2_frame.c | 8 ++ lib/nghttp2_frame.h | 11 ++ lib/nghttp2_session.c | 183 +++++++++++++++++++++++++-------- lib/nghttp2_session.h | 16 ++- src/HttpServer.cc | 9 +- src/HttpServer.h | 1 + src/app_helper.cc | 30 ++++++ src/nghttp.cc | 16 ++- src/nghttpd.cc | 11 +- tests/main.c | 2 + tests/nghttp2_session_test.c | 92 +++++++++++++++++ tests/nghttp2_session_test.h | 1 + 13 files changed, 354 insertions(+), 53 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 773b0e2b..9864cdb8 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -147,6 +147,14 @@ typedef struct { */ #define NGHTTP2_CLIENT_CONNECTION_HEADER_LEN 24 +/** + * @macro + * + * The default value of DATA padding alignment. See + * :member:`NGHTTP2_OPT_DATA_PAD_ALIGNMENT`. + */ +#define NGHTTP2_DATA_PAD_ALIGNMENT 256 + /** * @enum * @@ -599,6 +607,11 @@ typedef struct { */ typedef struct { nghttp2_frame_hd hd; + /** + * The length of the padding in this frame. This includes PAD_HIGH + * and PAD_LOW. + */ + size_t padlen; } nghttp2_data; /** @@ -1309,7 +1322,15 @@ typedef enum { * will be overwritten if the local endpoint receives * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint. */ - NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 2 + NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 2, + /** + * This option specifies the alignment of padding in DATA frame. If + * this option is set to N, padding is added to DATA payload so that + * its payload length is divisible by N. Due to flow control, + * padding is not always added according to this alignment. The + * option value must be greater than or equal to 8. + */ + NGHTTP2_OPT_DATA_PAD_ALIGNMENT = 1 << 3 } nghttp2_opt; /** @@ -1330,6 +1351,10 @@ typedef struct { * :enum:`NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE` */ uint8_t no_auto_connection_window_update; + /** + * :enum:`NGHTTP2_OPT_DATA_PAD_ALIGNMENT` + */ + uint16_t data_pad_alignment; } nghttp2_opt_set; /** diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index 1b9a4c6b..b0b29b47 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -185,6 +185,7 @@ void nghttp2_frame_window_update_free(nghttp2_window_update *frame) void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata) { frame->hd = pdata->hd; + frame->padlen = pdata->padlen; /* flags may have NGHTTP2_FLAG_END_STREAM even if the sent chunk is not the end of the stream */ if(!pdata->eof) { @@ -192,6 +193,13 @@ void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata) } } +size_t nghttp2_frame_data_trail_padlen(nghttp2_data *frame) +{ + return frame->padlen + - ((frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH) > 0) + - ((frame->hd.flags & NGHTTP2_FLAG_PAD_LOW) > 0); +} + void nghttp2_frame_private_data_init(nghttp2_private_data *frame, uint8_t flags, int32_t stream_id, diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index 841bce35..79e4b089 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -71,6 +71,11 @@ typedef struct { * The data to be sent for this DATA frame. */ nghttp2_data_provider data_prd; + /** + * The number of bytes added as padding. This includes PAD_HIGH and + * PAD_LOW. + */ + size_t padlen; /** * The flag to indicate whether EOF was reached or not. Initially * |eof| is 0. It becomes 1 after all data were read. This is used @@ -421,6 +426,12 @@ void nghttp2_frame_window_update_free(nghttp2_window_update *frame); void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata); +/* + * Returns the number of padding data after application data + * payload. Thus this does not include the PAD_HIGH and PAD_LOW. + */ +size_t nghttp2_frame_data_trail_padlen(nghttp2_data *frame); + void nghttp2_frame_private_data_init(nghttp2_private_data *frame, uint8_t flags, int32_t stream_id, diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 7020947a..7068e32a 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -223,6 +223,12 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE; } + if((opt_set_mask & NGHTTP2_OPT_DATA_PAD_ALIGNMENT) && + opt_set->data_pad_alignment >= 8) { + (*session_ptr)->data_pad_alignment = opt_set->data_pad_alignment; + } else { + (*session_ptr)->data_pad_alignment = NGHTTP2_DATA_PAD_ALIGNMENT; + } (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; (*session_ptr)->recv_window_size = 0; @@ -1271,6 +1277,7 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, framebuflen = nghttp2_session_pack_data(session, &session->aob.framebuf, &session->aob.framebufmax, + &session->aob.framebufoff, next_readmax, data_frame); if(framebuflen == NGHTTP2_ERR_DEFERRED) { @@ -1589,8 +1596,20 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) } else if(item->frame_cat == NGHTTP2_CAT_DATA) { nghttp2_private_data *data_frame; nghttp2_outbound_item* next_item; + nghttp2_stream *stream; + size_t effective_payloadlen; data_frame = nghttp2_outbound_item_get_data_frame(session->aob.item); + stream = nghttp2_session_get_stream(session, data_frame->hd.stream_id); + /* We update flow control window after a frame was completely + sent. This is possible because we choose payload length not to + exceed the window */ + effective_payloadlen = data_frame->hd.length - data_frame->padlen; + session->remote_window_size -= effective_payloadlen; + if(stream) { + stream->remote_window_size -= effective_payloadlen; + } + if(session->callbacks.on_frame_send_callback) { nghttp2_frame public_data_frame; nghttp2_frame_data_init(&public_data_frame.data, data_frame); @@ -1599,15 +1618,13 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) return rv; } } - if(data_frame->eof && (data_frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { - nghttp2_stream *stream = - nghttp2_session_get_stream(session, data_frame->hd.stream_id); - if(stream) { - nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); - rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); - if(nghttp2_is_fatal(rv)) { - return rv; - } + + if(stream && data_frame->eof && + (data_frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) { + nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR); + rv = nghttp2_session_close_stream_if_shut_rdwr(session, stream); + if(nghttp2_is_fatal(rv)) { + return rv; } } /* If session is closed or RST_STREAM was queued, we won't send @@ -1618,16 +1635,14 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) nghttp2_active_outbound_item_reset(&session->aob); return 0; } + /* Assuming stream is not NULL */ + assert(stream); next_item = nghttp2_session_get_next_ob_item(session); /* If priority of this stream is higher or equal to other stream waiting at the top of the queue, we continue to send this data. */ if(next_item == NULL || session->aob.item->pri < next_item->pri) { size_t next_readmax; - nghttp2_stream *stream; - stream = nghttp2_session_get_stream(session, data_frame->hd.stream_id); - /* Assuming stream is not NULL */ - assert(stream); next_readmax = nghttp2_session_next_data_read(session, stream); if(next_readmax == 0) { nghttp2_stream_defer_data(stream, session->aob.item, @@ -1639,6 +1654,7 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) rv = nghttp2_session_pack_data(session, &session->aob.framebuf, &session->aob.framebufmax, + &session->aob.framebufoff, next_readmax, data_frame); if(nghttp2_is_fatal(rv)) { @@ -1666,7 +1682,6 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) } assert(rv >= 0); session->aob.framebuflen = session->aob.framebufmark = rv; - session->aob.framebufoff = 0; return 0; } /* Update seq to interleave other streams with the same @@ -1740,6 +1755,7 @@ int nghttp2_session_send(nghttp2_session *session) if(item->frame_cat == NGHTTP2_CAT_CTRL) { nghttp2_frame *frame = nghttp2_outbound_item_get_ctrl_frame(item); session->aob.framebufmark = + session->aob.framebufoff + frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH; r = session_call_before_frame_send(session, frame); if(nghttp2_is_fatal(r)) { @@ -1748,10 +1764,13 @@ int nghttp2_session_send(nghttp2_session *session) } else { nghttp2_private_data *frame; frame = nghttp2_outbound_item_get_data_frame(session->aob.item); + /* session->aob.framebufmark = session->aob.framebuflen; */ session->aob.framebufmark = + session->aob.framebufoff + frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH; } } + data = session->aob.framebuf + session->aob.framebufoff; datalen = session->aob.framebufmark - session->aob.framebufoff; sentlen = session->callbacks.send_callback(session, data, datalen, 0, @@ -1763,23 +1782,6 @@ int nghttp2_session_send(nghttp2_session *session) return NGHTTP2_ERR_CALLBACK_FAILURE; } } else { - if(session->aob.item->frame_cat == NGHTTP2_CAT_DATA && - session->aob.framebufoff + sentlen > NGHTTP2_FRAME_HEAD_LENGTH) { - nghttp2_private_data *frame; - nghttp2_stream *stream; - uint16_t len; - if(session->aob.framebufoff < NGHTTP2_FRAME_HEAD_LENGTH) { - len = session->aob.framebufoff + sentlen - NGHTTP2_FRAME_HEAD_LENGTH; - } else { - len = sentlen; - } - frame = nghttp2_outbound_item_get_data_frame(session->aob.item); - stream = nghttp2_session_get_stream(session, frame->hd.stream_id); - if(stream) { - stream->remote_window_size -= len; - } - session->remote_window_size -= len; - } session->aob.framebufoff += sentlen; if(session->aob.framebufoff == session->aob.framebufmark) { /* Frame has completely sent */ @@ -3338,6 +3340,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, switch(iframe->frame.hd.type) { case NGHTTP2_DATA: { DEBUGF(fprintf(stderr, "DATA\n")); + iframe->frame.data.padlen = 0; /* Check stream is open. If it is not open or closing, ignore payload. */ busy = 1; @@ -3351,6 +3354,25 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, if(nghttp2_is_fatal(rv)) { return rv; } + if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) { + if((iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) == 0) { + iframe->state = NGHTTP2_IB_IGN_DATA; + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + break; + } + iframe->state = NGHTTP2_IB_READ_NBYTE; + iframe->left = 2; + break; + } + if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) { + iframe->state = NGHTTP2_IB_READ_NBYTE; + iframe->left = 1; + break; + } iframe->state = NGHTTP2_IB_READ_DATA; break; } @@ -3454,7 +3476,26 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } switch(iframe->frame.hd.type) { case NGHTTP2_DATA: - assert(0); + busy = 1; + iframe->frame.data.padlen = iframe->buf[0]; + if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) { + iframe->frame.data.padlen <<= 8; + iframe->frame.data.padlen |= iframe->buf[1]; + ++iframe->frame.data.padlen; + } + ++iframe->frame.data.padlen; + + DEBUGF(fprintf(stderr, "padlen=%zu\n", iframe->frame.data.padlen)); + if(iframe->frame.data.padlen > iframe->frame.hd.length) { + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_DATA; + break; + } + iframe->state = NGHTTP2_IB_READ_DATA; break; case NGHTTP2_HEADERS: rv = session_process_headers_frame(session); @@ -3703,6 +3744,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n", readlen, iframe->payloadleft)); if(readlen > 0) { + size_t data_readlen = readlen; rv = nghttp2_session_update_recv_connection_window_size (session, readlen); if(nghttp2_is_fatal(rv)) { @@ -3721,13 +3763,25 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } } } - if(session->callbacks.on_data_chunk_recv_callback) { + if(nghttp2_frame_data_trail_padlen(&iframe->frame.data) > + iframe->payloadleft) { + size_t trail_padlen; + trail_padlen = nghttp2_frame_data_trail_padlen(&iframe->frame.data) + - iframe->payloadleft; + if(readlen < trail_padlen) { + data_readlen = 0; + } else { + data_readlen -= trail_padlen; + } + } + DEBUGF(fprintf(stderr, "data_readlen=%zu\n", data_readlen)); + if(data_readlen > 0 && session->callbacks.on_data_chunk_recv_callback) { rv = session->callbacks.on_data_chunk_recv_callback (session, iframe->frame.hd.flags, iframe->frame.hd.stream_id, in - readlen, - readlen, + data_readlen, session->user_data); if(rv == NGHTTP2_ERR_PAUSE) { /* Set type to NGHTTP2_DATA, so that we can see what was @@ -3937,10 +3991,18 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags, ssize_t nghttp2_session_pack_data(nghttp2_session *session, uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, size_t datamax, nghttp2_private_data *frame) { - ssize_t framelen = datamax+8, r; + /* extra 2 bytes for PAD_HIGH and PAD_LOW. We allocate extra 2 bytes + for padding. Based on the padding length, we adjust the starting + offset of frame data. The starting offset is assigned into + |*bufoff_ptr|. */ + size_t headoff = 2; + size_t dataoff = NGHTTP2_FRAME_HEAD_LENGTH + headoff; + ssize_t framelen = dataoff + datamax; + ssize_t r; int eof_flags; uint8_t flags; r = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen); @@ -3949,7 +4011,7 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, } eof_flags = 0; r = frame->data_prd.read_callback - (session, frame->hd.stream_id, (*buf_ptr)+8, datamax, + (session, frame->hd.stream_id, (*buf_ptr) + dataoff, datamax, &eof_flags, &frame->data_prd.source, session->user_data); if(r == NGHTTP2_ERR_DEFERRED || r == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { return r; @@ -3957,19 +4019,56 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, /* This is the error code when callback is failed. */ return NGHTTP2_ERR_CALLBACK_FAILURE; } - frame->hd.length = r; - memset(*buf_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH); - nghttp2_put_uint16be(&(*buf_ptr)[0], r); + + /* Clear flags, because this may contain previous flags of previous + DATA */ + frame->hd.flags &= ~(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); flags = 0; + + if((session->opt_flags & NGHTTP2_OPTMASK_NO_DATA_PADDING) == 0 && + r > 0 && (size_t)r < datamax) { + const size_t align = session->data_pad_alignment; + size_t nextlen = nghttp2_min((r + align - 1) / align * align, datamax); + size_t padlen = nextlen - r; + size_t trail_padlen = 0; + if(padlen > 257) { + headoff = 0; + trail_padlen = padlen - 2; + flags |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW; + (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen >> 8; + (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen & 0xff; + } else if(padlen > 0) { + headoff = 1; + trail_padlen = padlen - 1; + flags |= NGHTTP2_FLAG_PAD_LOW; + (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen; + } + frame->padlen = padlen; + memset((*buf_ptr) + dataoff + r, 0, trail_padlen); + frame->hd.length = nextlen; + } else { + frame->padlen = 0; + frame->hd.length = r; + } + + /* Set PAD flags so that we can supply frame to the callback with + the correct flags */ + frame->hd.flags |= flags; + + memset(*buf_ptr + headoff, 0, NGHTTP2_FRAME_HEAD_LENGTH); + nghttp2_put_uint16be(&(*buf_ptr)[headoff], frame->hd.length); + if(eof_flags) { frame->eof = 1; if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { flags |= NGHTTP2_FLAG_END_STREAM; } } - (*buf_ptr)[3] = flags; - nghttp2_put_uint32be(&(*buf_ptr)[4], frame->hd.stream_id); - return r+8; + (*buf_ptr)[headoff + 3] = flags; + nghttp2_put_uint32be(&(*buf_ptr)[headoff + 4], frame->hd.stream_id); + *bufoff_ptr = headoff; + + return frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH + headoff; } void* nghttp2_session_get_stream_user_data(nghttp2_session *session, diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index f4f17922..9e4fb484 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -44,7 +44,10 @@ */ typedef enum { NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE = 1 << 0, - NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1 + NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1, + /* Option to disable DATA frame padding, which is currently hidden + from outside, but provided for ease of testing */ + NGHTTP2_OPTMASK_NO_DATA_PADDING = 1 << 2, } nghttp2_optmask; typedef struct { @@ -149,6 +152,8 @@ struct nghttp2_session { size_t num_incoming_streams; /* The number of bytes allocated for nvbuf */ size_t nvbuflen; + /* DATA padding alignemnt. See NGHTTP2_OPT_DATA_PAD_ALIGNMENT. */ + size_t data_pad_alignment; /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */ uint32_t next_stream_id; /* The largest stream ID received so far */ @@ -508,9 +513,11 @@ nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session, * Packs DATA frame |frame| in wire frame format and stores it in * |*buf_ptr|. The capacity of |*buf_ptr| is |*buflen_ptr| * length. This function expands |*buf_ptr| as necessary to store - * given |frame|. It packs header in first 8 bytes. Remaining bytes - * are the DATA apyload and are filled using |frame->data_prd|. The - * length of payload is at most |datamax| bytes. + * given |frame|. It packs header in first 8 bytes starting + * |*bufoff_ptr| offset. The |*bufoff_ptr| is calculated based on + * usage of padding. Remaining bytes are the DATA apyload and are + * filled using |frame->data_prd|. The length of payload is at most + * |datamax| bytes. * * This function returns the size of packed frame if it succeeds, or * one of the following negative error codes: @@ -526,6 +533,7 @@ nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session, */ ssize_t nghttp2_session_pack_data(nghttp2_session *session, uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, size_t datamax, nghttp2_private_data *frame); diff --git a/src/HttpServer.cc b/src/HttpServer.cc index cd3b1999..6e7374e0 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -66,6 +66,7 @@ const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION; Config::Config() : data_ptr(nullptr), output_upper_thres(1024*1024), + data_pad_alignment(NGHTTP2_DATA_PAD_ALIGNMENT), header_table_size(-1), port(0), verbose(false), @@ -361,8 +362,14 @@ int Http2Handler::on_connect() { int r; nghttp2_session_callbacks callbacks; + nghttp2_opt_set opt_set; + + memset(&opt_set, 0, sizeof(opt_set)); + opt_set.data_pad_alignment = sessions_->get_config()->data_pad_alignment; + fill_callback(callbacks, sessions_->get_config()); - r = nghttp2_session_server_new(&session_, &callbacks, this); + r = nghttp2_session_server_new2(&session_, &callbacks, this, + NGHTTP2_OPT_DATA_PAD_ALIGNMENT, &opt_set); if(r != 0) { return r; } diff --git a/src/HttpServer.h b/src/HttpServer.h index 3d909263..aeb6f43d 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -56,6 +56,7 @@ struct Config { std::string cert_file; void *data_ptr; size_t output_upper_thres; + size_t data_pad_alignment; ssize_t header_table_size; uint16_t port; bool verbose; diff --git a/src/app_helper.cc b/src/app_helper.cc index ce565202..46a231ba 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -77,6 +77,8 @@ const char* strstatus(nghttp2_error_code error_code) return "CONNECT_ERROR"; case NGHTTP2_ENHANCE_YOUR_CALM: return "ENHANCE_YOUR_CALM"; + case NGHTTP2_INADEQUATE_SECURITY: + return "INADEQUATE_SECURITY"; default: return "UNKNOWN"; } @@ -201,11 +203,35 @@ void print_flags(const nghttp2_frame_hd& hd) if(hd.flags & NGHTTP2_FLAG_END_STREAM) { s += "END_STREAM"; } + if(hd.flags & NGHTTP2_FLAG_END_SEGMENT) { + if(!s.empty()) { + s += " | "; + } + s += "END_SEGMENT"; + } + if(hd.flags & NGHTTP2_FLAG_PAD_LOW) { + if(!s.empty()) { + s += " | "; + } + s += "PAD_LOW"; + } + if(hd.flags & NGHTTP2_FLAG_PAD_HIGH) { + if(!s.empty()) { + s += " | "; + } + s += "PAD_HIGH"; + } break; case NGHTTP2_HEADERS: if(hd.flags & NGHTTP2_FLAG_END_STREAM) { s += "END_STREAM"; } + if(hd.flags & NGHTTP2_FLAG_END_SEGMENT) { + if(!s.empty()) { + s += " | "; + } + s += "END_SEGMENT"; + } if(hd.flags & NGHTTP2_FLAG_END_HEADERS) { if(!s.empty()) { s += " | "; @@ -265,6 +291,10 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) } switch(frame->hd.type) { case NGHTTP2_DATA: + if(frame->hd.flags & (NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW)) { + print_frame_attr_indent(); + printf("(padlen=%zu)\n", frame->data.padlen); + } break; case NGHTTP2_HEADERS: if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { diff --git a/src/nghttp.cc b/src/nghttp.cc index 04caa96d..4d11a09e 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -82,6 +82,7 @@ struct Config { std::string keyfile; std::string datafile; size_t output_upper_thres; + size_t data_pad_alignment; ssize_t peer_max_concurrent_streams; ssize_t header_table_size; int32_t pri; @@ -98,6 +99,7 @@ struct Config { bool upgrade; Config() : output_upper_thres(1024*1024), + data_pad_alignment(NGHTTP2_DATA_PAD_ALIGNMENT), peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS), header_table_size(-1), pri(NGHTTP2_PRI_DEFAULT), @@ -712,8 +714,10 @@ struct HttpClient { } nghttp2_opt_set opt_set; opt_set.peer_max_concurrent_streams = config.peer_max_concurrent_streams; + opt_set.data_pad_alignment = config.data_pad_alignment; rv = nghttp2_session_client_new2(&session, callbacks, this, - NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS, + NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS | + NGHTTP2_OPT_DATA_PAD_ALIGNMENT, &opt_set); if(rv != 0) { return -1; @@ -1637,7 +1641,7 @@ void print_usage(std::ostream& out) { out << "Usage: nghttp [-Oansuv] [-t ] [-w ] [-W ]\n" << " [--cert=] [--key=] [-d ] [-m ]\n" - << " [-p ] [-M ]\n" + << " [-p ] [-M ] [-b ]\n" << " ..." << std::endl; } @@ -1694,6 +1698,8 @@ void print_help(std::ostream& out) << " is large enough as it is seen as unlimited.\n" << " -c, --header-table-size=\n" << " Specify decoder header table size.\n" + << " -b, --data-pad=\n" + << " Alignment of DATA frame padding.\n" << " --color Force colored log output.\n" << std::endl; } @@ -1721,13 +1727,14 @@ int main(int argc, char **argv) {"pri", required_argument, nullptr, 'p'}, {"peer-max-concurrent-streams", required_argument, nullptr, 'M'}, {"header-table-size", required_argument, nullptr, 'c'}, + {"data-pad", required_argument, nullptr, 'b'}, {"cert", required_argument, &flag, 1}, {"key", required_argument, &flag, 2}, {"color", no_argument, &flag, 3}, {nullptr, 0, nullptr, 0 } }; int option_index = 0; - int c = getopt_long(argc, argv, "M:Oac:d:m:np:hH:vst:uw:W:", long_options, + int c = getopt_long(argc, argv, "M:Oab:c:d:m:np:hH:vst:uw:W:", long_options, &option_index); char *end; if(c == -1) { @@ -1744,6 +1751,9 @@ int main(int argc, char **argv) case 'h': print_help(std::cout); exit(EXIT_SUCCESS); + case 'b': + config.data_pad_alignment = strtol(optarg, nullptr, 10); + break; case 'n': config.null_out = true; break; diff --git a/src/nghttpd.cc b/src/nghttpd.cc index 582c457c..87db6143 100644 --- a/src/nghttpd.cc +++ b/src/nghttpd.cc @@ -75,7 +75,8 @@ int parse_push_config(Config& config, const char *optarg) namespace { void print_usage(std::ostream& out) { - out << "Usage: nghttpd [-DVhv] [-d ] [--no-tls] [ ]" + out << "Usage: nghttpd [-DVhpv] [-d ] [--no-tls] [-b ]\n" + << " [ ]" << std::endl; } } // namespace @@ -114,6 +115,8 @@ void print_help(std::ostream& out) << " -p/=/foo.png -p/doc=/bar.css\n" << " PATH and PUSH_PATHs are relative to document\n" << " root. See --htdocs option.\n" + << " -b, --data-pad=\n" + << " Alignment of DATA frame padding.\n" << " -h, --help Print this help.\n" << std::endl; } @@ -133,12 +136,13 @@ int main(int argc, char **argv) {"verify-client", no_argument, nullptr, 'V'}, {"header-table-size", required_argument, nullptr, 'c'}, {"push", required_argument, nullptr, 'p'}, + {"data-pad", required_argument, nullptr, 'b'}, {"no-tls", no_argument, &flag, 1}, {"color", no_argument, &flag, 2}, {nullptr, 0, nullptr, 0} }; int option_index = 0; - int c = getopt_long(argc, argv, "DVc:d:hp:v", long_options, &option_index); + int c = getopt_long(argc, argv, "DVb:c:d:hp:v", long_options, &option_index); char *end; if(c == -1) { break; @@ -150,6 +154,9 @@ int main(int argc, char **argv) case 'V': config.verify_client = true; break; + case 'b': + config.data_pad_alignment = strtol(optarg, nullptr, 10); + break; case 'd': config.htdocs = optarg; break; diff --git a/tests/main.c b/tests/main.c index f5df28cf..063c881e 100644 --- a/tests/main.c +++ b/tests/main.c @@ -193,6 +193,8 @@ int main(int argc, char* argv[]) test_nghttp2_session_set_option) || !CU_add_test(pSuite, "session_data_backoff_by_high_pri_frame", test_nghttp2_session_data_backoff_by_high_pri_frame) || + !CU_add_test(pSuite, "session_pack_data_with_padding", + test_nghttp2_session_pack_data_with_padding) || !CU_add_test(pSuite, "pack_settings_payload", test_nghttp2_pack_settings_payload) || !CU_add_test(pSuite, "frame_pack_headers", diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index e42529f7..98df0836 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -71,6 +71,7 @@ typedef struct { int header_cb_called; int begin_headers_cb_called; nghttp2_nv nv; + size_t data_chunk_len; } my_user_data; static void scripted_data_feed_init(scripted_data_feed *df, @@ -187,6 +188,7 @@ static int on_data_chunk_recv_callback(nghttp2_session *session, { my_user_data *ud = (my_user_data*)user_data; ++ud->data_chunk_recv_cb_called; + ud->data_chunk_len = len; return 0; } @@ -3814,6 +3816,96 @@ void test_nghttp2_session_data_backoff_by_high_pri_frame(void) nghttp2_session_del(session); } +static void check_session_recv_data_with_padding(const uint8_t *in, + size_t inlen, + size_t datalen) +{ + nghttp2_session *session; + my_user_data ud; + nghttp2_session_callbacks callbacks; + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.on_frame_recv_callback = on_frame_recv_callback; + callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback; + nghttp2_session_server_new(&session, &callbacks, &ud); + + nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, + NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING, + NULL); + + ud.frame_recv_cb_called = 0; + ud.data_chunk_len = 0; + CU_ASSERT((ssize_t)inlen == nghttp2_session_mem_recv(session, in, inlen)); + + CU_ASSERT(1 == ud.frame_recv_cb_called); + CU_ASSERT(datalen == ud.data_chunk_len); + + nghttp2_session_del(session); +} + +void test_nghttp2_session_pack_data_with_padding(void) +{ + nghttp2_session *session; + my_user_data ud; + nghttp2_session_callbacks callbacks; + nghttp2_data_provider data_prd; + nghttp2_private_data *frame; + size_t datalen = 55; + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.send_callback = block_count_send_callback; + callbacks.on_frame_send_callback = on_frame_send_callback; + data_prd.read_callback = fixed_length_data_source_read_callback; + + nghttp2_session_client_new(&session, &callbacks, &ud); + session->data_pad_alignment = 512; + + nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, &data_prd, + NULL); + ud.block_count = 1; + ud.data_source_length = datalen; + /* Sends HEADERS */ + CU_ASSERT(0 == nghttp2_session_send(session)); + CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type); + + frame = OB_DATA(session->aob.item); + CU_ASSERT(session->data_pad_alignment - datalen == frame->padlen); + CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); + CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH); + + /* Check reception of this DATA frame */ + check_session_recv_data_with_padding + (session->aob.framebuf + session->aob.framebufoff, + session->aob.framebufmark - session->aob.framebufoff, + datalen); + + nghttp2_session_del(session); + + /* Check without PAD_HIGH */ + nghttp2_session_client_new(&session, &callbacks, &ud); + + nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, &data_prd, + NULL); + ud.block_count = 1; + ud.data_source_length = datalen; + /* Sends HEADERS */ + CU_ASSERT(0 == nghttp2_session_send(session)); + CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type); + + frame = OB_DATA(session->aob.item); + CU_ASSERT(session->data_pad_alignment - datalen == frame->padlen); + CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); + CU_ASSERT(0 == (frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH)); + + /* Check reception of this DATA frame */ + check_session_recv_data_with_padding + (session->aob.framebuf + session->aob.framebufoff, + session->aob.framebufmark - session->aob.framebufoff, + datalen); + + nghttp2_session_del(session); +} + void test_nghttp2_pack_settings_payload(void) { nghttp2_settings_entry iv[2]; diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index 6b4977f8..4d88103b 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -87,6 +87,7 @@ void test_nghttp2_session_get_outbound_queue_size(void); void test_nghttp2_session_get_effective_local_window_size(void); void test_nghttp2_session_set_option(void); void test_nghttp2_session_data_backoff_by_high_pri_frame(void); +void test_nghttp2_session_pack_data_with_padding(void); void test_nghttp2_pack_settings_payload(void); #endif /* NGHTTP2_SESSION_TEST_H */ From be9d5efa4c7dbcb4d17ea022beed7185f91711ad Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 8 Feb 2014 00:22:19 +0900 Subject: [PATCH 09/56] nghttp: Add --continuation option to test CONTINUATION --- src/nghttp.cc | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/nghttp.cc b/src/nghttp.cc index 4d11a09e..8ee76756 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -97,6 +97,7 @@ struct Config { bool get_assets; bool stat; bool upgrade; + bool continuation; Config() : output_upper_thres(1024*1024), data_pad_alignment(NGHTTP2_DATA_PAD_ALIGNMENT), @@ -112,7 +113,8 @@ struct Config { verbose(false), get_assets(false), stat(false), - upgrade(false) + upgrade(false), + continuation(false) {} }; } // namespace @@ -961,6 +963,16 @@ int submit_request {"accept", "*/*"}, {"accept-encoding", "gzip, deflate"}, {"user-agent", "nghttp2/" NGHTTP2_VERSION}}; + if(config.continuation) { + build_headers.emplace_back("continuation-test-1", + std::string(4096, '-')); + build_headers.emplace_back("continuation-test-2", + std::string(4096, '-')); + build_headers.emplace_back("continuation-test-3", + std::string(4096, '-')); + build_headers.emplace_back("continuation-test-4", + std::string(4096, '-')); + } auto num_initial_headers = build_headers.size(); if(req->data_prd) { build_headers.emplace_back("content-length", util::utos(req->data_length)); @@ -1701,6 +1713,7 @@ void print_help(std::ostream& out) << " -b, --data-pad=\n" << " Alignment of DATA frame padding.\n" << " --color Force colored log output.\n" + << " --continuation Send large header to test CONTINUATION.\n" << std::endl; } } // namespace @@ -1731,6 +1744,7 @@ int main(int argc, char **argv) {"cert", required_argument, &flag, 1}, {"key", required_argument, &flag, 2}, {"color", no_argument, &flag, 3}, + {"continuation", no_argument, &flag, 4}, {nullptr, 0, nullptr, 0 } }; int option_index = 0; @@ -1865,6 +1879,10 @@ int main(int argc, char **argv) // color option color = true; break; + case 4: + // continuation option + config.continuation = true; + break; } break; default: From b6a0eff8a83e834704b55aac6af38d3eb788be1c Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 8 Feb 2014 00:32:50 +0900 Subject: [PATCH 10/56] Add more DEBUGFs --- lib/nghttp2_session.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 7068e32a..3cdc1b97 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3468,9 +3468,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } break; case NGHTTP2_IB_READ_NBYTE: + DEBUGF(fprintf(stderr, "[IB_READ_NBYTE]\n")); readlen = inbound_frame_buf_read(iframe, in, last); in += readlen; iframe->payloadleft -= readlen; + DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu, left=%zu\n", + readlen, iframe->payloadleft, iframe->left)); if(iframe->left) { return in - first; } @@ -3561,10 +3564,16 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; case NGHTTP2_IB_READ_HEADER_BLOCK: case NGHTTP2_IB_IGN_HEADER_BLOCK: - DEBUGF(fprintf(stderr, "[IB_READ_HEADER_BLOCK]\n")); +#ifdef DEBUGBUILD + if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { + fprintf(stderr, "[IB_READ_HEADER_BLOCK]\n"); + } else { + fprintf(stderr, "[IB_IGN_HEADER_BLOCK]\n"); + } +#endif /* DEBUGBUILD */ readlen = inbound_frame_payload_readlen(iframe, in, last); DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n", - readlen, iframe->payloadleft)); + readlen, iframe->payloadleft - readlen)); DEBUGF(fprintf(stderr, "block final=%d\n", (iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) && @@ -3628,15 +3637,19 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } break; case NGHTTP2_IB_IGN_PAYLOAD: + DEBUGF(fprintf(stderr, "[IB_IGN_PAYLOAD]\n")); readlen = inbound_frame_payload_readlen(iframe, in, last); iframe->payloadleft -= readlen; in += readlen; + DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n", + readlen, iframe->payloadleft)); if(iframe->payloadleft) { break; } nghttp2_inbound_frame_reset(session); break; case NGHTTP2_IB_FRAME_SIZE_ERROR: + DEBUGF(fprintf(stderr, "[IB_FRAME_SIZE_ERROR]\n")); rv = session_handle_frame_size_error(session, &iframe->frame); if(nghttp2_is_fatal(rv)) { return rv; @@ -3649,6 +3662,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, readlen = inbound_frame_buf_read(iframe, in, last); iframe->payloadleft -= readlen; in += readlen; + DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n", + readlen, iframe->payloadleft)); if(iframe->left) { break; } @@ -3681,9 +3696,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, nghttp2_inbound_frame_reset(session); break; case NGHTTP2_IB_READ_GOAWAY_DEBUG: + DEBUGF(fprintf(stderr, "[IB_READ_GOAWAY_DEBUG]\n")); readlen = inbound_frame_payload_readlen(iframe, in, last); iframe->payloadleft -= readlen; in += readlen; + DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n", + readlen, iframe->payloadleft)); if(iframe->payloadleft) { break; } @@ -3808,6 +3826,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, readlen = inbound_frame_payload_readlen(iframe, in, last); iframe->payloadleft -= readlen; in += readlen; + DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n", + readlen, iframe->payloadleft)); if(readlen > 0) { /* Update connection-level flow control window for ignored DATA frame too */ From 748f6e65bd57581f66715db9a433c12625a535a7 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 8 Feb 2014 17:44:34 +0900 Subject: [PATCH 11/56] Run test after doc so that we can see test result in terminal --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 5fd7f459..064f87d0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,7 @@ # 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. -SUBDIRS = lib third-party src examples python tests doc +SUBDIRS = lib third-party src examples python doc tests ACLOCAL_AMFLAGS = -I m4 From 2ff3d97b2ef1c935ee596a3702292ebd84675705 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 8 Feb 2014 17:46:21 +0900 Subject: [PATCH 12/56] Add nghttp2_frame_add_pad to deal with adding pads --- lib/nghttp2_frame.c | 39 ++++++++++++++++++++++++ lib/nghttp2_frame.h | 31 +++++++++++++++++++ lib/nghttp2_session.c | 69 +++++++++++++++++++------------------------ 3 files changed, 101 insertions(+), 38 deletions(-) diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index b0b29b47..be1fc177 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -647,3 +647,42 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) } return 1; } + +ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, + uint8_t *flags_ptr, + size_t payloadlen, + size_t payloadmax, + size_t align) +{ + int rv; + size_t nextlen = nghttp2_min((payloadlen + align - 1) / align * align, + payloadmax); + size_t padlen = nextlen - payloadlen; + size_t trail_padlen = 0; + size_t headoff = 2; + size_t trail_padoff = headoff + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen; + if(padlen > 257) { + headoff = 0; + trail_padlen = padlen - 2; + *flags_ptr |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW; + (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen >> 8; + (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen & 0xff; + } else if(padlen > 0) { + headoff = 1; + trail_padlen = padlen - 1; + *flags_ptr |= NGHTTP2_FLAG_PAD_LOW; + (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen; + } + + rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, + trail_padoff + trail_padlen); + if(rv != 0) { + return rv; + } + + memset((*buf_ptr) + trail_padoff, 0, trail_padlen); + *bufoff_ptr = headoff; + + return padlen; +} diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index 79e4b089..b9224fd4 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -492,4 +492,35 @@ void nghttp2_nv_array_del(nghttp2_nv *nva); */ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); +/* + * Add padding to the payload in the |*buf_ptr| of length + * |*buflen_ptr|. The payload length is given in |payloadlen|. The + * payload must start at offset NGHTTP2_FRAME_HEAD_LENGTH + 2 from + * |*buf_ptr| to account for PAD_HIGH and PAD_LOW. The maximum payload + * allowed is given in the |payloadmax|. The padding will not be made + * more than |payloadmax|. The padding alignment is given in the + * |align|. + * + * The |*flags_ptr| is updated to include NGHTTP2_FLAG_PAD_LOW and + * NGHTTP2_FLAG_PAD_HIGH based on the padding length. The + * |*bufoff_ptr| will have the offset starting the frame header in + * |*buf_ptr|. + * + * The |*buf_ptr| and |*buflen_ptr| may be extended to include padding + * bytes. + * + * This function returns the number of padding added to the payload + * including PAD_HIGH and PAD_LOW if it succeeds, or one of the + * following negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, + uint8_t *flags_ptr, + size_t payloadlen, + size_t payloadmax, + size_t align); + #endif /* NGHTTP2_FRAME_H */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 3cdc1b97..2b518a7e 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -4019,23 +4019,27 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, for padding. Based on the padding length, we adjust the starting offset of frame data. The starting offset is assigned into |*bufoff_ptr|. */ - size_t headoff = 2; - size_t dataoff = NGHTTP2_FRAME_HEAD_LENGTH + headoff; - ssize_t framelen = dataoff + datamax; - ssize_t r; + size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2; + ssize_t framelen = payloadoff + datamax; + ssize_t rv; int eof_flags; uint8_t flags; - r = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen); - if(r != 0) { - return r; + ssize_t payloadlen; + + rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen); + if(rv != 0) { + return rv; } eof_flags = 0; - r = frame->data_prd.read_callback - (session, frame->hd.stream_id, (*buf_ptr) + dataoff, datamax, + payloadlen = frame->data_prd.read_callback + (session, frame->hd.stream_id, (*buf_ptr) + payloadoff, datamax, &eof_flags, &frame->data_prd.source, session->user_data); - if(r == NGHTTP2_ERR_DEFERRED || r == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - return r; - } else if(r < 0 || datamax < (size_t)r) { + + if(payloadlen == NGHTTP2_ERR_DEFERRED || + payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + return payloadlen; + } + if(payloadlen < 0 || datamax < (size_t)payloadlen) { /* This is the error code when callback is failed. */ return NGHTTP2_ERR_CALLBACK_FAILURE; } @@ -4046,37 +4050,27 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, flags = 0; if((session->opt_flags & NGHTTP2_OPTMASK_NO_DATA_PADDING) == 0 && - r > 0 && (size_t)r < datamax) { - const size_t align = session->data_pad_alignment; - size_t nextlen = nghttp2_min((r + align - 1) / align * align, datamax); - size_t padlen = nextlen - r; - size_t trail_padlen = 0; - if(padlen > 257) { - headoff = 0; - trail_padlen = padlen - 2; - flags |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW; - (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen >> 8; - (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen & 0xff; - } else if(padlen > 0) { - headoff = 1; - trail_padlen = padlen - 1; - flags |= NGHTTP2_FLAG_PAD_LOW; - (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen; + payloadlen > 0 && (size_t)payloadlen < datamax) { + rv = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, + &flags, payloadlen, datamax, + session->data_pad_alignment); + if(rv < 0) { + return rv; } - frame->padlen = padlen; - memset((*buf_ptr) + dataoff + r, 0, trail_padlen); - frame->hd.length = nextlen; + frame->padlen = rv; + frame->hd.length = payloadlen + rv; } else { + *bufoff_ptr = 0; frame->padlen = 0; - frame->hd.length = r; + frame->hd.length = payloadlen; } /* Set PAD flags so that we can supply frame to the callback with the correct flags */ frame->hd.flags |= flags; - memset(*buf_ptr + headoff, 0, NGHTTP2_FRAME_HEAD_LENGTH); - nghttp2_put_uint16be(&(*buf_ptr)[headoff], frame->hd.length); + memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH); + nghttp2_put_uint16be(&(*buf_ptr)[*bufoff_ptr], frame->hd.length); if(eof_flags) { frame->eof = 1; @@ -4084,11 +4078,10 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, flags |= NGHTTP2_FLAG_END_STREAM; } } - (*buf_ptr)[headoff + 3] = flags; - nghttp2_put_uint32be(&(*buf_ptr)[headoff + 4], frame->hd.stream_id); - *bufoff_ptr = headoff; + (*buf_ptr)[*bufoff_ptr + 3] = flags; + nghttp2_put_uint32be(&(*buf_ptr)[*bufoff_ptr + 4], frame->hd.stream_id); - return frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH + headoff; + return frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH + *bufoff_ptr; } void* nghttp2_session_get_stream_user_data(nghttp2_session *session, From e9d1ba25393ba443b2ea8d374602f91b20856f25 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 8 Feb 2014 18:02:57 +0900 Subject: [PATCH 13/56] Handle incoming PAD_HIGH and PAD_LOW in inbound_frame_handle_padding --- lib/nghttp2_session.c | 47 +++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 2b518a7e..b05ec379 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3313,6 +3313,29 @@ static int inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) return 0; } +/* + * Checks PAD_HIGH and PAD_LOW flags and set next state + * accordingly. If padding is set, this function returns 1. If no + * padding is set, this function returns 0. On error, returns -1. + */ +static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe) +{ + if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) { + if((iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) == 0) { + return -1; + } + iframe->state = NGHTTP2_IB_READ_NBYTE; + iframe->left = 2; + return 1; + } + if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) { + iframe->state = NGHTTP2_IB_READ_NBYTE; + iframe->left = 1; + return 1; + } + return 0; +} + ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, size_t inlen) { @@ -3354,26 +3377,20 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, if(nghttp2_is_fatal(rv)) { return rv; } - if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) { - if((iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) == 0) { - iframe->state = NGHTTP2_IB_IGN_DATA; - rv = nghttp2_session_terminate_session(session, - NGHTTP2_PROTOCOL_ERROR); - if(nghttp2_is_fatal(rv)) { - return rv; - } - break; + rv = inbound_frame_handle_pad(iframe); + if(rv < 0) { + iframe->state = NGHTTP2_IB_IGN_DATA; + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; } - iframe->state = NGHTTP2_IB_READ_NBYTE; - iframe->left = 2; break; } - if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) { - iframe->state = NGHTTP2_IB_READ_NBYTE; - iframe->left = 1; + if(rv == 0) { + iframe->state = NGHTTP2_IB_READ_DATA; break; } - iframe->state = NGHTTP2_IB_READ_DATA; break; } case NGHTTP2_HEADERS: From 9c30ed1a64329ce25e41b2402645b6e00b9675e3 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 8 Feb 2014 18:03:58 +0900 Subject: [PATCH 14/56] Update flags --- lib/includes/nghttp2/nghttp2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 9864cdb8..4ef0f410 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -417,11 +417,11 @@ typedef enum { /** * The PAD_LOW flag. */ - NGHTTP2_FLAG_PAD_LOW = 0x4, + NGHTTP2_FLAG_PAD_LOW = 0x10, /** * The PAD_HIGH flag. */ - NGHTTP2_FLAG_PAD_HIGH = 0x8 + NGHTTP2_FLAG_PAD_HIGH = 0x20 } nghttp2_flag; /** From 10feab02e8a7a425b4da9585e22f358641bf6500 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 8 Feb 2014 18:21:09 +0900 Subject: [PATCH 15/56] Fix bufoff_ptr if no padding is made --- lib/nghttp2_session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index b05ec379..6f77ff17 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -4077,7 +4077,7 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, frame->padlen = rv; frame->hd.length = payloadlen + rv; } else { - *bufoff_ptr = 0; + *bufoff_ptr = 2; frame->padlen = 0; frame->hd.length = payloadlen; } From 1db21953894657b6225be50bd369fe9870f71687 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 00:35:21 +0900 Subject: [PATCH 16/56] Implement padding for HEADERS and CONTINUATION --- lib/includes/nghttp2/nghttp2.h | 31 +++- lib/nghttp2_frame.c | 83 +++++---- lib/nghttp2_frame.h | 22 ++- lib/nghttp2_session.c | 329 ++++++++++++++++++++++++--------- lib/nghttp2_session.h | 13 +- src/HttpServer.cc | 6 +- src/HttpServer.h | 2 +- src/app_helper.cc | 36 +++- src/nghttp.cc | 14 +- src/nghttpd.cc | 6 +- tests/nghttp2_frame_test.c | 28 ++- tests/nghttp2_session_test.c | 74 ++++---- tests/nghttp2_test_helper.c | 5 + tests/nghttp2_test_helper.h | 3 + 14 files changed, 453 insertions(+), 199 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 4ef0f410..15b9173f 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -151,9 +151,9 @@ typedef struct { * @macro * * The default value of DATA padding alignment. See - * :member:`NGHTTP2_OPT_DATA_PAD_ALIGNMENT`. + * :member:`NGHTTP2_OPT_PAD_ALIGNMENT`. */ -#define NGHTTP2_DATA_PAD_ALIGNMENT 256 +#define NGHTTP2_PAD_ALIGNMENT 256 /** * @enum @@ -655,6 +655,11 @@ typedef struct { * The frame header. */ nghttp2_frame_hd hd; + /** + * The length of the padding in this frame. This includes PAD_HIGH + * and PAD_LOW. + */ + size_t padlen; /** * The name/value pairs. */ @@ -746,6 +751,11 @@ typedef struct { * The frame header. */ nghttp2_frame_hd hd; + /** + * The length of the padding in this frame. This includes PAD_HIGH + * and PAD_LOW. + */ + size_t padlen; /** * The name/value pairs. */ @@ -1324,13 +1334,14 @@ typedef enum { */ NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 2, /** - * This option specifies the alignment of padding in DATA frame. If - * this option is set to N, padding is added to DATA payload so that - * its payload length is divisible by N. Due to flow control, - * padding is not always added according to this alignment. The - * option value must be greater than or equal to 8. + * This option specifies the alignment of padding in frame + * payload. If this option is set to N, padding is added to frame + * payload so that its payload length is divisible by N. For DATA + * frame, due to flow control, padding is not always added according + * to this alignment. The option value must be greater than or equal + * to 8. */ - NGHTTP2_OPT_DATA_PAD_ALIGNMENT = 1 << 3 + NGHTTP2_OPT_PAD_ALIGNMENT = 1 << 3 } nghttp2_opt; /** @@ -1352,9 +1363,9 @@ typedef struct { */ uint8_t no_auto_connection_window_update; /** - * :enum:`NGHTTP2_OPT_DATA_PAD_ALIGNMENT` + * :enum:`NGHTTP2_OPT_PAD_ALIGNMENT` */ - uint16_t data_pad_alignment; + uint16_t pad_alignment; } nghttp2_opt_set; /** diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index be1fc177..9e7096a0 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -193,9 +193,9 @@ void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata) } } -size_t nghttp2_frame_data_trail_padlen(nghttp2_data *frame) +size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen) { - return frame->padlen + return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH) > 0) - ((frame->hd.flags & NGHTTP2_FLAG_PAD_LOW) > 0); } @@ -214,19 +214,6 @@ void nghttp2_frame_private_data_init(nghttp2_private_data *frame, void nghttp2_frame_private_data_free(nghttp2_private_data *frame) {} -/* - * Returns the offset of the name/header block in the HEADERS frame, - * including frame header length. - */ -static size_t headers_nv_offset(nghttp2_headers *frame) -{ - if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { - return NGHTTP2_FRAME_HEAD_LENGTH + 4; - } else { - return NGHTTP2_FRAME_HEAD_LENGTH; - } -} - size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame) { if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { @@ -238,23 +225,41 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame) ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, nghttp2_headers *frame, - nghttp2_hd_deflater *deflater) + nghttp2_hd_deflater *deflater, + size_t align) { - ssize_t framelen; - size_t nv_offset = headers_nv_offset(frame); + size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2; + size_t nv_offset = + payloadoff + nghttp2_frame_headers_payload_nv_offset(frame); ssize_t rv; + size_t payloadlen; + rv = nghttp2_hd_deflate_hd(deflater, buf_ptr, buflen_ptr, nv_offset, frame->nva, frame->nvlen); if(rv < 0) { return rv; } - framelen = rv + nv_offset; - if(NGHTTP2_FRAME_HEAD_LENGTH + NGHTTP2_MAX_FRAME_LENGTH < rv + nv_offset) { - frame->hd.length = NGHTTP2_MAX_FRAME_LENGTH; - frame->hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; + + payloadlen = nghttp2_frame_headers_payload_nv_offset(frame) + rv; + + if(align > 0) { + ssize_t padlen; + padlen = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, + &frame->hd.flags, + payloadlen, + payloadlen + align, + align); + if(padlen < 0) { + return padlen; + } + frame->padlen = padlen; + frame->hd.length = payloadlen + padlen; } else { - frame->hd.length = framelen - NGHTTP2_FRAME_HEAD_LENGTH; + *bufoff_ptr = 2; + frame->padlen = 0; + frame->hd.length = payloadlen; } /* If frame->nvlen == 0, *buflen_ptr may be smaller than nv_offset */ @@ -262,13 +267,21 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, if(rv < 0) { return rv; } - memset(*buf_ptr, 0, nv_offset); + memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH); /* pack ctrl header after length is determined */ - nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd); - if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { - nghttp2_put_uint32be(&(*buf_ptr)[8], frame->pri); + if(NGHTTP2_FRAME_HEAD_LENGTH + NGHTTP2_MAX_FRAME_LENGTH < rv + nv_offset) { + /* Needs CONTINUATION */ + nghttp2_frame_hd hd = frame->hd; + hd.flags &= ~(NGHTTP2_FLAG_END_HEADERS | + NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); + nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd); + } else { + nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd); } - return framelen; + if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { + nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->pri); + } + return frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH + *bufoff_ptr; } int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, @@ -276,7 +289,6 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, size_t payloadlen) { if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { - assert(payloadlen == 4); frame->pri = nghttp2_get_uint32(payload) & NGHTTP2_PRIORITY_MASK; } else { frame->pri = NGHTTP2_PRI_DEFAULT; @@ -660,19 +672,23 @@ ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, payloadmax); size_t padlen = nextlen - payloadlen; size_t trail_padlen = 0; - size_t headoff = 2; - size_t trail_padoff = headoff + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen; + /* extra 2 bytes for PAD_HIGH and PAD_LOW. */ + size_t trail_padoff = 2 + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen; + if(padlen > 257) { - headoff = 0; + *bufoff_ptr = 0; trail_padlen = padlen - 2; *flags_ptr |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW; (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen >> 8; (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen & 0xff; } else if(padlen > 0) { - headoff = 1; + *bufoff_ptr = 1; trail_padlen = padlen - 1; *flags_ptr |= NGHTTP2_FLAG_PAD_LOW; (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen; + } else { + *bufoff_ptr = 2; + return 0; } rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, @@ -682,7 +698,6 @@ ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, } memset((*buf_ptr) + trail_padoff, 0, trail_padlen); - *bufoff_ptr = headoff; return padlen; } diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index b9224fd4..3496863c 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -104,14 +104,21 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame); * expansion occurred, memory previously pointed by |*buf_ptr| may * change. |*buf_ptr| and |*buflen_ptr| are updated accordingly. * + * The first byte the frame is serialized is returned in the + * |*bufoff_ptr|. + * + * The |align| is used as padding alignment. If the |align| is zero, + * no padding is added. + * * frame->hd.length is assigned after length is determined during * packing process. If payload length is strictly larger than * NGHTTP2_MAX_FRAME_LENGTH, payload data is still serialized as is, * but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and * NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags. * - * This function returns the size of packed frame if it succeeds, or - * returns one of the following negative error codes: + * This function returns the size of packed frame (which includes + * |*bufoff_ptr| bytes) if it succeeds, or returns one of the + * following negative error codes: * * NGHTTP2_ERR_HEADER_COMP * The deflate operation failed. @@ -122,8 +129,10 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame); */ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, nghttp2_headers *frame, - nghttp2_hd_deflater *deflater); + nghttp2_hd_deflater *deflater, + size_t align); /* * Unpacks HEADERS frame byte sequence into |frame|. This function @@ -427,10 +436,11 @@ void nghttp2_frame_window_update_free(nghttp2_window_update *frame); void nghttp2_frame_data_init(nghttp2_data *frame, nghttp2_private_data *pdata); /* - * Returns the number of padding data after application data - * payload. Thus this does not include the PAD_HIGH and PAD_LOW. + * Returns the number of padding bytes after payload. The total + * padding length is given in the |padlen|. The returned value does + * not include the PAD_HIGH and PAD_LOW. */ -size_t nghttp2_frame_data_trail_padlen(nghttp2_data *frame); +size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen); void nghttp2_frame_private_data_init(nghttp2_private_data *frame, uint8_t flags, diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 6f77ff17..cba080ed 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -173,6 +173,7 @@ static void nghttp2_inbound_frame_reset(nghttp2_session *session) iframe->left = NGHTTP2_FRAME_HEAD_LENGTH; iframe->niv = 0; iframe->payloadleft = 0; + iframe->padlen = 0; iframe->error_code = 0; iframe->buflen = 0; } @@ -223,11 +224,11 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE; } - if((opt_set_mask & NGHTTP2_OPT_DATA_PAD_ALIGNMENT) && - opt_set->data_pad_alignment >= 8) { - (*session_ptr)->data_pad_alignment = opt_set->data_pad_alignment; + if((opt_set_mask & NGHTTP2_OPT_PAD_ALIGNMENT) && + opt_set->pad_alignment >= 8) { + (*session_ptr)->pad_alignment = opt_set->pad_alignment; } else { - (*session_ptr)->data_pad_alignment = NGHTTP2_DATA_PAD_ALIGNMENT; + (*session_ptr)->pad_alignment = NGHTTP2_PAD_ALIGNMENT; } (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; @@ -1119,8 +1120,10 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, } framebuflen = nghttp2_frame_pack_headers(&session->aob.framebuf, &session->aob.framebufmax, + &session->aob.framebufoff, &frame->headers, - &session->hd_deflater); + &session->hd_deflater, + session->pad_alignment); if(framebuflen < 0) { return framebuflen; } @@ -1442,8 +1445,11 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) session->aob.framebufmark, NGHTTP2_MAX_FRAME_LENGTH); cont_hd.type = NGHTTP2_CONTINUATION; - if(cont_hd.length < NGHTTP2_MAX_FRAME_LENGTH) { + if(cont_hd.length + session->aob.framebufmark == + session->aob.framebuflen) { cont_hd.flags = NGHTTP2_FLAG_END_HEADERS; + cont_hd.flags |= + (NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW) & frame->hd.flags; } else { cont_hd.flags = NGHTTP2_FLAG_NONE; } @@ -1456,9 +1462,6 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) session->aob.framebufoff -= NGHTTP2_FRAME_HEAD_LENGTH; return 0; } - /* Update frame payload length to include data sent in - CONTINUATION frame. */ - frame->hd.length = session->aob.framebuflen - NGHTTP2_FRAME_HEAD_LENGTH; } rv = session_call_on_frame_send(session, frame); if(nghttp2_is_fatal(rv)) { @@ -3318,24 +3321,73 @@ static int inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) * accordingly. If padding is set, this function returns 1. If no * padding is set, this function returns 0. On error, returns -1. */ -static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe) +static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, + nghttp2_frame_hd *hd) { - if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) { - if((iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) == 0) { + if(hd->flags & NGHTTP2_FLAG_PAD_HIGH) { + if((hd->flags & NGHTTP2_FLAG_PAD_LOW) == 0) { return -1; } iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->left = 2; return 1; } - if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) { + if(hd->flags & NGHTTP2_FLAG_PAD_LOW) { iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->left = 1; return 1; } + DEBUGF(fprintf(stderr, "no padding\n")); return 0; } +/* + * Computes number of padding based on flags. This function returns + * the calculated length if it succeeds, or -1. + */ +static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) +{ + size_t padlen; + padlen = iframe->buf[0]; + if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) { + padlen <<= 8; + padlen |= iframe->buf[1]; + ++padlen; + } + ++padlen; + DEBUGF(fprintf(stderr, "padlen=%zu\n", padlen)); + if(padlen > iframe->frame.hd.length) { + return -1; + } + iframe->padlen = padlen; + return padlen; +} + +/* + * This function returns the effective payload length in the data of + * length |readlen| when the remaning payload is |payloadleft|. The + * |payloadleft| does not include |readlen|. If padding was started + * strictly before this data chunk, this function returns -1. + */ +static ssize_t inbound_frame_effective_readlen(nghttp2_inbound_frame *iframe, + size_t payloadleft, + size_t readlen) +{ + size_t trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame, + iframe->padlen); + + if(trail_padlen > payloadleft) { + size_t padlen; + padlen = trail_padlen - payloadleft; + if(readlen < padlen) { + return -1; + } else { + return readlen - padlen; + } + } + return readlen; +} + ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in, size_t inlen) { @@ -3363,7 +3415,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, switch(iframe->frame.hd.type) { case NGHTTP2_DATA: { DEBUGF(fprintf(stderr, "DATA\n")); - iframe->frame.data.padlen = 0; /* Check stream is open. If it is not open or closing, ignore payload. */ busy = 1; @@ -3377,7 +3428,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, if(nghttp2_is_fatal(rv)) { return rv; } - rv = inbound_frame_handle_pad(iframe); + rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); if(rv < 0) { iframe->state = NGHTTP2_IB_IGN_DATA; rv = nghttp2_session_terminate_session(session, @@ -3395,6 +3446,20 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } case NGHTTP2_HEADERS: DEBUGF(fprintf(stderr, "HEADERS\n")); + rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); + if(rv < 0) { + busy = 1; + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + break; + } + if(rv == 1) { + break; + } if(iframe->frame.hd.flags & NGHTTP2_FLAG_PRIORITY) { if(iframe->payloadleft < 4) { busy = 1; @@ -3497,16 +3562,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, switch(iframe->frame.hd.type) { case NGHTTP2_DATA: busy = 1; - iframe->frame.data.padlen = iframe->buf[0]; - if(iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_HIGH) { - iframe->frame.data.padlen <<= 8; - iframe->frame.data.padlen |= iframe->buf[1]; - ++iframe->frame.data.padlen; - } - ++iframe->frame.data.padlen; - - DEBUGF(fprintf(stderr, "padlen=%zu\n", iframe->frame.data.padlen)); - if(iframe->frame.data.padlen > iframe->frame.hd.length) { + rv = inbound_frame_compute_pad(iframe); + if(rv < 0) { rv = nghttp2_session_terminate_session(session, NGHTTP2_PROTOCOL_ERROR); if(nghttp2_is_fatal(rv)) { @@ -3515,9 +3572,36 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_IGN_DATA; break; } + iframe->frame.data.padlen = rv; iframe->state = NGHTTP2_IB_READ_DATA; break; case NGHTTP2_HEADERS: + if(iframe->padlen == 0 && + iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) { + rv = inbound_frame_compute_pad(iframe); + if(rv < 0) { + busy = 1; + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + break; + } + iframe->frame.headers.padlen = rv; + if(iframe->frame.hd.flags & NGHTTP2_FLAG_PRIORITY) { + if(iframe->payloadleft < 4) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + iframe->state = NGHTTP2_IB_READ_NBYTE; + iframe->left = 4; + iframe->buflen = 0; + break; + } + } rv = session_process_headers_frame(session); if(nghttp2_is_fatal(rv)) { return rv; @@ -3580,7 +3664,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } break; case NGHTTP2_IB_READ_HEADER_BLOCK: - case NGHTTP2_IB_IGN_HEADER_BLOCK: + case NGHTTP2_IB_IGN_HEADER_BLOCK: { + ssize_t data_readlen; #ifdef DEBUGBUILD if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { fprintf(stderr, "[IB_READ_HEADER_BLOCK]\n"); @@ -3591,68 +3676,94 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, readlen = inbound_frame_payload_readlen(iframe, in, last); DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n", readlen, iframe->payloadleft - readlen)); - DEBUGF(fprintf(stderr, "block final=%d\n", - (iframe->frame.hd.flags & - NGHTTP2_FLAG_END_HEADERS) && - iframe->payloadleft == readlen)); - rv = inflate_header_block(session, &iframe->frame, &readlen, - (uint8_t*)in, readlen, - (iframe->frame.hd.flags & - NGHTTP2_FLAG_END_HEADERS) && - iframe->payloadleft == readlen, - iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK); - if(nghttp2_is_fatal(rv)) { - return rv; - } - in += readlen; - iframe->payloadleft -= readlen; - if(rv == NGHTTP2_ERR_PAUSE) { - return in - first; - } - if(rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { - /* The application says no more headers. We decompress the - rest of the header block but not invoke on_header_callback - and on_frame_recv_callback. */ - rv = nghttp2_session_add_rst_stream(session, - iframe->frame.hd.stream_id, - NGHTTP2_INTERNAL_ERROR); + + data_readlen = inbound_frame_effective_readlen + (iframe, iframe->payloadleft - readlen, readlen); + if(data_readlen >= 0) { + size_t trail_padlen; + size_t hd_proclen = 0; + trail_padlen = nghttp2_frame_trail_padlen(&iframe->frame, + iframe->padlen); + DEBUGF(fprintf(stderr, "block final=%d\n", + (iframe->frame.hd.flags & + NGHTTP2_FLAG_END_HEADERS) && + iframe->payloadleft - data_readlen == trail_padlen)); + + rv = inflate_header_block + (session, &iframe->frame, &hd_proclen, + (uint8_t*)in, data_readlen, + (iframe->frame.hd.flags & + NGHTTP2_FLAG_END_HEADERS) && + iframe->payloadleft - data_readlen == trail_padlen, + iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK); + if(nghttp2_is_fatal(rv)) { return rv; } - iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; - break; - } - if(rv == NGHTTP2_ERR_HEADER_COMP) { - /* GOAWAY is already issued */ - if(iframe->payloadleft == 0) { - nghttp2_inbound_frame_reset(session); - } else { - iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + + if(rv == NGHTTP2_ERR_PAUSE) { + in += hd_proclen; + iframe->payloadleft -= hd_proclen; + + return in - first; } - break; + + in += readlen; + iframe->payloadleft -= readlen; + + if(rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + /* The application says no more headers. We decompress the + rest of the header block but not invoke on_header_callback + and on_frame_recv_callback. */ + rv = nghttp2_session_add_rst_stream(session, + iframe->frame.hd.stream_id, + NGHTTP2_INTERNAL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + busy = 1; + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + break; + } + if(rv == NGHTTP2_ERR_HEADER_COMP) { + /* GOAWAY is already issued */ + if(iframe->payloadleft == 0) { + nghttp2_inbound_frame_reset(session); + } else { + busy = 1; + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + } + break; + } + } else { + in += readlen; + iframe->payloadleft -= readlen; } + if(iframe->payloadleft) { break; } - if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { - rv = session_after_header_block_received(session); - if(nghttp2_is_fatal(rv)) { - return rv; - } - } if((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) { iframe->left = NGHTTP2_FRAME_HEAD_LENGTH; iframe->error_code = 0; iframe->buflen = 0; + iframe->padlen = 0; if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { iframe->state = NGHTTP2_IB_EXPECT_CONTINUATION; } else { iframe->state = NGHTTP2_IB_IGN_CONTINUATION; } } else { + if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { + rv = session_after_header_block_received(session); + if(nghttp2_is_fatal(rv)) { + return rv; + } + } nghttp2_inbound_frame_reset(session); } break; + } case NGHTTP2_IB_IGN_PAYLOAD: DEBUGF(fprintf(stderr, "[IB_IGN_PAYLOAD]\n")); readlen = inbound_frame_payload_readlen(iframe, in, last); @@ -3761,9 +3872,30 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_IGN_PAYLOAD; break; } - if(cont_hd.flags & NGHTTP2_FLAG_END_HEADERS) { - iframe->frame.hd.flags |= NGHTTP2_FLAG_END_HEADERS; + iframe->frame.hd.flags |= cont_hd.flags & + (NGHTTP2_FLAG_END_HEADERS | + NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); + + rv = inbound_frame_handle_pad(iframe, &cont_hd); + if(rv < 0) { + busy = 1; + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + break; } + if(rv == 1) { + if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { + iframe->state = NGHTTP2_IB_READ_PAD_CONTINUATION; + } else { + iframe->state = NGHTTP2_IB_IGN_PAD_CONTINUATION; + } + break; + } + busy = 1; if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; @@ -3771,6 +3903,46 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; } break; + case NGHTTP2_IB_READ_PAD_CONTINUATION: + case NGHTTP2_IB_IGN_PAD_CONTINUATION: +#ifdef DEBUGBUILD + if(iframe->state == NGHTTP2_IB_READ_PAD_CONTINUATION) { + fprintf(stderr, "[IB_READ_PAD_CONTINUATION]\n"); + } else { + fprintf(stderr, "[IB_IGN_PAD_CONTINUATION]\n"); + } +#endif /* DEBUGBUILD */ + readlen = inbound_frame_buf_read(iframe, in, last); + in += readlen; + iframe->payloadleft -= readlen; + DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu, left=%zu\n", + readlen, iframe->payloadleft, iframe->left)); + if(iframe->left) { + return in - first; + } + busy = 1; + rv = inbound_frame_compute_pad(iframe); + if(rv < 0) { + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + break; + } + iframe->padlen = rv; + if(iframe->frame.hd.type == NGHTTP2_HEADERS) { + iframe->frame.headers.padlen += rv; + } else { + iframe->frame.push_promise.padlen += rv; + } + if(iframe->state == NGHTTP2_IB_READ_PAD_CONTINUATION) { + iframe->state = NGHTTP2_IB_READ_HEADER_BLOCK; + } else { + iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; + } + break; case NGHTTP2_IB_READ_DATA: DEBUGF(fprintf(stderr, "[IB_READ_DATA]\n")); readlen = inbound_frame_payload_readlen(iframe, in, last); @@ -3779,7 +3951,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu\n", readlen, iframe->payloadleft)); if(readlen > 0) { - size_t data_readlen = readlen; + ssize_t data_readlen; rv = nghttp2_session_update_recv_connection_window_size (session, readlen); if(nghttp2_is_fatal(rv)) { @@ -3798,17 +3970,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } } } - if(nghttp2_frame_data_trail_padlen(&iframe->frame.data) > - iframe->payloadleft) { - size_t trail_padlen; - trail_padlen = nghttp2_frame_data_trail_padlen(&iframe->frame.data) - - iframe->payloadleft; - if(readlen < trail_padlen) { - data_readlen = 0; - } else { - data_readlen -= trail_padlen; - } - } + data_readlen = inbound_frame_effective_readlen + (iframe, iframe->payloadleft, readlen); DEBUGF(fprintf(stderr, "data_readlen=%zu\n", data_readlen)); if(data_readlen > 0 && session->callbacks.on_data_chunk_recv_callback) { rv = session->callbacks.on_data_chunk_recv_callback @@ -4066,11 +4229,11 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, frame->hd.flags &= ~(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); flags = 0; - if((session->opt_flags & NGHTTP2_OPTMASK_NO_DATA_PADDING) == 0 && + if(session->pad_alignment && payloadlen > 0 && (size_t)payloadlen < datamax) { rv = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, &flags, payloadlen, datamax, - session->data_pad_alignment); + session->pad_alignment); if(rv < 0) { return rv; } diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 9e4fb484..a205cb60 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -44,10 +44,7 @@ */ typedef enum { NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE = 1 << 0, - NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1, - /* Option to disable DATA frame padding, which is currently hidden - from outside, but provided for ease of testing */ - NGHTTP2_OPTMASK_NO_DATA_PADDING = 1 << 2, + NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE = 1 << 1 } nghttp2_optmask; typedef struct { @@ -89,6 +86,8 @@ typedef enum { NGHTTP2_IB_READ_GOAWAY_DEBUG, NGHTTP2_IB_EXPECT_CONTINUATION, NGHTTP2_IB_IGN_CONTINUATION, + NGHTTP2_IB_READ_PAD_CONTINUATION, + NGHTTP2_IB_IGN_PAD_CONTINUATION, NGHTTP2_IB_READ_DATA, NGHTTP2_IB_IGN_DATA } nghttp2_inbound_state; @@ -105,6 +104,8 @@ typedef struct { size_t left; /* How many bytes we still need to receive for current frame */ size_t payloadleft; + /* padding length for the current frame */ + size_t padlen; nghttp2_inbound_state state; /* TODO, remove this. Error code */ int error_code; @@ -152,8 +153,8 @@ struct nghttp2_session { size_t num_incoming_streams; /* The number of bytes allocated for nvbuf */ size_t nvbuflen; - /* DATA padding alignemnt. See NGHTTP2_OPT_DATA_PAD_ALIGNMENT. */ - size_t data_pad_alignment; + /* padding alignemnt. See NGHTTP2_OPT_PAD_ALIGNMENT. */ + size_t pad_alignment; /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */ uint32_t next_stream_id; /* The largest stream ID received so far */ diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 6e7374e0..df09f4e4 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -66,7 +66,7 @@ const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION; Config::Config() : data_ptr(nullptr), output_upper_thres(1024*1024), - data_pad_alignment(NGHTTP2_DATA_PAD_ALIGNMENT), + pad_alignment(NGHTTP2_PAD_ALIGNMENT), header_table_size(-1), port(0), verbose(false), @@ -365,11 +365,11 @@ int Http2Handler::on_connect() nghttp2_opt_set opt_set; memset(&opt_set, 0, sizeof(opt_set)); - opt_set.data_pad_alignment = sessions_->get_config()->data_pad_alignment; + opt_set.pad_alignment = sessions_->get_config()->pad_alignment; fill_callback(callbacks, sessions_->get_config()); r = nghttp2_session_server_new2(&session_, &callbacks, this, - NGHTTP2_OPT_DATA_PAD_ALIGNMENT, &opt_set); + NGHTTP2_OPT_PAD_ALIGNMENT, &opt_set); if(r != 0) { return r; } diff --git a/src/HttpServer.h b/src/HttpServer.h index aeb6f43d..ad5feefa 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -56,7 +56,7 @@ struct Config { std::string cert_file; void *data_ptr; size_t output_upper_thres; - size_t data_pad_alignment; + size_t pad_alignment; ssize_t header_table_size; uint16_t port; bool verbose; diff --git a/src/app_helper.cc b/src/app_helper.cc index 46a231ba..ed19172e 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -244,6 +244,18 @@ void print_flags(const nghttp2_frame_hd& hd) } s += "PRIORITY"; } + if(hd.flags & NGHTTP2_FLAG_PAD_LOW) { + if(!s.empty()) { + s += " | "; + } + s += "PAD_LOW"; + } + if(hd.flags & NGHTTP2_FLAG_PAD_HIGH) { + if(!s.empty()) { + s += " | "; + } + s += "PAD_HIGH"; + } break; case NGHTTP2_SETTINGS: if(hd.flags & NGHTTP2_FLAG_ACK) { @@ -254,6 +266,18 @@ void print_flags(const nghttp2_frame_hd& hd) if(hd.flags & NGHTTP2_FLAG_END_PUSH_PROMISE) { s += "END_PUSH_PROMISE"; } + if(hd.flags & NGHTTP2_FLAG_PAD_LOW) { + if(!s.empty()) { + s += " | "; + } + s += "PAD_LOW"; + } + if(hd.flags & NGHTTP2_FLAG_PAD_HIGH) { + if(!s.empty()) { + s += " | "; + } + s += "PAD_HIGH"; + } break; case NGHTTP2_PING: if(hd.flags & NGHTTP2_FLAG_ACK) { @@ -297,10 +321,9 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) } break; case NGHTTP2_HEADERS: - if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { - print_frame_attr_indent(); - printf("(pri=%d)\n", frame->headers.pri); - } + print_frame_attr_indent(); + printf("(pri=%d, padlen=%zu)\n", + frame->headers.pri, frame->headers.padlen); switch(frame->headers.cat) { case NGHTTP2_HCAT_REQUEST: print_frame_attr_indent(); @@ -342,8 +365,9 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) break; case NGHTTP2_PUSH_PROMISE: print_frame_attr_indent(); - printf("(promised_stream_id=%d)\n", - frame->push_promise.promised_stream_id); + printf("(promised_stream_id=%d, padlen=%zu)\n", + frame->push_promise.promised_stream_id, + frame->push_promise.padlen); print_nv(frame->push_promise.nva, frame->push_promise.nvlen); break; case NGHTTP2_PING: diff --git a/src/nghttp.cc b/src/nghttp.cc index 8ee76756..27837404 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -82,7 +82,7 @@ struct Config { std::string keyfile; std::string datafile; size_t output_upper_thres; - size_t data_pad_alignment; + size_t pad_alignment; ssize_t peer_max_concurrent_streams; ssize_t header_table_size; int32_t pri; @@ -100,7 +100,7 @@ struct Config { bool continuation; Config() : output_upper_thres(1024*1024), - data_pad_alignment(NGHTTP2_DATA_PAD_ALIGNMENT), + pad_alignment(NGHTTP2_PAD_ALIGNMENT), peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS), header_table_size(-1), pri(NGHTTP2_PRI_DEFAULT), @@ -716,10 +716,10 @@ struct HttpClient { } nghttp2_opt_set opt_set; opt_set.peer_max_concurrent_streams = config.peer_max_concurrent_streams; - opt_set.data_pad_alignment = config.data_pad_alignment; + opt_set.pad_alignment = config.pad_alignment; rv = nghttp2_session_client_new2(&session, callbacks, this, NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS | - NGHTTP2_OPT_DATA_PAD_ALIGNMENT, + NGHTTP2_OPT_PAD_ALIGNMENT, &opt_set); if(rv != 0) { return -1; @@ -1710,8 +1710,8 @@ void print_help(std::ostream& out) << " is large enough as it is seen as unlimited.\n" << " -c, --header-table-size=\n" << " Specify decoder header table size.\n" - << " -b, --data-pad=\n" - << " Alignment of DATA frame padding.\n" + << " -b, --pad=\n" + << " Alignment of frame payload padding.\n" << " --color Force colored log output.\n" << " --continuation Send large header to test CONTINUATION.\n" << std::endl; @@ -1766,7 +1766,7 @@ int main(int argc, char **argv) print_help(std::cout); exit(EXIT_SUCCESS); case 'b': - config.data_pad_alignment = strtol(optarg, nullptr, 10); + config.pad_alignment = strtol(optarg, nullptr, 10); break; case 'n': config.null_out = true; diff --git a/src/nghttpd.cc b/src/nghttpd.cc index 87db6143..741475d0 100644 --- a/src/nghttpd.cc +++ b/src/nghttpd.cc @@ -115,8 +115,8 @@ void print_help(std::ostream& out) << " -p/=/foo.png -p/doc=/bar.css\n" << " PATH and PUSH_PATHs are relative to document\n" << " root. See --htdocs option.\n" - << " -b, --data-pad=\n" - << " Alignment of DATA frame padding.\n" + << " -b, --pad=\n" + << " Alignment of frame payload padding.\n" << " -h, --help Print this help.\n" << std::endl; } @@ -155,7 +155,7 @@ int main(int argc, char **argv) config.verify_client = true; break; case 'b': - config.data_pad_alignment = strtol(optarg, nullptr, 10); + config.pad_alignment = strtol(optarg, nullptr, 10); break; case 'd': config.htdocs = optarg; diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 74d01563..2188d208 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -74,6 +74,7 @@ void test_nghttp2_frame_pack_headers() nghttp2_headers frame, oframe; uint8_t *buf = NULL; size_t buflen = 0; + size_t bufoff; ssize_t framelen; nghttp2_nv *nva; ssize_t nvlen; @@ -89,17 +90,21 @@ void test_nghttp2_frame_pack_headers() NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, 1000000007, 1 << 20, nva, nvlen); - framelen = nghttp2_frame_pack_headers(&buf, &buflen, &frame, &deflater); + framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, + &deflater, 0); - CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen)); - check_frame_header(framelen - NGHTTP2_FRAME_HEAD_LENGTH, NGHTTP2_HEADERS, + CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, + framelen - bufoff)); + check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, + NGHTTP2_HEADERS, NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS, 1000000007, &oframe.hd); /* We didn't include PRIORITY flag so priority is not packed */ CU_ASSERT(1 << 30 == oframe.pri); - CU_ASSERT(framelen - 8 == - inflate_hd(&inflater, &out, buf + 8, framelen - 8)); + CU_ASSERT(framelen - (ssize_t)bufoff - 8 == + inflate_hd(&inflater, &out, + buf + bufoff + 8, framelen - bufoff - 8)); CU_ASSERT(7 == out.nvlen); CU_ASSERT(nvnameeq("method", &out.nva[0])); @@ -111,10 +116,13 @@ void test_nghttp2_frame_pack_headers() memset(&oframe, 0, sizeof(oframe)); /* Next, include PRIORITY flag */ frame.hd.flags |= NGHTTP2_FLAG_PRIORITY; - framelen = nghttp2_frame_pack_headers(&buf, &buflen, &frame, &deflater); + framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, + &deflater, 0); - CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen)); - check_frame_header(framelen - NGHTTP2_FRAME_HEAD_LENGTH, NGHTTP2_HEADERS, + CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, + framelen - bufoff)); + check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, + NGHTTP2_HEADERS, NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY, 1000000007, &oframe.hd); @@ -140,6 +148,7 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void) nghttp2_headers frame; uint8_t *buf = NULL; size_t buflen = 0; + size_t bufoff; ssize_t framelen; nghttp2_nv *nva; ssize_t nvlen; @@ -163,7 +172,8 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void) NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, 1000000007, 0, nva, nvlen); - framelen = nghttp2_frame_pack_headers(&buf, &buflen, &frame, &deflater); + framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, + &deflater, 0); CU_ASSERT_EQUAL(NGHTTP2_ERR_HEADER_COMP, framelen); nghttp2_frame_headers_free(&frame); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 98df0836..ff3e699b 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -336,9 +336,10 @@ void test_nghttp2_session_recv(void) }; uint8_t *framedata = NULL; size_t framedatalen = 0; + size_t bufoff; ssize_t framelen; nghttp2_frame frame; - int i; + size_t i; nghttp2_outbound_item *item; nghttp2_nv *nva; ssize_t nvlen; @@ -355,13 +356,13 @@ void test_nghttp2_session_recv(void) nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); - framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, + framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater); + &deflater, 0); - scripted_data_feed_init(&df, framedata, framelen); + scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); /* Send 1 byte per each read */ - for(i = 0; i < framelen; ++i) { + for(i = 0; i < framelen - bufoff; ++i) { df.feedseq[i] = 1; } nghttp2_frame_headers_free(&frame.headers); @@ -375,13 +376,13 @@ void test_nghttp2_session_recv(void) /* Received HEADERS without header block, which is valid */ nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 5, NGHTTP2_PRI_DEFAULT, NULL, 0); - framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, + framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater); + &deflater, 0); nghttp2_frame_headers_free(&frame.headers); - scripted_data_feed_init(&df, framedata, framelen); + scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); user_data.frame_recv_cb_called = 0; CU_ASSERT(0 == nghttp2_session_recv(session)); CU_ASSERT(1 == user_data.frame_recv_cb_called); @@ -421,6 +422,7 @@ void test_nghttp2_session_recv_invalid_stream_id(void) my_user_data user_data; uint8_t *framedata = NULL; size_t framedatalen = 0; + size_t bufoff; ssize_t framelen; nghttp2_frame frame; nghttp2_hd_deflater deflater; @@ -436,11 +438,11 @@ void test_nghttp2_session_recv_invalid_stream_id(void) nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2, NGHTTP2_PRI_DEFAULT, NULL, 0); - framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, + framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater); + &deflater, 0); - scripted_data_feed_init(&df, framedata, framelen); + scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); nghttp2_frame_headers_free(&frame.headers); CU_ASSERT(0 == nghttp2_session_recv(session)); @@ -462,6 +464,7 @@ void test_nghttp2_session_recv_invalid_frame(void) }; uint8_t *framedata = NULL; size_t framedatalen = 0; + size_t bufoff; ssize_t framelen; nghttp2_frame frame; nghttp2_nv *nva; @@ -480,11 +483,11 @@ void test_nghttp2_session_recv_invalid_frame(void) nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); - framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, + framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater); + &deflater, 0); - scripted_data_feed_init(&df, framedata, framelen); + scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); CU_ASSERT(0 == nghttp2_session_recv(session)); CU_ASSERT(0 == nghttp2_session_send(session)); @@ -492,7 +495,7 @@ void test_nghttp2_session_recv_invalid_frame(void) /* Receive exactly same bytes of HEADERS is treated as subsequent HEADERS (e.g., trailers */ - scripted_data_feed_init(&df, framedata, framelen); + scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); CU_ASSERT(0 == nghttp2_session_recv(session)); CU_ASSERT(0 == nghttp2_session_send(session)); @@ -660,6 +663,7 @@ void test_nghttp2_session_recv_continuation(void) uint8_t *framedata = NULL; size_t framedatacap = 0; size_t framedatalen; + size_t bufoff; size_t framedataoff; ssize_t rv; my_user_data ud; @@ -681,13 +685,14 @@ void test_nghttp2_session_recv_continuation(void) nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE, 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, + &bufoff, &frame.headers, - &deflater); + &deflater, 0); nghttp2_frame_headers_free(&frame.headers); - memcpy(data, framedata, 9); + memcpy(data, framedata + bufoff, 9); datalen = 9; - framedataoff = NGHTTP2_FRAME_HEAD_LENGTH + 1; + framedataoff = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 1; nghttp2_put_uint16be(data, 1); @@ -735,12 +740,12 @@ void test_nghttp2_session_recv_continuation(void) nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE, 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); - framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, + framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, &bufoff, &frame.headers, - &deflater); + &deflater, 0); nghttp2_frame_headers_free(&frame.headers); - memcpy(data, framedata, framedatalen); - datalen = framedatalen; + memcpy(data, framedata + bufoff, framedatalen - bufoff); + datalen = framedatalen - bufoff; /* Followed by PRIORITY */ nghttp2_frame_priority_init(&frame.priority, 1, 0); @@ -782,6 +787,7 @@ void test_nghttp2_session_continue(void) uint8_t buffer[4096]; uint8_t *bufp = buffer; size_t buflen; + size_t bufoff; nghttp2_frame frame; nghttp2_nv *nva; ssize_t nvlen; @@ -804,22 +810,24 @@ void test_nghttp2_session_continue(void) nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); - framelen1 = nghttp2_frame_pack_headers(&framedata, &framedatalen, + framelen1 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater); + &deflater, 0); nghttp2_frame_headers_free(&frame.headers); - memcpy(buffer, framedata, framelen1); + memcpy(buffer, framedata + bufoff, framelen1 - bufoff); + framelen1 -= bufoff; nvlen = nghttp2_nv_array_copy(&nva, nv2, ARRLEN(nv2)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 3, NGHTTP2_PRI_DEFAULT, nva, nvlen); - framelen2 = nghttp2_frame_pack_headers(&framedata, &framedatalen, + framelen2 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater); + &deflater, 0); nghttp2_frame_headers_free(&frame.headers); - memcpy(buffer + framelen1, framedata, framelen2); + memcpy(buffer + framelen1, framedata + bufoff, framelen2 - bufoff); + framelen2 -= bufoff; buflen = framelen1 + framelen2; /* Receive 1st HEADERS and pause */ @@ -955,6 +963,7 @@ void test_nghttp2_session_add_frame(void) acc.length = 0; user_data.acc = &acc; CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &user_data)); + session_disable_pad(session); frame = malloc(sizeof(nghttp2_frame)); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); @@ -2173,6 +2182,7 @@ void test_nghttp2_submit_request_without_data(void) memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); callbacks.send_callback = accumulator_send_callback; CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); + session_disable_pad(session); nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); CU_ASSERT(0 == nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, nva, ARRLEN(nva), &data_prd, NULL)); @@ -2244,6 +2254,7 @@ void test_nghttp2_submit_response_without_data(void) memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); callbacks.send_callback = accumulator_send_callback; CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud)); + session_disable_pad(session); nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_RESPONSE); nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM, NGHTTP2_PRI_DEFAULT, @@ -2415,6 +2426,7 @@ void test_nghttp2_submit_headers(void) callbacks.on_frame_send_callback = on_frame_send_callback; CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); + session_disable_pad(session); nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, @@ -3858,7 +3870,7 @@ void test_nghttp2_session_pack_data_with_padding(void) data_prd.read_callback = fixed_length_data_source_read_callback; nghttp2_session_client_new(&session, &callbacks, &ud); - session->data_pad_alignment = 512; + session->pad_alignment = 512; nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, &data_prd, NULL); @@ -3869,7 +3881,7 @@ void test_nghttp2_session_pack_data_with_padding(void) CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type); frame = OB_DATA(session->aob.item); - CU_ASSERT(session->data_pad_alignment - datalen == frame->padlen); + CU_ASSERT(session->pad_alignment - datalen == frame->padlen); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH); @@ -3893,7 +3905,7 @@ void test_nghttp2_session_pack_data_with_padding(void) CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type); frame = OB_DATA(session->aob.item); - CU_ASSERT(session->data_pad_alignment - datalen == frame->padlen); + CU_ASSERT(session->pad_alignment - datalen == frame->padlen); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); CU_ASSERT(0 == (frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH)); diff --git a/tests/nghttp2_test_helper.c b/tests/nghttp2_test_helper.c index aec305bd..ef40e4ac 100644 --- a/tests/nghttp2_test_helper.c +++ b/tests/nghttp2_test_helper.c @@ -159,3 +159,8 @@ ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out, nghttp2_hd_inflate_end_headers(inflater); return initial - buflen; } + +void session_disable_pad(nghttp2_session *session) +{ + session->pad_alignment = 0; +} diff --git a/tests/nghttp2_test_helper.h b/tests/nghttp2_test_helper.h index 4ad2a672..e881bf1f 100644 --- a/tests/nghttp2_test_helper.h +++ b/tests/nghttp2_test_helper.h @@ -29,6 +29,7 @@ # include #endif /* HAVE_CONFIG_H */ +#include "nghttp2_session.h" #include "nghttp2_frame.h" #include "nghttp2_hd.h" @@ -57,4 +58,6 @@ void add_out(nva_out *out, nghttp2_nv *nv); ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out, uint8_t *buf, size_t buflen); +void session_disable_pad(nghttp2_session *session); + #endif /* NGHTTP2_TEST_HELPER_H */ From 945c57c3352ce7ab0a778853f7ae6c5627510809 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 15:16:58 +0900 Subject: [PATCH 17/56] Add test for nghttp2_frame_pack_headers with padding --- tests/main.c | 2 + tests/nghttp2_frame_test.c | 128 ++++++++++++++++++++++++++++++++++++ tests/nghttp2_frame_test.h | 1 + tests/nghttp2_hd_test.c | 9 --- tests/nghttp2_test_helper.c | 6 +- tests/nghttp2_test_helper.h | 18 +++++ 6 files changed, 154 insertions(+), 10 deletions(-) diff --git a/tests/main.c b/tests/main.c index 063c881e..0301c8cb 100644 --- a/tests/main.c +++ b/tests/main.c @@ -201,6 +201,8 @@ int main(int argc, char* argv[]) test_nghttp2_frame_pack_headers) || !CU_add_test(pSuite, "frame_pack_headers_frame_too_large", test_nghttp2_frame_pack_headers_frame_too_large) || + !CU_add_test(pSuite, "frame_pack_headers_with_padding", + test_nghttp2_frame_pack_headers_with_padding) || !CU_add_test(pSuite, "frame_pack_priority", test_nghttp2_frame_pack_priority) || !CU_add_test(pSuite, "frame_pack_rst_stream", diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 2188d208..c8f127fb 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -184,6 +184,134 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void) nghttp2_hd_deflate_free(&deflater); } + +void test_nghttp2_frame_pack_headers_with_padding(void) +{ + nghttp2_hd_deflater deflater; + nghttp2_hd_inflater inflater; + nghttp2_headers frame, oframe; + uint8_t *buf = NULL; + size_t buflen = 0; + size_t bufoff; + ssize_t framelen; + nghttp2_nv *nva; + ssize_t nvlen; + nva_out out; + size_t trail_padlen; + size_t header_blocklen; + + nva_out_init(&out); + nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + + /* Payload length is 0, so no padding */ + nghttp2_frame_headers_init(&frame, + NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, + 1000000007, NGHTTP2_PRI_DEFAULT, NULL, 0); + framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, + &deflater, 128); + + CU_ASSERT(2 == bufoff); + CU_ASSERT((ssize_t)bufoff + NGHTTP2_FRAME_HEAD_LENGTH == framelen); + + CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, + framelen - bufoff)); + check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, + NGHTTP2_HEADERS, + NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS, + 1000000007, &oframe.hd); + + CU_ASSERT(NGHTTP2_PRI_DEFAULT == oframe.pri); + nghttp2_frame_headers_free(&oframe); + + /* Include priroty */ + frame.hd.flags |= NGHTTP2_FLAG_PRIORITY; + frame.pri = 1000000009; + bufoff = 0; + + framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, + &deflater, 128); + + CU_ASSERT(1 == bufoff); + CU_ASSERT((ssize_t)bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 128 == framelen); + + CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, + framelen - bufoff)); + check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, + NGHTTP2_HEADERS, + NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | + NGHTTP2_FLAG_PRIORITY | NGHTTP2_FLAG_PAD_LOW, + 1000000007, &oframe.hd); + + CU_ASSERT(1000000009 == oframe.pri); + nghttp2_frame_headers_free(&oframe); + + /* padding more than 256 */ + bufoff = 0; + + framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, + &deflater, 512); + + CU_ASSERT(0 == bufoff); + CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH + 512 == framelen); + + CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, + framelen - bufoff)); + check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, + NGHTTP2_HEADERS, + NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | + NGHTTP2_FLAG_PRIORITY | + NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW, + 1000000007, &oframe.hd); + + CU_ASSERT(1000000009 == oframe.pri); + nghttp2_frame_headers_free(&oframe); + + /* Include priority + headers */ + nva = headers(); + nvlen = HEADERS_LENGTH; + frame.nva = nva; + frame.nvlen = nvlen; + bufoff = 0; + + framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, + &deflater, 512); + + CU_ASSERT(0 == bufoff); + CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH + 512 == framelen); + + CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, + framelen - bufoff)); + check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, + NGHTTP2_HEADERS, + NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | + NGHTTP2_FLAG_PRIORITY | + NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW, + 1000000007, &oframe.hd); + + CU_ASSERT(1000000009 == oframe.pri); + trail_padlen = (buf[NGHTTP2_FRAME_HEAD_LENGTH] << 8) | + buf[NGHTTP2_FRAME_HEAD_LENGTH + 1]; + + header_blocklen = framelen - NGHTTP2_FRAME_HEAD_LENGTH - 2 - 4 + - trail_padlen; + CU_ASSERT((ssize_t)header_blocklen == + inflate_hd(&inflater, &out, + buf + NGHTTP2_FRAME_HEAD_LENGTH + 2 + 4, + header_blocklen)); + + CU_ASSERT(nvlen == (ssize_t)out.nvlen); + assert_nv_equal(nva, out.nva, nvlen); + + nghttp2_frame_headers_free(&oframe); + nva_out_reset(&out); + + free(buf); + nghttp2_frame_headers_free(&frame); + nghttp2_hd_inflate_free(&inflater); + nghttp2_hd_deflate_free(&deflater); +} + void test_nghttp2_frame_pack_priority(void) { nghttp2_priority frame, oframe; diff --git a/tests/nghttp2_frame_test.h b/tests/nghttp2_frame_test.h index 9a04c23d..a45732e8 100644 --- a/tests/nghttp2_frame_test.h +++ b/tests/nghttp2_frame_test.h @@ -27,6 +27,7 @@ void test_nghttp2_frame_pack_headers(void); void test_nghttp2_frame_pack_headers_frame_too_large(void); +void test_nghttp2_frame_pack_headers_with_padding(void); void test_nghttp2_frame_pack_priority(void); void test_nghttp2_frame_pack_rst_stream(void); void test_nghttp2_frame_pack_settings(void); diff --git a/tests/nghttp2_hd_test.c b/tests/nghttp2_hd_test.c index ad30c120..7d75eddd 100644 --- a/tests/nghttp2_hd_test.c +++ b/tests/nghttp2_hd_test.c @@ -35,15 +35,6 @@ #define GET_TABLE_ENT(context, index) nghttp2_hd_table_get(context, index) -static void assert_nv_equal(nghttp2_nv *a, nghttp2_nv *b, size_t len) -{ - size_t i; - nghttp2_nv_array_sort(b, len); - for(i = 0; i < len; ++i, ++a, ++b) { - CU_ASSERT(nghttp2_nv_equal(a, b)); - } -} - void test_nghttp2_hd_deflate(void) { nghttp2_hd_deflater deflater; diff --git a/tests/nghttp2_test_helper.c b/tests/nghttp2_test_helper.c index ef40e4ac..baff5835 100644 --- a/tests/nghttp2_test_helper.c +++ b/tests/nghttp2_test_helper.c @@ -33,11 +33,15 @@ int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len) ssize_t rv = 0; const uint8_t *payload = in + NGHTTP2_FRAME_HEAD_LENGTH; size_t payloadlen = len - NGHTTP2_FRAME_HEAD_LENGTH; + size_t payloadoff; + nghttp2_frame_unpack_frame_hd(&frame->hd, in); switch(frame->hd.type) { case NGHTTP2_HEADERS: + payloadoff = ((frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH) > 0) + + ((frame->hd.flags & NGHTTP2_FLAG_PAD_LOW) > 0); rv = nghttp2_frame_unpack_headers_payload - (&frame->headers, payload, payloadlen); + (&frame->headers, payload + payloadoff, payloadlen - payloadoff); break; case NGHTTP2_PRIORITY: nghttp2_frame_unpack_priority_payload diff --git a/tests/nghttp2_test_helper.h b/tests/nghttp2_test_helper.h index e881bf1f..0f72a4b8 100644 --- a/tests/nghttp2_test_helper.h +++ b/tests/nghttp2_test_helper.h @@ -37,6 +37,24 @@ { (uint8_t*)NAME, (uint8_t*)VALUE, strlen(NAME), strlen(VALUE) } #define ARRLEN(ARR) (sizeof(ARR)/sizeof(ARR[0])) +#define assert_nv_equal(A, B, len) \ + do { \ + size_t alloclen = sizeof(nghttp2_nv) * len; \ + nghttp2_nv *sa = A, *sb = B; \ + nghttp2_nv *a = malloc(alloclen); \ + nghttp2_nv *b = malloc(alloclen); \ + ssize_t i_; \ + memcpy(a, sa, alloclen); \ + memcpy(b, sb, alloclen); \ + nghttp2_nv_array_sort(a, len); \ + nghttp2_nv_array_sort(b, len); \ + for(i_ = 0; i_ < (ssize_t)len; ++i_) { \ + CU_ASSERT(nghttp2_nv_equal(&a[i_], &b[i_])); \ + } \ + free(b); \ + free(a); \ + } while(0); + int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len); int strmemeq(const char *a, const uint8_t *b, size_t bn); From dffa078c118ddc03404b490bf8b479bec19c824f Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 16:49:24 +0900 Subject: [PATCH 18/56] Update doc --- lib/nghttp2_frame.c | 3 ++- lib/nghttp2_frame.h | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index 9e7096a0..1d656081 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -696,7 +696,8 @@ ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, if(rv != 0) { return rv; } - + /* We have to zero out padding bytes so that we won't reveal the + possible internal data to the remote peer */ memset((*buf_ptr) + trail_padoff, 0, trail_padlen); return padlen; diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index 3496863c..92d6f0fa 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -519,6 +519,57 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); * The |*buf_ptr| and |*buflen_ptr| may be extended to include padding * bytes. * + * The padding specifier PAD_HIGH and PAD_LOW are located right after + * the frame header. But they may not be there depending of the length + * of the padding. To save the additional buffer copy, we allocate + * buffer size as if these 2 bytes always exist. Depending of the + * length of the padding, we move the location of frame header and + * adjust |*bufoff_ptr|. If more than or equal to 256 padding is made, + * the |*bufoff_ptr| is 0 and the content of the |*buf_ptr| looks like + * this: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Frame header ... + * +---------------------------------------------------------------+ + * . Frame header | + * +---------------+---------------+-------------------------------+ + * | Pad high | Pad low | Payload ... + * +---------------+---------------+-------------------------------+ + * + * + * If padding is less than 256 but strictly more than 0, the + * |*bufoff_ptr| is 1 and the |*buf_ptr| looks like this: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Unused | Frame header ... + * +---------------+-----------------------------------------------+ + * . Frame header ... + * +---------------+---------------+-------------------------------+ + * . Frame Header | Pad low | Payload ... + * +---------------+---------------+-------------------------------+ + * + * If no padding is added, the |*bufoff_ptr| is 2 and the |*buf_ptr| + * looks like this: + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Unused | Frame header ... + * +-------------------------------+-------------------------------+ + * . Frame header ... + * +-------------------------------+-------------------------------+ + * . Frame Header | Payload ... + * +-------------------------------+-------------------------------+ + * + * Notice that the position of payload does not change. This way, we + * can set PAD_HIGH and PAD_LOW after payload was serialized and no + * additional copy operation is required (if the |*buf_ptr| is large + * enough to account the additional padding, of course). + * * This function returns the number of padding added to the payload * including PAD_HIGH and PAD_LOW if it succeeds, or one of the * following negative error codes: From 72e2e145c5af48657a76b469e76651828a5ee0fa Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 17:42:20 +0900 Subject: [PATCH 19/56] Revert 748f6e65bd57581f66715db9a433c12625a535a7 --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 064f87d0..5fd7f459 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,7 @@ # 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. -SUBDIRS = lib third-party src examples python doc tests +SUBDIRS = lib third-party src examples python tests doc ACLOCAL_AMFLAGS = -I m4 From ba95cd936d3056a9cf203af59b866a558a302d60 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 18:26:46 +0900 Subject: [PATCH 20/56] Fix flow control error because padding is excluded --- lib/nghttp2_session.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index cba080ed..76cfbfcc 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1600,17 +1600,15 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) nghttp2_private_data *data_frame; nghttp2_outbound_item* next_item; nghttp2_stream *stream; - size_t effective_payloadlen; data_frame = nghttp2_outbound_item_get_data_frame(session->aob.item); stream = nghttp2_session_get_stream(session, data_frame->hd.stream_id); /* We update flow control window after a frame was completely sent. This is possible because we choose payload length not to exceed the window */ - effective_payloadlen = data_frame->hd.length - data_frame->padlen; - session->remote_window_size -= effective_payloadlen; + session->remote_window_size -= data_frame->hd.length; if(stream) { - stream->remote_window_size -= effective_payloadlen; + stream->remote_window_size -= data_frame->hd.length; } if(session->callbacks.on_frame_send_callback) { From 256c97d89b096a7701617a8f59190edad169a56c Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 18:27:34 +0900 Subject: [PATCH 21/56] Change default padding size to 16 --- lib/includes/nghttp2/nghttp2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 15b9173f..d268e622 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -153,7 +153,7 @@ typedef struct { * The default value of DATA padding alignment. See * :member:`NGHTTP2_OPT_PAD_ALIGNMENT`. */ -#define NGHTTP2_PAD_ALIGNMENT 256 +#define NGHTTP2_PAD_ALIGNMENT 16 /** * @enum From 909b79e69b570acd9693a30668f626547d07e3de Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 18:33:27 +0900 Subject: [PATCH 22/56] Fix test --- tests/nghttp2_session_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index ff3e699b..7bc2b8d3 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -3905,7 +3905,7 @@ void test_nghttp2_session_pack_data_with_padding(void) CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type); frame = OB_DATA(session->aob.item); - CU_ASSERT(session->pad_alignment - datalen == frame->padlen); + CU_ASSERT((frame->padlen + datalen) % session->pad_alignment == 0); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); CU_ASSERT(0 == (frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH)); From c7c283f3a980d4e3831dbd174dbe7d58fe9e0abf Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 18:47:26 +0900 Subject: [PATCH 23/56] nghttpx: Add --frontend-frame-debug option to debug HTTP/2 frame in upstream The output format is the same one with nghttp/nghttpd. The output is made into stderr to make it sync with logging. --- src/Makefile.am | 1 + src/app_helper.cc | 141 +++++++++++++++++++----------------- src/app_helper.h | 4 + src/shrpx.cc | 21 +++++- src/shrpx_config.cc | 3 + src/shrpx_config.h | 2 + src/shrpx_http2_upstream.cc | 11 +++ 7 files changed, 117 insertions(+), 66 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 5f19fc25..65fe4ef1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -71,6 +71,7 @@ nghttpd_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttpd.cc \ NGHTTPX_SRCS = \ util.cc util.h http2.cc http2.h timegm.c timegm.h base64.h \ + app_helper.cc app_helper.h \ shrpx_config.cc shrpx_config.h \ shrpx_error.h \ shrpx_listen_handler.cc shrpx_listen_handler.h \ diff --git a/src/app_helper.cc b/src/app_helper.cc index ed19172e..059bde55 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -131,13 +131,6 @@ const char* strframetype(uint8_t type) }; } // namespace -namespace { -void print_frame_attr_indent() -{ - printf(" "); -} -} // namespace - namespace { bool color_output = false; } // namespace @@ -147,6 +140,22 @@ void set_color_output(bool f) color_output = f; } +namespace { +FILE *outfile = stdout; +} // namespace + +void set_output(FILE *file) +{ + outfile = file; +} + +namespace { +void print_frame_attr_indent() +{ + fprintf(outfile, " "); +} +} // namespace + namespace { const char* ansi_esc(const char *code) { @@ -168,11 +177,11 @@ void print_nv(nghttp2_nv *nva, size_t nvlen, bool indent = true) if(indent) { print_frame_attr_indent(); } - printf("%s", ansi_esc("\033[1;34m")); - fwrite(nv.name, nv.namelen, 1, stdout); - printf("%s: ", ansi_escend()); - fwrite(nv.value, nv.valuelen, 1, stdout); - printf("\n"); + fprintf(outfile, "%s", ansi_esc("\033[1;34m")); + fwrite(nv.name, nv.namelen, 1, outfile); + fprintf(outfile, "%s: ", ansi_escend()); + fwrite(nv.value, nv.valuelen, 1, outfile); + fprintf(outfile, "\n"); } } } // namelen @@ -180,17 +189,17 @@ void print_nv(nghttp2_nv *nva, size_t nvlen, bool indent = true) void print_timer() { auto millis = get_timer(); - printf("%s[%3ld.%03ld]%s", - ansi_esc("\033[33m"), - (long int)(millis.count()/1000), (long int)(millis.count()%1000), - ansi_escend()); + fprintf(outfile, "%s[%3ld.%03ld]%s", + ansi_esc("\033[33m"), + (long int)(millis.count()/1000), (long int)(millis.count()%1000), + ansi_escend()); } namespace { void print_frame_hd(const nghttp2_frame_hd& hd) { - printf("\n", - hd.length, hd.flags, hd.stream_id); + fprintf(outfile, "\n", + hd.length, hd.flags, hd.stream_id); } } // namespace @@ -285,7 +294,7 @@ void print_flags(const nghttp2_frame_hd& hd) } break; } - printf("; %s\n", s.c_str()); + fprintf(outfile, "; %s\n", s.c_str()); } } // namespace @@ -304,10 +313,10 @@ const char* frame_name_ansi_esc(print_type ptype) namespace { void print_frame(print_type ptype, const nghttp2_frame *frame) { - printf("%s%s%s frame ", - frame_name_ansi_esc(ptype), - strframetype(frame->hd.type), - ansi_escend()); + fprintf(outfile, "%s%s%s frame ", + frame_name_ansi_esc(ptype), + strframetype(frame->hd.type), + ansi_escend()); print_frame_hd(frame->hd); if(frame->hd.flags) { print_frame_attr_indent(); @@ -317,25 +326,25 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) case NGHTTP2_DATA: if(frame->hd.flags & (NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW)) { print_frame_attr_indent(); - printf("(padlen=%zu)\n", frame->data.padlen); + fprintf(outfile, "(padlen=%zu)\n", frame->data.padlen); } break; case NGHTTP2_HEADERS: print_frame_attr_indent(); - printf("(pri=%d, padlen=%zu)\n", - frame->headers.pri, frame->headers.padlen); + fprintf(outfile, "(pri=%d, padlen=%zu)\n", + frame->headers.pri, frame->headers.padlen); switch(frame->headers.cat) { case NGHTTP2_HCAT_REQUEST: print_frame_attr_indent(); - printf("; Open new stream\n"); + fprintf(outfile, "; Open new stream\n"); break; case NGHTTP2_HCAT_RESPONSE: print_frame_attr_indent(); - printf("; First response header\n"); + fprintf(outfile, "; First response header\n"); break; case NGHTTP2_HCAT_PUSH_RESPONSE: print_frame_attr_indent(); - printf("; First push response header\n"); + fprintf(outfile, "; First push response header\n"); break; default: break; @@ -344,54 +353,56 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) break; case NGHTTP2_PRIORITY: print_frame_attr_indent(); - printf("(pri=%d)\n", frame->priority.pri); + fprintf(outfile, "(pri=%d)\n", frame->priority.pri); break; case NGHTTP2_RST_STREAM: print_frame_attr_indent(); - printf("(error_code=%s(%u))\n", - strstatus(frame->rst_stream.error_code), - frame->rst_stream.error_code); + fprintf(outfile, "(error_code=%s(%u))\n", + strstatus(frame->rst_stream.error_code), + frame->rst_stream.error_code); break; case NGHTTP2_SETTINGS: print_frame_attr_indent(); - printf("(niv=%lu)\n", static_cast(frame->settings.niv)); + fprintf(outfile, "(niv=%lu)\n", + static_cast(frame->settings.niv)); for(size_t i = 0; i < frame->settings.niv; ++i) { print_frame_attr_indent(); - printf("[%s(%d):%u]\n", - strsettingsid(frame->settings.iv[i].settings_id), - frame->settings.iv[i].settings_id, - frame->settings.iv[i].value); + fprintf(outfile, "[%s(%d):%u]\n", + strsettingsid(frame->settings.iv[i].settings_id), + frame->settings.iv[i].settings_id, + frame->settings.iv[i].value); } break; case NGHTTP2_PUSH_PROMISE: print_frame_attr_indent(); - printf("(promised_stream_id=%d, padlen=%zu)\n", - frame->push_promise.promised_stream_id, - frame->push_promise.padlen); + fprintf(outfile, "(promised_stream_id=%d, padlen=%zu)\n", + frame->push_promise.promised_stream_id, + frame->push_promise.padlen); print_nv(frame->push_promise.nva, frame->push_promise.nvlen); break; case NGHTTP2_PING: print_frame_attr_indent(); - printf("(opaque_data=%s)\n", - util::format_hex(frame->ping.opaque_data, 8).c_str()); + fprintf(outfile, "(opaque_data=%s)\n", + util::format_hex(frame->ping.opaque_data, 8).c_str()); break; case NGHTTP2_GOAWAY: print_frame_attr_indent(); - printf("(last_stream_id=%d, error_code=%s(%u), opaque_data(%u)=[%s])\n", - frame->goaway.last_stream_id, - strstatus(frame->goaway.error_code), - frame->goaway.error_code, - static_cast(frame->goaway.opaque_data_len), - util::format_hex(frame->goaway.opaque_data, - frame->goaway.opaque_data_len).c_str()); + fprintf(outfile, + "(last_stream_id=%d, error_code=%s(%u), opaque_data(%u)=[%s])\n", + frame->goaway.last_stream_id, + strstatus(frame->goaway.error_code), + frame->goaway.error_code, + static_cast(frame->goaway.opaque_data_len), + util::format_hex(frame->goaway.opaque_data, + frame->goaway.opaque_data_len).c_str()); break; case NGHTTP2_WINDOW_UPDATE: print_frame_attr_indent(); - printf("(window_size_increment=%d)\n", - frame->window_update.window_size_increment); + fprintf(outfile, "(window_size_increment=%d)\n", + frame->window_update.window_size_increment); break; default: - printf("\n"); + fprintf(outfile, "\n"); break; } } @@ -408,7 +419,7 @@ int verbose_on_header_callback(nghttp2_session *session, static_cast(namelen), static_cast(valuelen) }; print_timer(); - printf(" (stream_id=%d) ", frame->hd.stream_id); + fprintf(outfile, " (stream_id=%d) ", frame->hd.stream_id); print_nv(&nv, 1, false /* no indent */); return 0; } @@ -417,9 +428,9 @@ int verbose_on_frame_recv_callback (nghttp2_session *session, const nghttp2_frame *frame, void *user_data) { print_timer(); - printf(" recv "); + fprintf(outfile, " recv "); print_frame(PRINT_RECV, frame); - fflush(stdout); + fflush(outfile); return 0; } @@ -428,9 +439,9 @@ int verbose_on_invalid_frame_recv_callback nghttp2_error_code error_code, void *user_data) { print_timer(); - printf(" [INVALID; status=%s] recv ", strstatus(error_code)); + fprintf(outfile, " [INVALID; status=%s] recv ", strstatus(error_code)); print_frame(PRINT_RECV, frame); - fflush(stdout); + fflush(outfile); return 0; } @@ -439,11 +450,11 @@ void dump_header(const uint8_t *head, size_t headlen) { size_t i; print_frame_attr_indent(); - printf("Header dump: "); + fprintf(outfile, "Header dump: "); for(i = 0; i < headlen; ++i) { - printf("%02X ", head[i]); + fprintf(outfile, "%02X ", head[i]); } - printf("\n"); + fprintf(outfile, "\n"); } } // namespace @@ -455,9 +466,9 @@ int verbose_on_unknown_frame_recv_callback(nghttp2_session *session, void *user_data) { print_timer(); - printf(" recv unknown frame\n"); + fprintf(outfile, " recv unknown frame\n"); dump_header(head, headlen); - fflush(stdout); + fflush(outfile); return 0; } @@ -465,9 +476,9 @@ int verbose_on_frame_send_callback (nghttp2_session *session, const nghttp2_frame *frame, void *user_data) { print_timer(); - printf(" send "); + fprintf(outfile, " send "); print_frame(PRINT_SEND, frame); - fflush(stdout); + fflush(outfile); return 0; } diff --git a/src/app_helper.h b/src/app_helper.h index 8e54bbe8..e9f74664 100644 --- a/src/app_helper.h +++ b/src/app_helper.h @@ -86,6 +86,10 @@ void print_timer(); // variable. void set_color_output(bool f); +// Set output file when printing HTTP2 frames. By default, stdout is +// used. +void set_output(FILE *file); + } // namespace nghttp2 #endif // APP_HELPER_H diff --git a/src/shrpx.cc b/src/shrpx.cc index cb069604..a2daecad 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -53,6 +53,7 @@ #include "shrpx_listen_handler.h" #include "shrpx_ssl.h" #include "util.h" +#include "app_helper.h" using namespace nghttp2; @@ -435,6 +436,7 @@ void fill_default_config() mod_config()->http2_upstream_dump_request_header = nullptr; mod_config()->http2_upstream_dump_response_header = nullptr; mod_config()->http2_no_cookie_crumbling = false; + mod_config()->upstream_frame_debug = false; } } // namespace @@ -736,6 +738,10 @@ void print_help(std::ostream& out) << " an empty line.\n" << " This option is not thread safe and MUST NOT\n" << " be used with option -n=N, where N >= 2.\n" + << " -o, --frontend-frame-debug\n" + << " Print HTTP/2 frames in frontend to stderr.\n" + << " This option is not thread safe and MUST NOT\n" + << " be used with option -n=N, where N >= 2.\n" << " -D, --daemon Run in a background. If -D is used, the\n" << " current working directory is changed to '/'.\n" << " --pid-file= Set path to save PID of this program.\n" @@ -771,6 +777,7 @@ int main(int argc, char **argv) {"client-proxy", no_argument, nullptr, 'p'}, {"http2-proxy", no_argument, nullptr, 's'}, {"version", no_argument, nullptr, 'v'}, + {"frontend-frame-debug", no_argument, nullptr, 'o'}, {"add-x-forwarded-for", no_argument, &flag, 1}, {"frontend-http2-read-timeout", required_argument, &flag, 2}, {"frontend-read-timeout", required_argument, &flag, 3}, @@ -821,7 +828,7 @@ int main(int argc, char **argv) }; int option_index = 0; - int c = getopt_long(argc, argv, "DL:b:c:f:hkn:psv", long_options, + int c = getopt_long(argc, argv, "DL:b:c:f:hkn:opsv", long_options, &option_index); if(c == -1) { break; @@ -851,6 +858,9 @@ int main(int argc, char **argv) case 'n': cmdcfgs.emplace_back(SHRPX_OPT_WORKERS, optarg); break; + case 'o': + cmdcfgs.emplace_back(SHRPX_OPT_FRONTEND_FRAME_DEBUG, "yes"); + break; case 'p': cmdcfgs.emplace_back(SHRPX_OPT_CLIENT_PROXY, "yes"); break; @@ -1204,6 +1214,15 @@ int main(int argc, char **argv) get_rate_limit(get_config()->write_burst), nullptr); + if(get_config()->upstream_frame_debug) { + // To make it sync to logging + set_output(stderr); + if(isatty(fileno(stdout))) { + set_color_output(true); + } + reset_timer(); + } + struct sigaction act; memset(&act, 0, sizeof(struct sigaction)); act.sa_handler = SIG_IGN; diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 9312d6e2..d2f5b504 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -115,6 +115,7 @@ const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER[] = const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[] = "frontend-http2-dump-response-header"; const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[] = "http2-no-cookie-crumbling"; +const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[] = "frontend-frame-debug"; namespace { Config *config = nullptr; @@ -480,6 +481,8 @@ int parse_config(const char *opt, const char *optarg) mod_config()->http2_upstream_dump_response_header = f; } else if(util::strieq(opt, SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING)) { mod_config()->http2_no_cookie_crumbling = util::strieq(optarg, "yes"); + } else if(util::strieq(opt, SHRPX_OPT_FRONTEND_FRAME_DEBUG)) { + mod_config()->upstream_frame_debug = util::strieq(optarg, "yes"); } else if(util::strieq(opt, "conf")) { LOG(WARNING) << "conf is ignored"; } else { diff --git a/src/shrpx_config.h b/src/shrpx_config.h index b801e7bb..6ca420e0 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -102,6 +102,7 @@ extern const char SHRPX_OPT_CLIENT_CERT_FILE[]; extern const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER[]; extern const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[]; extern const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[]; +extern const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[]; union sockaddr_union { sockaddr sa; @@ -213,6 +214,7 @@ struct Config { // true if stderr refers to a terminal. bool tty; bool http2_no_cookie_crumbling; + bool upstream_frame_debug; }; const Config* get_config(); diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index dd033298..d469b7c5 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -39,6 +39,7 @@ #include "http2.h" #include "util.h" #include "base64.h" +#include "app_helper.h" using namespace nghttp2; @@ -205,6 +206,10 @@ int on_header_callback(nghttp2_session *session, const uint8_t *value, size_t valuelen, void *user_data) { + if(get_config()->upstream_frame_debug) { + verbose_on_header_callback(session, frame, name, namelen, value, valuelen, + user_data); + } if(frame->hd.type != NGHTTP2_HEADERS || frame->headers.cat != NGHTTP2_HCAT_REQUEST) { return 0; @@ -359,6 +364,9 @@ int on_frame_recv_callback (nghttp2_session *session, const nghttp2_frame *frame, void *user_data) { int rv; + if(get_config()->upstream_frame_debug) { + verbose_on_frame_recv_callback(session, frame, user_data); + } auto upstream = static_cast(user_data); switch(frame->hd.type) { case NGHTTP2_DATA: { @@ -428,6 +436,9 @@ namespace { int on_frame_send_callback(nghttp2_session* session, const nghttp2_frame *frame, void *user_data) { + if(get_config()->upstream_frame_debug) { + verbose_on_frame_send_callback(session, frame, user_data); + } auto upstream = static_cast(user_data); if(frame->hd.type == NGHTTP2_SETTINGS && (frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) { From ce53d7bd9edab56d00e5f20ec9e019e0c947acf1 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 21:34:28 +0900 Subject: [PATCH 24/56] src: Don't output priority if NGHTTP2_FLAG_PRIORITY is not set --- src/app_helper.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app_helper.cc b/src/app_helper.cc index 059bde55..e4620bee 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -331,8 +331,11 @@ void print_frame(print_type ptype, const nghttp2_frame *frame) break; case NGHTTP2_HEADERS: print_frame_attr_indent(); - fprintf(outfile, "(pri=%d, padlen=%zu)\n", - frame->headers.pri, frame->headers.padlen); + fprintf(outfile, "("); + if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { + fprintf(outfile, "pri=%d, ", frame->headers.pri); + } + fprintf(outfile, "padlen=%zu)\n", frame->headers.padlen); switch(frame->headers.cat) { case NGHTTP2_HCAT_REQUEST: print_frame_attr_indent(); From 68b5ffc1dcbe6e5c24995d7b6c8903e0b1b5272b Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 21:46:15 +0900 Subject: [PATCH 25/56] Rename padding related names --- lib/includes/nghttp2/nghttp2.h | 10 +++++----- lib/nghttp2_frame.c | 15 ++++++++------- lib/nghttp2_frame.h | 12 ++++++------ lib/nghttp2_session.c | 14 +++++++------- lib/nghttp2_session.h | 4 ++-- src/HttpServer.cc | 6 +++--- src/HttpServer.h | 2 +- src/nghttp.cc | 16 ++++++++-------- src/nghttpd.cc | 8 ++++---- tests/nghttp2_session_test.c | 6 +++--- 10 files changed, 47 insertions(+), 46 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index d268e622..6983b1d4 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -151,9 +151,9 @@ typedef struct { * @macro * * The default value of DATA padding alignment. See - * :member:`NGHTTP2_OPT_PAD_ALIGNMENT`. + * :member:`NGHTTP2_OPT_PADDING_BOUNDARY`. */ -#define NGHTTP2_PAD_ALIGNMENT 16 +#define NGHTTP2_PADDING_BOUNDARY 64 /** * @enum @@ -1341,7 +1341,7 @@ typedef enum { * to this alignment. The option value must be greater than or equal * to 8. */ - NGHTTP2_OPT_PAD_ALIGNMENT = 1 << 3 + NGHTTP2_OPT_PADDING_BOUNDARY = 1 << 3 } nghttp2_opt; /** @@ -1363,9 +1363,9 @@ typedef struct { */ uint8_t no_auto_connection_window_update; /** - * :enum:`NGHTTP2_OPT_PAD_ALIGNMENT` + * :enum:`NGHTTP2_OPT_PADDING_BOUNDARY` */ - uint16_t pad_alignment; + uint16_t padding_boundary; } nghttp2_opt_set; /** diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index 1d656081..6cdcf3ec 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -228,7 +228,7 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, size_t *bufoff_ptr, nghttp2_headers *frame, nghttp2_hd_deflater *deflater, - size_t align) + size_t boundary) { size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2; size_t nv_offset = @@ -244,13 +244,13 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, payloadlen = nghttp2_frame_headers_payload_nv_offset(frame) + rv; - if(align > 0) { + if(boundary > 0) { ssize_t padlen; padlen = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, &frame->hd.flags, payloadlen, - payloadlen + align, - align); + payloadlen + boundary, + boundary); if(padlen < 0) { return padlen; } @@ -665,11 +665,12 @@ ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, uint8_t *flags_ptr, size_t payloadlen, size_t payloadmax, - size_t align) + size_t boundary) { int rv; - size_t nextlen = nghttp2_min((payloadlen + align - 1) / align * align, - payloadmax); + size_t nextlen = + nghttp2_min((payloadlen + boundary - 1) / boundary * boundary, + payloadmax); size_t padlen = nextlen - payloadlen; size_t trail_padlen = 0; /* extra 2 bytes for PAD_HIGH and PAD_LOW. */ diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index 92d6f0fa..4aa592f6 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -107,8 +107,8 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame); * The first byte the frame is serialized is returned in the * |*bufoff_ptr|. * - * The |align| is used as padding alignment. If the |align| is zero, - * no padding is added. + * The |boundary| is used as padding boundary. If the |boundary| is + * zero, no padding is added. * * frame->hd.length is assigned after length is determined during * packing process. If payload length is strictly larger than @@ -132,7 +132,7 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, size_t *bufoff_ptr, nghttp2_headers *frame, nghttp2_hd_deflater *deflater, - size_t align); + size_t boundary); /* * Unpacks HEADERS frame byte sequence into |frame|. This function @@ -508,8 +508,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); * payload must start at offset NGHTTP2_FRAME_HEAD_LENGTH + 2 from * |*buf_ptr| to account for PAD_HIGH and PAD_LOW. The maximum payload * allowed is given in the |payloadmax|. The padding will not be made - * more than |payloadmax|. The padding alignment is given in the - * |align|. + * more than |payloadmax|. The padding boundary is given in the + * |boundary|. * * The |*flags_ptr| is updated to include NGHTTP2_FLAG_PAD_LOW and * NGHTTP2_FLAG_PAD_HIGH based on the padding length. The @@ -582,6 +582,6 @@ ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, uint8_t *flags_ptr, size_t payloadlen, size_t payloadmax, - size_t align); + size_t boundary); #endif /* NGHTTP2_FRAME_H */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 76cfbfcc..52fa3267 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -224,11 +224,11 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE; } - if((opt_set_mask & NGHTTP2_OPT_PAD_ALIGNMENT) && - opt_set->pad_alignment >= 8) { - (*session_ptr)->pad_alignment = opt_set->pad_alignment; + if((opt_set_mask & NGHTTP2_OPT_PADDING_BOUNDARY) && + opt_set->padding_boundary >= 8) { + (*session_ptr)->padding_boundary = opt_set->padding_boundary; } else { - (*session_ptr)->pad_alignment = NGHTTP2_PAD_ALIGNMENT; + (*session_ptr)->padding_boundary = NGHTTP2_PADDING_BOUNDARY; } (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; @@ -1123,7 +1123,7 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, &session->aob.framebufoff, &frame->headers, &session->hd_deflater, - session->pad_alignment); + session->padding_boundary); if(framebuflen < 0) { return framebuflen; } @@ -4227,11 +4227,11 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, frame->hd.flags &= ~(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); flags = 0; - if(session->pad_alignment && + if(session->padding_boundary && payloadlen > 0 && (size_t)payloadlen < datamax) { rv = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, &flags, payloadlen, datamax, - session->pad_alignment); + session->padding_boundary); if(rv < 0) { return rv; } diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index a205cb60..d17b8105 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -153,8 +153,8 @@ struct nghttp2_session { size_t num_incoming_streams; /* The number of bytes allocated for nvbuf */ size_t nvbuflen; - /* padding alignemnt. See NGHTTP2_OPT_PAD_ALIGNMENT. */ - size_t pad_alignment; + /* padding alignemnt. See NGHTTP2_OPT_PADDING_BOUNDARY. */ + size_t padding_boundary; /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */ uint32_t next_stream_id; /* The largest stream ID received so far */ diff --git a/src/HttpServer.cc b/src/HttpServer.cc index df09f4e4..4fb59244 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -66,7 +66,7 @@ const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION; Config::Config() : data_ptr(nullptr), output_upper_thres(1024*1024), - pad_alignment(NGHTTP2_PAD_ALIGNMENT), + padding_boundary(NGHTTP2_PADDING_BOUNDARY), header_table_size(-1), port(0), verbose(false), @@ -365,11 +365,11 @@ int Http2Handler::on_connect() nghttp2_opt_set opt_set; memset(&opt_set, 0, sizeof(opt_set)); - opt_set.pad_alignment = sessions_->get_config()->pad_alignment; + opt_set.padding_boundary = sessions_->get_config()->padding_boundary; fill_callback(callbacks, sessions_->get_config()); r = nghttp2_session_server_new2(&session_, &callbacks, this, - NGHTTP2_OPT_PAD_ALIGNMENT, &opt_set); + NGHTTP2_OPT_PADDING_BOUNDARY, &opt_set); if(r != 0) { return r; } diff --git a/src/HttpServer.h b/src/HttpServer.h index ad5feefa..308d3b10 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -56,7 +56,7 @@ struct Config { std::string cert_file; void *data_ptr; size_t output_upper_thres; - size_t pad_alignment; + size_t padding_boundary; ssize_t header_table_size; uint16_t port; bool verbose; diff --git a/src/nghttp.cc b/src/nghttp.cc index 27837404..197b4c26 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -82,7 +82,7 @@ struct Config { std::string keyfile; std::string datafile; size_t output_upper_thres; - size_t pad_alignment; + size_t padding_boundary; ssize_t peer_max_concurrent_streams; ssize_t header_table_size; int32_t pri; @@ -100,7 +100,7 @@ struct Config { bool continuation; Config() : output_upper_thres(1024*1024), - pad_alignment(NGHTTP2_PAD_ALIGNMENT), + padding_boundary(NGHTTP2_PADDING_BOUNDARY), peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS), header_table_size(-1), pri(NGHTTP2_PRI_DEFAULT), @@ -716,10 +716,10 @@ struct HttpClient { } nghttp2_opt_set opt_set; opt_set.peer_max_concurrent_streams = config.peer_max_concurrent_streams; - opt_set.pad_alignment = config.pad_alignment; + opt_set.padding_boundary = config.padding_boundary; rv = nghttp2_session_client_new2(&session, callbacks, this, NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS | - NGHTTP2_OPT_PAD_ALIGNMENT, + NGHTTP2_OPT_PADDING_BOUNDARY, &opt_set); if(rv != 0) { return -1; @@ -1710,8 +1710,8 @@ void print_help(std::ostream& out) << " is large enough as it is seen as unlimited.\n" << " -c, --header-table-size=\n" << " Specify decoder header table size.\n" - << " -b, --pad=\n" - << " Alignment of frame payload padding.\n" + << " -b, --padding=\n" + << " Padding boundary for frame payload.\n" << " --color Force colored log output.\n" << " --continuation Send large header to test CONTINUATION.\n" << std::endl; @@ -1740,7 +1740,7 @@ int main(int argc, char **argv) {"pri", required_argument, nullptr, 'p'}, {"peer-max-concurrent-streams", required_argument, nullptr, 'M'}, {"header-table-size", required_argument, nullptr, 'c'}, - {"data-pad", required_argument, nullptr, 'b'}, + {"padding", required_argument, nullptr, 'b'}, {"cert", required_argument, &flag, 1}, {"key", required_argument, &flag, 2}, {"color", no_argument, &flag, 3}, @@ -1766,7 +1766,7 @@ int main(int argc, char **argv) print_help(std::cout); exit(EXIT_SUCCESS); case 'b': - config.pad_alignment = strtol(optarg, nullptr, 10); + config.padding_boundary = strtol(optarg, nullptr, 10); break; case 'n': config.null_out = true; diff --git a/src/nghttpd.cc b/src/nghttpd.cc index 741475d0..2287171d 100644 --- a/src/nghttpd.cc +++ b/src/nghttpd.cc @@ -115,8 +115,8 @@ void print_help(std::ostream& out) << " -p/=/foo.png -p/doc=/bar.css\n" << " PATH and PUSH_PATHs are relative to document\n" << " root. See --htdocs option.\n" - << " -b, --pad=\n" - << " Alignment of frame payload padding.\n" + << " -b, --padding=\n" + << " Padding boundary for frame payload.\n" << " -h, --help Print this help.\n" << std::endl; } @@ -136,7 +136,7 @@ int main(int argc, char **argv) {"verify-client", no_argument, nullptr, 'V'}, {"header-table-size", required_argument, nullptr, 'c'}, {"push", required_argument, nullptr, 'p'}, - {"data-pad", required_argument, nullptr, 'b'}, + {"padding", required_argument, nullptr, 'b'}, {"no-tls", no_argument, &flag, 1}, {"color", no_argument, &flag, 2}, {nullptr, 0, nullptr, 0} @@ -155,7 +155,7 @@ int main(int argc, char **argv) config.verify_client = true; break; case 'b': - config.pad_alignment = strtol(optarg, nullptr, 10); + config.padding_boundary = strtol(optarg, nullptr, 10); break; case 'd': config.htdocs = optarg; diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 7bc2b8d3..e30c7e0f 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -3870,7 +3870,7 @@ void test_nghttp2_session_pack_data_with_padding(void) data_prd.read_callback = fixed_length_data_source_read_callback; nghttp2_session_client_new(&session, &callbacks, &ud); - session->pad_alignment = 512; + session->padding_boundary = 512; nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, &data_prd, NULL); @@ -3881,7 +3881,7 @@ void test_nghttp2_session_pack_data_with_padding(void) CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type); frame = OB_DATA(session->aob.item); - CU_ASSERT(session->pad_alignment - datalen == frame->padlen); + CU_ASSERT(session->padding_boundary - datalen == frame->padlen); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH); @@ -3905,7 +3905,7 @@ void test_nghttp2_session_pack_data_with_padding(void) CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type); frame = OB_DATA(session->aob.item); - CU_ASSERT((frame->padlen + datalen) % session->pad_alignment == 0); + CU_ASSERT((frame->padlen + datalen) % session->padding_boundary == 0); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); CU_ASSERT(0 == (frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH)); From 5b58b4ace5919c825a38c34824c655f2eb99aaeb Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 22:01:07 +0900 Subject: [PATCH 26/56] Add padding if payload length is zero --- lib/nghttp2_frame.c | 3 ++- lib/nghttp2_session.c | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index 6cdcf3ec..f365984f 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -669,7 +669,8 @@ ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, { int rv; size_t nextlen = - nghttp2_min((payloadlen + boundary - 1) / boundary * boundary, + nghttp2_min(((payloadlen == 0 ? 1 : payloadlen) + boundary - 1) + / boundary * boundary, payloadmax); size_t padlen = nextlen - payloadlen; size_t trail_padlen = 0; diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 52fa3267..0bfa2ede 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -4227,8 +4227,7 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, frame->hd.flags &= ~(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); flags = 0; - if(session->padding_boundary && - payloadlen > 0 && (size_t)payloadlen < datamax) { + if(session->padding_boundary && (size_t)payloadlen < datamax) { rv = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, &flags, payloadlen, datamax, session->padding_boundary); From 118ed09da5d322f37d6d3b31fe1139c9ed60a2f4 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Feb 2014 23:53:53 +0900 Subject: [PATCH 27/56] Allow disabling padding --- lib/includes/nghttp2/nghttp2.h | 3 +-- lib/nghttp2_session.c | 3 +-- src/nghttp.cc | 3 ++- src/nghttpd.cc | 3 ++- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 6983b1d4..b24217ad 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -1338,8 +1338,7 @@ typedef enum { * payload. If this option is set to N, padding is added to frame * payload so that its payload length is divisible by N. For DATA * frame, due to flow control, padding is not always added according - * to this alignment. The option value must be greater than or equal - * to 8. + * to this alignment. Specifying 0 to this option disables padding. */ NGHTTP2_OPT_PADDING_BOUNDARY = 1 << 3 } nghttp2_opt; diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 0bfa2ede..609297d6 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -224,8 +224,7 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE; } - if((opt_set_mask & NGHTTP2_OPT_PADDING_BOUNDARY) && - opt_set->padding_boundary >= 8) { + if(opt_set_mask & NGHTTP2_OPT_PADDING_BOUNDARY) { (*session_ptr)->padding_boundary = opt_set->padding_boundary; } else { (*session_ptr)->padding_boundary = NGHTTP2_PADDING_BOUNDARY; diff --git a/src/nghttp.cc b/src/nghttp.cc index 197b4c26..dcd9d8ae 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -1711,7 +1711,8 @@ void print_help(std::ostream& out) << " -c, --header-table-size=\n" << " Specify decoder header table size.\n" << " -b, --padding=\n" - << " Padding boundary for frame payload.\n" + << " Padding boundary for frame payload. Specify\n" + << " 0 to disable padding.\n" << " --color Force colored log output.\n" << " --continuation Send large header to test CONTINUATION.\n" << std::endl; diff --git a/src/nghttpd.cc b/src/nghttpd.cc index 2287171d..30bbeb0e 100644 --- a/src/nghttpd.cc +++ b/src/nghttpd.cc @@ -116,7 +116,8 @@ void print_help(std::ostream& out) << " PATH and PUSH_PATHs are relative to document\n" << " root. See --htdocs option.\n" << " -b, --padding=\n" - << " Padding boundary for frame payload.\n" + << " Padding boundary for frame payload. Specify\n" + << " 0 to disable padding.\n" << " -h, --help Print this help.\n" << std::endl; } From 78d202ac3002d09a883cb01b3246d944a401c9cd Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 15:28:44 +0900 Subject: [PATCH 28/56] Callback based padding from application Now previous padding options are removed and instead we added select_padding_callback to select padding length for each frame by application. If this callback is not implemented by application, no padding is added. This change also fixes the broken session_detect_idle_stream() if stream_id is our side. --- lib/includes/nghttp2/nghttp2.h | 47 +++++---- lib/nghttp2_frame.c | 62 ++++------- lib/nghttp2_frame.h | 32 +++--- lib/nghttp2_session.c | 185 ++++++++++++++++++++++++--------- lib/nghttp2_session.h | 2 - src/HttpServer.cc | 28 +++-- src/nghttp.cc | 35 ++++--- tests/main.c | 2 - tests/nghttp2_frame_test.c | 134 +----------------------- tests/nghttp2_frame_test.h | 1 - tests/nghttp2_session_test.c | 59 +++++++---- tests/nghttp2_test_helper.c | 5 - tests/nghttp2_test_helper.h | 3 - 13 files changed, 282 insertions(+), 313 deletions(-) diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index b24217ad..e81c1d58 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -147,14 +147,6 @@ typedef struct { */ #define NGHTTP2_CLIENT_CONNECTION_HEADER_LEN 24 -/** - * @macro - * - * The default value of DATA padding alignment. See - * :member:`NGHTTP2_OPT_PADDING_BOUNDARY`. - */ -#define NGHTTP2_PADDING_BOUNDARY 64 - /** * @enum * @@ -1184,6 +1176,26 @@ typedef int (*nghttp2_on_header_callback) const uint8_t *value, size_t valuelen, void *user_data); +/** + * @functypedef + * + * Callback function invoked when the library asks application how + * much padding is required for the transmission of the |frame|. The + * application must choose the total length of payload including + * padded bytes in range [frame->hd.length, max_payloadlen], + * inclusive. Choosing number not in this range will be treated as + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. Returning + * ``frame->hd.length`` means no padding is added. Returning + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make + * `nghttp2_session_send()` function immediately return + * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`. + */ +typedef ssize_t (*nghttp2_select_padding_callback) +(nghttp2_session *session, + const nghttp2_frame *frame, + size_t max_payloadlen, + void *user_data); + /** * @struct * @@ -1247,6 +1259,11 @@ typedef struct { * received. */ nghttp2_on_header_callback on_header_callback; + /** + * Callback function invoked when the library asks application how + * much padding is required for the transmission of the given frame. + */ + nghttp2_select_padding_callback select_padding_callback; } nghttp2_session_callbacks; /** @@ -1332,15 +1349,7 @@ typedef enum { * will be overwritten if the local endpoint receives * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint. */ - NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 2, - /** - * This option specifies the alignment of padding in frame - * payload. If this option is set to N, padding is added to frame - * payload so that its payload length is divisible by N. For DATA - * frame, due to flow control, padding is not always added according - * to this alignment. Specifying 0 to this option disables padding. - */ - NGHTTP2_OPT_PADDING_BOUNDARY = 1 << 3 + NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 2 } nghttp2_opt; /** @@ -1361,10 +1370,6 @@ typedef struct { * :enum:`NGHTTP2_OPT_NO_AUTO_CONNECTION_WINDOW_UPDATE` */ uint8_t no_auto_connection_window_update; - /** - * :enum:`NGHTTP2_OPT_PADDING_BOUNDARY` - */ - uint16_t padding_boundary; } nghttp2_opt_set; /** diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index f365984f..077ae1e6 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -227,8 +227,7 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr, size_t *bufoff_ptr, nghttp2_headers *frame, - nghttp2_hd_deflater *deflater, - size_t boundary) + nghttp2_hd_deflater *deflater) { size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2; size_t nv_offset = @@ -244,23 +243,9 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, payloadlen = nghttp2_frame_headers_payload_nv_offset(frame) + rv; - if(boundary > 0) { - ssize_t padlen; - padlen = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, - &frame->hd.flags, - payloadlen, - payloadlen + boundary, - boundary); - if(padlen < 0) { - return padlen; - } - frame->padlen = padlen; - frame->hd.length = payloadlen + padlen; - } else { - *bufoff_ptr = 2; - frame->padlen = 0; - frame->hd.length = payloadlen; - } + *bufoff_ptr = 2; + frame->padlen = 0; + frame->hd.length = payloadlen; /* If frame->nvlen == 0, *buflen_ptr may be smaller than nv_offset */ rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset); @@ -269,11 +254,11 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, } memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH); /* pack ctrl header after length is determined */ - if(NGHTTP2_FRAME_HEAD_LENGTH + NGHTTP2_MAX_FRAME_LENGTH < rv + nv_offset) { + if(NGHTTP2_MAX_FRAME_LENGTH < payloadlen) { /* Needs CONTINUATION */ nghttp2_frame_hd hd = frame->hd; - hd.flags &= ~(NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); + hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; + hd.length = NGHTTP2_MAX_FRAME_LENGTH; nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd); } else { nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd); @@ -660,36 +645,31 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) return 1; } -ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, - size_t *bufoff_ptr, - uint8_t *flags_ptr, - size_t payloadlen, - size_t payloadmax, - size_t boundary) +int nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, + uint8_t *flags_ptr, + size_t payloadlen, + size_t padlen) { int rv; - size_t nextlen = - nghttp2_min(((payloadlen == 0 ? 1 : payloadlen) + boundary - 1) - / boundary * boundary, - payloadmax); - size_t padlen = nextlen - payloadlen; size_t trail_padlen = 0; /* extra 2 bytes for PAD_HIGH and PAD_LOW. */ - size_t trail_padoff = 2 + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen; + size_t trail_padoff = *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + payloadlen; if(padlen > 257) { - *bufoff_ptr = 0; + uint8_t *p; + *bufoff_ptr -= 2; trail_padlen = padlen - 2; *flags_ptr |= NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW; - (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen >> 8; - (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen & 0xff; + p = *buf_ptr + *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH; + *p++ = trail_padlen >> 8; + *p = trail_padlen & 0xff; } else if(padlen > 0) { - *bufoff_ptr = 1; + --*bufoff_ptr; trail_padlen = padlen - 1; *flags_ptr |= NGHTTP2_FLAG_PAD_LOW; - (*buf_ptr)[NGHTTP2_FRAME_HEAD_LENGTH + 1] = trail_padlen; + (*buf_ptr)[*bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH] = trail_padlen; } else { - *bufoff_ptr = 2; return 0; } @@ -702,5 +682,5 @@ ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, possible internal data to the remote peer */ memset((*buf_ptr) + trail_padoff, 0, trail_padlen); - return padlen; + return 0; } diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index 4aa592f6..ee0e0b84 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -105,10 +105,8 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame); * change. |*buf_ptr| and |*buflen_ptr| are updated accordingly. * * The first byte the frame is serialized is returned in the - * |*bufoff_ptr|. - * - * The |boundary| is used as padding boundary. If the |boundary| is - * zero, no padding is added. + * |*bufoff_ptr|. Currently, it is always 2 to account for possible + * PAD_HIGH and PAD_LOW. * * frame->hd.length is assigned after length is determined during * packing process. If payload length is strictly larger than @@ -131,8 +129,7 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, size_t *buflen_ptr, size_t *bufoff_ptr, nghttp2_headers *frame, - nghttp2_hd_deflater *deflater, - size_t boundary); + nghttp2_hd_deflater *deflater); /* * Unpacks HEADERS frame byte sequence into |frame|. This function @@ -505,11 +502,10 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); /* * Add padding to the payload in the |*buf_ptr| of length * |*buflen_ptr|. The payload length is given in |payloadlen|. The - * payload must start at offset NGHTTP2_FRAME_HEAD_LENGTH + 2 from - * |*buf_ptr| to account for PAD_HIGH and PAD_LOW. The maximum payload - * allowed is given in the |payloadmax|. The padding will not be made - * more than |payloadmax|. The padding boundary is given in the - * |boundary|. + * frame header starts at offset |*bufoff_ptr|. Therefore, the payload + * must start at offset *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH from + * |*buf_ptr| to account for PAD_HIGH and PAD_LOW. The padding is + * given in the |padlen|. * * The |*flags_ptr| is updated to include NGHTTP2_FLAG_PAD_LOW and * NGHTTP2_FLAG_PAD_HIGH based on the padding length. The @@ -570,18 +566,14 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv); * additional copy operation is required (if the |*buf_ptr| is large * enough to account the additional padding, of course). * - * This function returns the number of padding added to the payload - * including PAD_HIGH and PAD_LOW if it succeeds, or one of the - * following negative error codes: + * This function returns 0 if it succeeds, or one of the following + * negative error codes: * * NGHTTP2_ERR_NOMEM * Out of memory. */ -ssize_t nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, - size_t *bufoff_ptr, - uint8_t *flags_ptr, - size_t payloadlen, - size_t payloadmax, - size_t boundary); +int nghttp2_frame_add_pad(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, uint8_t *flags_ptr, + size_t payloadlen, size_t padlen); #endif /* NGHTTP2_FRAME_H */ diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 609297d6..2d666ac1 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -224,11 +224,6 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, (*session_ptr)->opt_flags |= NGHTTP2_OPTMASK_NO_AUTO_CONNECTION_WINDOW_UPDATE; } - if(opt_set_mask & NGHTTP2_OPT_PADDING_BOUNDARY) { - (*session_ptr)->padding_boundary = opt_set->padding_boundary; - } else { - (*session_ptr)->padding_boundary = NGHTTP2_PADDING_BOUNDARY; - } (*session_ptr)->remote_window_size = NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE; (*session_ptr)->recv_window_size = 0; @@ -1080,6 +1075,23 @@ static int nghttp2_session_predicate_data_send(nghttp2_session *session, return NGHTTP2_ERR_INVALID_STREAM_STATE; } +static ssize_t session_call_select_padding(nghttp2_session *session, + const nghttp2_frame *frame, + size_t max_payloadlen) +{ + ssize_t rv; + if(session->callbacks.select_padding_callback) { + rv = session->callbacks.select_padding_callback(session, frame, + max_payloadlen, + session->user_data); + if(rv < frame->hd.length || rv > max_payloadlen) { + return NGHTTP2_ERR_CALLBACK_FAILURE; + } + return rv; + } + return frame->hd.length; +} + static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, nghttp2_outbound_item *item) { @@ -1089,11 +1101,12 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, frame = nghttp2_outbound_item_get_ctrl_frame(item); switch(frame->hd.type) { case NGHTTP2_HEADERS: { + int r; nghttp2_headers_aux_data *aux_data; + ssize_t padded_payloadlen; aux_data = (nghttp2_headers_aux_data*)item->aux_data; if(frame->hd.stream_id == -1) { /* initial HEADERS, which opens stream */ - int r; frame->headers.cat = NGHTTP2_HCAT_REQUEST; r = nghttp2_session_predicate_request_headers_send(session, &frame->headers); @@ -1109,7 +1122,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, (session, frame->hd.stream_id) == 0) { frame->headers.cat = NGHTTP2_HCAT_RESPONSE; } else { - int r; frame->headers.cat = NGHTTP2_HCAT_HEADERS; r = nghttp2_session_predicate_headers_send(session, frame->hd.stream_id); @@ -1121,11 +1133,47 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, &session->aob.framebufmax, &session->aob.framebufoff, &frame->headers, - &session->hd_deflater, - session->padding_boundary); + &session->hd_deflater); if(framebuflen < 0) { return framebuflen; } + padded_payloadlen = session_call_select_padding + (session, frame, + (frame->hd.length == 0 ? NGHTTP2_MAX_FRAME_LENGTH : + (frame->hd.length + NGHTTP2_MAX_FRAME_LENGTH - 1) + / NGHTTP2_MAX_FRAME_LENGTH * NGHTTP2_MAX_FRAME_LENGTH)); + if(nghttp2_is_fatal(padded_payloadlen)) { + return padded_payloadlen; + } + + frame->headers.padlen = padded_payloadlen - frame->hd.length; + frame->hd.length = padded_payloadlen; + + if(frame->hd.length > NGHTTP2_MAX_FRAME_LENGTH) { + /* PAD_HIGH and PAD_LOW will be added in + nghttp2_session_after_frame_sent(). */ + /* This may make framebuflen > session->aob.framebufmax. But + before we access the missing part, we will allocate it in + nghttp2_session_after_frame_sent(). */ + framebuflen += frame->headers.padlen; + } else if(frame->hd.length <= NGHTTP2_MAX_FRAME_LENGTH && + padded_payloadlen > frame->hd.length) { + r = nghttp2_frame_add_pad(&session->aob.framebuf, + &session->aob.framebufmax, + &session->aob.framebufoff, + &frame->hd.flags, + frame->hd.length, + padded_payloadlen - frame->hd.length); + if(nghttp2_is_fatal(r)) { + return r; + } + framebuflen = session->aob.framebufoff + frame->hd.length + + NGHTTP2_FRAME_HEAD_LENGTH; + + nghttp2_frame_pack_frame_hd + (session->aob.framebuf + session->aob.framebufoff, &frame->hd); + } + switch(frame->headers.cat) { case NGHTTP2_HCAT_REQUEST: { if(nghttp2_session_open_stream @@ -1444,21 +1492,38 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) session->aob.framebufmark, NGHTTP2_MAX_FRAME_LENGTH); cont_hd.type = NGHTTP2_CONTINUATION; + cont_hd.stream_id = frame->hd.stream_id; + /* Reuse previous buffers for frame header */ + session->aob.framebufoff -= NGHTTP2_FRAME_HEAD_LENGTH; if(cont_hd.length + session->aob.framebufmark == session->aob.framebuflen) { + DEBUGF(fprintf(stderr, + "last CONTINUATION payloadlen=%zu, padlen=%zu\n", + cont_hd.length, frame->headers.padlen)); + cont_hd.flags = NGHTTP2_FLAG_END_HEADERS; - cont_hd.flags |= - (NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW) & frame->hd.flags; + rv = nghttp2_frame_add_pad(&session->aob.framebuf, + &session->aob.framebufmax, + &session->aob.framebufoff, + &cont_hd.flags, + cont_hd.length - frame->headers.padlen, + frame->headers.padlen); + if(nghttp2_is_fatal(rv)) { + return rv; + } + /* we reuses previous up to 2 bytes for PAD_HIGH and + PAD_LOW. Because of this, session->aob.framebuflen is 1 + or 2 bytes longer. Re-compute the value here. */ + session->aob.framebuflen = session->aob.framebufmark = + session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH + + cont_hd.length; } else { cont_hd.flags = NGHTTP2_FLAG_NONE; + session->aob.framebufmark += cont_hd.length; } - cont_hd.stream_id = frame->hd.stream_id; nghttp2_frame_pack_frame_hd(session->aob.framebuf + - session->aob.framebufmark - - NGHTTP2_FRAME_HEAD_LENGTH, + session->aob.framebufoff, &cont_hd); - session->aob.framebufmark += cont_hd.length; - session->aob.framebufoff -= NGHTTP2_FRAME_HEAD_LENGTH; return 0; } } @@ -1754,9 +1819,13 @@ int nghttp2_session_send(nghttp2_session *session) if(item->frame_cat == NGHTTP2_CAT_CTRL) { nghttp2_frame *frame = nghttp2_outbound_item_get_ctrl_frame(item); + /* We have to get frame size from headers, because + frame->hd.length does not always shows the actual frame + size, especially for HEADERS size > + NGHTTP2_MAX_FRAME_LENGTH */ session->aob.framebufmark = - session->aob.framebufoff + - frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH; + session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH + + nghttp2_get_uint16(session->aob.framebuf + session->aob.framebufoff); r = session_call_before_frame_send(session, frame); if(nghttp2_is_fatal(r)) { return r; @@ -1766,8 +1835,8 @@ int nghttp2_session_send(nghttp2_session *session) frame = nghttp2_outbound_item_get_data_frame(session->aob.item); /* session->aob.framebufmark = session->aob.framebuflen; */ session->aob.framebufmark = - session->aob.framebufoff + - frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH; + session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH + + frame->hd.length; } } @@ -1887,7 +1956,7 @@ static int session_detect_idle_stream(nghttp2_session *session, { /* Assume that stream object with stream_id does not exist */ if(nghttp2_session_is_my_stream_id(session, stream_id)) { - if(session->next_stream_id >= (uint32_t)stream_id) { + if(session->next_stream_id <= (uint32_t)stream_id) { return 1; } return 0; @@ -2812,7 +2881,7 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, if(!stream || stream->state == NGHTTP2_STREAM_CLOSING) { if(!stream) { if(session_detect_idle_stream(session, frame->hd.stream_id)) { - return nghttp2_session_handle_invalid_connection + return nghttp2_session_inflate_handle_invalid_connection (session, frame, NGHTTP2_PROTOCOL_ERROR); } } @@ -3327,11 +3396,13 @@ static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, } iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->left = 2; + iframe->buflen = 0; return 1; } if(hd->flags & NGHTTP2_FLAG_PAD_LOW) { iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->left = 1; + iframe->buflen = 0; return 1; } DEBUGF(fprintf(stderr, "no padding\n")); @@ -3353,7 +3424,8 @@ static ssize_t inbound_frame_compute_pad(nghttp2_inbound_frame *iframe) } ++padlen; DEBUGF(fprintf(stderr, "padlen=%zu\n", padlen)); - if(padlen > iframe->frame.hd.length) { + /* We cannot use iframe->frame.hd.length because of CONTINUATION */ + if(padlen - (padlen > 255) - 1 > iframe->payloadleft) { return -1; } iframe->padlen = padlen; @@ -3837,7 +3909,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, nghttp2_inbound_frame_reset(session); break; case NGHTTP2_IB_EXPECT_CONTINUATION: - case NGHTTP2_IB_IGN_CONTINUATION: + case NGHTTP2_IB_IGN_CONTINUATION: { + nghttp2_inbound_state state_back; #ifdef DEBUGBUILD if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { fprintf(stderr, "[IB_EXPECT_CONTINUATION]\n"); @@ -3872,7 +3945,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->frame.hd.flags |= cont_hd.flags & (NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); + iframe->frame.hd.length += cont_hd.length; + state_back = iframe->state; rv = inbound_frame_handle_pad(iframe, &cont_hd); if(rv < 0) { busy = 1; @@ -3885,7 +3960,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } if(rv == 1) { - if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { + if(state_back == NGHTTP2_IB_EXPECT_CONTINUATION) { iframe->state = NGHTTP2_IB_READ_PAD_CONTINUATION; } else { iframe->state = NGHTTP2_IB_IGN_PAD_CONTINUATION; @@ -3900,6 +3975,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; } break; + } case NGHTTP2_IB_READ_PAD_CONTINUATION: case NGHTTP2_IB_IGN_PAD_CONTINUATION: #ifdef DEBUGBUILD @@ -4192,16 +4268,22 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, size_t datamax, nghttp2_private_data *frame) { - /* extra 2 bytes for PAD_HIGH and PAD_LOW. We allocate extra 2 bytes - for padding. Based on the padding length, we adjust the starting - offset of frame data. The starting offset is assigned into - |*bufoff_ptr|. */ - size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2; - ssize_t framelen = payloadoff + datamax; + size_t payloadoff; + ssize_t framelen; ssize_t rv; int eof_flags; uint8_t flags; ssize_t payloadlen; + ssize_t padded_payloadlen; + nghttp2_frame data_frame; + + /* extra 2 bytes for PAD_HIGH and PAD_LOW. We allocate extra 2 bytes + for padding. Based on the padding length, we adjust the starting + offset of frame data. The starting offset is assigned into + |*bufoff_ptr|. */ + *bufoff_ptr = 2; + payloadoff = *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH; + framelen = payloadoff + datamax; rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, framelen); if(rv != 0) { @@ -4226,21 +4308,32 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, frame->hd.flags &= ~(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); flags = 0; - if(session->padding_boundary && (size_t)payloadlen < datamax) { - rv = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, - &flags, payloadlen, datamax, - session->padding_boundary); - if(rv < 0) { - return rv; + if(eof_flags) { + frame->eof = 1; + if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { + flags |= NGHTTP2_FLAG_END_STREAM; } - frame->padlen = rv; - frame->hd.length = payloadlen + rv; - } else { - *bufoff_ptr = 2; - frame->padlen = 0; - frame->hd.length = payloadlen; } + memset(&data_frame, 0, sizeof(data_frame)); + data_frame.hd.length = payloadlen; + data_frame.hd.stream_id = frame->hd.stream_id; + data_frame.hd.type = NGHTTP2_DATA; + data_frame.hd.flags = flags; + + padded_payloadlen = session_call_select_padding(session, &data_frame, + datamax); + if(nghttp2_is_fatal(padded_payloadlen)) { + return padded_payloadlen; + } + rv = nghttp2_frame_add_pad(buf_ptr, buflen_ptr, bufoff_ptr, &flags, + payloadlen, padded_payloadlen - payloadlen); + if(nghttp2_is_fatal(rv)) { + return rv; + } + frame->padlen = padded_payloadlen - payloadlen; + frame->hd.length = padded_payloadlen; + /* Set PAD flags so that we can supply frame to the callback with the correct flags */ frame->hd.flags |= flags; @@ -4248,12 +4341,6 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH); nghttp2_put_uint16be(&(*buf_ptr)[*bufoff_ptr], frame->hd.length); - if(eof_flags) { - frame->eof = 1; - if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { - flags |= NGHTTP2_FLAG_END_STREAM; - } - } (*buf_ptr)[*bufoff_ptr + 3] = flags; nghttp2_put_uint32be(&(*buf_ptr)[*bufoff_ptr + 4], frame->hd.stream_id); diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index d17b8105..bfa55d5d 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -153,8 +153,6 @@ struct nghttp2_session { size_t num_incoming_streams; /* The number of bytes allocated for nvbuf */ size_t nvbuflen; - /* padding alignemnt. See NGHTTP2_OPT_PADDING_BOUNDARY. */ - size_t padding_boundary; /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */ uint32_t next_stream_id; /* The largest stream ID received so far */ diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 4fb59244..196a0999 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -66,7 +66,7 @@ const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION; Config::Config() : data_ptr(nullptr), output_upper_thres(1024*1024), - padding_boundary(NGHTTP2_PADDING_BOUNDARY), + padding_boundary(0), header_table_size(-1), port(0), verbose(false), @@ -362,14 +362,8 @@ int Http2Handler::on_connect() { int r; nghttp2_session_callbacks callbacks; - nghttp2_opt_set opt_set; - - memset(&opt_set, 0, sizeof(opt_set)); - opt_set.padding_boundary = sessions_->get_config()->padding_boundary; - fill_callback(callbacks, sessions_->get_config()); - r = nghttp2_session_server_new2(&session_, &callbacks, this, - NGHTTP2_OPT_PADDING_BOUNDARY, &opt_set); + r = nghttp2_session_server_new(&session_, &callbacks, this); if(r != 0) { return r; } @@ -931,6 +925,23 @@ int hd_on_frame_send_callback } } // namespace +namespace { +ssize_t select_padding_callback +(nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload, + void *user_data) +{ + auto hd = static_cast(user_data); + auto bd = hd->get_config()->padding_boundary; + if(bd == 0) { + return frame->hd.length; + } + if(frame->hd.length == 0) { + return bd; + } + return std::min(max_payload, (frame->hd.length + bd - 1) / bd * bd); +} +} // namespace + namespace { int on_data_chunk_recv_callback (nghttp2_session *session, uint8_t flags, int32_t stream_id, @@ -977,6 +988,7 @@ void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config) callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback; callbacks.on_header_callback = on_header_callback; callbacks.on_begin_headers_callback = on_begin_headers_callback; + callbacks.select_padding_callback = select_padding_callback; } } // namespace diff --git a/src/nghttp.cc b/src/nghttp.cc index dcd9d8ae..69d35d5b 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -100,7 +100,7 @@ struct Config { bool continuation; Config() : output_upper_thres(1024*1024), - padding_boundary(NGHTTP2_PADDING_BOUNDARY), + padding_boundary(0), peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS), header_table_size(-1), pri(NGHTTP2_PRI_DEFAULT), @@ -716,10 +716,8 @@ struct HttpClient { } nghttp2_opt_set opt_set; opt_set.peer_max_concurrent_streams = config.peer_max_concurrent_streams; - opt_set.padding_boundary = config.padding_boundary; rv = nghttp2_session_client_new2(&session, callbacks, this, - NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS | - NGHTTP2_OPT_PADDING_BOUNDARY, + NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS, &opt_set); if(rv != 0) { return -1; @@ -964,14 +962,10 @@ int submit_request {"accept-encoding", "gzip, deflate"}, {"user-agent", "nghttp2/" NGHTTP2_VERSION}}; if(config.continuation) { - build_headers.emplace_back("continuation-test-1", - std::string(4096, '-')); - build_headers.emplace_back("continuation-test-2", - std::string(4096, '-')); - build_headers.emplace_back("continuation-test-3", - std::string(4096, '-')); - build_headers.emplace_back("continuation-test-4", - std::string(4096, '-')); + for(size_t i = 0; i < 8; ++i) { + build_headers.emplace_back("continuation-test-" + util::utos(i+1), + std::string(4096, '-')); + } } auto num_initial_headers = build_headers.size(); if(req->data_prd) { @@ -1132,6 +1126,22 @@ int before_frame_send_callback } } // namespace +namespace { +ssize_t select_padding_callback +(nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload, + void *user_data) +{ + auto bd = config.padding_boundary; + if(bd == 0) { + return frame->hd.length; + } + if(frame->hd.length == 0) { + return bd; + } + return std::min(max_payload, (frame->hd.length + bd - 1) / bd * bd); +} +} // namespace + namespace { void check_response_header(nghttp2_session *session, Request* req) { @@ -1588,6 +1598,7 @@ int run(char **uris, int n) } callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback; callbacks.on_header_callback = on_header_callback; + callbacks.select_padding_callback = select_padding_callback; std::string prev_scheme; std::string prev_host; diff --git a/tests/main.c b/tests/main.c index 0301c8cb..063c881e 100644 --- a/tests/main.c +++ b/tests/main.c @@ -201,8 +201,6 @@ int main(int argc, char* argv[]) test_nghttp2_frame_pack_headers) || !CU_add_test(pSuite, "frame_pack_headers_frame_too_large", test_nghttp2_frame_pack_headers_frame_too_large) || - !CU_add_test(pSuite, "frame_pack_headers_with_padding", - test_nghttp2_frame_pack_headers_with_padding) || !CU_add_test(pSuite, "frame_pack_priority", test_nghttp2_frame_pack_priority) || !CU_add_test(pSuite, "frame_pack_rst_stream", diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index c8f127fb..cb1f51e6 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -91,7 +91,7 @@ void test_nghttp2_frame_pack_headers() 1000000007, 1 << 20, nva, nvlen); framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, - &deflater, 0); + &deflater); CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, framelen - bufoff)); @@ -117,7 +117,7 @@ void test_nghttp2_frame_pack_headers() /* Next, include PRIORITY flag */ frame.hd.flags |= NGHTTP2_FLAG_PRIORITY; framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, - &deflater, 0); + &deflater); CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, framelen - bufoff)); @@ -173,7 +173,7 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void) 1000000007, 0, nva, nvlen); framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, - &deflater, 0); + &deflater); CU_ASSERT_EQUAL(NGHTTP2_ERR_HEADER_COMP, framelen); nghttp2_frame_headers_free(&frame); @@ -184,134 +184,6 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void) nghttp2_hd_deflate_free(&deflater); } - -void test_nghttp2_frame_pack_headers_with_padding(void) -{ - nghttp2_hd_deflater deflater; - nghttp2_hd_inflater inflater; - nghttp2_headers frame, oframe; - uint8_t *buf = NULL; - size_t buflen = 0; - size_t bufoff; - ssize_t framelen; - nghttp2_nv *nva; - ssize_t nvlen; - nva_out out; - size_t trail_padlen; - size_t header_blocklen; - - nva_out_init(&out); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); - - /* Payload length is 0, so no padding */ - nghttp2_frame_headers_init(&frame, - NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, - 1000000007, NGHTTP2_PRI_DEFAULT, NULL, 0); - framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, - &deflater, 128); - - CU_ASSERT(2 == bufoff); - CU_ASSERT((ssize_t)bufoff + NGHTTP2_FRAME_HEAD_LENGTH == framelen); - - CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, - framelen - bufoff)); - check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, - NGHTTP2_HEADERS, - NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS, - 1000000007, &oframe.hd); - - CU_ASSERT(NGHTTP2_PRI_DEFAULT == oframe.pri); - nghttp2_frame_headers_free(&oframe); - - /* Include priroty */ - frame.hd.flags |= NGHTTP2_FLAG_PRIORITY; - frame.pri = 1000000009; - bufoff = 0; - - framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, - &deflater, 128); - - CU_ASSERT(1 == bufoff); - CU_ASSERT((ssize_t)bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 128 == framelen); - - CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, - framelen - bufoff)); - check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, - NGHTTP2_HEADERS, - NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY | NGHTTP2_FLAG_PAD_LOW, - 1000000007, &oframe.hd); - - CU_ASSERT(1000000009 == oframe.pri); - nghttp2_frame_headers_free(&oframe); - - /* padding more than 256 */ - bufoff = 0; - - framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, - &deflater, 512); - - CU_ASSERT(0 == bufoff); - CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH + 512 == framelen); - - CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, - framelen - bufoff)); - check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, - NGHTTP2_HEADERS, - NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY | - NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW, - 1000000007, &oframe.hd); - - CU_ASSERT(1000000009 == oframe.pri); - nghttp2_frame_headers_free(&oframe); - - /* Include priority + headers */ - nva = headers(); - nvlen = HEADERS_LENGTH; - frame.nva = nva; - frame.nvlen = nvlen; - bufoff = 0; - - framelen = nghttp2_frame_pack_headers(&buf, &buflen, &bufoff, &frame, - &deflater, 512); - - CU_ASSERT(0 == bufoff); - CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH + 512 == framelen); - - CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf + bufoff, - framelen - bufoff)); - check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, - NGHTTP2_HEADERS, - NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS | - NGHTTP2_FLAG_PRIORITY | - NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW, - 1000000007, &oframe.hd); - - CU_ASSERT(1000000009 == oframe.pri); - trail_padlen = (buf[NGHTTP2_FRAME_HEAD_LENGTH] << 8) | - buf[NGHTTP2_FRAME_HEAD_LENGTH + 1]; - - header_blocklen = framelen - NGHTTP2_FRAME_HEAD_LENGTH - 2 - 4 - - trail_padlen; - CU_ASSERT((ssize_t)header_blocklen == - inflate_hd(&inflater, &out, - buf + NGHTTP2_FRAME_HEAD_LENGTH + 2 + 4, - header_blocklen)); - - CU_ASSERT(nvlen == (ssize_t)out.nvlen); - assert_nv_equal(nva, out.nva, nvlen); - - nghttp2_frame_headers_free(&oframe); - nva_out_reset(&out); - - free(buf); - nghttp2_frame_headers_free(&frame); - nghttp2_hd_inflate_free(&inflater); - nghttp2_hd_deflate_free(&deflater); -} - void test_nghttp2_frame_pack_priority(void) { nghttp2_priority frame, oframe; diff --git a/tests/nghttp2_frame_test.h b/tests/nghttp2_frame_test.h index a45732e8..9a04c23d 100644 --- a/tests/nghttp2_frame_test.h +++ b/tests/nghttp2_frame_test.h @@ -27,7 +27,6 @@ void test_nghttp2_frame_pack_headers(void); void test_nghttp2_frame_pack_headers_frame_too_large(void); -void test_nghttp2_frame_pack_headers_with_padding(void); void test_nghttp2_frame_pack_priority(void); void test_nghttp2_frame_pack_rst_stream(void); void test_nghttp2_frame_pack_settings(void); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index e30c7e0f..fcb5c2f5 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -72,6 +72,7 @@ typedef struct { int begin_headers_cb_called; nghttp2_nv nv; size_t data_chunk_len; + size_t padding_boundary; } my_user_data; static void scripted_data_feed_init(scripted_data_feed *df, @@ -202,6 +203,17 @@ static int pause_on_data_chunk_recv_callback(nghttp2_session *session, return NGHTTP2_ERR_PAUSE; } +static ssize_t select_padding_callback(nghttp2_session *session, + const nghttp2_frame *frame, + size_t max_payloadlen, + void *user_data) +{ + my_user_data *ud = (my_user_data*)user_data; + return nghttp2_min(max_payloadlen, + (frame->hd.length + ud->padding_boundary - 1) + / ud->padding_boundary * ud->padding_boundary); +} + static ssize_t fixed_length_data_source_read_callback (nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t len, int *eof, @@ -358,7 +370,7 @@ void test_nghttp2_session_recv(void) 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater, 0); + &deflater); scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); /* Send 1 byte per each read */ @@ -378,7 +390,7 @@ void test_nghttp2_session_recv(void) 5, NGHTTP2_PRI_DEFAULT, NULL, 0); framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater, 0); + &deflater); nghttp2_frame_headers_free(&frame.headers); @@ -440,7 +452,7 @@ void test_nghttp2_session_recv_invalid_stream_id(void) NGHTTP2_PRI_DEFAULT, NULL, 0); framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater, 0); + &deflater); scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); nghttp2_frame_headers_free(&frame.headers); @@ -485,7 +497,7 @@ void test_nghttp2_session_recv_invalid_frame(void) NGHTTP2_PRI_DEFAULT, nva, nvlen); framelen = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater, 0); + &deflater); scripted_data_feed_init(&df, framedata + bufoff, framelen - bufoff); @@ -687,7 +699,7 @@ void test_nghttp2_session_recv_continuation(void) framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, &bufoff, &frame.headers, - &deflater, 0); + &deflater); nghttp2_frame_headers_free(&frame.headers); memcpy(data, framedata + bufoff, 9); @@ -742,7 +754,7 @@ void test_nghttp2_session_recv_continuation(void) 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, &bufoff, &frame.headers, - &deflater, 0); + &deflater); nghttp2_frame_headers_free(&frame.headers); memcpy(data, framedata + bufoff, framedatalen - bufoff); datalen = framedatalen - bufoff; @@ -812,7 +824,7 @@ void test_nghttp2_session_continue(void) 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); framelen1 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater, 0); + &deflater); nghttp2_frame_headers_free(&frame.headers); memcpy(buffer, framedata + bufoff, framelen1 - bufoff); @@ -823,7 +835,7 @@ void test_nghttp2_session_continue(void) 3, NGHTTP2_PRI_DEFAULT, nva, nvlen); framelen2 = nghttp2_frame_pack_headers(&framedata, &framedatalen, &bufoff, &frame.headers, - &deflater, 0); + &deflater); nghttp2_frame_headers_free(&frame.headers); memcpy(buffer + framelen1, framedata + bufoff, framelen2 - bufoff); @@ -963,7 +975,6 @@ void test_nghttp2_session_add_frame(void) acc.length = 0; user_data.acc = &acc; CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &user_data)); - session_disable_pad(session); frame = malloc(sizeof(nghttp2_frame)); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); @@ -1488,11 +1499,17 @@ void test_nghttp2_session_on_push_promise_received(void) CU_ASSERT(0 == user_data.begin_headers_cb_called); CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8)); item = nghttp2_session_get_next_ob_item(session); - CU_ASSERT(NGHTTP2_RST_STREAM == OB_CTRL_TYPE(item)); - CU_ASSERT(8 == OB_CTRL(item)->hd.stream_id); - CU_ASSERT(NGHTTP2_REFUSED_STREAM == OB_CTRL(item)->rst_stream.error_code); + CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item)); + CU_ASSERT(0 == OB_CTRL(item)->hd.stream_id); + CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == OB_CTRL(item)->goaway.error_code); CU_ASSERT(0 == nghttp2_session_send(session)); + nghttp2_session_del(session); + + nghttp2_session_client_new(&session, &callbacks, &user_data); + memset(session->iframe.buf, 0, 4); + session->iframe.buflen = 4; + /* Same ID twice */ stream->state = NGHTTP2_STREAM_OPENING; @@ -2182,7 +2199,7 @@ void test_nghttp2_submit_request_without_data(void) memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); callbacks.send_callback = accumulator_send_callback; CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); - session_disable_pad(session); + nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); CU_ASSERT(0 == nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, nva, ARRLEN(nva), &data_prd, NULL)); @@ -2254,7 +2271,7 @@ void test_nghttp2_submit_response_without_data(void) memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); callbacks.send_callback = accumulator_send_callback; CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud)); - session_disable_pad(session); + nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_RESPONSE); nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM, NGHTTP2_PRI_DEFAULT, @@ -2426,7 +2443,7 @@ void test_nghttp2_submit_headers(void) callbacks.on_frame_send_callback = on_frame_send_callback; CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); - session_disable_pad(session); + nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, @@ -3867,10 +3884,13 @@ void test_nghttp2_session_pack_data_with_padding(void) memset(&callbacks, 0, sizeof(callbacks)); callbacks.send_callback = block_count_send_callback; callbacks.on_frame_send_callback = on_frame_send_callback; + callbacks.select_padding_callback = select_padding_callback; + data_prd.read_callback = fixed_length_data_source_read_callback; nghttp2_session_client_new(&session, &callbacks, &ud); - session->padding_boundary = 512; + + ud.padding_boundary = 512; nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, &data_prd, NULL); @@ -3881,7 +3901,8 @@ void test_nghttp2_session_pack_data_with_padding(void) CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type); frame = OB_DATA(session->aob.item); - CU_ASSERT(session->padding_boundary - datalen == frame->padlen); + + CU_ASSERT(ud.padding_boundary - datalen == frame->padlen); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH); @@ -3896,6 +3917,8 @@ void test_nghttp2_session_pack_data_with_padding(void) /* Check without PAD_HIGH */ nghttp2_session_client_new(&session, &callbacks, &ud); + ud.padding_boundary = 64; + nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, NULL, 0, &data_prd, NULL); ud.block_count = 1; @@ -3905,7 +3928,7 @@ void test_nghttp2_session_pack_data_with_padding(void) CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type); frame = OB_DATA(session->aob.item); - CU_ASSERT((frame->padlen + datalen) % session->padding_boundary == 0); + CU_ASSERT((frame->padlen + datalen) % ud.padding_boundary == 0); CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PAD_LOW); CU_ASSERT(0 == (frame->hd.flags & NGHTTP2_FLAG_PAD_HIGH)); diff --git a/tests/nghttp2_test_helper.c b/tests/nghttp2_test_helper.c index baff5835..79e0edc8 100644 --- a/tests/nghttp2_test_helper.c +++ b/tests/nghttp2_test_helper.c @@ -163,8 +163,3 @@ ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out, nghttp2_hd_inflate_end_headers(inflater); return initial - buflen; } - -void session_disable_pad(nghttp2_session *session) -{ - session->pad_alignment = 0; -} diff --git a/tests/nghttp2_test_helper.h b/tests/nghttp2_test_helper.h index 0f72a4b8..51efa85a 100644 --- a/tests/nghttp2_test_helper.h +++ b/tests/nghttp2_test_helper.h @@ -29,7 +29,6 @@ # include #endif /* HAVE_CONFIG_H */ -#include "nghttp2_session.h" #include "nghttp2_frame.h" #include "nghttp2_hd.h" @@ -76,6 +75,4 @@ void add_out(nva_out *out, nghttp2_nv *nv); ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out, uint8_t *buf, size_t buflen); -void session_disable_pad(nghttp2_session *session); - #endif /* NGHTTP2_TEST_HELPER_H */ From 109b8cedde351e3f6e913794fe4cb1c2bb03eb42 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 16:12:26 +0900 Subject: [PATCH 29/56] Fix compile error and test failures --- tests/nghttp2_frame_test.c | 12 ++++++++---- tests/nghttp2_session_test.c | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index cb1f51e6..56abc95d 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -79,6 +79,7 @@ void test_nghttp2_frame_pack_headers() nghttp2_nv *nva; ssize_t nvlen; nva_out out; + ssize_t nv_offset; nva_out_init(&out); nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); @@ -102,9 +103,10 @@ void test_nghttp2_frame_pack_headers() /* We didn't include PRIORITY flag so priority is not packed */ CU_ASSERT(1 << 30 == oframe.pri); - CU_ASSERT(framelen - (ssize_t)bufoff - 8 == + nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH; + CU_ASSERT(framelen - nv_offset == inflate_hd(&inflater, &out, - buf + bufoff + 8, framelen - bufoff - 8)); + buf + nv_offset, framelen - nv_offset)); CU_ASSERT(7 == out.nvlen); CU_ASSERT(nvnameeq("method", &out.nva[0])); @@ -128,8 +130,10 @@ void test_nghttp2_frame_pack_headers() 1000000007, &oframe.hd); CU_ASSERT(1 << 20 == oframe.pri); - CU_ASSERT(framelen - 12 == - inflate_hd(&inflater, &out, buf + 12, framelen - 12)); + nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 4; + CU_ASSERT(framelen - nv_offset == + inflate_hd(&inflater, &out, + buf + nv_offset, framelen - nv_offset)); nghttp2_nv_array_sort(out.nva, out.nvlen); CU_ASSERT(nvnameeq("method", &out.nva[0])); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 8d457e67..c4b42e4a 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -797,6 +797,7 @@ void test_nghttp2_session_recv_premature_headers(void) my_user_data ud; nghttp2_hd_deflater deflater; nghttp2_outbound_item *item; + size_t bufoff = 0; memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); @@ -808,14 +809,16 @@ void test_nghttp2_session_recv_premature_headers(void) nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); framedatalen = nghttp2_frame_pack_headers(&framedata, &framedatacap, + &bufoff, &frame.headers, &deflater); nghttp2_frame_headers_free(&frame.headers); /* Intentionally feed payload cutting last 1 byte off */ - nghttp2_put_uint16be(framedata, frame.hd.length - 1); - rv = nghttp2_session_mem_recv(session, framedata, framedatalen - 1); - CU_ASSERT((ssize_t)framedatalen - 1 == rv); + nghttp2_put_uint16be(framedata + bufoff, frame.hd.length - 1); + rv = nghttp2_session_mem_recv(session, framedata + bufoff, + framedatalen - bufoff - 1); + CU_ASSERT((ssize_t)framedatalen - bufoff - 1 == rv); item = nghttp2_session_get_next_ob_item(session); CU_ASSERT(NULL != item); From 9865b4690562f84ad318b0f520e85d49523129f0 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 16:24:21 +0900 Subject: [PATCH 30/56] Don't change state in inbound_frame_handle_pad --- lib/nghttp2_session.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 2d666ac1..8ed64586 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3383,9 +3383,10 @@ static int inbound_frame_set_settings_entry(nghttp2_inbound_frame *iframe) } /* - * Checks PAD_HIGH and PAD_LOW flags and set next state - * accordingly. If padding is set, this function returns 1. If no - * padding is set, this function returns 0. On error, returns -1. + * Checks PAD_HIGH and PAD_LOW flags and set iframe->left and + * iframe->buflen accordingly. If padding is set, this function + * returns 1. If no padding is set, this function returns 0. On error, + * returns -1. */ static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, nghttp2_frame_hd *hd) @@ -3394,13 +3395,11 @@ static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, if((hd->flags & NGHTTP2_FLAG_PAD_LOW) == 0) { return -1; } - iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->left = 2; iframe->buflen = 0; return 1; } if(hd->flags & NGHTTP2_FLAG_PAD_LOW) { - iframe->state = NGHTTP2_IB_READ_NBYTE; iframe->left = 1; iframe->buflen = 0; return 1; @@ -3507,10 +3506,11 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } break; } - if(rv == 0) { - iframe->state = NGHTTP2_IB_READ_DATA; + if(rv == 1) { + iframe->state = NGHTTP2_IB_READ_NBYTE; break; } + iframe->state = NGHTTP2_IB_READ_DATA; break; } case NGHTTP2_HEADERS: @@ -3527,6 +3527,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } if(rv == 1) { + iframe->state = NGHTTP2_IB_READ_NBYTE; break; } if(iframe->frame.hd.flags & NGHTTP2_FLAG_PRIORITY) { @@ -3909,8 +3910,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, nghttp2_inbound_frame_reset(session); break; case NGHTTP2_IB_EXPECT_CONTINUATION: - case NGHTTP2_IB_IGN_CONTINUATION: { - nghttp2_inbound_state state_back; + case NGHTTP2_IB_IGN_CONTINUATION: #ifdef DEBUGBUILD if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { fprintf(stderr, "[IB_EXPECT_CONTINUATION]\n"); @@ -3947,7 +3947,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); iframe->frame.hd.length += cont_hd.length; - state_back = iframe->state; rv = inbound_frame_handle_pad(iframe, &cont_hd); if(rv < 0) { busy = 1; @@ -3960,7 +3959,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } if(rv == 1) { - if(state_back == NGHTTP2_IB_EXPECT_CONTINUATION) { + if(iframe->state == NGHTTP2_IB_EXPECT_CONTINUATION) { iframe->state = NGHTTP2_IB_READ_PAD_CONTINUATION; } else { iframe->state = NGHTTP2_IB_IGN_PAD_CONTINUATION; @@ -3975,7 +3974,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; } break; - } case NGHTTP2_IB_READ_PAD_CONTINUATION: case NGHTTP2_IB_IGN_PAD_CONTINUATION: #ifdef DEBUGBUILD From eb2856f3df3c76f80b0ed1870ed9e408aaa7cfa7 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 16:33:07 +0900 Subject: [PATCH 31/56] Add inbound_frame_reset_left() not to forget to reset iframe->buflen --- lib/nghttp2_session.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 8ed64586..333547f2 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3340,6 +3340,17 @@ static size_t inbound_frame_payload_readlen(nghttp2_inbound_frame *iframe, return nghttp2_min((size_t)(last - in), iframe->payloadleft); } +/* + * Resets iframe->left to |left| and iframe->buflen to 0 for the next + * short buffering. + */ +static void inbound_frame_reset_left(nghttp2_inbound_frame *iframe, + size_t left) +{ + iframe->left = left; + iframe->buflen = 0; +} + static size_t inbound_frame_buf_read(nghttp2_inbound_frame *iframe, const uint8_t *in, const uint8_t *last) { @@ -3395,13 +3406,11 @@ static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, if((hd->flags & NGHTTP2_FLAG_PAD_LOW) == 0) { return -1; } - iframe->left = 2; - iframe->buflen = 0; + inbound_frame_reset_left(iframe, 2); return 1; } if(hd->flags & NGHTTP2_FLAG_PAD_LOW) { - iframe->left = 1; - iframe->buflen = 0; + inbound_frame_reset_left(iframe, 1); return 1; } DEBUGF(fprintf(stderr, "no padding\n")); @@ -3478,7 +3487,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->buf); iframe->payloadleft = iframe->frame.hd.length; - iframe->buflen = 0; switch(iframe->frame.hd.type) { case NGHTTP2_DATA: { @@ -3537,7 +3545,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } iframe->state = NGHTTP2_IB_READ_NBYTE; - iframe->left = 4; + inbound_frame_reset_left(iframe, 4); break; } rv = session_process_headers_frame(session); @@ -3560,7 +3568,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } iframe->state = NGHTTP2_IB_READ_NBYTE; - iframe->left = 4; + inbound_frame_reset_left(iframe, 4); break; case NGHTTP2_SETTINGS: DEBUGF(fprintf(stderr, "SETTINGS\n")); @@ -3573,11 +3581,12 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } iframe->state = NGHTTP2_IB_READ_SETTINGS; if(iframe->payloadleft) { - iframe->left = NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; + inbound_frame_reset_left(iframe, + NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH); break; } busy = 1; - iframe->left = 0; + inbound_frame_reset_left(iframe, 0); break; case NGHTTP2_PUSH_PROMISE: if(iframe->payloadleft < 4) { @@ -3586,7 +3595,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } iframe->state = NGHTTP2_IB_READ_NBYTE; - iframe->left = 4; + inbound_frame_reset_left(iframe, 4); break; case NGHTTP2_PING: if(iframe->payloadleft != 8) { @@ -3595,7 +3604,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } iframe->state = NGHTTP2_IB_READ_NBYTE; - iframe->left = 8; + inbound_frame_reset_left(iframe, 8); break; case NGHTTP2_GOAWAY: if(iframe->payloadleft < 8) { @@ -3604,7 +3613,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } iframe->state = NGHTTP2_IB_READ_NBYTE; - iframe->left = 8; + inbound_frame_reset_left(iframe, 8); break; default: /* Receiving unknown frame type and CONTINUATION in this state @@ -3667,8 +3676,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } iframe->state = NGHTTP2_IB_READ_NBYTE; - iframe->left = 4; - iframe->buflen = 0; + inbound_frame_reset_left(iframe, 4); break; } } @@ -3814,9 +3822,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } if((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) { - iframe->left = NGHTTP2_FRAME_HEAD_LENGTH; + inbound_frame_reset_left(iframe, NGHTTP2_FRAME_HEAD_LENGTH); iframe->error_code = 0; - iframe->buflen = 0; iframe->padlen = 0; if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { iframe->state = NGHTTP2_IB_EXPECT_CONTINUATION; @@ -3883,8 +3890,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } } if(iframe->payloadleft) { - iframe->left = NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; - iframe->buflen = 0; + inbound_frame_reset_left(iframe, NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH); break; } rv = session_process_settings_frame(session); From 3144bcbe2066549da29165aabe144070df638ac9 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 16:34:42 +0900 Subject: [PATCH 32/56] Remove unused iframe->error_code --- lib/nghttp2_session.c | 5 ----- lib/nghttp2_session.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 333547f2..539a4ee3 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -174,7 +174,6 @@ static void nghttp2_inbound_frame_reset(nghttp2_session *session) iframe->niv = 0; iframe->payloadleft = 0; iframe->padlen = 0; - iframe->error_code = 0; iframe->buflen = 0; } @@ -3823,7 +3822,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } if((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) { inbound_frame_reset_left(iframe, NGHTTP2_FRAME_HEAD_LENGTH); - iframe->error_code = 0; iframe->padlen = 0; if(iframe->state == NGHTTP2_IB_READ_HEADER_BLOCK) { iframe->state = NGHTTP2_IB_EXPECT_CONTINUATION; @@ -4059,9 +4057,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, data_readlen, session->user_data); if(rv == NGHTTP2_ERR_PAUSE) { - /* Set type to NGHTTP2_DATA, so that we can see what was - paused in nghttp2_session_continue() */ - session->iframe.error_code = NGHTTP2_ERR_PAUSE; return in - first; } if(nghttp2_is_fatal(rv)) { diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index bfa55d5d..63d019bb 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -107,8 +107,6 @@ typedef struct { /* padding length for the current frame */ size_t padlen; nghttp2_inbound_state state; - /* TODO, remove this. Error code */ - int error_code; uint8_t buf[8]; /* How many bytes have been written to |buf| */ uint8_t buflen; From 39fe7a5cfa54a51682d30a1974a4c539c4c941e3 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 16:48:27 +0900 Subject: [PATCH 33/56] Don't set select_padding_callback if padding_boundary is 0 or not set --- src/HttpServer.cc | 4 +++- src/nghttp.cc | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 196a0999..6a364dca 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -988,7 +988,9 @@ void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config) callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback; callbacks.on_header_callback = on_header_callback; callbacks.on_begin_headers_callback = on_begin_headers_callback; - callbacks.select_padding_callback = select_padding_callback; + if(config->padding_boundary) { + callbacks.select_padding_callback = select_padding_callback; + } } } // namespace diff --git a/src/nghttp.cc b/src/nghttp.cc index 69d35d5b..25bec8cf 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -1598,7 +1598,9 @@ int run(char **uris, int n) } callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback; callbacks.on_header_callback = on_header_callback; - callbacks.select_padding_callback = select_padding_callback; + if(config.padding_boundary) { + callbacks.select_padding_callback = select_padding_callback; + } std::string prev_scheme; std::string prev_host; From cf0b880b15943399ee23fcd68c4e3e8cb68f01c4 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 16:53:08 +0900 Subject: [PATCH 34/56] Error if undefined SETTINGS ID is detected in nghttp2_iv_check --- lib/nghttp2_frame.c | 2 ++ tests/nghttp2_frame_test.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index 077ae1e6..c6318c1e 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -640,6 +640,8 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) return 0; } break; + default: + return 0; } } return 1; diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 56abc95d..d6495d19 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -434,4 +434,9 @@ void test_nghttp2_iv_check(void) CU_ASSERT(nghttp2_iv_check(iv, 2)); iv[1].value = 3; CU_ASSERT(!nghttp2_iv_check(iv, 2)); + + /* Undefined SETTINGS ID */ + iv[1].settings_id = 1000000009; + iv[1].value = 0; + CU_ASSERT(!nghttp2_iv_check(iv, 2)); } From 788072af9bd4a8144cbdef77b85fadf585f1dbbf Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 17:21:34 +0900 Subject: [PATCH 35/56] Fix HEADERS padding is not added --- lib/nghttp2_session.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 539a4ee3..672813bd 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1156,13 +1156,13 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, nghttp2_session_after_frame_sent(). */ framebuflen += frame->headers.padlen; } else if(frame->hd.length <= NGHTTP2_MAX_FRAME_LENGTH && - padded_payloadlen > frame->hd.length) { + frame->headers.padlen > 0) { r = nghttp2_frame_add_pad(&session->aob.framebuf, &session->aob.framebufmax, &session->aob.framebufoff, &frame->hd.flags, - frame->hd.length, - padded_payloadlen - frame->hd.length); + frame->hd.length - frame->headers.padlen, + frame->headers.padlen); if(nghttp2_is_fatal(r)) { return r; } From c280cc7c4d591d1db4b1c68bcf7936dc4a960fc2 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 17:23:22 +0900 Subject: [PATCH 36/56] nghttpx: Add --padding option for debugging purpose --- src/shrpx.cc | 11 +++++++++++ src/shrpx_config.cc | 3 +++ src/shrpx_config.h | 2 ++ src/shrpx_http.cc | 11 +++++++++++ src/shrpx_http.h | 6 ++++++ src/shrpx_http2_session.cc | 3 +++ src/shrpx_http2_upstream.cc | 3 +++ 7 files changed, 39 insertions(+) diff --git a/src/shrpx.cc b/src/shrpx.cc index a2daecad..48242dc1 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -437,6 +437,7 @@ void fill_default_config() mod_config()->http2_upstream_dump_response_header = nullptr; mod_config()->http2_no_cookie_crumbling = false; mod_config()->upstream_frame_debug = false; + mod_config()->padding = 0; } } // namespace @@ -675,6 +676,11 @@ void print_help(std::ostream& out) << " --backend-no-tls Disable SSL/TLS on backend connections.\n" << " --http2-no-cookie-crumbling\n" << " Don't crumble cookie header field.\n" + << " --padding=\n" + << " Padding boundary for HTTP/2 frame payload.\n" + << " Specify 0 to disable padding. This option is\n" + << " meant for debugging purpose and not intended\n" + << " to enhance protocol security.\n" << "\n" << " Mode:\n" << " (default mode) Accept HTTP/2.0, SPDY and HTTP/1.1 over\n" @@ -824,6 +830,7 @@ int main(int argc, char **argv) {"frontend-http2-connection-window-bits", required_argument, &flag, 46}, {"backend-http2-connection-window-bits", required_argument, &flag, 47}, {"tls-proto-list", required_argument, &flag, 48}, + {"padding", required_argument, &flag, 49}, {nullptr, 0, nullptr, 0 } }; @@ -1060,6 +1067,10 @@ int main(int argc, char **argv) // --tls-proto-list cmdcfgs.emplace_back(SHRPX_OPT_TLS_PROTO_LIST, optarg); break; + case 49: + // --padding + cmdcfgs.emplace_back(SHRPX_OPT_PADDING, optarg); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index d2f5b504..2514d34c 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -116,6 +116,7 @@ const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[] = "frontend-http2-dump-response-header"; const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[] = "http2-no-cookie-crumbling"; const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[] = "frontend-frame-debug"; +const char SHRPX_OPT_PADDING[] = "padding"; namespace { Config *config = nullptr; @@ -483,6 +484,8 @@ int parse_config(const char *opt, const char *optarg) mod_config()->http2_no_cookie_crumbling = util::strieq(optarg, "yes"); } else if(util::strieq(opt, SHRPX_OPT_FRONTEND_FRAME_DEBUG)) { mod_config()->upstream_frame_debug = util::strieq(optarg, "yes"); + } else if(util::strieq(opt, SHRPX_OPT_PADDING)) { + mod_config()->padding = strtoul(optarg, nullptr, 10); } else if(util::strieq(opt, "conf")) { LOG(WARNING) << "conf is ignored"; } else { diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 6ca420e0..04da1801 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -103,6 +103,7 @@ extern const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_REQUEST_HEADER[]; extern const char SHRPX_OPT_FRONTEND_HTTP2_DUMP_RESPONSE_HEADER[]; extern const char SHRPX_OPT_HTTP2_NO_COOKIE_CRUMBLING[]; extern const char SHRPX_OPT_FRONTEND_FRAME_DEBUG[]; +extern const char SHRPX_OPT_PADDING[]; union sockaddr_union { sockaddr sa; @@ -180,6 +181,7 @@ struct Config { size_t npn_list_len; // The number of elements in tls_proto_list size_t tls_proto_list_len; + size_t padding; // downstream protocol; this will be determined by given options. shrpx_proto downstream_proto; int syslog_facility; diff --git a/src/shrpx_http.cc b/src/shrpx_http.cc index d2cc11d0..8f5e9dd5 100644 --- a/src/shrpx_http.cc +++ b/src/shrpx_http.cc @@ -94,6 +94,17 @@ std::string colorizeHeaders(const char *hdrs) return nhdrs; } +ssize_t select_padding_callback +(nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload, + void *user_data) +{ + auto bd = get_config()->padding; + if(frame->hd.length == 0) { + return bd; + } + return std::min(max_payload, (frame->hd.length + bd - 1) / bd * bd); +} + } // namespace http } // namespace shrpx diff --git a/src/shrpx_http.h b/src/shrpx_http.h index feace2a5..bd519b16 100644 --- a/src/shrpx_http.h +++ b/src/shrpx_http.h @@ -29,6 +29,8 @@ #include +#include + namespace shrpx { namespace http { @@ -40,6 +42,10 @@ std::string create_via_header_value(int major, int minor); // Adds ANSI color codes to HTTP headers |hdrs|. std::string colorizeHeaders(const char *hdrs); +ssize_t select_padding_callback +(nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload, + void *user_data); + } // namespace http } // namespace shrpx diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index ccf4b3e3..ebbf97c1 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -1193,6 +1193,9 @@ int Http2Session::on_connect() callbacks.on_unknown_frame_recv_callback = on_unknown_frame_recv_callback; callbacks.on_header_callback = on_header_callback; callbacks.on_begin_headers_callback = on_begin_headers_callback; + if(get_config()->padding) { + callbacks.select_padding_callback = http::select_padding_callback; + } nghttp2_opt_set opt_set; opt_set.no_auto_stream_window_update = 1; diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index d469b7c5..085d5f5d 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -519,6 +519,9 @@ Http2Upstream::Http2Upstream(ClientHandler *handler) callbacks.on_unknown_frame_recv_callback = on_unknown_frame_recv_callback; callbacks.on_header_callback = on_header_callback; callbacks.on_begin_headers_callback = on_begin_headers_callback; + if(get_config()->padding) { + callbacks.select_padding_callback = http::select_padding_callback; + } nghttp2_opt_set opt_set; opt_set.no_auto_stream_window_update = 1; From 16b5e99e8832c26a8378e5945c13ae9bf62a6cea Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 17:30:38 +0900 Subject: [PATCH 37/56] Bitwise-OR last CONTINUATION flags to first HEADERS flags --- lib/nghttp2_session.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 672813bd..2ed79c05 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1516,6 +1516,9 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) session->aob.framebuflen = session->aob.framebufmark = session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH + cont_hd.length; + /* Or-ing flags so that we can show these flags in + callback */ + frame->hd.flags |= cont_hd.flags; } else { cont_hd.flags = NGHTTP2_FLAG_NONE; session->aob.framebufmark += cont_hd.length; From 6364ae1a9839657b83fad195ca6a531ebf73a598 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 18:43:45 +0900 Subject: [PATCH 38/56] Fix nghttp2_active_outbound_item is not reset on DATA deferred --- lib/nghttp2_session.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 2ed79c05..e44a4c32 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -378,6 +378,8 @@ static void nghttp2_session_ob_pq_free(nghttp2_pq *pq) static void nghttp2_active_outbound_item_reset (nghttp2_active_outbound_item *aob) { + DEBUGF(fprintf(stderr, "reset nghttp2_active_outbound_item\n")); + DEBUGF(fprintf(stderr, "aob->item = %p\n", aob->item)); nghttp2_outbound_item_free(aob->item); free(aob->item); aob->item = NULL; @@ -1321,6 +1323,8 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, next_readmax = nghttp2_session_next_data_read(session, stream); if(next_readmax == 0) { nghttp2_stream_defer_data(stream, item, NGHTTP2_DEFERRED_FLOW_CONTROL); + session->aob.item = NULL; + nghttp2_active_outbound_item_reset(&session->aob); return NGHTTP2_ERR_DEFERRED; } framebuflen = nghttp2_session_pack_data(session, @@ -1331,6 +1335,8 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, data_frame); if(framebuflen == NGHTTP2_ERR_DEFERRED) { nghttp2_stream_defer_data(stream, item, NGHTTP2_DEFERRED_NONE); + session->aob.item = NULL; + nghttp2_active_outbound_item_reset(&session->aob); return NGHTTP2_ERR_DEFERRED; } else if(framebuflen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { r = nghttp2_session_add_rst_stream(session, data_frame->hd.stream_id, @@ -1803,6 +1809,7 @@ int nghttp2_session_send(nghttp2_session *session) } nghttp2_outbound_item_free(item); free(item); + nghttp2_active_outbound_item_reset(&session->aob); if(framebuflen == NGHTTP2_ERR_HEADER_COMP) { /* If header compression error occurred, should terminiate From dbb131d13dfb8fb655885f1179d39f5915c9e945 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 18:55:22 +0900 Subject: [PATCH 39/56] Simplify framebufmark calculation for DATA frame --- lib/nghttp2_session.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index e44a4c32..4ee107f6 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1840,12 +1840,7 @@ int nghttp2_session_send(nghttp2_session *session) return r; } } else { - nghttp2_private_data *frame; - frame = nghttp2_outbound_item_get_data_frame(session->aob.item); - /* session->aob.framebufmark = session->aob.framebuflen; */ - session->aob.framebufmark = - session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH + - frame->hd.length; + session->aob.framebufmark = session->aob.framebuflen; } } From cd3eae3dd2d9868a4b412c9f057b738ce147f7d2 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 19:19:00 +0900 Subject: [PATCH 40/56] src: Fix select_padding_callback which returns value greater than max_payload --- src/HttpServer.cc | 2 +- src/nghttp.cc | 2 +- src/shrpx_http.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 6a364dca..344fcfd0 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -936,7 +936,7 @@ ssize_t select_padding_callback return frame->hd.length; } if(frame->hd.length == 0) { - return bd; + return std::min(max_payload, bd); } return std::min(max_payload, (frame->hd.length + bd - 1) / bd * bd); } diff --git a/src/nghttp.cc b/src/nghttp.cc index 25bec8cf..573b3672 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -1136,7 +1136,7 @@ ssize_t select_padding_callback return frame->hd.length; } if(frame->hd.length == 0) { - return bd; + return std::min(max_payload, bd); } return std::min(max_payload, (frame->hd.length + bd - 1) / bd * bd); } diff --git a/src/shrpx_http.cc b/src/shrpx_http.cc index 8f5e9dd5..0c1db266 100644 --- a/src/shrpx_http.cc +++ b/src/shrpx_http.cc @@ -100,7 +100,7 @@ ssize_t select_padding_callback { auto bd = get_config()->padding; if(frame->hd.length == 0) { - return bd; + return std::min(max_payload, bd); } return std::min(max_payload, (frame->hd.length + bd - 1) / bd * bd); } From 7822bbd7e80740991d8ce2b881d00118664c724d Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 21:30:44 +0900 Subject: [PATCH 41/56] Fix PAD_HIGH and PAD_LOW are not counted in flow control --- lib/nghttp2_session.c | 46 ++++++++++++++++++++++++++---------- tests/main.c | 2 ++ tests/nghttp2_session_test.c | 40 +++++++++++++++++++++++++++++++ tests/nghttp2_session_test.h | 1 + 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 4ee107f6..e3f45837 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3204,7 +3204,8 @@ static int adjust_recv_window_size(int32_t *recv_window_size_ptr, static int nghttp2_session_update_recv_stream_window_size (nghttp2_session *session, nghttp2_stream *stream, - int32_t delta_size) + int32_t delta_size, + int send_window_update) { int rv; rv = adjust_recv_window_size(&stream->recv_window_size, delta_size, @@ -3213,7 +3214,10 @@ static int nghttp2_session_update_recv_stream_window_size return nghttp2_session_add_rst_stream(session, stream->stream_id, NGHTTP2_FLOW_CONTROL_ERROR); } - if(!(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE)) { + /* We don't have to send WINDOW_UPDATE if the data received is the + last chunk in the incoming stream. */ + if(send_window_update && + !(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE)) { /* We have to use local_settings here because it is the constraint the remote endpoint should honor. */ if(nghttp2_should_send_window_update(stream->local_window_size, @@ -3478,6 +3482,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, int rv; int busy = 0; nghttp2_frame_hd cont_hd; + nghttp2_stream *stream; for(;;) { switch(iframe->state) { @@ -3657,6 +3662,23 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } iframe->frame.data.padlen = rv; iframe->state = NGHTTP2_IB_READ_DATA; + /* PAD_HIGH and PAD_LOW are subject to flow control */ + rv = nghttp2_session_update_recv_connection_window_size + (session, iframe->buflen); + if(nghttp2_is_fatal(rv)) { + return rv; + } + stream = nghttp2_session_get_stream(session, + iframe->frame.hd.stream_id); + if(stream) { + rv = nghttp2_session_update_recv_stream_window_size + (session, stream, iframe->buflen, + iframe->payloadleft || + (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); + if(nghttp2_is_fatal(rv)) { + return rv; + } + } break; case NGHTTP2_HEADERS: if(iframe->padlen == 0 && @@ -4037,17 +4059,15 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, if(nghttp2_is_fatal(rv)) { return rv; } - if(iframe->payloadleft || - (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) { - nghttp2_stream *stream; - stream = nghttp2_session_get_stream(session, - iframe->frame.hd.stream_id); - if(stream) { - rv = nghttp2_session_update_recv_stream_window_size - (session, stream, readlen); - if(nghttp2_is_fatal(rv)) { - return rv; - } + stream = nghttp2_session_get_stream(session, + iframe->frame.hd.stream_id); + if(stream) { + rv = nghttp2_session_update_recv_stream_window_size + (session, stream, readlen, + iframe->payloadleft || + (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); + if(nghttp2_is_fatal(rv)) { + return rv; } } data_readlen = inbound_frame_effective_readlen diff --git a/tests/main.c b/tests/main.c index b7d70cdf..699fb3b5 100644 --- a/tests/main.c +++ b/tests/main.c @@ -181,6 +181,8 @@ int main(int argc, char* argv[]) test_nghttp2_session_flow_control) || !CU_add_test(pSuite, "session_flow_control_data_recv", test_nghttp2_session_flow_control_data_recv) || + !CU_add_test(pSuite, "session_flow_control_data_with_padding_recv", + test_nghttp2_session_flow_control_data_with_padding_recv) || !CU_add_test(pSuite, "session_data_read_temporal_failure", test_nghttp2_session_data_read_temporal_failure) || !CU_add_test(pSuite, "session_on_stream_close", diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index c4b42e4a..22bb54b5 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -3542,6 +3542,46 @@ void test_nghttp2_session_flow_control_data_recv(void) nghttp2_session_del(session); } +void test_nghttp2_session_flow_control_data_with_padding_recv(void) +{ + nghttp2_session *session; + nghttp2_session_callbacks callbacks; + uint8_t data[1024]; + nghttp2_frame_hd hd; + nghttp2_stream *stream; + + memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); + callbacks.send_callback = null_send_callback; + + /* Initial window size to 64KiB - 1*/ + nghttp2_session_client_new(&session, &callbacks, NULL); + + stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE, + NGHTTP2_PRI_DEFAULT, + NGHTTP2_STREAM_OPENED, NULL); + + /* Create DATA frame */ + memset(data, 0, sizeof(data)); + hd.length = 357; + hd.type = NGHTTP2_DATA; + hd.flags = NGHTTP2_FLAG_END_STREAM | + NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW;; + hd.stream_id = 1; + nghttp2_frame_pack_frame_hd(data, &hd); + /* Add 2 byte padding (PAD_LOW itself is padding) */ + data[NGHTTP2_FRAME_HEAD_LENGTH] = 1; + data[NGHTTP2_FRAME_HEAD_LENGTH + 1] = 1; + + CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH + hd.length == + nghttp2_session_mem_recv(session, data, + NGHTTP2_FRAME_HEAD_LENGTH + hd.length)); + + CU_ASSERT(hd.length == session->recv_window_size); + CU_ASSERT(hd.length == stream->recv_window_size); + + nghttp2_session_del(session); +} + void test_nghttp2_session_data_read_temporal_failure(void) { nghttp2_session *session; diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index e608d148..626963a4 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -81,6 +81,7 @@ void test_nghttp2_session_stop_data_with_rst_stream(void); void test_nghttp2_session_defer_data(void); void test_nghttp2_session_flow_control(void); void test_nghttp2_session_flow_control_data_recv(void); +void test_nghttp2_session_flow_control_data_with_padding_recv(void); void test_nghttp2_session_data_read_temporal_failure(void); void test_nghttp2_session_on_stream_close(void); void test_nghttp2_session_on_ctrl_not_send(void); From bac31e844a07a02953f0f210ab2c531dc9c08890 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 21:35:41 +0900 Subject: [PATCH 42/56] Add more debug output --- lib/nghttp2_session.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index e3f45837..9e6f0577 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1010,6 +1010,10 @@ static size_t nghttp2_session_next_data_read(nghttp2_session *session, nghttp2_stream *stream) { int32_t window_size = NGHTTP2_DATA_PAYLOAD_LENGTH; + + DEBUGF(fprintf(stderr, "connection remote_window_size=%d\n", + session->remote_window_size)); + /* Take into account both connection-level flow control here */ window_size = nghttp2_min(window_size, session->remote_window_size); window_size = nghttp2_min(window_size, stream->remote_window_size); @@ -1788,9 +1792,12 @@ int nghttp2_session_send(nghttp2_session *session) } framebuflen = nghttp2_session_prep_frame(session, item); if(framebuflen == NGHTTP2_ERR_DEFERRED) { + DEBUGF(fprintf(stderr, "frame deferred\n")); continue; } if(framebuflen < 0) { + DEBUGF(fprintf(stderr, "frame preparation failed with %s\n", + nghttp2_strerror(framebuflen))); /* TODO If the error comes from compressor, the connection must be closed. */ if(item->frame_cat == NGHTTP2_CAT_CTRL && @@ -3484,6 +3491,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, nghttp2_frame_hd cont_hd; nghttp2_stream *stream; + DEBUGF(fprintf(stderr, "connection recv_window_size=%d, local_window=%d\n", + session->recv_window_size, session->local_window_size)); + for(;;) { switch(iframe->state) { case NGHTTP2_IB_READ_HEAD: @@ -3571,6 +3581,19 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, case NGHTTP2_PRIORITY: case NGHTTP2_RST_STREAM: case NGHTTP2_WINDOW_UPDATE: +#ifdef DEBUGBUILD + switch(iframe->frame.hd.type) { + case NGHTTP2_PRIORITY: + DEBUGF(fprintf(stderr, "PRIORITY\n")); + break; + case NGHTTP2_RST_STREAM: + DEBUGF(fprintf(stderr, "RST_STREAM\n")); + break; + case NGHTTP2_WINDOW_UPDATE: + DEBUGF(fprintf(stderr, "WINDOW_UPDATE\n")); + break; + } +#endif /* DEBUGBUILD */ if(iframe->payloadleft != 4) { busy = 1; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; @@ -3598,6 +3621,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, inbound_frame_reset_left(iframe, 0); break; case NGHTTP2_PUSH_PROMISE: + DEBUGF(fprintf(stderr, "PUSH_PROMISE\n")); if(iframe->payloadleft < 4) { busy = 1; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; @@ -3607,6 +3631,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, inbound_frame_reset_left(iframe, 4); break; case NGHTTP2_PING: + DEBUGF(fprintf(stderr, "PING\n")); if(iframe->payloadleft != 8) { busy = 1; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; @@ -3616,6 +3641,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, inbound_frame_reset_left(iframe, 8); break; case NGHTTP2_GOAWAY: + DEBUGF(fprintf(stderr, "GOAWAY\n")); if(iframe->payloadleft < 8) { busy = 1; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; @@ -3625,6 +3651,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, inbound_frame_reset_left(iframe, 8); break; default: + DEBUGF(fprintf(stderr, "unknown frame\n")); /* Receiving unknown frame type and CONTINUATION in this state are subject to connection error of type PROTOCOL_ERROR */ rv = nghttp2_session_terminate_session(session, @@ -4320,6 +4347,8 @@ ssize_t nghttp2_session_pack_data(nghttp2_session *session, if(payloadlen == NGHTTP2_ERR_DEFERRED || payloadlen == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) { + DEBUGF(fprintf(stderr, "DATA postponed due to %s\n", + nghttp2_strerror(payloadlen))); return payloadlen; } if(payloadlen < 0 || datamax < (size_t)payloadlen) { From c7a17093cb48af3edf8f99ae4d6078efcff12787 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Tue, 11 Feb 2014 21:39:35 +0900 Subject: [PATCH 43/56] Fix compile errors with --enable-maintainer-mode --- lib/nghttp2_session.c | 2 +- tests/nghttp2_session_test.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 9e6f0577..1321a354 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1089,7 +1089,7 @@ static ssize_t session_call_select_padding(nghttp2_session *session, rv = session->callbacks.select_padding_callback(session, frame, max_payloadlen, session->user_data); - if(rv < frame->hd.length || rv > max_payloadlen) { + if(rv < (ssize_t)frame->hd.length || rv > (ssize_t)max_payloadlen) { return NGHTTP2_ERR_CALLBACK_FAILURE; } return rv; diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index cd632bda..568e1153 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -818,7 +818,7 @@ void test_nghttp2_session_recv_premature_headers(void) nghttp2_put_uint16be(framedata + bufoff, frame.hd.length - 1); rv = nghttp2_session_mem_recv(session, framedata + bufoff, framedatalen - bufoff - 1); - CU_ASSERT((ssize_t)framedatalen - bufoff - 1 == rv); + CU_ASSERT((ssize_t)(framedatalen - bufoff - 1) == rv); item = nghttp2_session_get_next_ob_item(session); CU_ASSERT(NULL != item); @@ -3576,12 +3576,12 @@ void test_nghttp2_session_flow_control_data_with_padding_recv(void) data[NGHTTP2_FRAME_HEAD_LENGTH] = 1; data[NGHTTP2_FRAME_HEAD_LENGTH + 1] = 1; - CU_ASSERT(NGHTTP2_FRAME_HEAD_LENGTH + hd.length == + CU_ASSERT((ssize_t)(NGHTTP2_FRAME_HEAD_LENGTH + hd.length) == nghttp2_session_mem_recv(session, data, NGHTTP2_FRAME_HEAD_LENGTH + hd.length)); - CU_ASSERT(hd.length == session->recv_window_size); - CU_ASSERT(hd.length == stream->recv_window_size); + CU_ASSERT((int32_t)hd.length == session->recv_window_size); + CU_ASSERT((int32_t)hd.length == stream->recv_window_size); nghttp2_session_del(session); } From 082876d92d78ffc9dd5909cab5e3e28a1df8ca5a Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 12 Feb 2014 21:35:40 +0900 Subject: [PATCH 44/56] Contribute flow control window for each byte PAD_HIGH and _LOW in DATA This may help the pathological situation where window is too small. --- lib/nghttp2_session.c | 78 +++++++++++++++++++++++++------------------ lib/nghttp2_session.h | 1 + 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 1321a354..8e3064fa 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -3534,7 +3534,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; } if(rv == 1) { - iframe->state = NGHTTP2_IB_READ_NBYTE; + iframe->state = NGHTTP2_IB_READ_PAD_DATA; break; } iframe->state = NGHTTP2_IB_READ_DATA; @@ -3675,38 +3675,6 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, return in - first; } switch(iframe->frame.hd.type) { - case NGHTTP2_DATA: - busy = 1; - rv = inbound_frame_compute_pad(iframe); - if(rv < 0) { - rv = nghttp2_session_terminate_session(session, - NGHTTP2_PROTOCOL_ERROR); - if(nghttp2_is_fatal(rv)) { - return rv; - } - iframe->state = NGHTTP2_IB_IGN_DATA; - break; - } - iframe->frame.data.padlen = rv; - iframe->state = NGHTTP2_IB_READ_DATA; - /* PAD_HIGH and PAD_LOW are subject to flow control */ - rv = nghttp2_session_update_recv_connection_window_size - (session, iframe->buflen); - if(nghttp2_is_fatal(rv)) { - return rv; - } - stream = nghttp2_session_get_stream(session, - iframe->frame.hd.stream_id); - if(stream) { - rv = nghttp2_session_update_recv_stream_window_size - (session, stream, iframe->buflen, - iframe->payloadleft || - (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); - if(nghttp2_is_fatal(rv)) { - return rv; - } - } - break; case NGHTTP2_HEADERS: if(iframe->padlen == 0 && iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) { @@ -4072,6 +4040,50 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK; } break; + case NGHTTP2_IB_READ_PAD_DATA: + DEBUGF(fprintf(stderr, "[IB_READ_PAD_DATA]\n")); + readlen = inbound_frame_buf_read(iframe, in, last); + in += readlen; + iframe->payloadleft -= readlen; + DEBUGF(fprintf(stderr, "readlen=%zu, payloadleft=%zu, left=%zu\n", + readlen, iframe->payloadleft, iframe->left)); + + /* PAD_HIGH and PAD_LOW are subject to flow control */ + rv = nghttp2_session_update_recv_connection_window_size + (session, readlen); + if(nghttp2_is_fatal(rv)) { + return rv; + } + stream = nghttp2_session_get_stream(session, + iframe->frame.hd.stream_id); + if(stream) { + rv = nghttp2_session_update_recv_stream_window_size + (session, stream, readlen, + iframe->payloadleft || + (iframe->frame.hd.flags & NGHTTP2_FLAG_END_STREAM) == 0); + if(nghttp2_is_fatal(rv)) { + return rv; + } + } + + if(iframe->left) { + return in - first; + } + + busy = 1; + rv = inbound_frame_compute_pad(iframe); + if(rv < 0) { + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_DATA; + break; + } + iframe->frame.data.padlen = rv; + iframe->state = NGHTTP2_IB_READ_DATA; + break; case NGHTTP2_IB_READ_DATA: DEBUGF(fprintf(stderr, "[IB_READ_DATA]\n")); readlen = inbound_frame_payload_readlen(iframe, in, last); diff --git a/lib/nghttp2_session.h b/lib/nghttp2_session.h index 63d019bb..635648df 100644 --- a/lib/nghttp2_session.h +++ b/lib/nghttp2_session.h @@ -88,6 +88,7 @@ typedef enum { NGHTTP2_IB_IGN_CONTINUATION, NGHTTP2_IB_READ_PAD_CONTINUATION, NGHTTP2_IB_IGN_PAD_CONTINUATION, + NGHTTP2_IB_READ_PAD_DATA, NGHTTP2_IB_READ_DATA, NGHTTP2_IB_IGN_DATA } nghttp2_inbound_state; From fd88c6160d4bf22a08be61694c4e3ef6b71bf88a Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 13 Feb 2014 23:22:52 +0900 Subject: [PATCH 45/56] HPACK post -05 updates * Use 1 Huffman code table for both request and response * Remove complicated deflater side table size management * Add encoding context update * Fix memory leak in inflater --- lib/nghttp2_hd.c | 339 +-- lib/nghttp2_hd.h | 106 +- lib/nghttp2_hd_huffman.c | 35 +- lib/nghttp2_hd_huffman.h | 1 - lib/nghttp2_hd_huffman_data.c | 5131 +-------------------------------- lib/nghttp2_session.c | 19 +- python/cnghttp2.pxd | 16 +- python/hpackcheck.py | 9 +- python/hpackmake.py | 7 +- python/nghttp2.pyx | 76 +- src/comp_helper.c | 18 +- src/comp_helper.h | 2 +- src/deflatehd.c | 34 +- src/inflatehd.c | 37 +- tests/main.c | 2 - tests/nghttp2_frame_test.c | 10 +- tests/nghttp2_hd_test.c | 379 ++- tests/nghttp2_hd_test.h | 1 - tests/nghttp2_session_test.c | 20 +- 19 files changed, 471 insertions(+), 5771 deletions(-) diff --git a/lib/nghttp2_hd.c b/lib/nghttp2_hd.c index 71b2fe36..fa0ebd72 100644 --- a/lib/nghttp2_hd.c +++ b/lib/nghttp2_hd.c @@ -286,13 +286,10 @@ static void nghttp2_hd_ringbuf_pop_back(nghttp2_hd_ringbuf *ringbuf) } static int nghttp2_hd_context_init(nghttp2_hd_context *context, - nghttp2_hd_role role, - nghttp2_hd_side side, - size_t deflate_hd_table_bufsize_max) + nghttp2_hd_role role) { int rv; context->role = role; - context->side = side; context->bad = 0; context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; rv = nghttp2_hd_ringbuf_init @@ -302,41 +299,41 @@ static int nghttp2_hd_context_init(nghttp2_hd_context *context, return rv; } - context->deflate_hd_table_bufsize_max = deflate_hd_table_bufsize_max; - context->deflate_hd_table_bufsize = 0; - context->deflate_hd_tablelen = 0; context->hd_table_bufsize = 0; return 0; } -int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_hd_side side) +int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater) { - return nghttp2_hd_deflate_init2(deflater, side, + return nghttp2_hd_deflate_init2(deflater, NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE); } int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, - nghttp2_hd_side side, size_t deflate_hd_table_bufsize_max) { int rv; - rv = nghttp2_hd_context_init(&deflater->ctx, NGHTTP2_HD_ROLE_DEFLATE, side, - deflate_hd_table_bufsize_max); + rv = nghttp2_hd_context_init(&deflater->ctx, NGHTTP2_HD_ROLE_DEFLATE); if(rv != 0) { return rv; } deflater->no_refset = 0; + deflater->deflate_hd_table_bufsize_max = deflate_hd_table_bufsize_max; return 0; } -int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_hd_side side) +int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater) { int rv; - rv = nghttp2_hd_context_init(&inflater->ctx, NGHTTP2_HD_ROLE_INFLATE, side, - NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE); + + rv = nghttp2_hd_context_init(&inflater->ctx, NGHTTP2_HD_ROLE_INFLATE); if(rv != 0) { return rv; } + + inflater->settings_hd_table_bufsize_max = + NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; + inflater->ent_keep = NULL; inflater->name_keep = NULL; inflater->value_keep = NULL; @@ -559,16 +556,38 @@ static uint8_t* decode_length(ssize_t *res, int *final, ssize_t initial, return in + 1; } -static int emit_indexed0(uint8_t **buf_ptr, size_t *buflen_ptr, - size_t *offset_ptr) +static int emit_clear_refset(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *offset_ptr) { int rv; - rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, 1); + uint8_t *bufp; + rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, 2); if(rv != 0) { return rv; } - *(*buf_ptr + *offset_ptr) = 0x80u; - ++*offset_ptr; + bufp = *buf_ptr + *offset_ptr; + *bufp++ = 0x80u; + *bufp = 0x80u; + *offset_ptr += 2; + return 0; +} + +static int emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *offset_ptr, size_t table_size) +{ + int rv; + uint8_t *bufp; + size_t blocklen = 1 + count_encoded_length(table_size, 7); + rv = ensure_write_buffer(buf_ptr, buflen_ptr, *offset_ptr, blocklen); + if(rv != 0) { + return rv; + } + DEBUGF(fprintf(stderr, "emit table_size=%zu\n", table_size)); + bufp = *buf_ptr + *offset_ptr; + *bufp++ = 0x80u; + *bufp = 0; + encode_length(bufp, table_size, 7); + *offset_ptr += blocklen; return 0; } @@ -591,15 +610,14 @@ static int emit_indexed_block(uint8_t **buf_ptr, size_t *buflen_ptr, static size_t emit_string(uint8_t *buf, size_t buflen, size_t enclen, int huffman, - const uint8_t *str, size_t len, - nghttp2_hd_side side) + const uint8_t *str, size_t len) { size_t rv; *buf = huffman ? 1 << 7 : 0; rv = encode_length(buf, enclen, 7); buf += rv; if(huffman) { - nghttp2_hd_huff_encode(buf, buflen - rv, str, len, side); + nghttp2_hd_huff_encode(buf, buflen - rv, str, len); } else { assert(enclen == len); memcpy(buf, str, len); @@ -610,12 +628,11 @@ static size_t emit_string(uint8_t *buf, size_t buflen, static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, size_t *offset_ptr, size_t index, const uint8_t *value, size_t valuelen, - int inc_indexing, - nghttp2_hd_side side) + int inc_indexing) { int rv; uint8_t *bufp; - size_t encvallen = nghttp2_hd_huff_encode_count(value, valuelen, side); + size_t encvallen = nghttp2_hd_huff_encode_count(value, valuelen); size_t blocklen = count_encoded_length(index + 1, 6); int huffman = encvallen < valuelen; if(!huffman) { @@ -630,7 +647,7 @@ static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, *bufp = inc_indexing ? 0 : 0x40u; bufp += encode_length(bufp, index + 1, 6); bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr), - encvallen, huffman, value, valuelen, side); + encvallen, huffman, value, valuelen); assert(bufp - (*buf_ptr + *offset_ptr) == (ssize_t)blocklen); *offset_ptr += blocklen; return 0; @@ -638,15 +655,14 @@ static int emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, size_t *offset_ptr, nghttp2_nv *nv, - int inc_indexing, - nghttp2_hd_side side) + int inc_indexing) { int rv; uint8_t *bufp; size_t encnamelen = - nghttp2_hd_huff_encode_count(nv->name, nv->namelen, side); + nghttp2_hd_huff_encode_count(nv->name, nv->namelen); size_t encvallen = - nghttp2_hd_huff_encode_count(nv->value, nv->valuelen, side); + nghttp2_hd_huff_encode_count(nv->value, nv->valuelen); size_t blocklen = 1; int name_huffman = encnamelen < nv->namelen; int value_huffman = encvallen < nv->valuelen; @@ -665,9 +681,9 @@ static int emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, bufp = *buf_ptr + *offset_ptr; *bufp++ = inc_indexing ? 0 : 0x40u; bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr), - encnamelen, name_huffman, nv->name, nv->namelen, side); + encnamelen, name_huffman, nv->name, nv->namelen); bufp += emit_string(bufp, *buflen_ptr - (bufp - *buf_ptr), - encvallen, value_huffman, nv->value, nv->valuelen, side); + encvallen, value_huffman, nv->value, nv->valuelen); *offset_ptr += blocklen; return 0; } @@ -707,11 +723,6 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context, size_t index = context->hd_table.len - 1; nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index); context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen); - if(context->hd_table_bufsize < context->deflate_hd_table_bufsize) { - context->deflate_hd_table_bufsize -= entry_room(ent->nv.namelen, - ent->nv.valuelen); - --context->deflate_hd_tablelen; - } if(context->role == NGHTTP2_HD_ROLE_DEFLATE) { if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) { /* Emit common header just before it slips away from the @@ -734,82 +745,19 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context, free(ent); } } - while(context->deflate_hd_table_bufsize + room > - context->deflate_hd_table_bufsize_max - && context->deflate_hd_tablelen > 0) { - size_t index = context->deflate_hd_tablelen - 1; - nghttp2_hd_entry *ent = - nghttp2_hd_ringbuf_get(&context->hd_table, index); - context->deflate_hd_table_bufsize -= entry_room(ent->nv.namelen, - ent->nv.valuelen); - --context->deflate_hd_tablelen; - if(ent->flags & NGHTTP2_HD_FLAG_IMPLICIT_EMIT) { - /* Just like a normal eviction, implicit header must be - emitted twice. */ - rv = emit_implicit(buf_ptr, buflen_ptr, offset_ptr, index); - if(rv != 0) { - return NULL; - } - ent->flags ^= NGHTTP2_HD_FLAG_IMPLICIT_EMIT; - } - if(ent->flags & NGHTTP2_HD_FLAG_REFSET) { - /* We need to drop entry from reference set. */ - rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index); - if(rv != 0) { - return NULL; - } - ent->flags ^= NGHTTP2_HD_FLAG_REFSET; - } - /* Release memory. We don't remove entry from the header table - at this moment. */ - if(ent->flags & NGHTTP2_HD_FLAG_NAME_ALLOC) { - free(ent->nv.name); - ent->nv.name = NULL; - ent->flags ^= NGHTTP2_HD_FLAG_NAME_ALLOC; - } - if(ent->flags & NGHTTP2_HD_FLAG_VALUE_ALLOC) { - free(ent->nv.value); - ent->nv.value = NULL; - ent->flags ^= NGHTTP2_HD_FLAG_VALUE_ALLOC; - } - } new_ent = malloc(sizeof(nghttp2_hd_entry)); if(new_ent == NULL) { return NULL; } - if(context->role == NGHTTP2_HD_ROLE_DEFLATE && - room > context->deflate_hd_table_bufsize_max) { - uint8_t flags = entry_flags & - ~(NGHTTP2_HD_FLAG_NAME_ALLOC | NGHTTP2_HD_FLAG_VALUE_ALLOC | - NGHTTP2_HD_FLAG_NAME_GIFT | NGHTTP2_HD_FLAG_VALUE_GIFT); - rv = nghttp2_hd_entry_init(new_ent, flags, - NULL, nv->namelen, NULL, nv->valuelen); - if(rv != 0) { - free(new_ent); - return NULL; - } - if(flags & NGHTTP2_HD_FLAG_NAME_GIFT) { - free(nv->name); - nv->name = NULL; - } - if(flags & NGHTTP2_HD_FLAG_VALUE_GIFT) { - free(nv->value); - nv->value = NULL; - } - /* caller must emit indexed repr to toggle off new_ent from - reference set. We cannot do it here because it may break the - indexing. */ - } else { - rv = nghttp2_hd_entry_init(new_ent, - entry_flags, - nv->name, nv->namelen, nv->value, nv->valuelen); - if(rv != 0) { - free(new_ent); - return NULL; - } + rv = nghttp2_hd_entry_init(new_ent, entry_flags, + nv->name, nv->namelen, nv->value, nv->valuelen); + if(rv != 0) { + free(new_ent); + return NULL; } + if(room > context->hd_table_bufsize_max) { /* The entry taking more than NGHTTP2_HD_MAX_BUFFER_SIZE is immediately evicted. */ @@ -817,11 +765,8 @@ static nghttp2_hd_entry* add_hd_table_incremental(nghttp2_hd_context *context, } else { context->hd_table_bufsize += room; nghttp2_hd_ringbuf_push_front(&context->hd_table, new_ent); - if(room <= context->deflate_hd_table_bufsize_max) { - new_ent->flags |= NGHTTP2_HD_FLAG_REFSET; - context->deflate_hd_table_bufsize += room; - ++context->deflate_hd_tablelen; - } + + new_ent->flags |= NGHTTP2_HD_FLAG_REFSET; } return new_ent; } @@ -851,7 +796,7 @@ static search_result search_hd_table(nghttp2_hd_context *context, uint32_t value_hash = hash(nv->value, nv->valuelen); ssize_t left = -1, right = STATIC_TABLE_LENGTH; - for(i = 0; i < context->deflate_hd_tablelen; ++i) { + for(i = 0; i < context->hd_table.len; ++i) { nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&context->hd_table, i); if(ent->name_hash == name_hash && name_eq(&ent->nv, nv)) { if(res.index == -1) { @@ -893,35 +838,59 @@ static search_result search_hd_table(nghttp2_hd_context *context, return res; } -int nghttp2_hd_change_table_size(nghttp2_hd_context *context, - size_t hd_table_bufsize_max) +static void hd_context_shrink_table_size(nghttp2_hd_context *context) { - int rv; - rv = nghttp2_hd_ringbuf_reserve - (&context->hd_table, hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD); - if(rv != 0) { - return rv; - } - context->hd_table_bufsize_max = hd_table_bufsize_max; - if(context->role == NGHTTP2_HD_ROLE_INFLATE) { - context->deflate_hd_table_bufsize_max = hd_table_bufsize_max; - } while(context->hd_table_bufsize > context->hd_table_bufsize_max && context->hd_table.len > 0) { size_t index = context->hd_table.len - 1; nghttp2_hd_entry* ent = nghttp2_hd_ringbuf_get(&context->hd_table, index); context->hd_table_bufsize -= entry_room(ent->nv.namelen, ent->nv.valuelen); - if(context->hd_table_bufsize < context->deflate_hd_table_bufsize) { - context->deflate_hd_table_bufsize -= entry_room(ent->nv.namelen, - ent->nv.valuelen); - --context->deflate_hd_tablelen; - } nghttp2_hd_ringbuf_pop_back(&context->hd_table); if(--ent->ref == 0) { nghttp2_hd_entry_free(ent); free(ent); } } +} + +int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, + size_t settings_hd_table_bufsize_max) +{ + int rv; + size_t next_bufsize = nghttp2_min(settings_hd_table_bufsize_max, + deflater->deflate_hd_table_bufsize_max); + rv = nghttp2_hd_ringbuf_reserve + (&deflater->ctx.hd_table, next_bufsize / NGHTTP2_HD_ENTRY_OVERHEAD); + if(rv != 0) { + return rv; + } + + deflater->ctx.hd_table_bufsize_max = settings_hd_table_bufsize_max; + + if(settings_hd_table_bufsize_max >= deflater->deflate_hd_table_bufsize_max) { + /* On the next encoding, we sends encoding context update with + deflater->deflate_hd_table_bufsize_max if it is strictly + smaller than settings_hd_table_bufsize_max. */ + return 0; + } + hd_context_shrink_table_size(&deflater->ctx); + return 0; +} + +int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater, + size_t settings_hd_table_bufsize_max) +{ + int rv; + + rv = nghttp2_hd_ringbuf_reserve + (&inflater->ctx.hd_table, + settings_hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD); + if(rv != 0) { + return rv; + } + inflater->settings_hd_table_bufsize_max = settings_hd_table_bufsize_max; + inflater->ctx.hd_table_bufsize_max = settings_hd_table_bufsize_max; + hd_context_shrink_table_size(&inflater->ctx); return 0; } @@ -962,9 +931,8 @@ nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context, static int hd_deflate_should_indexing(nghttp2_hd_deflater *deflater, const nghttp2_nv *nv) { - size_t table_size = nghttp2_min(deflater->ctx.deflate_hd_table_bufsize_max, - deflater->ctx.hd_table_bufsize_max); - if(entry_room(nv->namelen, nv->valuelen) > table_size * 3 / 4) { + if(entry_room(nv->namelen, nv->valuelen) > + deflater->ctx.hd_table_bufsize_max * 3 / 4) { return 0; } #ifdef NGHTTP2_XHD @@ -1006,9 +974,9 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_hd_entry_free(new_ent); free(new_ent); new_ent = NULL; - } else if(new_ent->nv.name != NULL) { - /* new_ent->ref > 0 and nv.name is not NULL means that new_ent is - in the reference set and in deflate_hd_table_bufsize */ + } else { + /* new_ent->ref > 0 means that new_ent is in the reference + set */ new_ent->flags |= NGHTTP2_HD_FLAG_EMIT; } rv = emit_indexed_block(buf_ptr, buflen_ptr, offset_ptr, index); @@ -1080,20 +1048,18 @@ static int deflate_nv(nghttp2_hd_deflater *deflater, if(new_ent->ref == 0) { nghttp2_hd_entry_free(new_ent); free(new_ent); - } else if(new_ent->nv.name != NULL) { - /* new_ent->ref > 0 and nv.name is not NULL means that new_ent is - in the reference set and in deflate_hd_table_bufsize */ + } else { + /* new_ent->ref > 0 means that new_ent is in the reference + set. */ new_ent->flags |= NGHTTP2_HD_FLAG_EMIT; } incidx = 1; } if(index == -1) { - rv = emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, incidx, - deflater->ctx.side); + rv = emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, incidx); } else { rv = emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, index, - nv->value, nv->valuelen, incidx, - deflater->ctx.side); + nv->value, nv->valuelen, incidx); } if(rv != 0) { return rv; @@ -1135,8 +1101,20 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, return NGHTTP2_ERR_HEADER_COMP; } offset = nv_offset; + + if(deflater->ctx.hd_table_bufsize_max > + deflater->deflate_hd_table_bufsize_max) { + rv = emit_table_size(buf_ptr, buflen_ptr, &offset, + deflater->deflate_hd_table_bufsize_max); + if(rv != 0) { + goto fail; + } + deflater->ctx.hd_table_bufsize_max = + deflater->deflate_hd_table_bufsize_max; + } + if(deflater->no_refset) { - rv = emit_indexed0(buf_ptr, buflen_ptr, &offset); + rv = emit_clear_refset(buf_ptr, buflen_ptr, &offset); if(rv != 0) { goto fail; } @@ -1148,7 +1126,7 @@ ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, goto fail; } } - for(i = 0; i < deflater->ctx.deflate_hd_tablelen; ++i) { + for(i = 0; i < deflater->ctx.hd_table.len; ++i) { nghttp2_hd_entry *ent = nghttp2_hd_ringbuf_get(&deflater->ctx.hd_table, i); rv = deflate_post_process_hd_entry(ent, i, buf_ptr, buflen_ptr, &offset); if(rv != 0) { @@ -1414,11 +1392,17 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, DEBUGF(fprintf(stderr, "nghtp2_hd_infalte_hd start state=%d\n", inflater->state)); + hd_inflate_keep_free(inflater); *inflate_flags = NGHTTP2_HD_INFLATE_NONE; for(; in != last;) { switch(inflater->state) { case NGHTTP2_HD_STATE_OPCODE: - if(*in & 0x80u) { + if(*in == 0x80u) { + DEBUGF(fprintf(stderr, "Encoding context update\n")); + inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED; + inflater->state = NGHTTP2_HD_STATE_CONTEXT_UPDATE; + ++in; + } else if(*in & 0x80u) { DEBUGF(fprintf(stderr, "Indexed repr\n")); inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED; inflater->state = NGHTTP2_HD_STATE_READ_INDEX; @@ -1441,6 +1425,38 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, } inflater->left = 0; break; + case NGHTTP2_HD_STATE_CONTEXT_UPDATE: + if(*in & 0x80u) { + if(*in != 0x80u) { + rv = NGHTTP2_ERR_HEADER_COMP; + goto fail; + } + ++in; + DEBUGF(fprintf(stderr, "Clearing reference set\n")); + clear_refset(&inflater->ctx); + inflater->state = NGHTTP2_HD_STATE_OPCODE; + break; + } + /* Header table size change */ + DEBUGF(fprintf(stderr, "Header table size change\n")); + inflater->state = NGHTTP2_HD_STATE_READ_TABLE_SIZE; + break; + case NGHTTP2_HD_STATE_READ_TABLE_SIZE: + rfin = 0; + rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, + inflater->settings_hd_table_bufsize_max); + if(rv < 0) { + goto fail; + } + in += rv; + if(!rfin) { + return in - first; + } + DEBUGF(fprintf(stderr, "table_size=%zd\n", inflater->left)); + inflater->ctx.hd_table_bufsize_max = inflater->left; + hd_context_shrink_table_size(&inflater->ctx); + inflater->state = NGHTTP2_HD_STATE_OPCODE; + break; case NGHTTP2_HD_STATE_READ_INDEX: rfin = 0; rv = hd_inflate_read_len(inflater, &rfin, in, last, @@ -1457,12 +1473,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, DEBUGF(fprintf(stderr, "index=%zd\n", inflater->left)); if(inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) { inflater->index = inflater->left; - if(inflater->index == 0) { - DEBUGF(fprintf(stderr, "Clearing reference set\n")); - clear_refset(&inflater->ctx); - inflater->state = NGHTTP2_HD_STATE_OPCODE; - break; - } + assert(inflater->index > 0); --inflater->index; rv = hd_inflate_commit_indexed(inflater, nv_out); if(rv < 0) { @@ -1504,8 +1515,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, } rv = 0; if(inflater->huffman_encoded) { - nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx, - inflater->ctx.side); + nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); rv = nghttp2_buffer_reserve(&inflater->namebuf, guess_huff_decode_len(inflater->left)); if(rv != 0) { @@ -1579,8 +1589,7 @@ ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, return in - first; } if(inflater->huffman_encoded) { - nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx, - inflater->ctx.side); + nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx); rv = nghttp2_buffer_reserve(&inflater->valuebuf, guess_huff_decode_len(inflater->left)); inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF; @@ -1678,19 +1687,21 @@ int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater) int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, size_t *offset_ptr, size_t index, const uint8_t *value, size_t valuelen, - int inc_indexing, - nghttp2_hd_side side) + int inc_indexing) { return emit_indname_block(buf_ptr, buflen_ptr, offset_ptr, - index, value, valuelen, inc_indexing, - side); + index, value, valuelen, inc_indexing); } int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, size_t *offset_ptr, nghttp2_nv *nv, - int inc_indexing, - nghttp2_hd_side side) + int inc_indexing) { - return emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, inc_indexing, - side); + return emit_newname_block(buf_ptr, buflen_ptr, offset_ptr, nv, inc_indexing); +} + +int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *offset_ptr, size_t table_size) +{ + return emit_table_size(buf_ptr, buflen_ptr, offset_ptr, table_size); } diff --git a/lib/nghttp2_hd.h b/lib/nghttp2_hd.h index c77101e2..d8db8ce0 100644 --- a/lib/nghttp2_hd.h +++ b/lib/nghttp2_hd.h @@ -22,8 +22,8 @@ * 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_HD_COMP_H -#define NGHTTP2_HD_COMP_H +#ifndef NGHTTP2_HD_H +#define NGHTTP2_HD_H #ifdef HAVE_CONFIG_H # include @@ -48,11 +48,6 @@ encoder only uses the memory up to this value. */ #define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12) -typedef enum { - NGHTTP2_HD_SIDE_REQUEST = 0, - NGHTTP2_HD_SIDE_RESPONSE = 1 -} nghttp2_hd_side; - typedef enum { NGHTTP2_HD_ROLE_DEFLATE, NGHTTP2_HD_ROLE_INFLATE @@ -108,6 +103,8 @@ typedef enum { typedef enum { NGHTTP2_HD_STATE_OPCODE, + NGHTTP2_HD_STATE_CONTEXT_UPDATE, + NGHTTP2_HD_STATE_READ_TABLE_SIZE, NGHTTP2_HD_STATE_READ_INDEX, NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN, NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN, @@ -126,30 +123,10 @@ typedef struct { is the sum of length of name/value in hd_table + NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */ size_t hd_table_bufsize; - /* The header table size for decoding. If the context is initialized - as encoder, this value is advertised by remote endpoint - decoder. */ + /* The effective header table size. */ size_t hd_table_bufsize_max; - /* The current effective header table size for encoding. This value - is always equal to |hd_table_bufsize| on decoder - context. |deflate_hd_table_bufsize| <= |hd_table_bufsize| must be - hold. */ - size_t deflate_hd_table_bufsize; - /* The maximum effective header table for encoding. Although header - table size is bounded by |hd_table_bufsize_max|, the encoder can - use smaller buffer by not retaining the header name/values beyond - the |deflate_hd_table_bufsize_max| and not referencing those - entries. This value is always equal to |hd_table_bufsize_max| on - decoder context. */ - size_t deflate_hd_table_bufsize_max; - /* The number of effective entry in |hd_table|. This value is always - equal to hd_table.len on decoder side. */ - size_t deflate_hd_tablelen; /* Role of this context; deflate or infalte */ nghttp2_hd_role role; - /* NGHTTP2_HD_SIDE_REQUEST for processing request, otherwise - response. */ - nghttp2_hd_side side; /* If inflate/deflate error occurred, this value is set to 1 and further invocation of inflate/deflate will fail with NGHTTP2_ERR_HEADER_COMP. */ @@ -158,6 +135,8 @@ typedef struct { typedef struct { nghttp2_hd_context ctx; + /* The upper limit of the header table size the deflater accepts. */ + size_t deflate_hd_table_bufsize_max; /* Set to this nonzero to clear reference set on each deflation each time. */ uint8_t no_refset; @@ -189,6 +168,9 @@ typedef struct { /* The index of header table to toggle off the entry from reference set at the end of decompression. */ size_t end_headers_index; + /* The maximum header table size the inflater supports. This is the + same value transmitted in SETTINGS_HEADER_TABLE_SIZE */ + size_t settings_hd_table_bufsize_max; nghttp2_hd_opcode opcode; nghttp2_hd_inflate_state state; /* nonzero if string is huffman encoded */ @@ -230,8 +212,7 @@ void nghttp2_hd_entry_free(nghttp2_hd_entry *ent); * NGHTTP2_ERR_NOMEM * Out of memory. */ -int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, - nghttp2_hd_side side); +int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater); /* * Initializes |deflater| for deflating name/values pairs. @@ -247,7 +228,6 @@ int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, * Out of memory. */ int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, - nghttp2_hd_side side, size_t deflate_hd_table_bufsize_max); /* @@ -259,8 +239,7 @@ int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, * NGHTTP2_ERR_NOMEM * Out of memory. */ -int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, - nghttp2_hd_side side); +int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater); /* * Deallocates any resources allocated for |deflater|. @@ -282,10 +261,11 @@ void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater, uint8_t no_refset); /* - * Changes header table size in |context|. This may trigger eviction - * in the dynamic table. + * Changes header table size of the |deflater|. This may trigger + * eviction in the dynamic table. * - * This function can be used for deflater and inflater. + * The |settings_hd_table_bufsize_max| should be the value received in + * SETTINGS_HEADER_TABLE_SIZE. * * This function returns 0 if it succeeds, or one of the following * negative error codes: @@ -293,8 +273,25 @@ void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater, * NGHTTP2_ERR_NOMEM * Out of memory. */ -int nghttp2_hd_change_table_size(nghttp2_hd_context *context, - size_t hd_table_bufsize_max); +int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, + size_t settings_hd_table_bufsize_max); + +/* + * Changes header table size in the |inflater|. This may trigger + * eviction in the dynamic table. + * + * The |settings_hd_table_bufsize_max| should be the value transmitted + * in SETTINGS_HEADER_TABLE_SIZE. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * NGHTTP2_ERR_NOMEM + * Out of memory. + */ +int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater, + size_t settings_hd_table_bufsize_max); + /* * Deflates the |nva|, which has the |nvlen| name/value pairs, into @@ -379,14 +376,16 @@ int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater); int nghttp2_hd_emit_indname_block(uint8_t **buf_ptr, size_t *buflen_ptr, size_t *offset_ptr, size_t index, const uint8_t *value, size_t valuelen, - int inc_indexing, - nghttp2_hd_side side); + int inc_indexing); /* For unittesting purpose */ int nghttp2_hd_emit_newname_block(uint8_t **buf_ptr, size_t *buflen_ptr, size_t *offset_ptr, nghttp2_nv *nv, - int inc_indexing, - nghttp2_hd_side side); + int inc_indexing); + +/* For unittesting purpose */ +int nghttp2_hd_emit_table_size(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *offset_ptr, size_t table_size); /* For unittesting purpose */ nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context, @@ -395,37 +394,30 @@ nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context, /* Huffman encoding/decoding functions */ /* - * Counts the required bytes to encode |src| with length |len|. If - * |side| is NGHTTP2_HD_SIDE_REQUEST, the request huffman code table - * is used. Otherwise, the response code table is used. + * Counts the required bytes to encode |src| with length |len|. * * This function returns the number of required bytes to encode given * data, including padding of prefix of terminal symbol code. This * function always succeeds. */ -size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len, - nghttp2_hd_side side); +size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len); /* * Encodes the given data |src| with length |srclen| to the given * memory location pointed by |dest|, allocated at lest |destlen| * bytes. The caller is responsible to specify |destlen| at least the - * length that nghttp2_hd_huff_encode_count() returns. If |side| is - * NGHTTP2_HD_SIDE_REQUEST, the request huffman code table is - * used. Otherwise, the response code table is used. + * length that nghttp2_hd_huff_encode_count() returns. * * This function returns the number of written bytes, including * padding of prefix of terminal symbol code. This return value is * exactly the same with the return value of - * nghttp2_hd_huff_encode_count() if it is given with the same |src|, - * |srclen|, and |side|. This function always succeeds. + * nghttp2_hd_huff_encode_count() if it is given with the same |src| + * and |srclen|. This function always succeeds. */ ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen, - const uint8_t *src, size_t srclen, - nghttp2_hd_side side); + const uint8_t *src, size_t srclen); -void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx, - nghttp2_hd_side side); +void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx); /* * Decodes the given data |src| with length |srclen|. The |ctx| must @@ -453,4 +445,4 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, nghttp2_buffer *dest, const uint8_t *src, size_t srclen, int final); -#endif /* NGHTTP2_HD_COMP_H */ +#endif /* NGHTTP2_HD_H */ diff --git a/lib/nghttp2_hd_huffman.c b/lib/nghttp2_hd_huffman.c index 9c47f0b5..93abafe9 100644 --- a/lib/nghttp2_hd_huffman.c +++ b/lib/nghttp2_hd_huffman.c @@ -30,11 +30,8 @@ #include "nghttp2_hd.h" -extern const nghttp2_huff_sym req_huff_sym_table[]; -extern const nghttp2_huff_decode req_huff_decode_table[][16]; - -extern const nghttp2_huff_sym res_huff_sym_table[]; -extern const nghttp2_huff_decode res_huff_decode_table[][16]; +extern const nghttp2_huff_sym huff_sym_table[]; +extern const nghttp2_huff_decode huff_decode_table[][16]; /* * Encodes huffman code |sym| into |*dest_ptr|, whose least |rembits| @@ -65,18 +62,11 @@ static size_t huff_encode_sym(uint8_t **dest_ptr, size_t rembits, return rembits; } -size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len, - nghttp2_hd_side side) +size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) { size_t i; size_t nbits = 0; - const nghttp2_huff_sym *huff_sym_table; - if(side == NGHTTP2_HD_SIDE_REQUEST) { - huff_sym_table = req_huff_sym_table; - } else { - huff_sym_table = res_huff_sym_table; - } for(i = 0; i < len; ++i) { nbits += huff_sym_table[src[i]].nbits; } @@ -85,19 +75,12 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len, } ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen, - const uint8_t *src, size_t srclen, - nghttp2_hd_side side) + const uint8_t *src, size_t srclen) { int rembits = 8; uint8_t *dest_first = dest; size_t i; - const nghttp2_huff_sym *huff_sym_table; - if(side == NGHTTP2_HD_SIDE_REQUEST) { - huff_sym_table = req_huff_sym_table; - } else { - huff_sym_table = res_huff_sym_table; - } for(i = 0; i < srclen; ++i) { const nghttp2_huff_sym *sym = &huff_sym_table[src[i]]; if(rembits == 8) { @@ -114,14 +97,8 @@ ssize_t nghttp2_hd_huff_encode(uint8_t *dest, size_t destlen, return dest - dest_first; } -void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx, - nghttp2_hd_side side) +void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) { - if(side == NGHTTP2_HD_SIDE_REQUEST) { - ctx->huff_decode_table = req_huff_decode_table; - } else { - ctx->huff_decode_table = res_huff_decode_table; - } ctx->state = 0; ctx->accept = 1; } @@ -137,7 +114,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, for(i = 0; i < srclen; ++i) { uint8_t in = src[i] >> 4; for(j = 0; j < 2; ++j) { - const nghttp2_huff_decode *t = &ctx->huff_decode_table[ctx->state][in]; + const nghttp2_huff_decode *t = &huff_decode_table[ctx->state][in]; if(t->state == -1) { return NGHTTP2_ERR_HEADER_COMP; } diff --git a/lib/nghttp2_hd_huffman.h b/lib/nghttp2_hd_huffman.h index 50372b9d..fa992061 100644 --- a/lib/nghttp2_hd_huffman.h +++ b/lib/nghttp2_hd_huffman.h @@ -52,7 +52,6 @@ typedef struct { typedef nghttp2_huff_decode huff_decode_table_type[16]; typedef struct { - const huff_decode_table_type *huff_decode_table; /* Current huffman decoding state. We stripped leaf nodes, so the value range is [0..255], inclusive. */ uint8_t state; diff --git a/lib/nghttp2_hd_huffman_data.c b/lib/nghttp2_hd_huffman_data.c index 646aecdc..76ff83d1 100644 --- a/lib/nghttp2_hd_huffman_data.c +++ b/lib/nghttp2_hd_huffman_data.c @@ -24,7 +24,7 @@ */ #include "nghttp2_hd_huffman.h" -const nghttp2_huff_sym req_huff_sym_table[] = { +const nghttp2_huff_sym huff_sym_table[] = { { 27, 0x7ffffbau }, { 27, 0x7ffffbbu }, { 27, 0x7ffffbcu }, @@ -284,267 +284,7 @@ const nghttp2_huff_sym req_huff_sym_table[] = { { 26, 0x3ffffdcu } }; -const nghttp2_huff_sym res_huff_sym_table[] = { - { 25, 0x1ffffbcu }, - { 25, 0x1ffffbdu }, - { 25, 0x1ffffbeu }, - { 25, 0x1ffffbfu }, - { 25, 0x1ffffc0u }, - { 25, 0x1ffffc1u }, - { 25, 0x1ffffc2u }, - { 25, 0x1ffffc3u }, - { 25, 0x1ffffc4u }, - { 25, 0x1ffffc5u }, - { 25, 0x1ffffc6u }, - { 25, 0x1ffffc7u }, - { 25, 0x1ffffc8u }, - { 25, 0x1ffffc9u }, - { 25, 0x1ffffcau }, - { 25, 0x1ffffcbu }, - { 25, 0x1ffffccu }, - { 25, 0x1ffffcdu }, - { 25, 0x1ffffceu }, - { 25, 0x1ffffcfu }, - { 25, 0x1ffffd0u }, - { 25, 0x1ffffd1u }, - { 25, 0x1ffffd2u }, - { 25, 0x1ffffd3u }, - { 25, 0x1ffffd4u }, - { 25, 0x1ffffd5u }, - { 25, 0x1ffffd6u }, - { 25, 0x1ffffd7u }, - { 25, 0x1ffffd8u }, - { 25, 0x1ffffd9u }, - { 25, 0x1ffffdau }, - { 25, 0x1ffffdbu }, - { 4, 0x0u }, - { 12, 0xffau }, - { 7, 0x6au }, - { 13, 0x1ffau }, - { 14, 0x3ffcu }, - { 9, 0x1ecu }, - { 10, 0x3f8u }, - { 13, 0x1ffbu }, - { 9, 0x1edu }, - { 9, 0x1eeu }, - { 12, 0xffbu }, - { 11, 0x7fau }, - { 6, 0x22u }, - { 6, 0x23u }, - { 6, 0x24u }, - { 7, 0x6bu }, - { 4, 0x1u }, - { 4, 0x2u }, - { 4, 0x3u }, - { 5, 0x8u }, - { 5, 0x9u }, - { 5, 0xau }, - { 6, 0x25u }, - { 6, 0x26u }, - { 5, 0xbu }, - { 5, 0xcu }, - { 5, 0xdu }, - { 9, 0x1efu }, - { 16, 0xfffau }, - { 7, 0x6cu }, - { 13, 0x1ffcu }, - { 12, 0xffcu }, - { 16, 0xfffbu }, - { 7, 0x6du }, - { 8, 0xeau }, - { 8, 0xebu }, - { 8, 0xecu }, - { 8, 0xedu }, - { 8, 0xeeu }, - { 6, 0x27u }, - { 9, 0x1f0u }, - { 8, 0xefu }, - { 8, 0xf0u }, - { 10, 0x3f9u }, - { 9, 0x1f1u }, - { 6, 0x28u }, - { 8, 0xf1u }, - { 8, 0xf2u }, - { 9, 0x1f2u }, - { 10, 0x3fau }, - { 9, 0x1f3u }, - { 6, 0x29u }, - { 5, 0xeu }, - { 9, 0x1f4u }, - { 9, 0x1f5u }, - { 8, 0xf3u }, - { 10, 0x3fbu }, - { 9, 0x1f6u }, - { 10, 0x3fcu }, - { 11, 0x7fbu }, - { 13, 0x1ffdu }, - { 11, 0x7fcu }, - { 15, 0x7ffcu }, - { 9, 0x1f7u }, - { 17, 0x1fffeu }, - { 5, 0xfu }, - { 7, 0x6eu }, - { 6, 0x2au }, - { 6, 0x2bu }, - { 5, 0x10u }, - { 7, 0x6fu }, - { 7, 0x70u }, - { 7, 0x71u }, - { 6, 0x2cu }, - { 9, 0x1f8u }, - { 9, 0x1f9u }, - { 7, 0x72u }, - { 6, 0x2du }, - { 6, 0x2eu }, - { 6, 0x2fu }, - { 6, 0x30u }, - { 9, 0x1fau }, - { 6, 0x31u }, - { 6, 0x32u }, - { 6, 0x33u }, - { 6, 0x34u }, - { 7, 0x73u }, - { 8, 0xf4u }, - { 7, 0x74u }, - { 8, 0xf5u }, - { 9, 0x1fbu }, - { 16, 0xfffcu }, - { 14, 0x3ffdu }, - { 16, 0xfffdu }, - { 16, 0xfffeu }, - { 25, 0x1ffffdcu }, - { 25, 0x1ffffddu }, - { 25, 0x1ffffdeu }, - { 25, 0x1ffffdfu }, - { 25, 0x1ffffe0u }, - { 25, 0x1ffffe1u }, - { 25, 0x1ffffe2u }, - { 25, 0x1ffffe3u }, - { 25, 0x1ffffe4u }, - { 25, 0x1ffffe5u }, - { 25, 0x1ffffe6u }, - { 25, 0x1ffffe7u }, - { 25, 0x1ffffe8u }, - { 25, 0x1ffffe9u }, - { 25, 0x1ffffeau }, - { 25, 0x1ffffebu }, - { 25, 0x1ffffecu }, - { 25, 0x1ffffedu }, - { 25, 0x1ffffeeu }, - { 25, 0x1ffffefu }, - { 25, 0x1fffff0u }, - { 25, 0x1fffff1u }, - { 25, 0x1fffff2u }, - { 25, 0x1fffff3u }, - { 25, 0x1fffff4u }, - { 25, 0x1fffff5u }, - { 25, 0x1fffff6u }, - { 25, 0x1fffff7u }, - { 25, 0x1fffff8u }, - { 25, 0x1fffff9u }, - { 25, 0x1fffffau }, - { 25, 0x1fffffbu }, - { 25, 0x1fffffcu }, - { 25, 0x1fffffdu }, - { 25, 0x1fffffeu }, - { 25, 0x1ffffffu }, - { 24, 0xffff80u }, - { 24, 0xffff81u }, - { 24, 0xffff82u }, - { 24, 0xffff83u }, - { 24, 0xffff84u }, - { 24, 0xffff85u }, - { 24, 0xffff86u }, - { 24, 0xffff87u }, - { 24, 0xffff88u }, - { 24, 0xffff89u }, - { 24, 0xffff8au }, - { 24, 0xffff8bu }, - { 24, 0xffff8cu }, - { 24, 0xffff8du }, - { 24, 0xffff8eu }, - { 24, 0xffff8fu }, - { 24, 0xffff90u }, - { 24, 0xffff91u }, - { 24, 0xffff92u }, - { 24, 0xffff93u }, - { 24, 0xffff94u }, - { 24, 0xffff95u }, - { 24, 0xffff96u }, - { 24, 0xffff97u }, - { 24, 0xffff98u }, - { 24, 0xffff99u }, - { 24, 0xffff9au }, - { 24, 0xffff9bu }, - { 24, 0xffff9cu }, - { 24, 0xffff9du }, - { 24, 0xffff9eu }, - { 24, 0xffff9fu }, - { 24, 0xffffa0u }, - { 24, 0xffffa1u }, - { 24, 0xffffa2u }, - { 24, 0xffffa3u }, - { 24, 0xffffa4u }, - { 24, 0xffffa5u }, - { 24, 0xffffa6u }, - { 24, 0xffffa7u }, - { 24, 0xffffa8u }, - { 24, 0xffffa9u }, - { 24, 0xffffaau }, - { 24, 0xffffabu }, - { 24, 0xffffacu }, - { 24, 0xffffadu }, - { 24, 0xffffaeu }, - { 24, 0xffffafu }, - { 24, 0xffffb0u }, - { 24, 0xffffb1u }, - { 24, 0xffffb2u }, - { 24, 0xffffb3u }, - { 24, 0xffffb4u }, - { 24, 0xffffb5u }, - { 24, 0xffffb6u }, - { 24, 0xffffb7u }, - { 24, 0xffffb8u }, - { 24, 0xffffb9u }, - { 24, 0xffffbau }, - { 24, 0xffffbbu }, - { 24, 0xffffbcu }, - { 24, 0xffffbdu }, - { 24, 0xffffbeu }, - { 24, 0xffffbfu }, - { 24, 0xffffc0u }, - { 24, 0xffffc1u }, - { 24, 0xffffc2u }, - { 24, 0xffffc3u }, - { 24, 0xffffc4u }, - { 24, 0xffffc5u }, - { 24, 0xffffc6u }, - { 24, 0xffffc7u }, - { 24, 0xffffc8u }, - { 24, 0xffffc9u }, - { 24, 0xffffcau }, - { 24, 0xffffcbu }, - { 24, 0xffffccu }, - { 24, 0xffffcdu }, - { 24, 0xffffceu }, - { 24, 0xffffcfu }, - { 24, 0xffffd0u }, - { 24, 0xffffd1u }, - { 24, 0xffffd2u }, - { 24, 0xffffd3u }, - { 24, 0xffffd4u }, - { 24, 0xffffd5u }, - { 24, 0xffffd6u }, - { 24, 0xffffd7u }, - { 24, 0xffffd8u }, - { 24, 0xffffd9u }, - { 24, 0xffffdau }, - { 24, 0xffffdbu }, - { 24, 0xffffdcu }, - { 24, 0xffffddu } -}; - -const nghttp2_huff_decode req_huff_decode_table[][16] = { +const nghttp2_huff_decode huff_decode_table[][16] = { /* 0 */ { {0, 0x03, 47}, @@ -5410,4870 +5150,3 @@ const nghttp2_huff_decode req_huff_decode_table[][16] = { {37, 0x03, 163}, }, }; - -const nghttp2_huff_decode res_huff_decode_table[][16] = { -/* 0 */ -{ - {0, 0x03, 32}, - {0, 0x03, 48}, - {0, 0x03, 49}, - {0, 0x03, 50}, - {7, 0x00, 0}, - {8, 0x00, 0}, - {10, 0x00, 0}, - {11, 0x00, 0}, - {15, 0x00, 0}, - {17, 0x00, 0}, - {21, 0x00, 0}, - {24, 0x00, 0}, - {29, 0x00, 0}, - {32, 0x00, 0}, - {39, 0x00, 0}, - {49, 0x01, 0}, -}, -/* 1 */ -{ - {1, 0x02, 32}, - {12, 0x03, 32}, - {1, 0x02, 48}, - {12, 0x03, 48}, - {1, 0x02, 49}, - {12, 0x03, 49}, - {1, 0x02, 50}, - {12, 0x03, 50}, - {0, 0x03, 51}, - {0, 0x03, 52}, - {0, 0x03, 53}, - {0, 0x03, 56}, - {0, 0x03, 57}, - {0, 0x03, 58}, - {0, 0x03, 84}, - {0, 0x03, 97}, -}, -/* 2 */ -{ - {2, 0x02, 32}, - {5, 0x02, 32}, - {13, 0x02, 32}, - {27, 0x03, 32}, - {2, 0x02, 48}, - {5, 0x02, 48}, - {13, 0x02, 48}, - {27, 0x03, 48}, - {2, 0x02, 49}, - {5, 0x02, 49}, - {13, 0x02, 49}, - {27, 0x03, 49}, - {2, 0x02, 50}, - {5, 0x02, 50}, - {13, 0x02, 50}, - {27, 0x03, 50}, -}, -/* 3 */ -{ - {3, 0x02, 32}, - {4, 0x02, 32}, - {6, 0x02, 32}, - {9, 0x02, 32}, - {14, 0x02, 32}, - {20, 0x02, 32}, - {28, 0x02, 32}, - {38, 0x03, 32}, - {3, 0x02, 48}, - {4, 0x02, 48}, - {6, 0x02, 48}, - {9, 0x02, 48}, - {14, 0x02, 48}, - {20, 0x02, 48}, - {28, 0x02, 48}, - {38, 0x03, 48}, -}, -/* 4 */ -{ - {3, 0x02, 49}, - {4, 0x02, 49}, - {6, 0x02, 49}, - {9, 0x02, 49}, - {14, 0x02, 49}, - {20, 0x02, 49}, - {28, 0x02, 49}, - {38, 0x03, 49}, - {3, 0x02, 50}, - {4, 0x02, 50}, - {6, 0x02, 50}, - {9, 0x02, 50}, - {14, 0x02, 50}, - {20, 0x02, 50}, - {28, 0x02, 50}, - {38, 0x03, 50}, -}, -/* 5 */ -{ - {1, 0x02, 51}, - {12, 0x03, 51}, - {1, 0x02, 52}, - {12, 0x03, 52}, - {1, 0x02, 53}, - {12, 0x03, 53}, - {1, 0x02, 56}, - {12, 0x03, 56}, - {1, 0x02, 57}, - {12, 0x03, 57}, - {1, 0x02, 58}, - {12, 0x03, 58}, - {1, 0x02, 84}, - {12, 0x03, 84}, - {1, 0x02, 97}, - {12, 0x03, 97}, -}, -/* 6 */ -{ - {2, 0x02, 51}, - {5, 0x02, 51}, - {13, 0x02, 51}, - {27, 0x03, 51}, - {2, 0x02, 52}, - {5, 0x02, 52}, - {13, 0x02, 52}, - {27, 0x03, 52}, - {2, 0x02, 53}, - {5, 0x02, 53}, - {13, 0x02, 53}, - {27, 0x03, 53}, - {2, 0x02, 56}, - {5, 0x02, 56}, - {13, 0x02, 56}, - {27, 0x03, 56}, -}, -/* 7 */ -{ - {3, 0x02, 51}, - {4, 0x02, 51}, - {6, 0x02, 51}, - {9, 0x02, 51}, - {14, 0x02, 51}, - {20, 0x02, 51}, - {28, 0x02, 51}, - {38, 0x03, 51}, - {3, 0x02, 52}, - {4, 0x02, 52}, - {6, 0x02, 52}, - {9, 0x02, 52}, - {14, 0x02, 52}, - {20, 0x02, 52}, - {28, 0x02, 52}, - {38, 0x03, 52}, -}, -/* 8 */ -{ - {3, 0x02, 53}, - {4, 0x02, 53}, - {6, 0x02, 53}, - {9, 0x02, 53}, - {14, 0x02, 53}, - {20, 0x02, 53}, - {28, 0x02, 53}, - {38, 0x03, 53}, - {3, 0x02, 56}, - {4, 0x02, 56}, - {6, 0x02, 56}, - {9, 0x02, 56}, - {14, 0x02, 56}, - {20, 0x02, 56}, - {28, 0x02, 56}, - {38, 0x03, 56}, -}, -/* 9 */ -{ - {2, 0x02, 57}, - {5, 0x02, 57}, - {13, 0x02, 57}, - {27, 0x03, 57}, - {2, 0x02, 58}, - {5, 0x02, 58}, - {13, 0x02, 58}, - {27, 0x03, 58}, - {2, 0x02, 84}, - {5, 0x02, 84}, - {13, 0x02, 84}, - {27, 0x03, 84}, - {2, 0x02, 97}, - {5, 0x02, 97}, - {13, 0x02, 97}, - {27, 0x03, 97}, -}, -/* 10 */ -{ - {3, 0x02, 57}, - {4, 0x02, 57}, - {6, 0x02, 57}, - {9, 0x02, 57}, - {14, 0x02, 57}, - {20, 0x02, 57}, - {28, 0x02, 57}, - {38, 0x03, 57}, - {3, 0x02, 58}, - {4, 0x02, 58}, - {6, 0x02, 58}, - {9, 0x02, 58}, - {14, 0x02, 58}, - {20, 0x02, 58}, - {28, 0x02, 58}, - {38, 0x03, 58}, -}, -/* 11 */ -{ - {3, 0x02, 84}, - {4, 0x02, 84}, - {6, 0x02, 84}, - {9, 0x02, 84}, - {14, 0x02, 84}, - {20, 0x02, 84}, - {28, 0x02, 84}, - {38, 0x03, 84}, - {3, 0x02, 97}, - {4, 0x02, 97}, - {6, 0x02, 97}, - {9, 0x02, 97}, - {14, 0x02, 97}, - {20, 0x02, 97}, - {28, 0x02, 97}, - {38, 0x03, 97}, -}, -/* 12 */ -{ - {0, 0x03, 101}, - {16, 0x00, 0}, - {18, 0x00, 0}, - {19, 0x00, 0}, - {22, 0x00, 0}, - {23, 0x00, 0}, - {25, 0x00, 0}, - {26, 0x00, 0}, - {30, 0x00, 0}, - {31, 0x00, 0}, - {33, 0x00, 0}, - {35, 0x00, 0}, - {40, 0x00, 0}, - {43, 0x00, 0}, - {50, 0x00, 0}, - {59, 0x01, 0}, -}, -/* 13 */ -{ - {1, 0x02, 101}, - {12, 0x03, 101}, - {0, 0x03, 44}, - {0, 0x03, 45}, - {0, 0x03, 46}, - {0, 0x03, 54}, - {0, 0x03, 55}, - {0, 0x03, 71}, - {0, 0x03, 77}, - {0, 0x03, 83}, - {0, 0x03, 99}, - {0, 0x03, 100}, - {0, 0x03, 105}, - {0, 0x03, 109}, - {0, 0x03, 110}, - {0, 0x03, 111}, -}, -/* 14 */ -{ - {2, 0x02, 101}, - {5, 0x02, 101}, - {13, 0x02, 101}, - {27, 0x03, 101}, - {1, 0x02, 44}, - {12, 0x03, 44}, - {1, 0x02, 45}, - {12, 0x03, 45}, - {1, 0x02, 46}, - {12, 0x03, 46}, - {1, 0x02, 54}, - {12, 0x03, 54}, - {1, 0x02, 55}, - {12, 0x03, 55}, - {1, 0x02, 71}, - {12, 0x03, 71}, -}, -/* 15 */ -{ - {3, 0x02, 101}, - {4, 0x02, 101}, - {6, 0x02, 101}, - {9, 0x02, 101}, - {14, 0x02, 101}, - {20, 0x02, 101}, - {28, 0x02, 101}, - {38, 0x03, 101}, - {2, 0x02, 44}, - {5, 0x02, 44}, - {13, 0x02, 44}, - {27, 0x03, 44}, - {2, 0x02, 45}, - {5, 0x02, 45}, - {13, 0x02, 45}, - {27, 0x03, 45}, -}, -/* 16 */ -{ - {3, 0x02, 44}, - {4, 0x02, 44}, - {6, 0x02, 44}, - {9, 0x02, 44}, - {14, 0x02, 44}, - {20, 0x02, 44}, - {28, 0x02, 44}, - {38, 0x03, 44}, - {3, 0x02, 45}, - {4, 0x02, 45}, - {6, 0x02, 45}, - {9, 0x02, 45}, - {14, 0x02, 45}, - {20, 0x02, 45}, - {28, 0x02, 45}, - {38, 0x03, 45}, -}, -/* 17 */ -{ - {2, 0x02, 46}, - {5, 0x02, 46}, - {13, 0x02, 46}, - {27, 0x03, 46}, - {2, 0x02, 54}, - {5, 0x02, 54}, - {13, 0x02, 54}, - {27, 0x03, 54}, - {2, 0x02, 55}, - {5, 0x02, 55}, - {13, 0x02, 55}, - {27, 0x03, 55}, - {2, 0x02, 71}, - {5, 0x02, 71}, - {13, 0x02, 71}, - {27, 0x03, 71}, -}, -/* 18 */ -{ - {3, 0x02, 46}, - {4, 0x02, 46}, - {6, 0x02, 46}, - {9, 0x02, 46}, - {14, 0x02, 46}, - {20, 0x02, 46}, - {28, 0x02, 46}, - {38, 0x03, 46}, - {3, 0x02, 54}, - {4, 0x02, 54}, - {6, 0x02, 54}, - {9, 0x02, 54}, - {14, 0x02, 54}, - {20, 0x02, 54}, - {28, 0x02, 54}, - {38, 0x03, 54}, -}, -/* 19 */ -{ - {3, 0x02, 55}, - {4, 0x02, 55}, - {6, 0x02, 55}, - {9, 0x02, 55}, - {14, 0x02, 55}, - {20, 0x02, 55}, - {28, 0x02, 55}, - {38, 0x03, 55}, - {3, 0x02, 71}, - {4, 0x02, 71}, - {6, 0x02, 71}, - {9, 0x02, 71}, - {14, 0x02, 71}, - {20, 0x02, 71}, - {28, 0x02, 71}, - {38, 0x03, 71}, -}, -/* 20 */ -{ - {1, 0x02, 77}, - {12, 0x03, 77}, - {1, 0x02, 83}, - {12, 0x03, 83}, - {1, 0x02, 99}, - {12, 0x03, 99}, - {1, 0x02, 100}, - {12, 0x03, 100}, - {1, 0x02, 105}, - {12, 0x03, 105}, - {1, 0x02, 109}, - {12, 0x03, 109}, - {1, 0x02, 110}, - {12, 0x03, 110}, - {1, 0x02, 111}, - {12, 0x03, 111}, -}, -/* 21 */ -{ - {2, 0x02, 77}, - {5, 0x02, 77}, - {13, 0x02, 77}, - {27, 0x03, 77}, - {2, 0x02, 83}, - {5, 0x02, 83}, - {13, 0x02, 83}, - {27, 0x03, 83}, - {2, 0x02, 99}, - {5, 0x02, 99}, - {13, 0x02, 99}, - {27, 0x03, 99}, - {2, 0x02, 100}, - {5, 0x02, 100}, - {13, 0x02, 100}, - {27, 0x03, 100}, -}, -/* 22 */ -{ - {3, 0x02, 77}, - {4, 0x02, 77}, - {6, 0x02, 77}, - {9, 0x02, 77}, - {14, 0x02, 77}, - {20, 0x02, 77}, - {28, 0x02, 77}, - {38, 0x03, 77}, - {3, 0x02, 83}, - {4, 0x02, 83}, - {6, 0x02, 83}, - {9, 0x02, 83}, - {14, 0x02, 83}, - {20, 0x02, 83}, - {28, 0x02, 83}, - {38, 0x03, 83}, -}, -/* 23 */ -{ - {3, 0x02, 99}, - {4, 0x02, 99}, - {6, 0x02, 99}, - {9, 0x02, 99}, - {14, 0x02, 99}, - {20, 0x02, 99}, - {28, 0x02, 99}, - {38, 0x03, 99}, - {3, 0x02, 100}, - {4, 0x02, 100}, - {6, 0x02, 100}, - {9, 0x02, 100}, - {14, 0x02, 100}, - {20, 0x02, 100}, - {28, 0x02, 100}, - {38, 0x03, 100}, -}, -/* 24 */ -{ - {2, 0x02, 105}, - {5, 0x02, 105}, - {13, 0x02, 105}, - {27, 0x03, 105}, - {2, 0x02, 109}, - {5, 0x02, 109}, - {13, 0x02, 109}, - {27, 0x03, 109}, - {2, 0x02, 110}, - {5, 0x02, 110}, - {13, 0x02, 110}, - {27, 0x03, 110}, - {2, 0x02, 111}, - {5, 0x02, 111}, - {13, 0x02, 111}, - {27, 0x03, 111}, -}, -/* 25 */ -{ - {3, 0x02, 105}, - {4, 0x02, 105}, - {6, 0x02, 105}, - {9, 0x02, 105}, - {14, 0x02, 105}, - {20, 0x02, 105}, - {28, 0x02, 105}, - {38, 0x03, 105}, - {3, 0x02, 109}, - {4, 0x02, 109}, - {6, 0x02, 109}, - {9, 0x02, 109}, - {14, 0x02, 109}, - {20, 0x02, 109}, - {28, 0x02, 109}, - {38, 0x03, 109}, -}, -/* 26 */ -{ - {3, 0x02, 110}, - {4, 0x02, 110}, - {6, 0x02, 110}, - {9, 0x02, 110}, - {14, 0x02, 110}, - {20, 0x02, 110}, - {28, 0x02, 110}, - {38, 0x03, 110}, - {3, 0x02, 111}, - {4, 0x02, 111}, - {6, 0x02, 111}, - {9, 0x02, 111}, - {14, 0x02, 111}, - {20, 0x02, 111}, - {28, 0x02, 111}, - {38, 0x03, 111}, -}, -/* 27 */ -{ - {0, 0x03, 112}, - {0, 0x03, 114}, - {0, 0x03, 115}, - {0, 0x03, 116}, - {0, 0x03, 117}, - {34, 0x00, 0}, - {36, 0x00, 0}, - {37, 0x00, 0}, - {41, 0x00, 0}, - {42, 0x00, 0}, - {44, 0x00, 0}, - {46, 0x00, 0}, - {51, 0x00, 0}, - {54, 0x00, 0}, - {60, 0x00, 0}, - {67, 0x01, 0}, -}, -/* 28 */ -{ - {1, 0x02, 112}, - {12, 0x03, 112}, - {1, 0x02, 114}, - {12, 0x03, 114}, - {1, 0x02, 115}, - {12, 0x03, 115}, - {1, 0x02, 116}, - {12, 0x03, 116}, - {1, 0x02, 117}, - {12, 0x03, 117}, - {0, 0x03, 34}, - {0, 0x03, 47}, - {0, 0x03, 61}, - {0, 0x03, 65}, - {0, 0x03, 98}, - {0, 0x03, 102}, -}, -/* 29 */ -{ - {2, 0x02, 112}, - {5, 0x02, 112}, - {13, 0x02, 112}, - {27, 0x03, 112}, - {2, 0x02, 114}, - {5, 0x02, 114}, - {13, 0x02, 114}, - {27, 0x03, 114}, - {2, 0x02, 115}, - {5, 0x02, 115}, - {13, 0x02, 115}, - {27, 0x03, 115}, - {2, 0x02, 116}, - {5, 0x02, 116}, - {13, 0x02, 116}, - {27, 0x03, 116}, -}, -/* 30 */ -{ - {3, 0x02, 112}, - {4, 0x02, 112}, - {6, 0x02, 112}, - {9, 0x02, 112}, - {14, 0x02, 112}, - {20, 0x02, 112}, - {28, 0x02, 112}, - {38, 0x03, 112}, - {3, 0x02, 114}, - {4, 0x02, 114}, - {6, 0x02, 114}, - {9, 0x02, 114}, - {14, 0x02, 114}, - {20, 0x02, 114}, - {28, 0x02, 114}, - {38, 0x03, 114}, -}, -/* 31 */ -{ - {3, 0x02, 115}, - {4, 0x02, 115}, - {6, 0x02, 115}, - {9, 0x02, 115}, - {14, 0x02, 115}, - {20, 0x02, 115}, - {28, 0x02, 115}, - {38, 0x03, 115}, - {3, 0x02, 116}, - {4, 0x02, 116}, - {6, 0x02, 116}, - {9, 0x02, 116}, - {14, 0x02, 116}, - {20, 0x02, 116}, - {28, 0x02, 116}, - {38, 0x03, 116}, -}, -/* 32 */ -{ - {2, 0x02, 117}, - {5, 0x02, 117}, - {13, 0x02, 117}, - {27, 0x03, 117}, - {1, 0x02, 34}, - {12, 0x03, 34}, - {1, 0x02, 47}, - {12, 0x03, 47}, - {1, 0x02, 61}, - {12, 0x03, 61}, - {1, 0x02, 65}, - {12, 0x03, 65}, - {1, 0x02, 98}, - {12, 0x03, 98}, - {1, 0x02, 102}, - {12, 0x03, 102}, -}, -/* 33 */ -{ - {3, 0x02, 117}, - {4, 0x02, 117}, - {6, 0x02, 117}, - {9, 0x02, 117}, - {14, 0x02, 117}, - {20, 0x02, 117}, - {28, 0x02, 117}, - {38, 0x03, 117}, - {2, 0x02, 34}, - {5, 0x02, 34}, - {13, 0x02, 34}, - {27, 0x03, 34}, - {2, 0x02, 47}, - {5, 0x02, 47}, - {13, 0x02, 47}, - {27, 0x03, 47}, -}, -/* 34 */ -{ - {3, 0x02, 34}, - {4, 0x02, 34}, - {6, 0x02, 34}, - {9, 0x02, 34}, - {14, 0x02, 34}, - {20, 0x02, 34}, - {28, 0x02, 34}, - {38, 0x03, 34}, - {3, 0x02, 47}, - {4, 0x02, 47}, - {6, 0x02, 47}, - {9, 0x02, 47}, - {14, 0x02, 47}, - {20, 0x02, 47}, - {28, 0x02, 47}, - {38, 0x03, 47}, -}, -/* 35 */ -{ - {2, 0x02, 61}, - {5, 0x02, 61}, - {13, 0x02, 61}, - {27, 0x03, 61}, - {2, 0x02, 65}, - {5, 0x02, 65}, - {13, 0x02, 65}, - {27, 0x03, 65}, - {2, 0x02, 98}, - {5, 0x02, 98}, - {13, 0x02, 98}, - {27, 0x03, 98}, - {2, 0x02, 102}, - {5, 0x02, 102}, - {13, 0x02, 102}, - {27, 0x03, 102}, -}, -/* 36 */ -{ - {3, 0x02, 61}, - {4, 0x02, 61}, - {6, 0x02, 61}, - {9, 0x02, 61}, - {14, 0x02, 61}, - {20, 0x02, 61}, - {28, 0x02, 61}, - {38, 0x03, 61}, - {3, 0x02, 65}, - {4, 0x02, 65}, - {6, 0x02, 65}, - {9, 0x02, 65}, - {14, 0x02, 65}, - {20, 0x02, 65}, - {28, 0x02, 65}, - {38, 0x03, 65}, -}, -/* 37 */ -{ - {3, 0x02, 98}, - {4, 0x02, 98}, - {6, 0x02, 98}, - {9, 0x02, 98}, - {14, 0x02, 98}, - {20, 0x02, 98}, - {28, 0x02, 98}, - {38, 0x03, 98}, - {3, 0x02, 102}, - {4, 0x02, 102}, - {6, 0x02, 102}, - {9, 0x02, 102}, - {14, 0x02, 102}, - {20, 0x02, 102}, - {28, 0x02, 102}, - {38, 0x03, 102}, -}, -/* 38 */ -{ - {0, 0x03, 103}, - {0, 0x03, 104}, - {0, 0x03, 108}, - {0, 0x03, 118}, - {0, 0x03, 120}, - {45, 0x00, 0}, - {47, 0x00, 0}, - {48, 0x00, 0}, - {52, 0x00, 0}, - {53, 0x00, 0}, - {55, 0x00, 0}, - {56, 0x00, 0}, - {61, 0x00, 0}, - {64, 0x00, 0}, - {68, 0x00, 0}, - {71, 0x01, 0}, -}, -/* 39 */ -{ - {1, 0x02, 103}, - {12, 0x03, 103}, - {1, 0x02, 104}, - {12, 0x03, 104}, - {1, 0x02, 108}, - {12, 0x03, 108}, - {1, 0x02, 118}, - {12, 0x03, 118}, - {1, 0x02, 120}, - {12, 0x03, 120}, - {0, 0x03, 66}, - {0, 0x03, 67}, - {0, 0x03, 68}, - {0, 0x03, 69}, - {0, 0x03, 70}, - {0, 0x03, 73}, -}, -/* 40 */ -{ - {2, 0x02, 103}, - {5, 0x02, 103}, - {13, 0x02, 103}, - {27, 0x03, 103}, - {2, 0x02, 104}, - {5, 0x02, 104}, - {13, 0x02, 104}, - {27, 0x03, 104}, - {2, 0x02, 108}, - {5, 0x02, 108}, - {13, 0x02, 108}, - {27, 0x03, 108}, - {2, 0x02, 118}, - {5, 0x02, 118}, - {13, 0x02, 118}, - {27, 0x03, 118}, -}, -/* 41 */ -{ - {3, 0x02, 103}, - {4, 0x02, 103}, - {6, 0x02, 103}, - {9, 0x02, 103}, - {14, 0x02, 103}, - {20, 0x02, 103}, - {28, 0x02, 103}, - {38, 0x03, 103}, - {3, 0x02, 104}, - {4, 0x02, 104}, - {6, 0x02, 104}, - {9, 0x02, 104}, - {14, 0x02, 104}, - {20, 0x02, 104}, - {28, 0x02, 104}, - {38, 0x03, 104}, -}, -/* 42 */ -{ - {3, 0x02, 108}, - {4, 0x02, 108}, - {6, 0x02, 108}, - {9, 0x02, 108}, - {14, 0x02, 108}, - {20, 0x02, 108}, - {28, 0x02, 108}, - {38, 0x03, 108}, - {3, 0x02, 118}, - {4, 0x02, 118}, - {6, 0x02, 118}, - {9, 0x02, 118}, - {14, 0x02, 118}, - {20, 0x02, 118}, - {28, 0x02, 118}, - {38, 0x03, 118}, -}, -/* 43 */ -{ - {2, 0x02, 120}, - {5, 0x02, 120}, - {13, 0x02, 120}, - {27, 0x03, 120}, - {1, 0x02, 66}, - {12, 0x03, 66}, - {1, 0x02, 67}, - {12, 0x03, 67}, - {1, 0x02, 68}, - {12, 0x03, 68}, - {1, 0x02, 69}, - {12, 0x03, 69}, - {1, 0x02, 70}, - {12, 0x03, 70}, - {1, 0x02, 73}, - {12, 0x03, 73}, -}, -/* 44 */ -{ - {3, 0x02, 120}, - {4, 0x02, 120}, - {6, 0x02, 120}, - {9, 0x02, 120}, - {14, 0x02, 120}, - {20, 0x02, 120}, - {28, 0x02, 120}, - {38, 0x03, 120}, - {2, 0x02, 66}, - {5, 0x02, 66}, - {13, 0x02, 66}, - {27, 0x03, 66}, - {2, 0x02, 67}, - {5, 0x02, 67}, - {13, 0x02, 67}, - {27, 0x03, 67}, -}, -/* 45 */ -{ - {3, 0x02, 66}, - {4, 0x02, 66}, - {6, 0x02, 66}, - {9, 0x02, 66}, - {14, 0x02, 66}, - {20, 0x02, 66}, - {28, 0x02, 66}, - {38, 0x03, 66}, - {3, 0x02, 67}, - {4, 0x02, 67}, - {6, 0x02, 67}, - {9, 0x02, 67}, - {14, 0x02, 67}, - {20, 0x02, 67}, - {28, 0x02, 67}, - {38, 0x03, 67}, -}, -/* 46 */ -{ - {2, 0x02, 68}, - {5, 0x02, 68}, - {13, 0x02, 68}, - {27, 0x03, 68}, - {2, 0x02, 69}, - {5, 0x02, 69}, - {13, 0x02, 69}, - {27, 0x03, 69}, - {2, 0x02, 70}, - {5, 0x02, 70}, - {13, 0x02, 70}, - {27, 0x03, 70}, - {2, 0x02, 73}, - {5, 0x02, 73}, - {13, 0x02, 73}, - {27, 0x03, 73}, -}, -/* 47 */ -{ - {3, 0x02, 68}, - {4, 0x02, 68}, - {6, 0x02, 68}, - {9, 0x02, 68}, - {14, 0x02, 68}, - {20, 0x02, 68}, - {28, 0x02, 68}, - {38, 0x03, 68}, - {3, 0x02, 69}, - {4, 0x02, 69}, - {6, 0x02, 69}, - {9, 0x02, 69}, - {14, 0x02, 69}, - {20, 0x02, 69}, - {28, 0x02, 69}, - {38, 0x03, 69}, -}, -/* 48 */ -{ - {3, 0x02, 70}, - {4, 0x02, 70}, - {6, 0x02, 70}, - {9, 0x02, 70}, - {14, 0x02, 70}, - {20, 0x02, 70}, - {28, 0x02, 70}, - {38, 0x03, 70}, - {3, 0x02, 73}, - {4, 0x02, 73}, - {6, 0x02, 73}, - {9, 0x02, 73}, - {14, 0x02, 73}, - {20, 0x02, 73}, - {28, 0x02, 73}, - {38, 0x03, 73}, -}, -/* 49 */ -{ - {0, 0x03, 74}, - {0, 0x03, 78}, - {0, 0x03, 79}, - {0, 0x03, 87}, - {0, 0x03, 119}, - {0, 0x03, 121}, - {57, 0x00, 0}, - {58, 0x00, 0}, - {62, 0x00, 0}, - {63, 0x00, 0}, - {65, 0x00, 0}, - {66, 0x00, 0}, - {69, 0x00, 0}, - {70, 0x00, 0}, - {72, 0x00, 0}, - {75, 0x00, 0}, -}, -/* 50 */ -{ - {1, 0x02, 74}, - {12, 0x03, 74}, - {1, 0x02, 78}, - {12, 0x03, 78}, - {1, 0x02, 79}, - {12, 0x03, 79}, - {1, 0x02, 87}, - {12, 0x03, 87}, - {1, 0x02, 119}, - {12, 0x03, 119}, - {1, 0x02, 121}, - {12, 0x03, 121}, - {0, 0x03, 37}, - {0, 0x03, 40}, - {0, 0x03, 41}, - {0, 0x03, 59}, -}, -/* 51 */ -{ - {2, 0x02, 74}, - {5, 0x02, 74}, - {13, 0x02, 74}, - {27, 0x03, 74}, - {2, 0x02, 78}, - {5, 0x02, 78}, - {13, 0x02, 78}, - {27, 0x03, 78}, - {2, 0x02, 79}, - {5, 0x02, 79}, - {13, 0x02, 79}, - {27, 0x03, 79}, - {2, 0x02, 87}, - {5, 0x02, 87}, - {13, 0x02, 87}, - {27, 0x03, 87}, -}, -/* 52 */ -{ - {3, 0x02, 74}, - {4, 0x02, 74}, - {6, 0x02, 74}, - {9, 0x02, 74}, - {14, 0x02, 74}, - {20, 0x02, 74}, - {28, 0x02, 74}, - {38, 0x03, 74}, - {3, 0x02, 78}, - {4, 0x02, 78}, - {6, 0x02, 78}, - {9, 0x02, 78}, - {14, 0x02, 78}, - {20, 0x02, 78}, - {28, 0x02, 78}, - {38, 0x03, 78}, -}, -/* 53 */ -{ - {3, 0x02, 79}, - {4, 0x02, 79}, - {6, 0x02, 79}, - {9, 0x02, 79}, - {14, 0x02, 79}, - {20, 0x02, 79}, - {28, 0x02, 79}, - {38, 0x03, 79}, - {3, 0x02, 87}, - {4, 0x02, 87}, - {6, 0x02, 87}, - {9, 0x02, 87}, - {14, 0x02, 87}, - {20, 0x02, 87}, - {28, 0x02, 87}, - {38, 0x03, 87}, -}, -/* 54 */ -{ - {2, 0x02, 119}, - {5, 0x02, 119}, - {13, 0x02, 119}, - {27, 0x03, 119}, - {2, 0x02, 121}, - {5, 0x02, 121}, - {13, 0x02, 121}, - {27, 0x03, 121}, - {1, 0x02, 37}, - {12, 0x03, 37}, - {1, 0x02, 40}, - {12, 0x03, 40}, - {1, 0x02, 41}, - {12, 0x03, 41}, - {1, 0x02, 59}, - {12, 0x03, 59}, -}, -/* 55 */ -{ - {3, 0x02, 119}, - {4, 0x02, 119}, - {6, 0x02, 119}, - {9, 0x02, 119}, - {14, 0x02, 119}, - {20, 0x02, 119}, - {28, 0x02, 119}, - {38, 0x03, 119}, - {3, 0x02, 121}, - {4, 0x02, 121}, - {6, 0x02, 121}, - {9, 0x02, 121}, - {14, 0x02, 121}, - {20, 0x02, 121}, - {28, 0x02, 121}, - {38, 0x03, 121}, -}, -/* 56 */ -{ - {2, 0x02, 37}, - {5, 0x02, 37}, - {13, 0x02, 37}, - {27, 0x03, 37}, - {2, 0x02, 40}, - {5, 0x02, 40}, - {13, 0x02, 40}, - {27, 0x03, 40}, - {2, 0x02, 41}, - {5, 0x02, 41}, - {13, 0x02, 41}, - {27, 0x03, 41}, - {2, 0x02, 59}, - {5, 0x02, 59}, - {13, 0x02, 59}, - {27, 0x03, 59}, -}, -/* 57 */ -{ - {3, 0x02, 37}, - {4, 0x02, 37}, - {6, 0x02, 37}, - {9, 0x02, 37}, - {14, 0x02, 37}, - {20, 0x02, 37}, - {28, 0x02, 37}, - {38, 0x03, 37}, - {3, 0x02, 40}, - {4, 0x02, 40}, - {6, 0x02, 40}, - {9, 0x02, 40}, - {14, 0x02, 40}, - {20, 0x02, 40}, - {28, 0x02, 40}, - {38, 0x03, 40}, -}, -/* 58 */ -{ - {3, 0x02, 41}, - {4, 0x02, 41}, - {6, 0x02, 41}, - {9, 0x02, 41}, - {14, 0x02, 41}, - {20, 0x02, 41}, - {28, 0x02, 41}, - {38, 0x03, 41}, - {3, 0x02, 59}, - {4, 0x02, 59}, - {6, 0x02, 59}, - {9, 0x02, 59}, - {14, 0x02, 59}, - {20, 0x02, 59}, - {28, 0x02, 59}, - {38, 0x03, 59}, -}, -/* 59 */ -{ - {0, 0x03, 72}, - {0, 0x03, 76}, - {0, 0x03, 80}, - {0, 0x03, 82}, - {0, 0x03, 85}, - {0, 0x03, 86}, - {0, 0x03, 89}, - {0, 0x03, 95}, - {0, 0x03, 106}, - {0, 0x03, 107}, - {0, 0x03, 113}, - {0, 0x03, 122}, - {73, 0x00, 0}, - {74, 0x00, 0}, - {76, 0x00, 0}, - {78, 0x00, 0}, -}, -/* 60 */ -{ - {1, 0x02, 72}, - {12, 0x03, 72}, - {1, 0x02, 76}, - {12, 0x03, 76}, - {1, 0x02, 80}, - {12, 0x03, 80}, - {1, 0x02, 82}, - {12, 0x03, 82}, - {1, 0x02, 85}, - {12, 0x03, 85}, - {1, 0x02, 86}, - {12, 0x03, 86}, - {1, 0x02, 89}, - {12, 0x03, 89}, - {1, 0x02, 95}, - {12, 0x03, 95}, -}, -/* 61 */ -{ - {2, 0x02, 72}, - {5, 0x02, 72}, - {13, 0x02, 72}, - {27, 0x03, 72}, - {2, 0x02, 76}, - {5, 0x02, 76}, - {13, 0x02, 76}, - {27, 0x03, 76}, - {2, 0x02, 80}, - {5, 0x02, 80}, - {13, 0x02, 80}, - {27, 0x03, 80}, - {2, 0x02, 82}, - {5, 0x02, 82}, - {13, 0x02, 82}, - {27, 0x03, 82}, -}, -/* 62 */ -{ - {3, 0x02, 72}, - {4, 0x02, 72}, - {6, 0x02, 72}, - {9, 0x02, 72}, - {14, 0x02, 72}, - {20, 0x02, 72}, - {28, 0x02, 72}, - {38, 0x03, 72}, - {3, 0x02, 76}, - {4, 0x02, 76}, - {6, 0x02, 76}, - {9, 0x02, 76}, - {14, 0x02, 76}, - {20, 0x02, 76}, - {28, 0x02, 76}, - {38, 0x03, 76}, -}, -/* 63 */ -{ - {3, 0x02, 80}, - {4, 0x02, 80}, - {6, 0x02, 80}, - {9, 0x02, 80}, - {14, 0x02, 80}, - {20, 0x02, 80}, - {28, 0x02, 80}, - {38, 0x03, 80}, - {3, 0x02, 82}, - {4, 0x02, 82}, - {6, 0x02, 82}, - {9, 0x02, 82}, - {14, 0x02, 82}, - {20, 0x02, 82}, - {28, 0x02, 82}, - {38, 0x03, 82}, -}, -/* 64 */ -{ - {2, 0x02, 85}, - {5, 0x02, 85}, - {13, 0x02, 85}, - {27, 0x03, 85}, - {2, 0x02, 86}, - {5, 0x02, 86}, - {13, 0x02, 86}, - {27, 0x03, 86}, - {2, 0x02, 89}, - {5, 0x02, 89}, - {13, 0x02, 89}, - {27, 0x03, 89}, - {2, 0x02, 95}, - {5, 0x02, 95}, - {13, 0x02, 95}, - {27, 0x03, 95}, -}, -/* 65 */ -{ - {3, 0x02, 85}, - {4, 0x02, 85}, - {6, 0x02, 85}, - {9, 0x02, 85}, - {14, 0x02, 85}, - {20, 0x02, 85}, - {28, 0x02, 85}, - {38, 0x03, 85}, - {3, 0x02, 86}, - {4, 0x02, 86}, - {6, 0x02, 86}, - {9, 0x02, 86}, - {14, 0x02, 86}, - {20, 0x02, 86}, - {28, 0x02, 86}, - {38, 0x03, 86}, -}, -/* 66 */ -{ - {3, 0x02, 89}, - {4, 0x02, 89}, - {6, 0x02, 89}, - {9, 0x02, 89}, - {14, 0x02, 89}, - {20, 0x02, 89}, - {28, 0x02, 89}, - {38, 0x03, 89}, - {3, 0x02, 95}, - {4, 0x02, 95}, - {6, 0x02, 95}, - {9, 0x02, 95}, - {14, 0x02, 95}, - {20, 0x02, 95}, - {28, 0x02, 95}, - {38, 0x03, 95}, -}, -/* 67 */ -{ - {1, 0x02, 106}, - {12, 0x03, 106}, - {1, 0x02, 107}, - {12, 0x03, 107}, - {1, 0x02, 113}, - {12, 0x03, 113}, - {1, 0x02, 122}, - {12, 0x03, 122}, - {0, 0x03, 38}, - {0, 0x03, 75}, - {0, 0x03, 81}, - {0, 0x03, 88}, - {0, 0x03, 90}, - {77, 0x00, 0}, - {79, 0x00, 0}, - {81, 0x00, 0}, -}, -/* 68 */ -{ - {2, 0x02, 106}, - {5, 0x02, 106}, - {13, 0x02, 106}, - {27, 0x03, 106}, - {2, 0x02, 107}, - {5, 0x02, 107}, - {13, 0x02, 107}, - {27, 0x03, 107}, - {2, 0x02, 113}, - {5, 0x02, 113}, - {13, 0x02, 113}, - {27, 0x03, 113}, - {2, 0x02, 122}, - {5, 0x02, 122}, - {13, 0x02, 122}, - {27, 0x03, 122}, -}, -/* 69 */ -{ - {3, 0x02, 106}, - {4, 0x02, 106}, - {6, 0x02, 106}, - {9, 0x02, 106}, - {14, 0x02, 106}, - {20, 0x02, 106}, - {28, 0x02, 106}, - {38, 0x03, 106}, - {3, 0x02, 107}, - {4, 0x02, 107}, - {6, 0x02, 107}, - {9, 0x02, 107}, - {14, 0x02, 107}, - {20, 0x02, 107}, - {28, 0x02, 107}, - {38, 0x03, 107}, -}, -/* 70 */ -{ - {3, 0x02, 113}, - {4, 0x02, 113}, - {6, 0x02, 113}, - {9, 0x02, 113}, - {14, 0x02, 113}, - {20, 0x02, 113}, - {28, 0x02, 113}, - {38, 0x03, 113}, - {3, 0x02, 122}, - {4, 0x02, 122}, - {6, 0x02, 122}, - {9, 0x02, 122}, - {14, 0x02, 122}, - {20, 0x02, 122}, - {28, 0x02, 122}, - {38, 0x03, 122}, -}, -/* 71 */ -{ - {1, 0x02, 38}, - {12, 0x03, 38}, - {1, 0x02, 75}, - {12, 0x03, 75}, - {1, 0x02, 81}, - {12, 0x03, 81}, - {1, 0x02, 88}, - {12, 0x03, 88}, - {1, 0x02, 90}, - {12, 0x03, 90}, - {0, 0x03, 43}, - {0, 0x03, 91}, - {0, 0x03, 93}, - {80, 0x00, 0}, - {82, 0x00, 0}, - {84, 0x00, 0}, -}, -/* 72 */ -{ - {2, 0x02, 38}, - {5, 0x02, 38}, - {13, 0x02, 38}, - {27, 0x03, 38}, - {2, 0x02, 75}, - {5, 0x02, 75}, - {13, 0x02, 75}, - {27, 0x03, 75}, - {2, 0x02, 81}, - {5, 0x02, 81}, - {13, 0x02, 81}, - {27, 0x03, 81}, - {2, 0x02, 88}, - {5, 0x02, 88}, - {13, 0x02, 88}, - {27, 0x03, 88}, -}, -/* 73 */ -{ - {3, 0x02, 38}, - {4, 0x02, 38}, - {6, 0x02, 38}, - {9, 0x02, 38}, - {14, 0x02, 38}, - {20, 0x02, 38}, - {28, 0x02, 38}, - {38, 0x03, 38}, - {3, 0x02, 75}, - {4, 0x02, 75}, - {6, 0x02, 75}, - {9, 0x02, 75}, - {14, 0x02, 75}, - {20, 0x02, 75}, - {28, 0x02, 75}, - {38, 0x03, 75}, -}, -/* 74 */ -{ - {3, 0x02, 81}, - {4, 0x02, 81}, - {6, 0x02, 81}, - {9, 0x02, 81}, - {14, 0x02, 81}, - {20, 0x02, 81}, - {28, 0x02, 81}, - {38, 0x03, 81}, - {3, 0x02, 88}, - {4, 0x02, 88}, - {6, 0x02, 88}, - {9, 0x02, 88}, - {14, 0x02, 88}, - {20, 0x02, 88}, - {28, 0x02, 88}, - {38, 0x03, 88}, -}, -/* 75 */ -{ - {2, 0x02, 90}, - {5, 0x02, 90}, - {13, 0x02, 90}, - {27, 0x03, 90}, - {1, 0x02, 43}, - {12, 0x03, 43}, - {1, 0x02, 91}, - {12, 0x03, 91}, - {1, 0x02, 93}, - {12, 0x03, 93}, - {0, 0x03, 33}, - {0, 0x03, 42}, - {0, 0x03, 63}, - {83, 0x00, 0}, - {85, 0x00, 0}, - {86, 0x00, 0}, -}, -/* 76 */ -{ - {3, 0x02, 90}, - {4, 0x02, 90}, - {6, 0x02, 90}, - {9, 0x02, 90}, - {14, 0x02, 90}, - {20, 0x02, 90}, - {28, 0x02, 90}, - {38, 0x03, 90}, - {2, 0x02, 43}, - {5, 0x02, 43}, - {13, 0x02, 43}, - {27, 0x03, 43}, - {2, 0x02, 91}, - {5, 0x02, 91}, - {13, 0x02, 91}, - {27, 0x03, 91}, -}, -/* 77 */ -{ - {3, 0x02, 43}, - {4, 0x02, 43}, - {6, 0x02, 43}, - {9, 0x02, 43}, - {14, 0x02, 43}, - {20, 0x02, 43}, - {28, 0x02, 43}, - {38, 0x03, 43}, - {3, 0x02, 91}, - {4, 0x02, 91}, - {6, 0x02, 91}, - {9, 0x02, 91}, - {14, 0x02, 91}, - {20, 0x02, 91}, - {28, 0x02, 91}, - {38, 0x03, 91}, -}, -/* 78 */ -{ - {2, 0x02, 93}, - {5, 0x02, 93}, - {13, 0x02, 93}, - {27, 0x03, 93}, - {1, 0x02, 33}, - {12, 0x03, 33}, - {1, 0x02, 42}, - {12, 0x03, 42}, - {1, 0x02, 63}, - {12, 0x03, 63}, - {0, 0x03, 35}, - {0, 0x03, 39}, - {0, 0x03, 62}, - {0, 0x03, 92}, - {87, 0x00, 0}, - {88, 0x00, 0}, -}, -/* 79 */ -{ - {3, 0x02, 93}, - {4, 0x02, 93}, - {6, 0x02, 93}, - {9, 0x02, 93}, - {14, 0x02, 93}, - {20, 0x02, 93}, - {28, 0x02, 93}, - {38, 0x03, 93}, - {2, 0x02, 33}, - {5, 0x02, 33}, - {13, 0x02, 33}, - {27, 0x03, 33}, - {2, 0x02, 42}, - {5, 0x02, 42}, - {13, 0x02, 42}, - {27, 0x03, 42}, -}, -/* 80 */ -{ - {3, 0x02, 33}, - {4, 0x02, 33}, - {6, 0x02, 33}, - {9, 0x02, 33}, - {14, 0x02, 33}, - {20, 0x02, 33}, - {28, 0x02, 33}, - {38, 0x03, 33}, - {3, 0x02, 42}, - {4, 0x02, 42}, - {6, 0x02, 42}, - {9, 0x02, 42}, - {14, 0x02, 42}, - {20, 0x02, 42}, - {28, 0x02, 42}, - {38, 0x03, 42}, -}, -/* 81 */ -{ - {2, 0x02, 63}, - {5, 0x02, 63}, - {13, 0x02, 63}, - {27, 0x03, 63}, - {1, 0x02, 35}, - {12, 0x03, 35}, - {1, 0x02, 39}, - {12, 0x03, 39}, - {1, 0x02, 62}, - {12, 0x03, 62}, - {1, 0x02, 92}, - {12, 0x03, 92}, - {0, 0x03, 36}, - {0, 0x03, 124}, - {89, 0x00, 0}, - {91, 0x00, 0}, -}, -/* 82 */ -{ - {3, 0x02, 63}, - {4, 0x02, 63}, - {6, 0x02, 63}, - {9, 0x02, 63}, - {14, 0x02, 63}, - {20, 0x02, 63}, - {28, 0x02, 63}, - {38, 0x03, 63}, - {2, 0x02, 35}, - {5, 0x02, 35}, - {13, 0x02, 35}, - {27, 0x03, 35}, - {2, 0x02, 39}, - {5, 0x02, 39}, - {13, 0x02, 39}, - {27, 0x03, 39}, -}, -/* 83 */ -{ - {3, 0x02, 35}, - {4, 0x02, 35}, - {6, 0x02, 35}, - {9, 0x02, 35}, - {14, 0x02, 35}, - {20, 0x02, 35}, - {28, 0x02, 35}, - {38, 0x03, 35}, - {3, 0x02, 39}, - {4, 0x02, 39}, - {6, 0x02, 39}, - {9, 0x02, 39}, - {14, 0x02, 39}, - {20, 0x02, 39}, - {28, 0x02, 39}, - {38, 0x03, 39}, -}, -/* 84 */ -{ - {2, 0x02, 62}, - {5, 0x02, 62}, - {13, 0x02, 62}, - {27, 0x03, 62}, - {2, 0x02, 92}, - {5, 0x02, 92}, - {13, 0x02, 92}, - {27, 0x03, 92}, - {1, 0x02, 36}, - {12, 0x03, 36}, - {1, 0x02, 124}, - {12, 0x03, 124}, - {0, 0x03, 94}, - {90, 0x00, 0}, - {92, 0x00, 0}, - {93, 0x00, 0}, -}, -/* 85 */ -{ - {3, 0x02, 62}, - {4, 0x02, 62}, - {6, 0x02, 62}, - {9, 0x02, 62}, - {14, 0x02, 62}, - {20, 0x02, 62}, - {28, 0x02, 62}, - {38, 0x03, 62}, - {3, 0x02, 92}, - {4, 0x02, 92}, - {6, 0x02, 92}, - {9, 0x02, 92}, - {14, 0x02, 92}, - {20, 0x02, 92}, - {28, 0x02, 92}, - {38, 0x03, 92}, -}, -/* 86 */ -{ - {2, 0x02, 36}, - {5, 0x02, 36}, - {13, 0x02, 36}, - {27, 0x03, 36}, - {2, 0x02, 124}, - {5, 0x02, 124}, - {13, 0x02, 124}, - {27, 0x03, 124}, - {1, 0x02, 94}, - {12, 0x03, 94}, - {0, 0x03, 60}, - {0, 0x03, 64}, - {0, 0x03, 123}, - {0, 0x03, 125}, - {0, 0x03, 126}, - {94, 0x00, 0}, -}, -/* 87 */ -{ - {3, 0x02, 36}, - {4, 0x02, 36}, - {6, 0x02, 36}, - {9, 0x02, 36}, - {14, 0x02, 36}, - {20, 0x02, 36}, - {28, 0x02, 36}, - {38, 0x03, 36}, - {3, 0x02, 124}, - {4, 0x02, 124}, - {6, 0x02, 124}, - {9, 0x02, 124}, - {14, 0x02, 124}, - {20, 0x02, 124}, - {28, 0x02, 124}, - {38, 0x03, 124}, -}, -/* 88 */ -{ - {2, 0x02, 94}, - {5, 0x02, 94}, - {13, 0x02, 94}, - {27, 0x03, 94}, - {1, 0x02, 60}, - {12, 0x03, 60}, - {1, 0x02, 64}, - {12, 0x03, 64}, - {1, 0x02, 123}, - {12, 0x03, 123}, - {1, 0x02, 125}, - {12, 0x03, 125}, - {1, 0x02, 126}, - {12, 0x03, 126}, - {0, 0x03, 96}, - {95, 0x00, 0}, -}, -/* 89 */ -{ - {3, 0x02, 94}, - {4, 0x02, 94}, - {6, 0x02, 94}, - {9, 0x02, 94}, - {14, 0x02, 94}, - {20, 0x02, 94}, - {28, 0x02, 94}, - {38, 0x03, 94}, - {2, 0x02, 60}, - {5, 0x02, 60}, - {13, 0x02, 60}, - {27, 0x03, 60}, - {2, 0x02, 64}, - {5, 0x02, 64}, - {13, 0x02, 64}, - {27, 0x03, 64}, -}, -/* 90 */ -{ - {3, 0x02, 60}, - {4, 0x02, 60}, - {6, 0x02, 60}, - {9, 0x02, 60}, - {14, 0x02, 60}, - {20, 0x02, 60}, - {28, 0x02, 60}, - {38, 0x03, 60}, - {3, 0x02, 64}, - {4, 0x02, 64}, - {6, 0x02, 64}, - {9, 0x02, 64}, - {14, 0x02, 64}, - {20, 0x02, 64}, - {28, 0x02, 64}, - {38, 0x03, 64}, -}, -/* 91 */ -{ - {2, 0x02, 123}, - {5, 0x02, 123}, - {13, 0x02, 123}, - {27, 0x03, 123}, - {2, 0x02, 125}, - {5, 0x02, 125}, - {13, 0x02, 125}, - {27, 0x03, 125}, - {2, 0x02, 126}, - {5, 0x02, 126}, - {13, 0x02, 126}, - {27, 0x03, 126}, - {1, 0x02, 96}, - {12, 0x03, 96}, - {96, 0x00, 0}, - {159, 0x00, 0}, -}, -/* 92 */ -{ - {3, 0x02, 123}, - {4, 0x02, 123}, - {6, 0x02, 123}, - {9, 0x02, 123}, - {14, 0x02, 123}, - {20, 0x02, 123}, - {28, 0x02, 123}, - {38, 0x03, 123}, - {3, 0x02, 125}, - {4, 0x02, 125}, - {6, 0x02, 125}, - {9, 0x02, 125}, - {14, 0x02, 125}, - {20, 0x02, 125}, - {28, 0x02, 125}, - {38, 0x03, 125}, -}, -/* 93 */ -{ - {3, 0x02, 126}, - {4, 0x02, 126}, - {6, 0x02, 126}, - {9, 0x02, 126}, - {14, 0x02, 126}, - {20, 0x02, 126}, - {28, 0x02, 126}, - {38, 0x03, 126}, - {2, 0x02, 96}, - {5, 0x02, 96}, - {13, 0x02, 96}, - {27, 0x03, 96}, - {97, 0x00, 0}, - {128, 0x00, 0}, - {160, 0x00, 0}, - {193, 0x00, 0}, -}, -/* 94 */ -{ - {3, 0x02, 96}, - {4, 0x02, 96}, - {6, 0x02, 96}, - {9, 0x02, 96}, - {14, 0x02, 96}, - {20, 0x02, 96}, - {28, 0x02, 96}, - {38, 0x03, 96}, - {98, 0x00, 0}, - {113, 0x00, 0}, - {129, 0x00, 0}, - {144, 0x00, 0}, - {161, 0x00, 0}, - {176, 0x00, 0}, - {194, 0x00, 0}, - {225, 0x00, 0}, -}, -/* 95 */ -{ - {99, 0x00, 0}, - {106, 0x00, 0}, - {114, 0x00, 0}, - {121, 0x00, 0}, - {130, 0x00, 0}, - {137, 0x00, 0}, - {145, 0x00, 0}, - {152, 0x00, 0}, - {162, 0x00, 0}, - {169, 0x00, 0}, - {177, 0x00, 0}, - {184, 0x00, 0}, - {195, 0x00, 0}, - {210, 0x00, 0}, - {226, 0x00, 0}, - {241, 0x00, 0}, -}, -/* 96 */ -{ - {100, 0x00, 0}, - {103, 0x00, 0}, - {107, 0x00, 0}, - {110, 0x00, 0}, - {115, 0x00, 0}, - {118, 0x00, 0}, - {122, 0x00, 0}, - {125, 0x00, 0}, - {131, 0x00, 0}, - {134, 0x00, 0}, - {138, 0x00, 0}, - {141, 0x00, 0}, - {146, 0x00, 0}, - {149, 0x00, 0}, - {153, 0x00, 0}, - {156, 0x00, 0}, -}, -/* 97 */ -{ - {101, 0x00, 0}, - {102, 0x00, 0}, - {104, 0x00, 0}, - {105, 0x00, 0}, - {108, 0x00, 0}, - {109, 0x00, 0}, - {111, 0x00, 0}, - {112, 0x00, 0}, - {116, 0x00, 0}, - {117, 0x00, 0}, - {119, 0x00, 0}, - {120, 0x00, 0}, - {123, 0x00, 0}, - {124, 0x00, 0}, - {126, 0x00, 0}, - {127, 0x00, 0}, -}, -/* 98 */ -{ - {0, 0x03, 163}, - {0, 0x03, 164}, - {0, 0x03, 165}, - {0, 0x03, 166}, - {0, 0x03, 167}, - {0, 0x03, 168}, - {0, 0x03, 169}, - {0, 0x03, 170}, - {0, 0x03, 171}, - {0, 0x03, 172}, - {0, 0x03, 173}, - {0, 0x03, 174}, - {0, 0x03, 175}, - {0, 0x03, 176}, - {0, 0x03, 177}, - {0, 0x03, 178}, -}, -/* 99 */ -{ - {1, 0x02, 163}, - {12, 0x03, 163}, - {1, 0x02, 164}, - {12, 0x03, 164}, - {1, 0x02, 165}, - {12, 0x03, 165}, - {1, 0x02, 166}, - {12, 0x03, 166}, - {1, 0x02, 167}, - {12, 0x03, 167}, - {1, 0x02, 168}, - {12, 0x03, 168}, - {1, 0x02, 169}, - {12, 0x03, 169}, - {1, 0x02, 170}, - {12, 0x03, 170}, -}, -/* 100 */ -{ - {2, 0x02, 163}, - {5, 0x02, 163}, - {13, 0x02, 163}, - {27, 0x03, 163}, - {2, 0x02, 164}, - {5, 0x02, 164}, - {13, 0x02, 164}, - {27, 0x03, 164}, - {2, 0x02, 165}, - {5, 0x02, 165}, - {13, 0x02, 165}, - {27, 0x03, 165}, - {2, 0x02, 166}, - {5, 0x02, 166}, - {13, 0x02, 166}, - {27, 0x03, 166}, -}, -/* 101 */ -{ - {3, 0x02, 163}, - {4, 0x02, 163}, - {6, 0x02, 163}, - {9, 0x02, 163}, - {14, 0x02, 163}, - {20, 0x02, 163}, - {28, 0x02, 163}, - {38, 0x03, 163}, - {3, 0x02, 164}, - {4, 0x02, 164}, - {6, 0x02, 164}, - {9, 0x02, 164}, - {14, 0x02, 164}, - {20, 0x02, 164}, - {28, 0x02, 164}, - {38, 0x03, 164}, -}, -/* 102 */ -{ - {3, 0x02, 165}, - {4, 0x02, 165}, - {6, 0x02, 165}, - {9, 0x02, 165}, - {14, 0x02, 165}, - {20, 0x02, 165}, - {28, 0x02, 165}, - {38, 0x03, 165}, - {3, 0x02, 166}, - {4, 0x02, 166}, - {6, 0x02, 166}, - {9, 0x02, 166}, - {14, 0x02, 166}, - {20, 0x02, 166}, - {28, 0x02, 166}, - {38, 0x03, 166}, -}, -/* 103 */ -{ - {2, 0x02, 167}, - {5, 0x02, 167}, - {13, 0x02, 167}, - {27, 0x03, 167}, - {2, 0x02, 168}, - {5, 0x02, 168}, - {13, 0x02, 168}, - {27, 0x03, 168}, - {2, 0x02, 169}, - {5, 0x02, 169}, - {13, 0x02, 169}, - {27, 0x03, 169}, - {2, 0x02, 170}, - {5, 0x02, 170}, - {13, 0x02, 170}, - {27, 0x03, 170}, -}, -/* 104 */ -{ - {3, 0x02, 167}, - {4, 0x02, 167}, - {6, 0x02, 167}, - {9, 0x02, 167}, - {14, 0x02, 167}, - {20, 0x02, 167}, - {28, 0x02, 167}, - {38, 0x03, 167}, - {3, 0x02, 168}, - {4, 0x02, 168}, - {6, 0x02, 168}, - {9, 0x02, 168}, - {14, 0x02, 168}, - {20, 0x02, 168}, - {28, 0x02, 168}, - {38, 0x03, 168}, -}, -/* 105 */ -{ - {3, 0x02, 169}, - {4, 0x02, 169}, - {6, 0x02, 169}, - {9, 0x02, 169}, - {14, 0x02, 169}, - {20, 0x02, 169}, - {28, 0x02, 169}, - {38, 0x03, 169}, - {3, 0x02, 170}, - {4, 0x02, 170}, - {6, 0x02, 170}, - {9, 0x02, 170}, - {14, 0x02, 170}, - {20, 0x02, 170}, - {28, 0x02, 170}, - {38, 0x03, 170}, -}, -/* 106 */ -{ - {1, 0x02, 171}, - {12, 0x03, 171}, - {1, 0x02, 172}, - {12, 0x03, 172}, - {1, 0x02, 173}, - {12, 0x03, 173}, - {1, 0x02, 174}, - {12, 0x03, 174}, - {1, 0x02, 175}, - {12, 0x03, 175}, - {1, 0x02, 176}, - {12, 0x03, 176}, - {1, 0x02, 177}, - {12, 0x03, 177}, - {1, 0x02, 178}, - {12, 0x03, 178}, -}, -/* 107 */ -{ - {2, 0x02, 171}, - {5, 0x02, 171}, - {13, 0x02, 171}, - {27, 0x03, 171}, - {2, 0x02, 172}, - {5, 0x02, 172}, - {13, 0x02, 172}, - {27, 0x03, 172}, - {2, 0x02, 173}, - {5, 0x02, 173}, - {13, 0x02, 173}, - {27, 0x03, 173}, - {2, 0x02, 174}, - {5, 0x02, 174}, - {13, 0x02, 174}, - {27, 0x03, 174}, -}, -/* 108 */ -{ - {3, 0x02, 171}, - {4, 0x02, 171}, - {6, 0x02, 171}, - {9, 0x02, 171}, - {14, 0x02, 171}, - {20, 0x02, 171}, - {28, 0x02, 171}, - {38, 0x03, 171}, - {3, 0x02, 172}, - {4, 0x02, 172}, - {6, 0x02, 172}, - {9, 0x02, 172}, - {14, 0x02, 172}, - {20, 0x02, 172}, - {28, 0x02, 172}, - {38, 0x03, 172}, -}, -/* 109 */ -{ - {3, 0x02, 173}, - {4, 0x02, 173}, - {6, 0x02, 173}, - {9, 0x02, 173}, - {14, 0x02, 173}, - {20, 0x02, 173}, - {28, 0x02, 173}, - {38, 0x03, 173}, - {3, 0x02, 174}, - {4, 0x02, 174}, - {6, 0x02, 174}, - {9, 0x02, 174}, - {14, 0x02, 174}, - {20, 0x02, 174}, - {28, 0x02, 174}, - {38, 0x03, 174}, -}, -/* 110 */ -{ - {2, 0x02, 175}, - {5, 0x02, 175}, - {13, 0x02, 175}, - {27, 0x03, 175}, - {2, 0x02, 176}, - {5, 0x02, 176}, - {13, 0x02, 176}, - {27, 0x03, 176}, - {2, 0x02, 177}, - {5, 0x02, 177}, - {13, 0x02, 177}, - {27, 0x03, 177}, - {2, 0x02, 178}, - {5, 0x02, 178}, - {13, 0x02, 178}, - {27, 0x03, 178}, -}, -/* 111 */ -{ - {3, 0x02, 175}, - {4, 0x02, 175}, - {6, 0x02, 175}, - {9, 0x02, 175}, - {14, 0x02, 175}, - {20, 0x02, 175}, - {28, 0x02, 175}, - {38, 0x03, 175}, - {3, 0x02, 176}, - {4, 0x02, 176}, - {6, 0x02, 176}, - {9, 0x02, 176}, - {14, 0x02, 176}, - {20, 0x02, 176}, - {28, 0x02, 176}, - {38, 0x03, 176}, -}, -/* 112 */ -{ - {3, 0x02, 177}, - {4, 0x02, 177}, - {6, 0x02, 177}, - {9, 0x02, 177}, - {14, 0x02, 177}, - {20, 0x02, 177}, - {28, 0x02, 177}, - {38, 0x03, 177}, - {3, 0x02, 178}, - {4, 0x02, 178}, - {6, 0x02, 178}, - {9, 0x02, 178}, - {14, 0x02, 178}, - {20, 0x02, 178}, - {28, 0x02, 178}, - {38, 0x03, 178}, -}, -/* 113 */ -{ - {0, 0x03, 179}, - {0, 0x03, 180}, - {0, 0x03, 181}, - {0, 0x03, 182}, - {0, 0x03, 183}, - {0, 0x03, 184}, - {0, 0x03, 185}, - {0, 0x03, 186}, - {0, 0x03, 187}, - {0, 0x03, 188}, - {0, 0x03, 189}, - {0, 0x03, 190}, - {0, 0x03, 191}, - {0, 0x03, 192}, - {0, 0x03, 193}, - {0, 0x03, 194}, -}, -/* 114 */ -{ - {1, 0x02, 179}, - {12, 0x03, 179}, - {1, 0x02, 180}, - {12, 0x03, 180}, - {1, 0x02, 181}, - {12, 0x03, 181}, - {1, 0x02, 182}, - {12, 0x03, 182}, - {1, 0x02, 183}, - {12, 0x03, 183}, - {1, 0x02, 184}, - {12, 0x03, 184}, - {1, 0x02, 185}, - {12, 0x03, 185}, - {1, 0x02, 186}, - {12, 0x03, 186}, -}, -/* 115 */ -{ - {2, 0x02, 179}, - {5, 0x02, 179}, - {13, 0x02, 179}, - {27, 0x03, 179}, - {2, 0x02, 180}, - {5, 0x02, 180}, - {13, 0x02, 180}, - {27, 0x03, 180}, - {2, 0x02, 181}, - {5, 0x02, 181}, - {13, 0x02, 181}, - {27, 0x03, 181}, - {2, 0x02, 182}, - {5, 0x02, 182}, - {13, 0x02, 182}, - {27, 0x03, 182}, -}, -/* 116 */ -{ - {3, 0x02, 179}, - {4, 0x02, 179}, - {6, 0x02, 179}, - {9, 0x02, 179}, - {14, 0x02, 179}, - {20, 0x02, 179}, - {28, 0x02, 179}, - {38, 0x03, 179}, - {3, 0x02, 180}, - {4, 0x02, 180}, - {6, 0x02, 180}, - {9, 0x02, 180}, - {14, 0x02, 180}, - {20, 0x02, 180}, - {28, 0x02, 180}, - {38, 0x03, 180}, -}, -/* 117 */ -{ - {3, 0x02, 181}, - {4, 0x02, 181}, - {6, 0x02, 181}, - {9, 0x02, 181}, - {14, 0x02, 181}, - {20, 0x02, 181}, - {28, 0x02, 181}, - {38, 0x03, 181}, - {3, 0x02, 182}, - {4, 0x02, 182}, - {6, 0x02, 182}, - {9, 0x02, 182}, - {14, 0x02, 182}, - {20, 0x02, 182}, - {28, 0x02, 182}, - {38, 0x03, 182}, -}, -/* 118 */ -{ - {2, 0x02, 183}, - {5, 0x02, 183}, - {13, 0x02, 183}, - {27, 0x03, 183}, - {2, 0x02, 184}, - {5, 0x02, 184}, - {13, 0x02, 184}, - {27, 0x03, 184}, - {2, 0x02, 185}, - {5, 0x02, 185}, - {13, 0x02, 185}, - {27, 0x03, 185}, - {2, 0x02, 186}, - {5, 0x02, 186}, - {13, 0x02, 186}, - {27, 0x03, 186}, -}, -/* 119 */ -{ - {3, 0x02, 183}, - {4, 0x02, 183}, - {6, 0x02, 183}, - {9, 0x02, 183}, - {14, 0x02, 183}, - {20, 0x02, 183}, - {28, 0x02, 183}, - {38, 0x03, 183}, - {3, 0x02, 184}, - {4, 0x02, 184}, - {6, 0x02, 184}, - {9, 0x02, 184}, - {14, 0x02, 184}, - {20, 0x02, 184}, - {28, 0x02, 184}, - {38, 0x03, 184}, -}, -/* 120 */ -{ - {3, 0x02, 185}, - {4, 0x02, 185}, - {6, 0x02, 185}, - {9, 0x02, 185}, - {14, 0x02, 185}, - {20, 0x02, 185}, - {28, 0x02, 185}, - {38, 0x03, 185}, - {3, 0x02, 186}, - {4, 0x02, 186}, - {6, 0x02, 186}, - {9, 0x02, 186}, - {14, 0x02, 186}, - {20, 0x02, 186}, - {28, 0x02, 186}, - {38, 0x03, 186}, -}, -/* 121 */ -{ - {1, 0x02, 187}, - {12, 0x03, 187}, - {1, 0x02, 188}, - {12, 0x03, 188}, - {1, 0x02, 189}, - {12, 0x03, 189}, - {1, 0x02, 190}, - {12, 0x03, 190}, - {1, 0x02, 191}, - {12, 0x03, 191}, - {1, 0x02, 192}, - {12, 0x03, 192}, - {1, 0x02, 193}, - {12, 0x03, 193}, - {1, 0x02, 194}, - {12, 0x03, 194}, -}, -/* 122 */ -{ - {2, 0x02, 187}, - {5, 0x02, 187}, - {13, 0x02, 187}, - {27, 0x03, 187}, - {2, 0x02, 188}, - {5, 0x02, 188}, - {13, 0x02, 188}, - {27, 0x03, 188}, - {2, 0x02, 189}, - {5, 0x02, 189}, - {13, 0x02, 189}, - {27, 0x03, 189}, - {2, 0x02, 190}, - {5, 0x02, 190}, - {13, 0x02, 190}, - {27, 0x03, 190}, -}, -/* 123 */ -{ - {3, 0x02, 187}, - {4, 0x02, 187}, - {6, 0x02, 187}, - {9, 0x02, 187}, - {14, 0x02, 187}, - {20, 0x02, 187}, - {28, 0x02, 187}, - {38, 0x03, 187}, - {3, 0x02, 188}, - {4, 0x02, 188}, - {6, 0x02, 188}, - {9, 0x02, 188}, - {14, 0x02, 188}, - {20, 0x02, 188}, - {28, 0x02, 188}, - {38, 0x03, 188}, -}, -/* 124 */ -{ - {3, 0x02, 189}, - {4, 0x02, 189}, - {6, 0x02, 189}, - {9, 0x02, 189}, - {14, 0x02, 189}, - {20, 0x02, 189}, - {28, 0x02, 189}, - {38, 0x03, 189}, - {3, 0x02, 190}, - {4, 0x02, 190}, - {6, 0x02, 190}, - {9, 0x02, 190}, - {14, 0x02, 190}, - {20, 0x02, 190}, - {28, 0x02, 190}, - {38, 0x03, 190}, -}, -/* 125 */ -{ - {2, 0x02, 191}, - {5, 0x02, 191}, - {13, 0x02, 191}, - {27, 0x03, 191}, - {2, 0x02, 192}, - {5, 0x02, 192}, - {13, 0x02, 192}, - {27, 0x03, 192}, - {2, 0x02, 193}, - {5, 0x02, 193}, - {13, 0x02, 193}, - {27, 0x03, 193}, - {2, 0x02, 194}, - {5, 0x02, 194}, - {13, 0x02, 194}, - {27, 0x03, 194}, -}, -/* 126 */ -{ - {3, 0x02, 191}, - {4, 0x02, 191}, - {6, 0x02, 191}, - {9, 0x02, 191}, - {14, 0x02, 191}, - {20, 0x02, 191}, - {28, 0x02, 191}, - {38, 0x03, 191}, - {3, 0x02, 192}, - {4, 0x02, 192}, - {6, 0x02, 192}, - {9, 0x02, 192}, - {14, 0x02, 192}, - {20, 0x02, 192}, - {28, 0x02, 192}, - {38, 0x03, 192}, -}, -/* 127 */ -{ - {3, 0x02, 193}, - {4, 0x02, 193}, - {6, 0x02, 193}, - {9, 0x02, 193}, - {14, 0x02, 193}, - {20, 0x02, 193}, - {28, 0x02, 193}, - {38, 0x03, 193}, - {3, 0x02, 194}, - {4, 0x02, 194}, - {6, 0x02, 194}, - {9, 0x02, 194}, - {14, 0x02, 194}, - {20, 0x02, 194}, - {28, 0x02, 194}, - {38, 0x03, 194}, -}, -/* 128 */ -{ - {132, 0x00, 0}, - {133, 0x00, 0}, - {135, 0x00, 0}, - {136, 0x00, 0}, - {139, 0x00, 0}, - {140, 0x00, 0}, - {142, 0x00, 0}, - {143, 0x00, 0}, - {147, 0x00, 0}, - {148, 0x00, 0}, - {150, 0x00, 0}, - {151, 0x00, 0}, - {154, 0x00, 0}, - {155, 0x00, 0}, - {157, 0x00, 0}, - {158, 0x00, 0}, -}, -/* 129 */ -{ - {0, 0x03, 195}, - {0, 0x03, 196}, - {0, 0x03, 197}, - {0, 0x03, 198}, - {0, 0x03, 199}, - {0, 0x03, 200}, - {0, 0x03, 201}, - {0, 0x03, 202}, - {0, 0x03, 203}, - {0, 0x03, 204}, - {0, 0x03, 205}, - {0, 0x03, 206}, - {0, 0x03, 207}, - {0, 0x03, 208}, - {0, 0x03, 209}, - {0, 0x03, 210}, -}, -/* 130 */ -{ - {1, 0x02, 195}, - {12, 0x03, 195}, - {1, 0x02, 196}, - {12, 0x03, 196}, - {1, 0x02, 197}, - {12, 0x03, 197}, - {1, 0x02, 198}, - {12, 0x03, 198}, - {1, 0x02, 199}, - {12, 0x03, 199}, - {1, 0x02, 200}, - {12, 0x03, 200}, - {1, 0x02, 201}, - {12, 0x03, 201}, - {1, 0x02, 202}, - {12, 0x03, 202}, -}, -/* 131 */ -{ - {2, 0x02, 195}, - {5, 0x02, 195}, - {13, 0x02, 195}, - {27, 0x03, 195}, - {2, 0x02, 196}, - {5, 0x02, 196}, - {13, 0x02, 196}, - {27, 0x03, 196}, - {2, 0x02, 197}, - {5, 0x02, 197}, - {13, 0x02, 197}, - {27, 0x03, 197}, - {2, 0x02, 198}, - {5, 0x02, 198}, - {13, 0x02, 198}, - {27, 0x03, 198}, -}, -/* 132 */ -{ - {3, 0x02, 195}, - {4, 0x02, 195}, - {6, 0x02, 195}, - {9, 0x02, 195}, - {14, 0x02, 195}, - {20, 0x02, 195}, - {28, 0x02, 195}, - {38, 0x03, 195}, - {3, 0x02, 196}, - {4, 0x02, 196}, - {6, 0x02, 196}, - {9, 0x02, 196}, - {14, 0x02, 196}, - {20, 0x02, 196}, - {28, 0x02, 196}, - {38, 0x03, 196}, -}, -/* 133 */ -{ - {3, 0x02, 197}, - {4, 0x02, 197}, - {6, 0x02, 197}, - {9, 0x02, 197}, - {14, 0x02, 197}, - {20, 0x02, 197}, - {28, 0x02, 197}, - {38, 0x03, 197}, - {3, 0x02, 198}, - {4, 0x02, 198}, - {6, 0x02, 198}, - {9, 0x02, 198}, - {14, 0x02, 198}, - {20, 0x02, 198}, - {28, 0x02, 198}, - {38, 0x03, 198}, -}, -/* 134 */ -{ - {2, 0x02, 199}, - {5, 0x02, 199}, - {13, 0x02, 199}, - {27, 0x03, 199}, - {2, 0x02, 200}, - {5, 0x02, 200}, - {13, 0x02, 200}, - {27, 0x03, 200}, - {2, 0x02, 201}, - {5, 0x02, 201}, - {13, 0x02, 201}, - {27, 0x03, 201}, - {2, 0x02, 202}, - {5, 0x02, 202}, - {13, 0x02, 202}, - {27, 0x03, 202}, -}, -/* 135 */ -{ - {3, 0x02, 199}, - {4, 0x02, 199}, - {6, 0x02, 199}, - {9, 0x02, 199}, - {14, 0x02, 199}, - {20, 0x02, 199}, - {28, 0x02, 199}, - {38, 0x03, 199}, - {3, 0x02, 200}, - {4, 0x02, 200}, - {6, 0x02, 200}, - {9, 0x02, 200}, - {14, 0x02, 200}, - {20, 0x02, 200}, - {28, 0x02, 200}, - {38, 0x03, 200}, -}, -/* 136 */ -{ - {3, 0x02, 201}, - {4, 0x02, 201}, - {6, 0x02, 201}, - {9, 0x02, 201}, - {14, 0x02, 201}, - {20, 0x02, 201}, - {28, 0x02, 201}, - {38, 0x03, 201}, - {3, 0x02, 202}, - {4, 0x02, 202}, - {6, 0x02, 202}, - {9, 0x02, 202}, - {14, 0x02, 202}, - {20, 0x02, 202}, - {28, 0x02, 202}, - {38, 0x03, 202}, -}, -/* 137 */ -{ - {1, 0x02, 203}, - {12, 0x03, 203}, - {1, 0x02, 204}, - {12, 0x03, 204}, - {1, 0x02, 205}, - {12, 0x03, 205}, - {1, 0x02, 206}, - {12, 0x03, 206}, - {1, 0x02, 207}, - {12, 0x03, 207}, - {1, 0x02, 208}, - {12, 0x03, 208}, - {1, 0x02, 209}, - {12, 0x03, 209}, - {1, 0x02, 210}, - {12, 0x03, 210}, -}, -/* 138 */ -{ - {2, 0x02, 203}, - {5, 0x02, 203}, - {13, 0x02, 203}, - {27, 0x03, 203}, - {2, 0x02, 204}, - {5, 0x02, 204}, - {13, 0x02, 204}, - {27, 0x03, 204}, - {2, 0x02, 205}, - {5, 0x02, 205}, - {13, 0x02, 205}, - {27, 0x03, 205}, - {2, 0x02, 206}, - {5, 0x02, 206}, - {13, 0x02, 206}, - {27, 0x03, 206}, -}, -/* 139 */ -{ - {3, 0x02, 203}, - {4, 0x02, 203}, - {6, 0x02, 203}, - {9, 0x02, 203}, - {14, 0x02, 203}, - {20, 0x02, 203}, - {28, 0x02, 203}, - {38, 0x03, 203}, - {3, 0x02, 204}, - {4, 0x02, 204}, - {6, 0x02, 204}, - {9, 0x02, 204}, - {14, 0x02, 204}, - {20, 0x02, 204}, - {28, 0x02, 204}, - {38, 0x03, 204}, -}, -/* 140 */ -{ - {3, 0x02, 205}, - {4, 0x02, 205}, - {6, 0x02, 205}, - {9, 0x02, 205}, - {14, 0x02, 205}, - {20, 0x02, 205}, - {28, 0x02, 205}, - {38, 0x03, 205}, - {3, 0x02, 206}, - {4, 0x02, 206}, - {6, 0x02, 206}, - {9, 0x02, 206}, - {14, 0x02, 206}, - {20, 0x02, 206}, - {28, 0x02, 206}, - {38, 0x03, 206}, -}, -/* 141 */ -{ - {2, 0x02, 207}, - {5, 0x02, 207}, - {13, 0x02, 207}, - {27, 0x03, 207}, - {2, 0x02, 208}, - {5, 0x02, 208}, - {13, 0x02, 208}, - {27, 0x03, 208}, - {2, 0x02, 209}, - {5, 0x02, 209}, - {13, 0x02, 209}, - {27, 0x03, 209}, - {2, 0x02, 210}, - {5, 0x02, 210}, - {13, 0x02, 210}, - {27, 0x03, 210}, -}, -/* 142 */ -{ - {3, 0x02, 207}, - {4, 0x02, 207}, - {6, 0x02, 207}, - {9, 0x02, 207}, - {14, 0x02, 207}, - {20, 0x02, 207}, - {28, 0x02, 207}, - {38, 0x03, 207}, - {3, 0x02, 208}, - {4, 0x02, 208}, - {6, 0x02, 208}, - {9, 0x02, 208}, - {14, 0x02, 208}, - {20, 0x02, 208}, - {28, 0x02, 208}, - {38, 0x03, 208}, -}, -/* 143 */ -{ - {3, 0x02, 209}, - {4, 0x02, 209}, - {6, 0x02, 209}, - {9, 0x02, 209}, - {14, 0x02, 209}, - {20, 0x02, 209}, - {28, 0x02, 209}, - {38, 0x03, 209}, - {3, 0x02, 210}, - {4, 0x02, 210}, - {6, 0x02, 210}, - {9, 0x02, 210}, - {14, 0x02, 210}, - {20, 0x02, 210}, - {28, 0x02, 210}, - {38, 0x03, 210}, -}, -/* 144 */ -{ - {0, 0x03, 211}, - {0, 0x03, 212}, - {0, 0x03, 213}, - {0, 0x03, 214}, - {0, 0x03, 215}, - {0, 0x03, 216}, - {0, 0x03, 217}, - {0, 0x03, 218}, - {0, 0x03, 219}, - {0, 0x03, 220}, - {0, 0x03, 221}, - {0, 0x03, 222}, - {0, 0x03, 223}, - {0, 0x03, 224}, - {0, 0x03, 225}, - {0, 0x03, 226}, -}, -/* 145 */ -{ - {1, 0x02, 211}, - {12, 0x03, 211}, - {1, 0x02, 212}, - {12, 0x03, 212}, - {1, 0x02, 213}, - {12, 0x03, 213}, - {1, 0x02, 214}, - {12, 0x03, 214}, - {1, 0x02, 215}, - {12, 0x03, 215}, - {1, 0x02, 216}, - {12, 0x03, 216}, - {1, 0x02, 217}, - {12, 0x03, 217}, - {1, 0x02, 218}, - {12, 0x03, 218}, -}, -/* 146 */ -{ - {2, 0x02, 211}, - {5, 0x02, 211}, - {13, 0x02, 211}, - {27, 0x03, 211}, - {2, 0x02, 212}, - {5, 0x02, 212}, - {13, 0x02, 212}, - {27, 0x03, 212}, - {2, 0x02, 213}, - {5, 0x02, 213}, - {13, 0x02, 213}, - {27, 0x03, 213}, - {2, 0x02, 214}, - {5, 0x02, 214}, - {13, 0x02, 214}, - {27, 0x03, 214}, -}, -/* 147 */ -{ - {3, 0x02, 211}, - {4, 0x02, 211}, - {6, 0x02, 211}, - {9, 0x02, 211}, - {14, 0x02, 211}, - {20, 0x02, 211}, - {28, 0x02, 211}, - {38, 0x03, 211}, - {3, 0x02, 212}, - {4, 0x02, 212}, - {6, 0x02, 212}, - {9, 0x02, 212}, - {14, 0x02, 212}, - {20, 0x02, 212}, - {28, 0x02, 212}, - {38, 0x03, 212}, -}, -/* 148 */ -{ - {3, 0x02, 213}, - {4, 0x02, 213}, - {6, 0x02, 213}, - {9, 0x02, 213}, - {14, 0x02, 213}, - {20, 0x02, 213}, - {28, 0x02, 213}, - {38, 0x03, 213}, - {3, 0x02, 214}, - {4, 0x02, 214}, - {6, 0x02, 214}, - {9, 0x02, 214}, - {14, 0x02, 214}, - {20, 0x02, 214}, - {28, 0x02, 214}, - {38, 0x03, 214}, -}, -/* 149 */ -{ - {2, 0x02, 215}, - {5, 0x02, 215}, - {13, 0x02, 215}, - {27, 0x03, 215}, - {2, 0x02, 216}, - {5, 0x02, 216}, - {13, 0x02, 216}, - {27, 0x03, 216}, - {2, 0x02, 217}, - {5, 0x02, 217}, - {13, 0x02, 217}, - {27, 0x03, 217}, - {2, 0x02, 218}, - {5, 0x02, 218}, - {13, 0x02, 218}, - {27, 0x03, 218}, -}, -/* 150 */ -{ - {3, 0x02, 215}, - {4, 0x02, 215}, - {6, 0x02, 215}, - {9, 0x02, 215}, - {14, 0x02, 215}, - {20, 0x02, 215}, - {28, 0x02, 215}, - {38, 0x03, 215}, - {3, 0x02, 216}, - {4, 0x02, 216}, - {6, 0x02, 216}, - {9, 0x02, 216}, - {14, 0x02, 216}, - {20, 0x02, 216}, - {28, 0x02, 216}, - {38, 0x03, 216}, -}, -/* 151 */ -{ - {3, 0x02, 217}, - {4, 0x02, 217}, - {6, 0x02, 217}, - {9, 0x02, 217}, - {14, 0x02, 217}, - {20, 0x02, 217}, - {28, 0x02, 217}, - {38, 0x03, 217}, - {3, 0x02, 218}, - {4, 0x02, 218}, - {6, 0x02, 218}, - {9, 0x02, 218}, - {14, 0x02, 218}, - {20, 0x02, 218}, - {28, 0x02, 218}, - {38, 0x03, 218}, -}, -/* 152 */ -{ - {1, 0x02, 219}, - {12, 0x03, 219}, - {1, 0x02, 220}, - {12, 0x03, 220}, - {1, 0x02, 221}, - {12, 0x03, 221}, - {1, 0x02, 222}, - {12, 0x03, 222}, - {1, 0x02, 223}, - {12, 0x03, 223}, - {1, 0x02, 224}, - {12, 0x03, 224}, - {1, 0x02, 225}, - {12, 0x03, 225}, - {1, 0x02, 226}, - {12, 0x03, 226}, -}, -/* 153 */ -{ - {2, 0x02, 219}, - {5, 0x02, 219}, - {13, 0x02, 219}, - {27, 0x03, 219}, - {2, 0x02, 220}, - {5, 0x02, 220}, - {13, 0x02, 220}, - {27, 0x03, 220}, - {2, 0x02, 221}, - {5, 0x02, 221}, - {13, 0x02, 221}, - {27, 0x03, 221}, - {2, 0x02, 222}, - {5, 0x02, 222}, - {13, 0x02, 222}, - {27, 0x03, 222}, -}, -/* 154 */ -{ - {3, 0x02, 219}, - {4, 0x02, 219}, - {6, 0x02, 219}, - {9, 0x02, 219}, - {14, 0x02, 219}, - {20, 0x02, 219}, - {28, 0x02, 219}, - {38, 0x03, 219}, - {3, 0x02, 220}, - {4, 0x02, 220}, - {6, 0x02, 220}, - {9, 0x02, 220}, - {14, 0x02, 220}, - {20, 0x02, 220}, - {28, 0x02, 220}, - {38, 0x03, 220}, -}, -/* 155 */ -{ - {3, 0x02, 221}, - {4, 0x02, 221}, - {6, 0x02, 221}, - {9, 0x02, 221}, - {14, 0x02, 221}, - {20, 0x02, 221}, - {28, 0x02, 221}, - {38, 0x03, 221}, - {3, 0x02, 222}, - {4, 0x02, 222}, - {6, 0x02, 222}, - {9, 0x02, 222}, - {14, 0x02, 222}, - {20, 0x02, 222}, - {28, 0x02, 222}, - {38, 0x03, 222}, -}, -/* 156 */ -{ - {2, 0x02, 223}, - {5, 0x02, 223}, - {13, 0x02, 223}, - {27, 0x03, 223}, - {2, 0x02, 224}, - {5, 0x02, 224}, - {13, 0x02, 224}, - {27, 0x03, 224}, - {2, 0x02, 225}, - {5, 0x02, 225}, - {13, 0x02, 225}, - {27, 0x03, 225}, - {2, 0x02, 226}, - {5, 0x02, 226}, - {13, 0x02, 226}, - {27, 0x03, 226}, -}, -/* 157 */ -{ - {3, 0x02, 223}, - {4, 0x02, 223}, - {6, 0x02, 223}, - {9, 0x02, 223}, - {14, 0x02, 223}, - {20, 0x02, 223}, - {28, 0x02, 223}, - {38, 0x03, 223}, - {3, 0x02, 224}, - {4, 0x02, 224}, - {6, 0x02, 224}, - {9, 0x02, 224}, - {14, 0x02, 224}, - {20, 0x02, 224}, - {28, 0x02, 224}, - {38, 0x03, 224}, -}, -/* 158 */ -{ - {3, 0x02, 225}, - {4, 0x02, 225}, - {6, 0x02, 225}, - {9, 0x02, 225}, - {14, 0x02, 225}, - {20, 0x02, 225}, - {28, 0x02, 225}, - {38, 0x03, 225}, - {3, 0x02, 226}, - {4, 0x02, 226}, - {6, 0x02, 226}, - {9, 0x02, 226}, - {14, 0x02, 226}, - {20, 0x02, 226}, - {28, 0x02, 226}, - {38, 0x03, 226}, -}, -/* 159 */ -{ - {163, 0x00, 0}, - {166, 0x00, 0}, - {170, 0x00, 0}, - {173, 0x00, 0}, - {178, 0x00, 0}, - {181, 0x00, 0}, - {185, 0x00, 0}, - {188, 0x00, 0}, - {196, 0x00, 0}, - {203, 0x00, 0}, - {211, 0x00, 0}, - {218, 0x00, 0}, - {227, 0x00, 0}, - {234, 0x00, 0}, - {242, 0x00, 0}, - {249, 0x00, 0}, -}, -/* 160 */ -{ - {164, 0x00, 0}, - {165, 0x00, 0}, - {167, 0x00, 0}, - {168, 0x00, 0}, - {171, 0x00, 0}, - {172, 0x00, 0}, - {174, 0x00, 0}, - {175, 0x00, 0}, - {179, 0x00, 0}, - {180, 0x00, 0}, - {182, 0x00, 0}, - {183, 0x00, 0}, - {186, 0x00, 0}, - {187, 0x00, 0}, - {189, 0x00, 0}, - {190, 0x00, 0}, -}, -/* 161 */ -{ - {0, 0x03, 227}, - {0, 0x03, 228}, - {0, 0x03, 229}, - {0, 0x03, 230}, - {0, 0x03, 231}, - {0, 0x03, 232}, - {0, 0x03, 233}, - {0, 0x03, 234}, - {0, 0x03, 235}, - {0, 0x03, 236}, - {0, 0x03, 237}, - {0, 0x03, 238}, - {0, 0x03, 239}, - {0, 0x03, 240}, - {0, 0x03, 241}, - {0, 0x03, 242}, -}, -/* 162 */ -{ - {1, 0x02, 227}, - {12, 0x03, 227}, - {1, 0x02, 228}, - {12, 0x03, 228}, - {1, 0x02, 229}, - {12, 0x03, 229}, - {1, 0x02, 230}, - {12, 0x03, 230}, - {1, 0x02, 231}, - {12, 0x03, 231}, - {1, 0x02, 232}, - {12, 0x03, 232}, - {1, 0x02, 233}, - {12, 0x03, 233}, - {1, 0x02, 234}, - {12, 0x03, 234}, -}, -/* 163 */ -{ - {2, 0x02, 227}, - {5, 0x02, 227}, - {13, 0x02, 227}, - {27, 0x03, 227}, - {2, 0x02, 228}, - {5, 0x02, 228}, - {13, 0x02, 228}, - {27, 0x03, 228}, - {2, 0x02, 229}, - {5, 0x02, 229}, - {13, 0x02, 229}, - {27, 0x03, 229}, - {2, 0x02, 230}, - {5, 0x02, 230}, - {13, 0x02, 230}, - {27, 0x03, 230}, -}, -/* 164 */ -{ - {3, 0x02, 227}, - {4, 0x02, 227}, - {6, 0x02, 227}, - {9, 0x02, 227}, - {14, 0x02, 227}, - {20, 0x02, 227}, - {28, 0x02, 227}, - {38, 0x03, 227}, - {3, 0x02, 228}, - {4, 0x02, 228}, - {6, 0x02, 228}, - {9, 0x02, 228}, - {14, 0x02, 228}, - {20, 0x02, 228}, - {28, 0x02, 228}, - {38, 0x03, 228}, -}, -/* 165 */ -{ - {3, 0x02, 229}, - {4, 0x02, 229}, - {6, 0x02, 229}, - {9, 0x02, 229}, - {14, 0x02, 229}, - {20, 0x02, 229}, - {28, 0x02, 229}, - {38, 0x03, 229}, - {3, 0x02, 230}, - {4, 0x02, 230}, - {6, 0x02, 230}, - {9, 0x02, 230}, - {14, 0x02, 230}, - {20, 0x02, 230}, - {28, 0x02, 230}, - {38, 0x03, 230}, -}, -/* 166 */ -{ - {2, 0x02, 231}, - {5, 0x02, 231}, - {13, 0x02, 231}, - {27, 0x03, 231}, - {2, 0x02, 232}, - {5, 0x02, 232}, - {13, 0x02, 232}, - {27, 0x03, 232}, - {2, 0x02, 233}, - {5, 0x02, 233}, - {13, 0x02, 233}, - {27, 0x03, 233}, - {2, 0x02, 234}, - {5, 0x02, 234}, - {13, 0x02, 234}, - {27, 0x03, 234}, -}, -/* 167 */ -{ - {3, 0x02, 231}, - {4, 0x02, 231}, - {6, 0x02, 231}, - {9, 0x02, 231}, - {14, 0x02, 231}, - {20, 0x02, 231}, - {28, 0x02, 231}, - {38, 0x03, 231}, - {3, 0x02, 232}, - {4, 0x02, 232}, - {6, 0x02, 232}, - {9, 0x02, 232}, - {14, 0x02, 232}, - {20, 0x02, 232}, - {28, 0x02, 232}, - {38, 0x03, 232}, -}, -/* 168 */ -{ - {3, 0x02, 233}, - {4, 0x02, 233}, - {6, 0x02, 233}, - {9, 0x02, 233}, - {14, 0x02, 233}, - {20, 0x02, 233}, - {28, 0x02, 233}, - {38, 0x03, 233}, - {3, 0x02, 234}, - {4, 0x02, 234}, - {6, 0x02, 234}, - {9, 0x02, 234}, - {14, 0x02, 234}, - {20, 0x02, 234}, - {28, 0x02, 234}, - {38, 0x03, 234}, -}, -/* 169 */ -{ - {1, 0x02, 235}, - {12, 0x03, 235}, - {1, 0x02, 236}, - {12, 0x03, 236}, - {1, 0x02, 237}, - {12, 0x03, 237}, - {1, 0x02, 238}, - {12, 0x03, 238}, - {1, 0x02, 239}, - {12, 0x03, 239}, - {1, 0x02, 240}, - {12, 0x03, 240}, - {1, 0x02, 241}, - {12, 0x03, 241}, - {1, 0x02, 242}, - {12, 0x03, 242}, -}, -/* 170 */ -{ - {2, 0x02, 235}, - {5, 0x02, 235}, - {13, 0x02, 235}, - {27, 0x03, 235}, - {2, 0x02, 236}, - {5, 0x02, 236}, - {13, 0x02, 236}, - {27, 0x03, 236}, - {2, 0x02, 237}, - {5, 0x02, 237}, - {13, 0x02, 237}, - {27, 0x03, 237}, - {2, 0x02, 238}, - {5, 0x02, 238}, - {13, 0x02, 238}, - {27, 0x03, 238}, -}, -/* 171 */ -{ - {3, 0x02, 235}, - {4, 0x02, 235}, - {6, 0x02, 235}, - {9, 0x02, 235}, - {14, 0x02, 235}, - {20, 0x02, 235}, - {28, 0x02, 235}, - {38, 0x03, 235}, - {3, 0x02, 236}, - {4, 0x02, 236}, - {6, 0x02, 236}, - {9, 0x02, 236}, - {14, 0x02, 236}, - {20, 0x02, 236}, - {28, 0x02, 236}, - {38, 0x03, 236}, -}, -/* 172 */ -{ - {3, 0x02, 237}, - {4, 0x02, 237}, - {6, 0x02, 237}, - {9, 0x02, 237}, - {14, 0x02, 237}, - {20, 0x02, 237}, - {28, 0x02, 237}, - {38, 0x03, 237}, - {3, 0x02, 238}, - {4, 0x02, 238}, - {6, 0x02, 238}, - {9, 0x02, 238}, - {14, 0x02, 238}, - {20, 0x02, 238}, - {28, 0x02, 238}, - {38, 0x03, 238}, -}, -/* 173 */ -{ - {2, 0x02, 239}, - {5, 0x02, 239}, - {13, 0x02, 239}, - {27, 0x03, 239}, - {2, 0x02, 240}, - {5, 0x02, 240}, - {13, 0x02, 240}, - {27, 0x03, 240}, - {2, 0x02, 241}, - {5, 0x02, 241}, - {13, 0x02, 241}, - {27, 0x03, 241}, - {2, 0x02, 242}, - {5, 0x02, 242}, - {13, 0x02, 242}, - {27, 0x03, 242}, -}, -/* 174 */ -{ - {3, 0x02, 239}, - {4, 0x02, 239}, - {6, 0x02, 239}, - {9, 0x02, 239}, - {14, 0x02, 239}, - {20, 0x02, 239}, - {28, 0x02, 239}, - {38, 0x03, 239}, - {3, 0x02, 240}, - {4, 0x02, 240}, - {6, 0x02, 240}, - {9, 0x02, 240}, - {14, 0x02, 240}, - {20, 0x02, 240}, - {28, 0x02, 240}, - {38, 0x03, 240}, -}, -/* 175 */ -{ - {3, 0x02, 241}, - {4, 0x02, 241}, - {6, 0x02, 241}, - {9, 0x02, 241}, - {14, 0x02, 241}, - {20, 0x02, 241}, - {28, 0x02, 241}, - {38, 0x03, 241}, - {3, 0x02, 242}, - {4, 0x02, 242}, - {6, 0x02, 242}, - {9, 0x02, 242}, - {14, 0x02, 242}, - {20, 0x02, 242}, - {28, 0x02, 242}, - {38, 0x03, 242}, -}, -/* 176 */ -{ - {0, 0x03, 243}, - {0, 0x03, 244}, - {0, 0x03, 245}, - {0, 0x03, 246}, - {0, 0x03, 247}, - {0, 0x03, 248}, - {0, 0x03, 249}, - {0, 0x03, 250}, - {0, 0x03, 251}, - {0, 0x03, 252}, - {0, 0x03, 253}, - {0, 0x03, 254}, - {0, 0x03, 255}, - {-1, 0x00, 0}, - {191, 0x00, 0}, - {192, 0x00, 0}, -}, -/* 177 */ -{ - {1, 0x02, 243}, - {12, 0x03, 243}, - {1, 0x02, 244}, - {12, 0x03, 244}, - {1, 0x02, 245}, - {12, 0x03, 245}, - {1, 0x02, 246}, - {12, 0x03, 246}, - {1, 0x02, 247}, - {12, 0x03, 247}, - {1, 0x02, 248}, - {12, 0x03, 248}, - {1, 0x02, 249}, - {12, 0x03, 249}, - {1, 0x02, 250}, - {12, 0x03, 250}, -}, -/* 178 */ -{ - {2, 0x02, 243}, - {5, 0x02, 243}, - {13, 0x02, 243}, - {27, 0x03, 243}, - {2, 0x02, 244}, - {5, 0x02, 244}, - {13, 0x02, 244}, - {27, 0x03, 244}, - {2, 0x02, 245}, - {5, 0x02, 245}, - {13, 0x02, 245}, - {27, 0x03, 245}, - {2, 0x02, 246}, - {5, 0x02, 246}, - {13, 0x02, 246}, - {27, 0x03, 246}, -}, -/* 179 */ -{ - {3, 0x02, 243}, - {4, 0x02, 243}, - {6, 0x02, 243}, - {9, 0x02, 243}, - {14, 0x02, 243}, - {20, 0x02, 243}, - {28, 0x02, 243}, - {38, 0x03, 243}, - {3, 0x02, 244}, - {4, 0x02, 244}, - {6, 0x02, 244}, - {9, 0x02, 244}, - {14, 0x02, 244}, - {20, 0x02, 244}, - {28, 0x02, 244}, - {38, 0x03, 244}, -}, -/* 180 */ -{ - {3, 0x02, 245}, - {4, 0x02, 245}, - {6, 0x02, 245}, - {9, 0x02, 245}, - {14, 0x02, 245}, - {20, 0x02, 245}, - {28, 0x02, 245}, - {38, 0x03, 245}, - {3, 0x02, 246}, - {4, 0x02, 246}, - {6, 0x02, 246}, - {9, 0x02, 246}, - {14, 0x02, 246}, - {20, 0x02, 246}, - {28, 0x02, 246}, - {38, 0x03, 246}, -}, -/* 181 */ -{ - {2, 0x02, 247}, - {5, 0x02, 247}, - {13, 0x02, 247}, - {27, 0x03, 247}, - {2, 0x02, 248}, - {5, 0x02, 248}, - {13, 0x02, 248}, - {27, 0x03, 248}, - {2, 0x02, 249}, - {5, 0x02, 249}, - {13, 0x02, 249}, - {27, 0x03, 249}, - {2, 0x02, 250}, - {5, 0x02, 250}, - {13, 0x02, 250}, - {27, 0x03, 250}, -}, -/* 182 */ -{ - {3, 0x02, 247}, - {4, 0x02, 247}, - {6, 0x02, 247}, - {9, 0x02, 247}, - {14, 0x02, 247}, - {20, 0x02, 247}, - {28, 0x02, 247}, - {38, 0x03, 247}, - {3, 0x02, 248}, - {4, 0x02, 248}, - {6, 0x02, 248}, - {9, 0x02, 248}, - {14, 0x02, 248}, - {20, 0x02, 248}, - {28, 0x02, 248}, - {38, 0x03, 248}, -}, -/* 183 */ -{ - {3, 0x02, 249}, - {4, 0x02, 249}, - {6, 0x02, 249}, - {9, 0x02, 249}, - {14, 0x02, 249}, - {20, 0x02, 249}, - {28, 0x02, 249}, - {38, 0x03, 249}, - {3, 0x02, 250}, - {4, 0x02, 250}, - {6, 0x02, 250}, - {9, 0x02, 250}, - {14, 0x02, 250}, - {20, 0x02, 250}, - {28, 0x02, 250}, - {38, 0x03, 250}, -}, -/* 184 */ -{ - {1, 0x02, 251}, - {12, 0x03, 251}, - {1, 0x02, 252}, - {12, 0x03, 252}, - {1, 0x02, 253}, - {12, 0x03, 253}, - {1, 0x02, 254}, - {12, 0x03, 254}, - {1, 0x02, 255}, - {12, 0x03, 255}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {0, 0x03, 0}, - {0, 0x03, 1}, - {0, 0x03, 2}, - {0, 0x03, 3}, -}, -/* 185 */ -{ - {2, 0x02, 251}, - {5, 0x02, 251}, - {13, 0x02, 251}, - {27, 0x03, 251}, - {2, 0x02, 252}, - {5, 0x02, 252}, - {13, 0x02, 252}, - {27, 0x03, 252}, - {2, 0x02, 253}, - {5, 0x02, 253}, - {13, 0x02, 253}, - {27, 0x03, 253}, - {2, 0x02, 254}, - {5, 0x02, 254}, - {13, 0x02, 254}, - {27, 0x03, 254}, -}, -/* 186 */ -{ - {3, 0x02, 251}, - {4, 0x02, 251}, - {6, 0x02, 251}, - {9, 0x02, 251}, - {14, 0x02, 251}, - {20, 0x02, 251}, - {28, 0x02, 251}, - {38, 0x03, 251}, - {3, 0x02, 252}, - {4, 0x02, 252}, - {6, 0x02, 252}, - {9, 0x02, 252}, - {14, 0x02, 252}, - {20, 0x02, 252}, - {28, 0x02, 252}, - {38, 0x03, 252}, -}, -/* 187 */ -{ - {3, 0x02, 253}, - {4, 0x02, 253}, - {6, 0x02, 253}, - {9, 0x02, 253}, - {14, 0x02, 253}, - {20, 0x02, 253}, - {28, 0x02, 253}, - {38, 0x03, 253}, - {3, 0x02, 254}, - {4, 0x02, 254}, - {6, 0x02, 254}, - {9, 0x02, 254}, - {14, 0x02, 254}, - {20, 0x02, 254}, - {28, 0x02, 254}, - {38, 0x03, 254}, -}, -/* 188 */ -{ - {2, 0x02, 255}, - {5, 0x02, 255}, - {13, 0x02, 255}, - {27, 0x03, 255}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {1, 0x02, 0}, - {12, 0x03, 0}, - {1, 0x02, 1}, - {12, 0x03, 1}, - {1, 0x02, 2}, - {12, 0x03, 2}, - {1, 0x02, 3}, - {12, 0x03, 3}, -}, -/* 189 */ -{ - {3, 0x02, 255}, - {4, 0x02, 255}, - {6, 0x02, 255}, - {9, 0x02, 255}, - {14, 0x02, 255}, - {20, 0x02, 255}, - {28, 0x02, 255}, - {38, 0x03, 255}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, - {-1, 0x00, 0}, -}, -/* 190 */ -{ - {2, 0x02, 0}, - {5, 0x02, 0}, - {13, 0x02, 0}, - {27, 0x03, 0}, - {2, 0x02, 1}, - {5, 0x02, 1}, - {13, 0x02, 1}, - {27, 0x03, 1}, - {2, 0x02, 2}, - {5, 0x02, 2}, - {13, 0x02, 2}, - {27, 0x03, 2}, - {2, 0x02, 3}, - {5, 0x02, 3}, - {13, 0x02, 3}, - {27, 0x03, 3}, -}, -/* 191 */ -{ - {3, 0x02, 0}, - {4, 0x02, 0}, - {6, 0x02, 0}, - {9, 0x02, 0}, - {14, 0x02, 0}, - {20, 0x02, 0}, - {28, 0x02, 0}, - {38, 0x03, 0}, - {3, 0x02, 1}, - {4, 0x02, 1}, - {6, 0x02, 1}, - {9, 0x02, 1}, - {14, 0x02, 1}, - {20, 0x02, 1}, - {28, 0x02, 1}, - {38, 0x03, 1}, -}, -/* 192 */ -{ - {3, 0x02, 2}, - {4, 0x02, 2}, - {6, 0x02, 2}, - {9, 0x02, 2}, - {14, 0x02, 2}, - {20, 0x02, 2}, - {28, 0x02, 2}, - {38, 0x03, 2}, - {3, 0x02, 3}, - {4, 0x02, 3}, - {6, 0x02, 3}, - {9, 0x02, 3}, - {14, 0x02, 3}, - {20, 0x02, 3}, - {28, 0x02, 3}, - {38, 0x03, 3}, -}, -/* 193 */ -{ - {197, 0x00, 0}, - {200, 0x00, 0}, - {204, 0x00, 0}, - {207, 0x00, 0}, - {212, 0x00, 0}, - {215, 0x00, 0}, - {219, 0x00, 0}, - {222, 0x00, 0}, - {228, 0x00, 0}, - {231, 0x00, 0}, - {235, 0x00, 0}, - {238, 0x00, 0}, - {243, 0x00, 0}, - {246, 0x00, 0}, - {250, 0x00, 0}, - {253, 0x00, 0}, -}, -/* 194 */ -{ - {198, 0x00, 0}, - {199, 0x00, 0}, - {201, 0x00, 0}, - {202, 0x00, 0}, - {205, 0x00, 0}, - {206, 0x00, 0}, - {208, 0x00, 0}, - {209, 0x00, 0}, - {213, 0x00, 0}, - {214, 0x00, 0}, - {216, 0x00, 0}, - {217, 0x00, 0}, - {220, 0x00, 0}, - {221, 0x00, 0}, - {223, 0x00, 0}, - {224, 0x00, 0}, -}, -/* 195 */ -{ - {0, 0x03, 4}, - {0, 0x03, 5}, - {0, 0x03, 6}, - {0, 0x03, 7}, - {0, 0x03, 8}, - {0, 0x03, 9}, - {0, 0x03, 10}, - {0, 0x03, 11}, - {0, 0x03, 12}, - {0, 0x03, 13}, - {0, 0x03, 14}, - {0, 0x03, 15}, - {0, 0x03, 16}, - {0, 0x03, 17}, - {0, 0x03, 18}, - {0, 0x03, 19}, -}, -/* 196 */ -{ - {1, 0x02, 4}, - {12, 0x03, 4}, - {1, 0x02, 5}, - {12, 0x03, 5}, - {1, 0x02, 6}, - {12, 0x03, 6}, - {1, 0x02, 7}, - {12, 0x03, 7}, - {1, 0x02, 8}, - {12, 0x03, 8}, - {1, 0x02, 9}, - {12, 0x03, 9}, - {1, 0x02, 10}, - {12, 0x03, 10}, - {1, 0x02, 11}, - {12, 0x03, 11}, -}, -/* 197 */ -{ - {2, 0x02, 4}, - {5, 0x02, 4}, - {13, 0x02, 4}, - {27, 0x03, 4}, - {2, 0x02, 5}, - {5, 0x02, 5}, - {13, 0x02, 5}, - {27, 0x03, 5}, - {2, 0x02, 6}, - {5, 0x02, 6}, - {13, 0x02, 6}, - {27, 0x03, 6}, - {2, 0x02, 7}, - {5, 0x02, 7}, - {13, 0x02, 7}, - {27, 0x03, 7}, -}, -/* 198 */ -{ - {3, 0x02, 4}, - {4, 0x02, 4}, - {6, 0x02, 4}, - {9, 0x02, 4}, - {14, 0x02, 4}, - {20, 0x02, 4}, - {28, 0x02, 4}, - {38, 0x03, 4}, - {3, 0x02, 5}, - {4, 0x02, 5}, - {6, 0x02, 5}, - {9, 0x02, 5}, - {14, 0x02, 5}, - {20, 0x02, 5}, - {28, 0x02, 5}, - {38, 0x03, 5}, -}, -/* 199 */ -{ - {3, 0x02, 6}, - {4, 0x02, 6}, - {6, 0x02, 6}, - {9, 0x02, 6}, - {14, 0x02, 6}, - {20, 0x02, 6}, - {28, 0x02, 6}, - {38, 0x03, 6}, - {3, 0x02, 7}, - {4, 0x02, 7}, - {6, 0x02, 7}, - {9, 0x02, 7}, - {14, 0x02, 7}, - {20, 0x02, 7}, - {28, 0x02, 7}, - {38, 0x03, 7}, -}, -/* 200 */ -{ - {2, 0x02, 8}, - {5, 0x02, 8}, - {13, 0x02, 8}, - {27, 0x03, 8}, - {2, 0x02, 9}, - {5, 0x02, 9}, - {13, 0x02, 9}, - {27, 0x03, 9}, - {2, 0x02, 10}, - {5, 0x02, 10}, - {13, 0x02, 10}, - {27, 0x03, 10}, - {2, 0x02, 11}, - {5, 0x02, 11}, - {13, 0x02, 11}, - {27, 0x03, 11}, -}, -/* 201 */ -{ - {3, 0x02, 8}, - {4, 0x02, 8}, - {6, 0x02, 8}, - {9, 0x02, 8}, - {14, 0x02, 8}, - {20, 0x02, 8}, - {28, 0x02, 8}, - {38, 0x03, 8}, - {3, 0x02, 9}, - {4, 0x02, 9}, - {6, 0x02, 9}, - {9, 0x02, 9}, - {14, 0x02, 9}, - {20, 0x02, 9}, - {28, 0x02, 9}, - {38, 0x03, 9}, -}, -/* 202 */ -{ - {3, 0x02, 10}, - {4, 0x02, 10}, - {6, 0x02, 10}, - {9, 0x02, 10}, - {14, 0x02, 10}, - {20, 0x02, 10}, - {28, 0x02, 10}, - {38, 0x03, 10}, - {3, 0x02, 11}, - {4, 0x02, 11}, - {6, 0x02, 11}, - {9, 0x02, 11}, - {14, 0x02, 11}, - {20, 0x02, 11}, - {28, 0x02, 11}, - {38, 0x03, 11}, -}, -/* 203 */ -{ - {1, 0x02, 12}, - {12, 0x03, 12}, - {1, 0x02, 13}, - {12, 0x03, 13}, - {1, 0x02, 14}, - {12, 0x03, 14}, - {1, 0x02, 15}, - {12, 0x03, 15}, - {1, 0x02, 16}, - {12, 0x03, 16}, - {1, 0x02, 17}, - {12, 0x03, 17}, - {1, 0x02, 18}, - {12, 0x03, 18}, - {1, 0x02, 19}, - {12, 0x03, 19}, -}, -/* 204 */ -{ - {2, 0x02, 12}, - {5, 0x02, 12}, - {13, 0x02, 12}, - {27, 0x03, 12}, - {2, 0x02, 13}, - {5, 0x02, 13}, - {13, 0x02, 13}, - {27, 0x03, 13}, - {2, 0x02, 14}, - {5, 0x02, 14}, - {13, 0x02, 14}, - {27, 0x03, 14}, - {2, 0x02, 15}, - {5, 0x02, 15}, - {13, 0x02, 15}, - {27, 0x03, 15}, -}, -/* 205 */ -{ - {3, 0x02, 12}, - {4, 0x02, 12}, - {6, 0x02, 12}, - {9, 0x02, 12}, - {14, 0x02, 12}, - {20, 0x02, 12}, - {28, 0x02, 12}, - {38, 0x03, 12}, - {3, 0x02, 13}, - {4, 0x02, 13}, - {6, 0x02, 13}, - {9, 0x02, 13}, - {14, 0x02, 13}, - {20, 0x02, 13}, - {28, 0x02, 13}, - {38, 0x03, 13}, -}, -/* 206 */ -{ - {3, 0x02, 14}, - {4, 0x02, 14}, - {6, 0x02, 14}, - {9, 0x02, 14}, - {14, 0x02, 14}, - {20, 0x02, 14}, - {28, 0x02, 14}, - {38, 0x03, 14}, - {3, 0x02, 15}, - {4, 0x02, 15}, - {6, 0x02, 15}, - {9, 0x02, 15}, - {14, 0x02, 15}, - {20, 0x02, 15}, - {28, 0x02, 15}, - {38, 0x03, 15}, -}, -/* 207 */ -{ - {2, 0x02, 16}, - {5, 0x02, 16}, - {13, 0x02, 16}, - {27, 0x03, 16}, - {2, 0x02, 17}, - {5, 0x02, 17}, - {13, 0x02, 17}, - {27, 0x03, 17}, - {2, 0x02, 18}, - {5, 0x02, 18}, - {13, 0x02, 18}, - {27, 0x03, 18}, - {2, 0x02, 19}, - {5, 0x02, 19}, - {13, 0x02, 19}, - {27, 0x03, 19}, -}, -/* 208 */ -{ - {3, 0x02, 16}, - {4, 0x02, 16}, - {6, 0x02, 16}, - {9, 0x02, 16}, - {14, 0x02, 16}, - {20, 0x02, 16}, - {28, 0x02, 16}, - {38, 0x03, 16}, - {3, 0x02, 17}, - {4, 0x02, 17}, - {6, 0x02, 17}, - {9, 0x02, 17}, - {14, 0x02, 17}, - {20, 0x02, 17}, - {28, 0x02, 17}, - {38, 0x03, 17}, -}, -/* 209 */ -{ - {3, 0x02, 18}, - {4, 0x02, 18}, - {6, 0x02, 18}, - {9, 0x02, 18}, - {14, 0x02, 18}, - {20, 0x02, 18}, - {28, 0x02, 18}, - {38, 0x03, 18}, - {3, 0x02, 19}, - {4, 0x02, 19}, - {6, 0x02, 19}, - {9, 0x02, 19}, - {14, 0x02, 19}, - {20, 0x02, 19}, - {28, 0x02, 19}, - {38, 0x03, 19}, -}, -/* 210 */ -{ - {0, 0x03, 20}, - {0, 0x03, 21}, - {0, 0x03, 22}, - {0, 0x03, 23}, - {0, 0x03, 24}, - {0, 0x03, 25}, - {0, 0x03, 26}, - {0, 0x03, 27}, - {0, 0x03, 28}, - {0, 0x03, 29}, - {0, 0x03, 30}, - {0, 0x03, 31}, - {0, 0x03, 127}, - {0, 0x03, 128}, - {0, 0x03, 129}, - {0, 0x03, 130}, -}, -/* 211 */ -{ - {1, 0x02, 20}, - {12, 0x03, 20}, - {1, 0x02, 21}, - {12, 0x03, 21}, - {1, 0x02, 22}, - {12, 0x03, 22}, - {1, 0x02, 23}, - {12, 0x03, 23}, - {1, 0x02, 24}, - {12, 0x03, 24}, - {1, 0x02, 25}, - {12, 0x03, 25}, - {1, 0x02, 26}, - {12, 0x03, 26}, - {1, 0x02, 27}, - {12, 0x03, 27}, -}, -/* 212 */ -{ - {2, 0x02, 20}, - {5, 0x02, 20}, - {13, 0x02, 20}, - {27, 0x03, 20}, - {2, 0x02, 21}, - {5, 0x02, 21}, - {13, 0x02, 21}, - {27, 0x03, 21}, - {2, 0x02, 22}, - {5, 0x02, 22}, - {13, 0x02, 22}, - {27, 0x03, 22}, - {2, 0x02, 23}, - {5, 0x02, 23}, - {13, 0x02, 23}, - {27, 0x03, 23}, -}, -/* 213 */ -{ - {3, 0x02, 20}, - {4, 0x02, 20}, - {6, 0x02, 20}, - {9, 0x02, 20}, - {14, 0x02, 20}, - {20, 0x02, 20}, - {28, 0x02, 20}, - {38, 0x03, 20}, - {3, 0x02, 21}, - {4, 0x02, 21}, - {6, 0x02, 21}, - {9, 0x02, 21}, - {14, 0x02, 21}, - {20, 0x02, 21}, - {28, 0x02, 21}, - {38, 0x03, 21}, -}, -/* 214 */ -{ - {3, 0x02, 22}, - {4, 0x02, 22}, - {6, 0x02, 22}, - {9, 0x02, 22}, - {14, 0x02, 22}, - {20, 0x02, 22}, - {28, 0x02, 22}, - {38, 0x03, 22}, - {3, 0x02, 23}, - {4, 0x02, 23}, - {6, 0x02, 23}, - {9, 0x02, 23}, - {14, 0x02, 23}, - {20, 0x02, 23}, - {28, 0x02, 23}, - {38, 0x03, 23}, -}, -/* 215 */ -{ - {2, 0x02, 24}, - {5, 0x02, 24}, - {13, 0x02, 24}, - {27, 0x03, 24}, - {2, 0x02, 25}, - {5, 0x02, 25}, - {13, 0x02, 25}, - {27, 0x03, 25}, - {2, 0x02, 26}, - {5, 0x02, 26}, - {13, 0x02, 26}, - {27, 0x03, 26}, - {2, 0x02, 27}, - {5, 0x02, 27}, - {13, 0x02, 27}, - {27, 0x03, 27}, -}, -/* 216 */ -{ - {3, 0x02, 24}, - {4, 0x02, 24}, - {6, 0x02, 24}, - {9, 0x02, 24}, - {14, 0x02, 24}, - {20, 0x02, 24}, - {28, 0x02, 24}, - {38, 0x03, 24}, - {3, 0x02, 25}, - {4, 0x02, 25}, - {6, 0x02, 25}, - {9, 0x02, 25}, - {14, 0x02, 25}, - {20, 0x02, 25}, - {28, 0x02, 25}, - {38, 0x03, 25}, -}, -/* 217 */ -{ - {3, 0x02, 26}, - {4, 0x02, 26}, - {6, 0x02, 26}, - {9, 0x02, 26}, - {14, 0x02, 26}, - {20, 0x02, 26}, - {28, 0x02, 26}, - {38, 0x03, 26}, - {3, 0x02, 27}, - {4, 0x02, 27}, - {6, 0x02, 27}, - {9, 0x02, 27}, - {14, 0x02, 27}, - {20, 0x02, 27}, - {28, 0x02, 27}, - {38, 0x03, 27}, -}, -/* 218 */ -{ - {1, 0x02, 28}, - {12, 0x03, 28}, - {1, 0x02, 29}, - {12, 0x03, 29}, - {1, 0x02, 30}, - {12, 0x03, 30}, - {1, 0x02, 31}, - {12, 0x03, 31}, - {1, 0x02, 127}, - {12, 0x03, 127}, - {1, 0x02, 128}, - {12, 0x03, 128}, - {1, 0x02, 129}, - {12, 0x03, 129}, - {1, 0x02, 130}, - {12, 0x03, 130}, -}, -/* 219 */ -{ - {2, 0x02, 28}, - {5, 0x02, 28}, - {13, 0x02, 28}, - {27, 0x03, 28}, - {2, 0x02, 29}, - {5, 0x02, 29}, - {13, 0x02, 29}, - {27, 0x03, 29}, - {2, 0x02, 30}, - {5, 0x02, 30}, - {13, 0x02, 30}, - {27, 0x03, 30}, - {2, 0x02, 31}, - {5, 0x02, 31}, - {13, 0x02, 31}, - {27, 0x03, 31}, -}, -/* 220 */ -{ - {3, 0x02, 28}, - {4, 0x02, 28}, - {6, 0x02, 28}, - {9, 0x02, 28}, - {14, 0x02, 28}, - {20, 0x02, 28}, - {28, 0x02, 28}, - {38, 0x03, 28}, - {3, 0x02, 29}, - {4, 0x02, 29}, - {6, 0x02, 29}, - {9, 0x02, 29}, - {14, 0x02, 29}, - {20, 0x02, 29}, - {28, 0x02, 29}, - {38, 0x03, 29}, -}, -/* 221 */ -{ - {3, 0x02, 30}, - {4, 0x02, 30}, - {6, 0x02, 30}, - {9, 0x02, 30}, - {14, 0x02, 30}, - {20, 0x02, 30}, - {28, 0x02, 30}, - {38, 0x03, 30}, - {3, 0x02, 31}, - {4, 0x02, 31}, - {6, 0x02, 31}, - {9, 0x02, 31}, - {14, 0x02, 31}, - {20, 0x02, 31}, - {28, 0x02, 31}, - {38, 0x03, 31}, -}, -/* 222 */ -{ - {2, 0x02, 127}, - {5, 0x02, 127}, - {13, 0x02, 127}, - {27, 0x03, 127}, - {2, 0x02, 128}, - {5, 0x02, 128}, - {13, 0x02, 128}, - {27, 0x03, 128}, - {2, 0x02, 129}, - {5, 0x02, 129}, - {13, 0x02, 129}, - {27, 0x03, 129}, - {2, 0x02, 130}, - {5, 0x02, 130}, - {13, 0x02, 130}, - {27, 0x03, 130}, -}, -/* 223 */ -{ - {3, 0x02, 127}, - {4, 0x02, 127}, - {6, 0x02, 127}, - {9, 0x02, 127}, - {14, 0x02, 127}, - {20, 0x02, 127}, - {28, 0x02, 127}, - {38, 0x03, 127}, - {3, 0x02, 128}, - {4, 0x02, 128}, - {6, 0x02, 128}, - {9, 0x02, 128}, - {14, 0x02, 128}, - {20, 0x02, 128}, - {28, 0x02, 128}, - {38, 0x03, 128}, -}, -/* 224 */ -{ - {3, 0x02, 129}, - {4, 0x02, 129}, - {6, 0x02, 129}, - {9, 0x02, 129}, - {14, 0x02, 129}, - {20, 0x02, 129}, - {28, 0x02, 129}, - {38, 0x03, 129}, - {3, 0x02, 130}, - {4, 0x02, 130}, - {6, 0x02, 130}, - {9, 0x02, 130}, - {14, 0x02, 130}, - {20, 0x02, 130}, - {28, 0x02, 130}, - {38, 0x03, 130}, -}, -/* 225 */ -{ - {229, 0x00, 0}, - {230, 0x00, 0}, - {232, 0x00, 0}, - {233, 0x00, 0}, - {236, 0x00, 0}, - {237, 0x00, 0}, - {239, 0x00, 0}, - {240, 0x00, 0}, - {244, 0x00, 0}, - {245, 0x00, 0}, - {247, 0x00, 0}, - {248, 0x00, 0}, - {251, 0x00, 0}, - {252, 0x00, 0}, - {254, 0x00, 0}, - {255, 0x00, 0}, -}, -/* 226 */ -{ - {0, 0x03, 131}, - {0, 0x03, 132}, - {0, 0x03, 133}, - {0, 0x03, 134}, - {0, 0x03, 135}, - {0, 0x03, 136}, - {0, 0x03, 137}, - {0, 0x03, 138}, - {0, 0x03, 139}, - {0, 0x03, 140}, - {0, 0x03, 141}, - {0, 0x03, 142}, - {0, 0x03, 143}, - {0, 0x03, 144}, - {0, 0x03, 145}, - {0, 0x03, 146}, -}, -/* 227 */ -{ - {1, 0x02, 131}, - {12, 0x03, 131}, - {1, 0x02, 132}, - {12, 0x03, 132}, - {1, 0x02, 133}, - {12, 0x03, 133}, - {1, 0x02, 134}, - {12, 0x03, 134}, - {1, 0x02, 135}, - {12, 0x03, 135}, - {1, 0x02, 136}, - {12, 0x03, 136}, - {1, 0x02, 137}, - {12, 0x03, 137}, - {1, 0x02, 138}, - {12, 0x03, 138}, -}, -/* 228 */ -{ - {2, 0x02, 131}, - {5, 0x02, 131}, - {13, 0x02, 131}, - {27, 0x03, 131}, - {2, 0x02, 132}, - {5, 0x02, 132}, - {13, 0x02, 132}, - {27, 0x03, 132}, - {2, 0x02, 133}, - {5, 0x02, 133}, - {13, 0x02, 133}, - {27, 0x03, 133}, - {2, 0x02, 134}, - {5, 0x02, 134}, - {13, 0x02, 134}, - {27, 0x03, 134}, -}, -/* 229 */ -{ - {3, 0x02, 131}, - {4, 0x02, 131}, - {6, 0x02, 131}, - {9, 0x02, 131}, - {14, 0x02, 131}, - {20, 0x02, 131}, - {28, 0x02, 131}, - {38, 0x03, 131}, - {3, 0x02, 132}, - {4, 0x02, 132}, - {6, 0x02, 132}, - {9, 0x02, 132}, - {14, 0x02, 132}, - {20, 0x02, 132}, - {28, 0x02, 132}, - {38, 0x03, 132}, -}, -/* 230 */ -{ - {3, 0x02, 133}, - {4, 0x02, 133}, - {6, 0x02, 133}, - {9, 0x02, 133}, - {14, 0x02, 133}, - {20, 0x02, 133}, - {28, 0x02, 133}, - {38, 0x03, 133}, - {3, 0x02, 134}, - {4, 0x02, 134}, - {6, 0x02, 134}, - {9, 0x02, 134}, - {14, 0x02, 134}, - {20, 0x02, 134}, - {28, 0x02, 134}, - {38, 0x03, 134}, -}, -/* 231 */ -{ - {2, 0x02, 135}, - {5, 0x02, 135}, - {13, 0x02, 135}, - {27, 0x03, 135}, - {2, 0x02, 136}, - {5, 0x02, 136}, - {13, 0x02, 136}, - {27, 0x03, 136}, - {2, 0x02, 137}, - {5, 0x02, 137}, - {13, 0x02, 137}, - {27, 0x03, 137}, - {2, 0x02, 138}, - {5, 0x02, 138}, - {13, 0x02, 138}, - {27, 0x03, 138}, -}, -/* 232 */ -{ - {3, 0x02, 135}, - {4, 0x02, 135}, - {6, 0x02, 135}, - {9, 0x02, 135}, - {14, 0x02, 135}, - {20, 0x02, 135}, - {28, 0x02, 135}, - {38, 0x03, 135}, - {3, 0x02, 136}, - {4, 0x02, 136}, - {6, 0x02, 136}, - {9, 0x02, 136}, - {14, 0x02, 136}, - {20, 0x02, 136}, - {28, 0x02, 136}, - {38, 0x03, 136}, -}, -/* 233 */ -{ - {3, 0x02, 137}, - {4, 0x02, 137}, - {6, 0x02, 137}, - {9, 0x02, 137}, - {14, 0x02, 137}, - {20, 0x02, 137}, - {28, 0x02, 137}, - {38, 0x03, 137}, - {3, 0x02, 138}, - {4, 0x02, 138}, - {6, 0x02, 138}, - {9, 0x02, 138}, - {14, 0x02, 138}, - {20, 0x02, 138}, - {28, 0x02, 138}, - {38, 0x03, 138}, -}, -/* 234 */ -{ - {1, 0x02, 139}, - {12, 0x03, 139}, - {1, 0x02, 140}, - {12, 0x03, 140}, - {1, 0x02, 141}, - {12, 0x03, 141}, - {1, 0x02, 142}, - {12, 0x03, 142}, - {1, 0x02, 143}, - {12, 0x03, 143}, - {1, 0x02, 144}, - {12, 0x03, 144}, - {1, 0x02, 145}, - {12, 0x03, 145}, - {1, 0x02, 146}, - {12, 0x03, 146}, -}, -/* 235 */ -{ - {2, 0x02, 139}, - {5, 0x02, 139}, - {13, 0x02, 139}, - {27, 0x03, 139}, - {2, 0x02, 140}, - {5, 0x02, 140}, - {13, 0x02, 140}, - {27, 0x03, 140}, - {2, 0x02, 141}, - {5, 0x02, 141}, - {13, 0x02, 141}, - {27, 0x03, 141}, - {2, 0x02, 142}, - {5, 0x02, 142}, - {13, 0x02, 142}, - {27, 0x03, 142}, -}, -/* 236 */ -{ - {3, 0x02, 139}, - {4, 0x02, 139}, - {6, 0x02, 139}, - {9, 0x02, 139}, - {14, 0x02, 139}, - {20, 0x02, 139}, - {28, 0x02, 139}, - {38, 0x03, 139}, - {3, 0x02, 140}, - {4, 0x02, 140}, - {6, 0x02, 140}, - {9, 0x02, 140}, - {14, 0x02, 140}, - {20, 0x02, 140}, - {28, 0x02, 140}, - {38, 0x03, 140}, -}, -/* 237 */ -{ - {3, 0x02, 141}, - {4, 0x02, 141}, - {6, 0x02, 141}, - {9, 0x02, 141}, - {14, 0x02, 141}, - {20, 0x02, 141}, - {28, 0x02, 141}, - {38, 0x03, 141}, - {3, 0x02, 142}, - {4, 0x02, 142}, - {6, 0x02, 142}, - {9, 0x02, 142}, - {14, 0x02, 142}, - {20, 0x02, 142}, - {28, 0x02, 142}, - {38, 0x03, 142}, -}, -/* 238 */ -{ - {2, 0x02, 143}, - {5, 0x02, 143}, - {13, 0x02, 143}, - {27, 0x03, 143}, - {2, 0x02, 144}, - {5, 0x02, 144}, - {13, 0x02, 144}, - {27, 0x03, 144}, - {2, 0x02, 145}, - {5, 0x02, 145}, - {13, 0x02, 145}, - {27, 0x03, 145}, - {2, 0x02, 146}, - {5, 0x02, 146}, - {13, 0x02, 146}, - {27, 0x03, 146}, -}, -/* 239 */ -{ - {3, 0x02, 143}, - {4, 0x02, 143}, - {6, 0x02, 143}, - {9, 0x02, 143}, - {14, 0x02, 143}, - {20, 0x02, 143}, - {28, 0x02, 143}, - {38, 0x03, 143}, - {3, 0x02, 144}, - {4, 0x02, 144}, - {6, 0x02, 144}, - {9, 0x02, 144}, - {14, 0x02, 144}, - {20, 0x02, 144}, - {28, 0x02, 144}, - {38, 0x03, 144}, -}, -/* 240 */ -{ - {3, 0x02, 145}, - {4, 0x02, 145}, - {6, 0x02, 145}, - {9, 0x02, 145}, - {14, 0x02, 145}, - {20, 0x02, 145}, - {28, 0x02, 145}, - {38, 0x03, 145}, - {3, 0x02, 146}, - {4, 0x02, 146}, - {6, 0x02, 146}, - {9, 0x02, 146}, - {14, 0x02, 146}, - {20, 0x02, 146}, - {28, 0x02, 146}, - {38, 0x03, 146}, -}, -/* 241 */ -{ - {0, 0x03, 147}, - {0, 0x03, 148}, - {0, 0x03, 149}, - {0, 0x03, 150}, - {0, 0x03, 151}, - {0, 0x03, 152}, - {0, 0x03, 153}, - {0, 0x03, 154}, - {0, 0x03, 155}, - {0, 0x03, 156}, - {0, 0x03, 157}, - {0, 0x03, 158}, - {0, 0x03, 159}, - {0, 0x03, 160}, - {0, 0x03, 161}, - {0, 0x03, 162}, -}, -/* 242 */ -{ - {1, 0x02, 147}, - {12, 0x03, 147}, - {1, 0x02, 148}, - {12, 0x03, 148}, - {1, 0x02, 149}, - {12, 0x03, 149}, - {1, 0x02, 150}, - {12, 0x03, 150}, - {1, 0x02, 151}, - {12, 0x03, 151}, - {1, 0x02, 152}, - {12, 0x03, 152}, - {1, 0x02, 153}, - {12, 0x03, 153}, - {1, 0x02, 154}, - {12, 0x03, 154}, -}, -/* 243 */ -{ - {2, 0x02, 147}, - {5, 0x02, 147}, - {13, 0x02, 147}, - {27, 0x03, 147}, - {2, 0x02, 148}, - {5, 0x02, 148}, - {13, 0x02, 148}, - {27, 0x03, 148}, - {2, 0x02, 149}, - {5, 0x02, 149}, - {13, 0x02, 149}, - {27, 0x03, 149}, - {2, 0x02, 150}, - {5, 0x02, 150}, - {13, 0x02, 150}, - {27, 0x03, 150}, -}, -/* 244 */ -{ - {3, 0x02, 147}, - {4, 0x02, 147}, - {6, 0x02, 147}, - {9, 0x02, 147}, - {14, 0x02, 147}, - {20, 0x02, 147}, - {28, 0x02, 147}, - {38, 0x03, 147}, - {3, 0x02, 148}, - {4, 0x02, 148}, - {6, 0x02, 148}, - {9, 0x02, 148}, - {14, 0x02, 148}, - {20, 0x02, 148}, - {28, 0x02, 148}, - {38, 0x03, 148}, -}, -/* 245 */ -{ - {3, 0x02, 149}, - {4, 0x02, 149}, - {6, 0x02, 149}, - {9, 0x02, 149}, - {14, 0x02, 149}, - {20, 0x02, 149}, - {28, 0x02, 149}, - {38, 0x03, 149}, - {3, 0x02, 150}, - {4, 0x02, 150}, - {6, 0x02, 150}, - {9, 0x02, 150}, - {14, 0x02, 150}, - {20, 0x02, 150}, - {28, 0x02, 150}, - {38, 0x03, 150}, -}, -/* 246 */ -{ - {2, 0x02, 151}, - {5, 0x02, 151}, - {13, 0x02, 151}, - {27, 0x03, 151}, - {2, 0x02, 152}, - {5, 0x02, 152}, - {13, 0x02, 152}, - {27, 0x03, 152}, - {2, 0x02, 153}, - {5, 0x02, 153}, - {13, 0x02, 153}, - {27, 0x03, 153}, - {2, 0x02, 154}, - {5, 0x02, 154}, - {13, 0x02, 154}, - {27, 0x03, 154}, -}, -/* 247 */ -{ - {3, 0x02, 151}, - {4, 0x02, 151}, - {6, 0x02, 151}, - {9, 0x02, 151}, - {14, 0x02, 151}, - {20, 0x02, 151}, - {28, 0x02, 151}, - {38, 0x03, 151}, - {3, 0x02, 152}, - {4, 0x02, 152}, - {6, 0x02, 152}, - {9, 0x02, 152}, - {14, 0x02, 152}, - {20, 0x02, 152}, - {28, 0x02, 152}, - {38, 0x03, 152}, -}, -/* 248 */ -{ - {3, 0x02, 153}, - {4, 0x02, 153}, - {6, 0x02, 153}, - {9, 0x02, 153}, - {14, 0x02, 153}, - {20, 0x02, 153}, - {28, 0x02, 153}, - {38, 0x03, 153}, - {3, 0x02, 154}, - {4, 0x02, 154}, - {6, 0x02, 154}, - {9, 0x02, 154}, - {14, 0x02, 154}, - {20, 0x02, 154}, - {28, 0x02, 154}, - {38, 0x03, 154}, -}, -/* 249 */ -{ - {1, 0x02, 155}, - {12, 0x03, 155}, - {1, 0x02, 156}, - {12, 0x03, 156}, - {1, 0x02, 157}, - {12, 0x03, 157}, - {1, 0x02, 158}, - {12, 0x03, 158}, - {1, 0x02, 159}, - {12, 0x03, 159}, - {1, 0x02, 160}, - {12, 0x03, 160}, - {1, 0x02, 161}, - {12, 0x03, 161}, - {1, 0x02, 162}, - {12, 0x03, 162}, -}, -/* 250 */ -{ - {2, 0x02, 155}, - {5, 0x02, 155}, - {13, 0x02, 155}, - {27, 0x03, 155}, - {2, 0x02, 156}, - {5, 0x02, 156}, - {13, 0x02, 156}, - {27, 0x03, 156}, - {2, 0x02, 157}, - {5, 0x02, 157}, - {13, 0x02, 157}, - {27, 0x03, 157}, - {2, 0x02, 158}, - {5, 0x02, 158}, - {13, 0x02, 158}, - {27, 0x03, 158}, -}, -/* 251 */ -{ - {3, 0x02, 155}, - {4, 0x02, 155}, - {6, 0x02, 155}, - {9, 0x02, 155}, - {14, 0x02, 155}, - {20, 0x02, 155}, - {28, 0x02, 155}, - {38, 0x03, 155}, - {3, 0x02, 156}, - {4, 0x02, 156}, - {6, 0x02, 156}, - {9, 0x02, 156}, - {14, 0x02, 156}, - {20, 0x02, 156}, - {28, 0x02, 156}, - {38, 0x03, 156}, -}, -/* 252 */ -{ - {3, 0x02, 157}, - {4, 0x02, 157}, - {6, 0x02, 157}, - {9, 0x02, 157}, - {14, 0x02, 157}, - {20, 0x02, 157}, - {28, 0x02, 157}, - {38, 0x03, 157}, - {3, 0x02, 158}, - {4, 0x02, 158}, - {6, 0x02, 158}, - {9, 0x02, 158}, - {14, 0x02, 158}, - {20, 0x02, 158}, - {28, 0x02, 158}, - {38, 0x03, 158}, -}, -/* 253 */ -{ - {2, 0x02, 159}, - {5, 0x02, 159}, - {13, 0x02, 159}, - {27, 0x03, 159}, - {2, 0x02, 160}, - {5, 0x02, 160}, - {13, 0x02, 160}, - {27, 0x03, 160}, - {2, 0x02, 161}, - {5, 0x02, 161}, - {13, 0x02, 161}, - {27, 0x03, 161}, - {2, 0x02, 162}, - {5, 0x02, 162}, - {13, 0x02, 162}, - {27, 0x03, 162}, -}, -/* 254 */ -{ - {3, 0x02, 159}, - {4, 0x02, 159}, - {6, 0x02, 159}, - {9, 0x02, 159}, - {14, 0x02, 159}, - {20, 0x02, 159}, - {28, 0x02, 159}, - {38, 0x03, 159}, - {3, 0x02, 160}, - {4, 0x02, 160}, - {6, 0x02, 160}, - {9, 0x02, 160}, - {14, 0x02, 160}, - {20, 0x02, 160}, - {28, 0x02, 160}, - {38, 0x03, 160}, -}, -/* 255 */ -{ - {3, 0x02, 161}, - {4, 0x02, 161}, - {6, 0x02, 161}, - {9, 0x02, 161}, - {14, 0x02, 161}, - {20, 0x02, 161}, - {28, 0x02, 161}, - {38, 0x03, 161}, - {3, 0x02, 162}, - {4, 0x02, 162}, - {6, 0x02, 162}, - {9, 0x02, 162}, - {14, 0x02, 162}, - {20, 0x02, 162}, - {28, 0x02, 162}, - {38, 0x03, 162}, -}, -}; diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 8e3064fa..00c4e65f 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -201,7 +201,7 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, const nghttp2_opt_set *opt_set) { int r; - nghttp2_hd_side side_deflate, side_inflate; + *session_ptr = malloc(sizeof(nghttp2_session)); if(*session_ptr == NULL) { r = NGHTTP2_ERR_NOMEM; @@ -236,17 +236,12 @@ static int nghttp2_session_new(nghttp2_session **session_ptr, if(server) { (*session_ptr)->server = 1; - side_deflate = NGHTTP2_HD_SIDE_RESPONSE; - side_inflate = NGHTTP2_HD_SIDE_REQUEST; - } else { - side_deflate = NGHTTP2_HD_SIDE_REQUEST; - side_inflate = NGHTTP2_HD_SIDE_RESPONSE; } - r = nghttp2_hd_deflate_init(&(*session_ptr)->hd_deflater, side_deflate); + r = nghttp2_hd_deflate_init(&(*session_ptr)->hd_deflater); if(r != 0) { goto fail_hd_deflater; } - r = nghttp2_hd_inflate_init(&(*session_ptr)->hd_inflater, side_inflate); + r = nghttp2_hd_inflate_init(&(*session_ptr)->hd_inflater); if(r != 0) { goto fail_hd_inflater; } @@ -2708,8 +2703,8 @@ int nghttp2_session_update_local_settings(nghttp2_session *session, header_table_size > NGHTTP2_MAX_HEADER_TABLE_SIZE) { return NGHTTP2_ERR_HEADER_COMP; } - rv = nghttp2_hd_change_table_size(&session->hd_inflater.ctx, - header_table_size); + rv = nghttp2_hd_inflate_change_table_size(&session->hd_inflater, + header_table_size); if(rv != 0) { return rv; } @@ -2791,8 +2786,8 @@ int nghttp2_session_on_settings_received(nghttp2_session *session, return nghttp2_session_handle_invalid_connection (session, frame, NGHTTP2_COMPRESSION_ERROR); } - rv = nghttp2_hd_change_table_size(&session->hd_deflater.ctx, - entry->value); + rv = nghttp2_hd_deflate_change_table_size(&session->hd_deflater, + entry->value); if(rv != 0) { if(nghttp2_is_fatal(rv)) { return rv; diff --git a/python/cnghttp2.pxd b/python/cnghttp2.pxd index 5089bec4..c57c788f 100644 --- a/python/cnghttp2.pxd +++ b/python/cnghttp2.pxd @@ -45,10 +45,6 @@ cdef extern from 'nghttp2_hd.h': # This is macro int NGHTTP2_HD_ENTRY_OVERHEAD - ctypedef enum nghttp2_hd_side: - NGHTTP2_HD_SIDE_REQUEST - NGHTTP2_HD_SIDE_RESPONSE - ctypedef enum nghttp2_hd_flags: NGHTTP2_HD_FLAG_REFSET @@ -73,12 +69,9 @@ cdef extern from 'nghttp2_hd.h': nghttp2_hd_context ctx int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater, - nghttp2_hd_side side, size_t deflate_hd_table_bufsize_max) - int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, - nghttp2_hd_side side) - + int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater) void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) @@ -87,8 +80,11 @@ cdef extern from 'nghttp2_hd.h': void nghttp2_hd_deflate_set_no_refset(nghttp2_hd_deflater *deflater, uint8_t no_refset) - int nghttp2_hd_change_table_size(nghttp2_hd_context *context, - size_t hd_table_bufsize_max) + int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater, + size_t hd_table_bufsize_max) + + int nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater, + size_t hd_table_bufsize_max) ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t **buf_ptr, size_t *buflen_ptr, diff --git a/python/hpackcheck.py b/python/hpackcheck.py index a2b256ad..09fb71c8 100755 --- a/python/hpackcheck.py +++ b/python/hpackcheck.py @@ -13,12 +13,7 @@ from binascii import a2b_hex import nghttp2 def testsuite(testdata): - if testdata['context'] == 'request': - side = nghttp2.HD_SIDE_REQUEST - else: - side = nghttp2.HD_SIDE_RESPONSE - - inflater = nghttp2.HDInflater(side) + inflater = nghttp2.HDInflater() for casenum, item in enumerate(testdata['cases']): if 'header_table_size' in item: @@ -47,7 +42,7 @@ def testsuite(testdata): if __name__ == '__main__': for filename in sys.argv[1:]: - sys.stderr.write('{}\n'.format(filename)) + sys.stderr.write('{}: '.format(filename)) with open(filename) as f: input = f.read() testsuite(json.loads(input)) diff --git a/python/hpackmake.py b/python/hpackmake.py index 498c6ebb..e3c8cc6c 100755 --- a/python/hpackmake.py +++ b/python/hpackmake.py @@ -14,11 +14,6 @@ from binascii import b2a_hex import nghttp2 def testsuite(testdata, filename, outdir, table_size, deflate_table_size): - if testdata['context'] == 'request': - side = nghttp2.HD_SIDE_REQUEST - else: - side = nghttp2.HD_SIDE_RESPONSE - res = { 'draft':5, 'context': testdata['context'], 'description': '''\ @@ -29,7 +24,7 @@ original. We make some headers not indexing at all, but this does not always \ result in less bits on the wire.''' } cases = [] - deflater = nghttp2.HDDeflater(side, deflate_table_size) + deflater = nghttp2.HDDeflater(deflate_table_size) deflater.change_table_size(table_size) for casenum, item in enumerate(testdata['cases']): outitem = { diff --git a/python/nghttp2.pyx b/python/nghttp2.pyx index 7580c2fe..6f86a832 100644 --- a/python/nghttp2.pyx +++ b/python/nghttp2.pyx @@ -26,9 +26,6 @@ from libc.stdlib cimport malloc, free from libc.string cimport memcpy, memset from libc.stdint cimport uint8_t, uint16_t, uint32_t, int32_t -HD_SIDE_REQUEST = cnghttp2.NGHTTP2_HD_SIDE_REQUEST -HD_SIDE_RESPONSE = cnghttp2.NGHTTP2_HD_SIDE_RESPONSE - HD_DEFLATE_HD_TABLE_BUFSIZE_MAX = 4096 HD_ENTRY_OVERHEAD = cnghttp2.NGHTTP2_HD_ENTRY_OVERHEAD @@ -45,12 +42,6 @@ class HDTableEntry: def space(self): return self.namelen + self.valuelen + HD_ENTRY_OVERHEAD -cdef _change_table_size(cnghttp2.nghttp2_hd_context *ctx, hd_table_bufsize_max): - cdef int rv - rv = cnghttp2.nghttp2_hd_change_table_size(ctx, hd_table_bufsize_max) - if rv != 0: - raise Exception(_strerror(rv)) - cdef _get_hd_table(cnghttp2.nghttp2_hd_context *ctx): cdef int length = ctx.hd_table.len cdef cnghttp2.nghttp2_hd_entry *entry @@ -65,35 +56,25 @@ cdef _get_hd_table(cnghttp2.nghttp2_hd_context *ctx): return res cdef _get_pybytes(uint8_t *b, uint16_t blen): - # While the |blen| is positive, the |b| could be NULL. This is - # because deflater may deallocate the byte strings its local table - # space. - if b == NULL and blen > 0: - val = None - else: - val = b[:blen] - return val + return b[:blen] cdef class HDDeflater: - '''Performs header compression. The header compression algorithm has - to know the header set to be compressed is request headers or - response headers. It is indicated by |side| parameter in the - constructor. The constructor also takes |hd_table_bufsize_max| - parameter, which limits the usage of header table in the given - amount of bytes. This is necessary because the header compressor - and decompressor has to share the same amount of header table and - the decompressor decides that number. The compressor may not want - to use all header table size because of limited memory - availability. In that case, the |hd_table_bufsize_max| can be used - to cap the upper limit of talbe size whatever the header table - size is chosen. The default value of |hd_table_bufsize_max| is - 4096 bytes. + '''Performs header compression. The constructor takes + |hd_table_bufsize_max| parameter, which limits the usage of header + table in the given amount of bytes. This is necessary because the + header compressor and decompressor has to share the same amount of + header table and the decompressor decides that number. The + compressor may not want to use all header table size because of + limited memory availability. In that case, the + |hd_table_bufsize_max| can be used to cap the upper limit of table + size whatever the header table size is chosen by the decompressor. + The default value of |hd_table_bufsize_max| is 4096 bytes. The following example shows how to compress request header sets: import binascii, nghttp2 - deflater = nghttp2.HDDeflater(nghttp2.HD_SIDE_REQUEST) + deflater = nghttp2.HDDeflater() res = deflater.deflate([(b'foo', b'bar'), (b'baz', b'buz')]) print(binascii.b2a_hex(res)) @@ -102,17 +83,13 @@ cdef class HDDeflater: cdef cnghttp2.nghttp2_hd_deflater _deflater - def __cinit__(self, side, + def __cinit__(self, hd_table_bufsize_max = HD_DEFLATE_HD_TABLE_BUFSIZE_MAX): - rv = cnghttp2.nghttp2_hd_deflate_init2(&self._deflater, side, + rv = cnghttp2.nghttp2_hd_deflate_init2(&self._deflater, hd_table_bufsize_max) if rv != 0: raise Exception(_strerror(rv)) - def __init__(self, side, - hd_table_bufsize_max = HD_DEFLATE_HD_TABLE_BUFSIZE_MAX): - super(HDDeflater, self).__init__() - def __dealloc__(self): cnghttp2.nghttp2_hd_deflate_free(&self._deflater) @@ -165,7 +142,11 @@ cdef class HDDeflater: An exception will be raised on error. ''' - _change_table_size(&self._deflater.ctx, hd_table_bufsize_max) + cdef int rv + rv = cnghttp2.nghttp2_hd_deflate_change_table_size(&self._deflater, + hd_table_bufsize_max) + if rv != 0: + raise Exception(_strerror(rv)) def get_hd_table(self,): '''Returns copy of current dynamic header table.''' @@ -177,7 +158,7 @@ cdef class HDInflater: The following example shows how to compress request header sets: data = b'0082c5ad82bd0f000362617a0362757a' - inflater = nghttp2.HDInflater(nghttp2.HD_SIDE_REQUEST) + inflater = nghttp2.HDInflater() hdrs = inflater.inflate(data) print(hdrs) @@ -185,14 +166,11 @@ cdef class HDInflater: cdef cnghttp2.nghttp2_hd_inflater _inflater - def __cinit__(self, side): - rv = cnghttp2.nghttp2_hd_inflate_init(&self._inflater, side) + def __cinit__(self): + rv = cnghttp2.nghttp2_hd_inflate_init(&self._inflater) if rv != 0: raise Exception(_strerror(rv)) - def __init__(self, side): - super(HDInflater, self).__init__() - def __dealloc__(self): cnghttp2.nghttp2_hd_inflate_free(&self._inflater) @@ -231,7 +209,11 @@ cdef class HDInflater: An exception will be raised on error. ''' - _change_table_size(&self._inflater.ctx, hd_table_bufsize_max) + cdef int rv + rv = cnghttp2.nghttp2_hd_inflate_change_table_size(&self._inflater, + hd_table_bufsize_max) + if rv != 0: + raise Exception(_strerror(rv)) def get_hd_table(self): '''Returns copy of current dynamic header table.''' @@ -255,5 +237,5 @@ def print_hd_table(hdtable): print('[{}] (s={}) (r={}) {}: {}'\ .format(idx, entry.space(), 'y' if entry.ref else 'n', - '**DEALLOCATED**' if entry.name is None else entry.name.decode('utf-8'), - '**DEALLOCATED**' if entry.value is None else entry.value.decode('utf-8'))) + entry.name.decode('utf-8'), + entry.value.decode('utf-8'))) diff --git a/src/comp_helper.c b/src/comp_helper.c index 9caac646..c258d78f 100644 --- a/src/comp_helper.c +++ b/src/comp_helper.c @@ -27,11 +27,7 @@ static void dump_val(json_t *jent, const char *key, uint8_t *val, size_t len) { - if(val == NULL && len > 0) { - json_object_set_new(jent, key, json_string("**DEALLOCATED**")); - } else { - json_object_set_new(jent, key, json_pack("s#", val, len)); - } + json_object_set_new(jent, key, json_pack("s#", val, len)); } json_t* dump_header_table(nghttp2_hd_context *context) @@ -58,12 +54,6 @@ json_t* dump_header_table(nghttp2_hd_context *context) json_object_set_new(obj, "size", json_integer(context->hd_table_bufsize)); json_object_set_new(obj, "max_size", json_integer(context->hd_table_bufsize_max)); - if(context->role == NGHTTP2_HD_ROLE_DEFLATE) { - json_object_set_new(obj, "deflate_size", - json_integer(context->deflate_hd_table_bufsize)); - json_object_set_new(obj, "max_deflate_size", - json_integer(context->deflate_hd_table_bufsize_max)); - } return obj; } @@ -93,13 +83,11 @@ json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen) return headers; } -void output_json_header(int side) +void output_json_header(void) { printf("{\n" - " \"context\": \"%s\",\n" " \"cases\":\n" - " [\n", - (side == NGHTTP2_HD_SIDE_REQUEST ? "request" : "response")); + " [\n"); } void output_json_footer(void) diff --git a/src/comp_helper.h b/src/comp_helper.h index fbf899f9..974afecb 100644 --- a/src/comp_helper.h +++ b/src/comp_helper.h @@ -40,7 +40,7 @@ json_t* dump_header(const uint8_t *name, size_t namelen, json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen); -void output_json_header(int side); +void output_json_header(void); void output_json_footer(void); diff --git a/src/deflatehd.c b/src/deflatehd.c index c492f679..cefa7118 100644 --- a/src/deflatehd.c +++ b/src/deflatehd.c @@ -44,7 +44,6 @@ typedef struct { size_t table_size; size_t deflate_table_size; - nghttp2_hd_side side; int http1text; int dump_header_table; int no_refset; @@ -174,11 +173,11 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq) return 0; } -static void init_deflater(nghttp2_hd_deflater *deflater, nghttp2_hd_side side) +static void init_deflater(nghttp2_hd_deflater *deflater) { - nghttp2_hd_deflate_init2(deflater, side, config.deflate_table_size); + nghttp2_hd_deflate_init2(deflater, config.deflate_table_size); nghttp2_hd_deflate_set_no_refset(deflater, config.no_refset); - nghttp2_hd_change_table_size(&deflater->ctx, config.table_size); + nghttp2_hd_deflate_change_table_size(deflater, config.table_size); } static void deinit_deflater(nghttp2_hd_deflater *deflater) @@ -193,19 +192,12 @@ static int perform(void) json_error_t error; size_t len; nghttp2_hd_deflater deflater; - nghttp2_hd_side side; json = json_loadf(stdin, 0, &error); if(json == NULL) { fprintf(stderr, "JSON loading failed\n"); exit(EXIT_FAILURE); } - if(strcmp("request", json_string_value(json_object_get(json, "context"))) - == 0) { - side = NGHTTP2_HD_SIDE_REQUEST; - } else { - side = NGHTTP2_HD_SIDE_RESPONSE; - } cases = json_object_get(json, "cases"); if(cases == NULL) { fprintf(stderr, "Missing 'cases' key in root object\n"); @@ -215,8 +207,8 @@ static int perform(void) fprintf(stderr, "'cases' must be JSON array\n"); exit(EXIT_FAILURE); } - init_deflater(&deflater, side); - output_json_header(side); + init_deflater(&deflater); + output_json_header(); len = json_array_size(cases); for(i = 0; i < len; ++i) { json_t *obj = json_array_get(cases, i); @@ -244,8 +236,8 @@ static int perform_from_http1text(void) nghttp2_nv nva[256]; int seq = 0; nghttp2_hd_deflater deflater; - init_deflater(&deflater, config.side); - output_json_header(config.side); + init_deflater(&deflater); + output_json_header(); for(;;) { size_t nvlen = 0; int end = 0; @@ -355,10 +347,6 @@ static void print_help(void) "The output of this program can be used as input for inflatehd.\n" "\n" "OPTIONS:\n" - " -r, --response Use response compression context instead of\n" - " request if -t is used. For JSON input, it is\n" - " determined by inspecting \"context\" key in\n" - " root JSON object.\n" " -t, --http1text Use HTTP/1 style header field text as input.\n" " Each header set is delimited by single empty\n" " line.\n" @@ -377,7 +365,6 @@ static void print_help(void) } static struct option long_options[] = { - {"response", no_argument, NULL, 'r'}, {"http1text", no_argument, NULL, 't'}, {"table-size", required_argument, NULL, 's'}, {"deflate-table-size", required_argument, NULL, 'S'}, @@ -390,7 +377,6 @@ int main(int argc, char **argv) { char *end; - config.side = NGHTTP2_HD_SIDE_REQUEST; config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; config.deflate_table_size = NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE; config.http1text = 0; @@ -398,15 +384,11 @@ int main(int argc, char **argv) config.no_refset = 0; while(1) { int option_index = 0; - int c = getopt_long(argc, argv, "S:cdhrs:t", long_options, &option_index); + int c = getopt_long(argc, argv, "S:cdhs:t", long_options, &option_index); if(c == -1) { break; } switch(c) { - case 'r': - /* --response */ - config.side = NGHTTP2_HD_SIDE_RESPONSE; - break; case 'h': print_help(); exit(EXIT_SUCCESS); diff --git a/src/inflatehd.c b/src/inflatehd.c index a2a0b787..5fcf319d 100644 --- a/src/inflatehd.c +++ b/src/inflatehd.c @@ -42,7 +42,6 @@ #include "comp_helper.h" typedef struct { - size_t table_size; int dump_header_table; } inflate_config; @@ -110,8 +109,8 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) seq); return -1; } - rv = nghttp2_hd_change_table_size(&inflater->ctx, - json_integer_value(table_size)); + rv = nghttp2_hd_inflate_change_table_size(inflater, + json_integer_value(table_size)); if(rv != 0) { fprintf(stderr, "nghttp2_hd_change_table_size() failed with error %s at %d\n", @@ -163,19 +162,12 @@ static int perform(void) json_t *json, *cases; json_error_t error; size_t len; - nghttp2_hd_side side; json = json_loadf(stdin, 0, &error); if(json == NULL) { fprintf(stderr, "JSON loading failed\n"); exit(EXIT_FAILURE); } - if(strcmp("request", json_string_value(json_object_get(json, "context"))) - == 0) { - side = NGHTTP2_HD_SIDE_REQUEST; - } else { - side = NGHTTP2_HD_SIDE_RESPONSE; - } cases = json_object_get(json, "cases"); if(cases == NULL) { fprintf(stderr, "Missing 'cases' key in root object\n"); @@ -185,10 +177,8 @@ static int perform(void) fprintf(stderr, "'cases' must be JSON array\n"); exit(EXIT_FAILURE); } - nghttp2_hd_inflate_init(&inflater, side); - nghttp2_hd_change_table_size(&inflater.ctx, config.table_size); - - output_json_header(side); + nghttp2_hd_inflate_init(&inflater); + output_json_header(); len = json_array_size(cases); for(i = 0; i < len; ++i) { json_t *obj = json_array_get(cases, i); @@ -241,29 +231,21 @@ static void print_help(void) "The output of this program can be used as input for deflatehd.\n" "\n" "OPTIONS:\n" - " -s, --table-size=\n" - " Set dynamic table size. In the HPACK\n" - " specification, this value is denoted by\n" - " SETTINGS_HEADER_TABLE_SIZE.\n" - " Default: 4096\n" " -d, --dump-header-table\n" " Output dynamic header table.\n"); } static struct option long_options[] = { - {"table-size", required_argument, NULL, 's'}, {"dump-header-table", no_argument, NULL, 'd'}, {NULL, 0, NULL, 0 } }; int main(int argc, char **argv) { - char *end; - config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE; config.dump_header_table = 0; while(1) { int option_index = 0; - int c = getopt_long(argc, argv, "dhs:", long_options, &option_index); + int c = getopt_long(argc, argv, "dh", long_options, &option_index); if(c == -1) { break; } @@ -271,15 +253,6 @@ int main(int argc, char **argv) case 'h': print_help(); exit(EXIT_SUCCESS); - case 's': - /* --table-size */ - errno = 0; - config.table_size = strtoul(optarg, &end, 10); - if(errno == ERANGE || *end != '\0') { - fprintf(stderr, "-s: Bad option value\n"); - exit(EXIT_FAILURE); - } - break; case 'd': /* --dump-header-table */ config.dump_header_table = 1; diff --git a/tests/main.c b/tests/main.c index 699fb3b5..415acc03 100644 --- a/tests/main.c +++ b/tests/main.c @@ -225,8 +225,6 @@ int main(int argc, char* argv[]) test_nghttp2_hd_deflate_same_indexed_repr) || !CU_add_test(pSuite, "hd_deflate_common_header_eviction", test_nghttp2_hd_deflate_common_header_eviction) || - !CU_add_test(pSuite, "hd_deflate_deflate_buffer", - test_nghttp2_hd_deflate_deflate_buffer) || !CU_add_test(pSuite, "hd_deflate_clear_refset", test_nghttp2_hd_deflate_clear_refset) || !CU_add_test(pSuite, "hd_inflate_indname_noinc", diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index d6495d19..9fe5cbbb 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -82,8 +82,8 @@ void test_nghttp2_frame_pack_headers() ssize_t nv_offset; nva_out_init(&out); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); + nghttp2_hd_inflate_init(&inflater); nva = headers(); nvlen = HEADERS_LENGTH; @@ -171,7 +171,7 @@ void test_nghttp2_frame_pack_headers_frame_too_large(void) } nvlen = nghttp2_nv_array_copy(&nva, big_hds, big_hdslen); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); nghttp2_frame_headers_init(&frame, NGHTTP2_FLAG_END_STREAM|NGHTTP2_FLAG_END_HEADERS, 1000000007, @@ -269,8 +269,8 @@ void test_nghttp2_frame_pack_push_promise() nva_out out; nva_out_init(&out); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_RESPONSE); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_RESPONSE); + nghttp2_hd_deflate_init(&deflater); + nghttp2_hd_inflate_init(&inflater); nva = headers(); nvlen = HEADERS_LENGTH; diff --git a/tests/nghttp2_hd_test.c b/tests/nghttp2_hd_test.c index 7d75eddd..d7756c37 100644 --- a/tests/nghttp2_hd_test.c +++ b/tests/nghttp2_hd_test.c @@ -59,8 +59,8 @@ void test_nghttp2_hd_deflate(void) nva_out out; nva_out_init(&out); - CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST)); - CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST)); + CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater)); + CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater)); blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, nv_offset, nva1, sizeof(nva1)/sizeof(nghttp2_nv)); CU_ASSERT(blocklen > 0); @@ -142,8 +142,8 @@ void test_nghttp2_hd_deflate_same_indexed_repr(void) nva_out out; nva_out_init(&out); - CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST)); - CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST)); + CU_ASSERT(0 == nghttp2_hd_deflate_init(&deflater)); + CU_ASSERT(0 == nghttp2_hd_inflate_init(&inflater)); /* Encode 2 same headers. cookie:alpha is not in the reference set, so first emit literal repr and then 2 emits of indexed repr. */ @@ -198,8 +198,8 @@ void test_nghttp2_hd_deflate_common_header_eviction(void) nva[i].valuelen = sizeof(value); } - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); + nghttp2_hd_inflate_init(&inflater); /* First emit "h1: ..." to put it in the reference set (index = 0). */ @@ -236,174 +236,6 @@ void test_nghttp2_hd_deflate_common_header_eviction(void) nghttp2_hd_deflate_free(&deflater); } -void test_nghttp2_hd_deflate_deflate_buffer(void) -{ - nghttp2_hd_deflater deflater; - nghttp2_hd_inflater inflater; - size_t i; - ssize_t blocklen; - uint8_t *buf = NULL; - size_t buflen = 0; - nghttp2_nv nva1[] = { MAKE_NV("k1", "v1"), /* 36 */ - MAKE_NV("k10", "v10"), /* 38 */ - MAKE_NV("k100", "v100"), /* 40 */ - MAKE_NV("k1000", "v1000") /* 42 */ - }; /* Total: 156 */ - nghttp2_nv nva2[] = { MAKE_NV("k10", "v10"), /* 38 */ - MAKE_NV("k1", "v1") /* 36 */ - }; - nghttp2_nv nv3; - uint8_t val[256]; - nghttp2_nv nva4[] = { MAKE_NV(":method", "GET"), - MAKE_NV(":scheme", "http") - }; - nghttp2_hd_entry *ent; - nva_out out; - - nva_out_init(&out); - memset(val, 'a', sizeof(val)); - nv3.name = nv3.value = val; - nv3.namelen = nv3.valuelen = sizeof(val); - - /* Check the case where entry from static table is inserted to - dynamic header table. And it is out of deflate header table - size. */ - nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, 32); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); - blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, - nva4, ARRLEN(nva4)); - CU_ASSERT(blocklen > 0); - /* Now header table should look like this: - * - * 0: :scheme, http (-) - * 1: :method, GET (-) - * - * name/value of all entries must be NULL. - */ - CU_ASSERT(2 == deflater.ctx.hd_table.len); - CU_ASSERT(0 == deflater.ctx.deflate_hd_tablelen); - CU_ASSERT(0 == deflater.ctx.deflate_hd_table_bufsize); - for(i = 0; i < 2; ++i) { - ent = nghttp2_hd_table_get(&deflater.ctx, i); - CU_ASSERT(ent->nv.name == NULL); - CU_ASSERT(ent->nv.value == NULL); - CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET)); - } - - CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen)); - - CU_ASSERT(2 == out.nvlen); - assert_nv_equal(nva4, out.nva, 2); - - nva_out_reset(&out); - - nghttp2_hd_deflate_free(&deflater); - nghttp2_hd_inflate_free(&inflater); - - /* 156 buffer size can hold all headers in deflate region */ - nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, 156); - blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, - nva1, ARRLEN(nva1)); - CU_ASSERT(blocklen > 0); - /* Now header table should look like this: - * - * 0: k1000, v100 - * 1: k100, v100 - * 2: k10, v10 - * 3: k1, v1 - */ - CU_ASSERT(4 == deflater.ctx.hd_table.len); - CU_ASSERT(4 == deflater.ctx.deflate_hd_tablelen); - CU_ASSERT(156 == deflater.ctx.deflate_hd_table_bufsize); - for(i = 0; i < 4; ++i) { - CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.name != NULL); - CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.value != NULL); - } - - CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 156)); - CU_ASSERT(4 == deflater.ctx.hd_table.len); - CU_ASSERT(4 == deflater.ctx.deflate_hd_tablelen); - CU_ASSERT(156 == deflater.ctx.deflate_hd_table_bufsize); - - blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, &nv3, 1); - CU_ASSERT(blocklen > 0); - /* Now header table should be unchanged, because we don't index - large header */ - CU_ASSERT(4 == deflater.ctx.hd_table.len); - CU_ASSERT(4 == deflater.ctx.deflate_hd_tablelen); - CU_ASSERT(156 == deflater.ctx.deflate_hd_table_bufsize); - - nghttp2_hd_deflate_free(&deflater); - - /* Check more complex use case */ - nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, 155); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); - blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, - nva1, ARRLEN(nva1)); - CU_ASSERT(blocklen > 0); - /* Now header table should look like this: - * - * 0: k1000, v100 (R) - * 1: k100, v100 (R) - * 2: k10, v10 (R) - * 3: k1, v1 (-) <- name, value must be NULL and not in reference set - * - * But due to the deflate table size limit, name/value of index=3 must - * be NULL. - */ - CU_ASSERT(4 == deflater.ctx.hd_table.len); - CU_ASSERT(3 == deflater.ctx.deflate_hd_tablelen); - CU_ASSERT(120 == deflater.ctx.deflate_hd_table_bufsize); - for(i = 0; i < 3; ++i) { - CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.name != NULL); - CU_ASSERT(nghttp2_hd_table_get(&deflater.ctx, i)->nv.value != NULL); - } - ent = nghttp2_hd_table_get(&deflater.ctx, 3); - CU_ASSERT(ent->nv.name == NULL); - CU_ASSERT(ent->nv.value == NULL); - CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET)); - - CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen)); - - CU_ASSERT(4 == out.nvlen); - assert_nv_equal(nva1, out.nva, 4); - - nva_out_reset(&out); - - blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, - nva2, ARRLEN(nva2)); - CU_ASSERT(blocklen > 0); - /* Now header table should look like this: - * - * 0: k1, v1 (R) - * 1: k1000, v100 (R) - * 2: k100, v100 (R) - * 3: k10, v10 (-) <- name, value must be NULL - * 4: k1, v1 (-) <- name, value must be NULL - */ - CU_ASSERT(5 == deflater.ctx.hd_table.len); - CU_ASSERT(3 == deflater.ctx.deflate_hd_tablelen); - CU_ASSERT(118 == deflater.ctx.deflate_hd_table_bufsize); - ent = nghttp2_hd_table_get(&deflater.ctx, 3); - CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET)); - ent = nghttp2_hd_table_get(&deflater.ctx, 3); - CU_ASSERT(0 == (ent->flags & NGHTTP2_HD_FLAG_REFSET)); - - CU_ASSERT(blocklen == inflate_hd(&inflater, &out, buf, blocklen)); - - CU_ASSERT(2 == out.nvlen); - /* Sort before comparison */ - nghttp2_nv_array_sort(nva2, 2); - assert_nv_equal(nva2, out.nva, 2); - - nva_out_reset(&out); - - free(buf); - nghttp2_hd_inflate_free(&inflater); - nghttp2_hd_deflate_free(&deflater); - -} - void test_nghttp2_hd_deflate_clear_refset(void) { nghttp2_hd_deflater deflater; @@ -419,10 +251,10 @@ void test_nghttp2_hd_deflate_clear_refset(void) nva_out out; nva_out_init(&out); - nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_SIDE_REQUEST, + nghttp2_hd_deflate_init2(&deflater, NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE); nghttp2_hd_deflate_set_no_refset(&deflater, 1); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); for(i = 0; i < 2; ++i) { blocklen = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, @@ -457,14 +289,13 @@ void test_nghttp2_hd_inflate_indname_noinc(void) nva_out out; nva_out_init(&out); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); for(i = 0; i < ARRLEN(nv); ++i) { offset = 0; CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56, nv[i].value, nv[i].valuelen, - 0, - NGHTTP2_HD_SIDE_REQUEST)); + 0)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT(1 == out.nvlen); @@ -488,11 +319,10 @@ void test_nghttp2_hd_inflate_indname_inc(void) nva_out out; nva_out_init(&out); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 56, - nv.value, nv.valuelen, 1, - NGHTTP2_HD_SIDE_REQUEST)); + nv.value, nv.valuelen, 1)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT(1 == out.nvlen); @@ -517,21 +347,17 @@ void test_nghttp2_hd_inflate_indname_inc_eviction(void) nva_out out; nva_out_init(&out); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); memset(value, '0', sizeof(value)); CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 13, - value, sizeof(value), 1, - NGHTTP2_HD_SIDE_REQUEST)); + value, sizeof(value), 1)); CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 14, - value, sizeof(value), 1, - NGHTTP2_HD_SIDE_REQUEST)); + value, sizeof(value), 1)); CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 15, - value, sizeof(value), 1, - NGHTTP2_HD_SIDE_REQUEST)); + value, sizeof(value), 1)); CU_ASSERT(0 == nghttp2_hd_emit_indname_block(&buf, &buflen, &offset, 16, - value, sizeof(value), 1, - NGHTTP2_HD_SIDE_REQUEST)); + value, sizeof(value), 1)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); @@ -569,12 +395,11 @@ void test_nghttp2_hd_inflate_newname_noinc(void) nva_out out; nva_out_init(&out); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); for(i = 0; i < ARRLEN(nv); ++i) { offset = 0; CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, - &nv[i], 0, - NGHTTP2_HD_SIDE_REQUEST)); + &nv[i], 0)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT(1 == out.nvlen); @@ -598,11 +423,10 @@ void test_nghttp2_hd_inflate_newname_inc(void) nva_out out; nva_out_init(&out); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, - &nv, 1, - NGHTTP2_HD_SIDE_REQUEST)); + &nv, 1)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT(1 == out.nvlen); @@ -635,11 +459,10 @@ void test_nghttp2_hd_inflate_clearall_inc(void) nv.value = value; nv.valuelen = sizeof(value); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, - &nv, 1, - NGHTTP2_HD_SIDE_REQUEST)); + &nv, 1)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT(1 == out.nvlen); @@ -663,8 +486,7 @@ void test_nghttp2_hd_inflate_clearall_inc(void) offset = 0; CU_ASSERT(0 == nghttp2_hd_emit_newname_block(&buf, &buflen, &offset, - &nv, 1, - NGHTTP2_HD_SIDE_REQUEST)); + &nv, 1)); CU_ASSERT((ssize_t)offset == inflate_hd(&inflater, &out, buf, offset)); CU_ASSERT(1 == out.nvlen); @@ -690,7 +512,7 @@ void test_nghttp2_hd_inflate_zero_length_huffman(void) buf[2] = 'x'; buf[3] = 0x80; - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); CU_ASSERT(4 == inflate_hd(&inflater, &out, buf, 4)); CU_ASSERT(1 == out.nvlen); @@ -706,35 +528,158 @@ void test_nghttp2_hd_inflate_zero_length_huffman(void) void test_nghttp2_hd_change_table_size(void) { nghttp2_hd_deflater deflater; + nghttp2_hd_inflater inflater; nghttp2_nv nva[] = { MAKE_NV(":method", "GET"), MAKE_NV(":path", "/") }; uint8_t *buf = NULL; size_t buflen = 0; ssize_t rv; + nva_out out; + size_t offset; + + nva_out_init(&out); + + nghttp2_hd_deflate_init(&deflater); + nghttp2_hd_inflate_init(&inflater); + + /* inflater changes notifies 8000 max header table size */ + CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 8000)); + CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 8000)); + + CU_ASSERT(127 == deflater.ctx.hd_table.mask); + CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max); + + CU_ASSERT(255 == inflater.ctx.hd_table.mask); + CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); + + /* This will emit encoding context update with header table size 4096 */ + rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); + CU_ASSERT(rv > 0); + CU_ASSERT(2 == deflater.ctx.hd_table.len); + CU_ASSERT(4096 == deflater.ctx.hd_table_bufsize_max); + + CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); + CU_ASSERT(2 == inflater.ctx.hd_table.len); + CU_ASSERT(4096 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); + + nva_out_reset(&out); + + /* inflater changes header table size to 1024 */ + CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 1024)); + CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 1024)); + + CU_ASSERT(127 == deflater.ctx.hd_table.mask); + CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max); + + CU_ASSERT(255 == inflater.ctx.hd_table.mask); + CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max); + + rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); + CU_ASSERT(rv >= 0); + CU_ASSERT(2 == deflater.ctx.hd_table.len); + CU_ASSERT(1024 == deflater.ctx.hd_table_bufsize_max); + + CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); + CU_ASSERT(2 == inflater.ctx.hd_table.len); + CU_ASSERT(1024 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(1024 == inflater.settings_hd_table_bufsize_max); + + nva_out_reset(&out); + + /* inflater changes header table size to 0 */ + CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 0)); + CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 0)); + + CU_ASSERT(127 == deflater.ctx.hd_table.mask); + CU_ASSERT(0 == deflater.ctx.hd_table.len); + CU_ASSERT(0 == deflater.ctx.hd_table_bufsize_max); + + CU_ASSERT(255 == inflater.ctx.hd_table.mask); + CU_ASSERT(0 == inflater.ctx.hd_table.len); + CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max); + + rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); + CU_ASSERT(rv >= 0); + CU_ASSERT(0 == deflater.ctx.hd_table.len); + CU_ASSERT(0 == deflater.ctx.hd_table_bufsize_max); + + CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); + CU_ASSERT(0 == inflater.ctx.hd_table.len); + CU_ASSERT(0 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(0 == inflater.settings_hd_table_bufsize_max); + + nva_out_reset(&out); + + free(buf); + nghttp2_hd_inflate_free(&inflater); + nghttp2_hd_deflate_free(&deflater); + + /* Check table buffer is expanded */ + buf = NULL; + buflen = 0; + nghttp2_hd_deflate_init2(&deflater, 8192); + nghttp2_hd_inflate_init(&inflater); + + /* First inflater changes header table size to 8000 */ + CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 8000)); + CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 8000)); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); - CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 8000)); CU_ASSERT(255 == deflater.ctx.hd_table.mask); CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max); + CU_ASSERT(255 == inflater.ctx.hd_table.mask); + CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); + rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); CU_ASSERT(rv > 0); CU_ASSERT(2 == deflater.ctx.hd_table.len); + CU_ASSERT(8000 == deflater.ctx.hd_table_bufsize_max); - CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 16384)); - CU_ASSERT(511 == deflater.ctx.hd_table.mask); + CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); + CU_ASSERT(2 == inflater.ctx.hd_table.len); + CU_ASSERT(8000 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(8000 == inflater.settings_hd_table_bufsize_max); + + nva_out_reset(&out); + + CU_ASSERT(0 == nghttp2_hd_inflate_change_table_size(&inflater, 16383)); + CU_ASSERT(0 == nghttp2_hd_deflate_change_table_size(&deflater, 16383)); + + CU_ASSERT(255 == deflater.ctx.hd_table.mask); + CU_ASSERT(16383 == deflater.ctx.hd_table_bufsize_max); + + CU_ASSERT(511 == inflater.ctx.hd_table.mask); + CU_ASSERT(16383 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max); + + rv = nghttp2_hd_deflate_hd(&deflater, &buf, &buflen, 0, nva, 2); + CU_ASSERT(rv >= 0); CU_ASSERT(2 == deflater.ctx.hd_table.len); - CU_ASSERT(2 == deflater.ctx.deflate_hd_tablelen); - CU_ASSERT(5 == - deflater.ctx.hd_table.buffer[deflater.ctx.hd_table.first] - ->nv.namelen); + CU_ASSERT(8192 == deflater.ctx.hd_table_bufsize_max); - CU_ASSERT(0 == nghttp2_hd_change_table_size(&deflater.ctx, 0)); - CU_ASSERT(511 == deflater.ctx.hd_table.mask); - CU_ASSERT(0 == deflater.ctx.hd_table.len); - CU_ASSERT(0 == deflater.ctx.deflate_hd_tablelen); + CU_ASSERT(rv == inflate_hd(&inflater, &out, buf, rv)); + CU_ASSERT(2 == inflater.ctx.hd_table.len); + CU_ASSERT(8192 == inflater.ctx.hd_table_bufsize_max); + CU_ASSERT(16383 == inflater.settings_hd_table_bufsize_max); + + nva_out_reset(&out); + + /* Lastly, check the error condition */ + offset = 0; + rv = nghttp2_hd_emit_table_size(&buf, &buflen, &offset, 25600); + CU_ASSERT(rv == 0); + CU_ASSERT(NGHTTP2_ERR_HEADER_COMP == + inflate_hd(&inflater, &out, buf, offset)); + + nva_out_reset(&out); free(buf); + nghttp2_hd_inflate_free(&inflater); nghttp2_hd_deflate_free(&deflater); } @@ -899,8 +844,8 @@ void test_nghttp2_hd_deflate_inflate(void) MAKE_NV("x-cache-lookup", "HIT from alphabravo:3128"), }; - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); + nghttp2_hd_inflate_init(&inflater); check_deflate_inflate(&deflater, &inflater, nv1, ARRLEN(nv1)); check_deflate_inflate(&deflater, &inflater, nv2, ARRLEN(nv2)); diff --git a/tests/nghttp2_hd_test.h b/tests/nghttp2_hd_test.h index 613ab322..1e9b763f 100644 --- a/tests/nghttp2_hd_test.h +++ b/tests/nghttp2_hd_test.h @@ -28,7 +28,6 @@ void test_nghttp2_hd_deflate(void); void test_nghttp2_hd_deflate_same_indexed_repr(void); void test_nghttp2_hd_deflate_common_header_eviction(void); -void test_nghttp2_hd_deflate_deflate_buffer(void); void test_nghttp2_hd_deflate_clear_refset(void); void test_nghttp2_hd_inflate_indname_noinc(void); void test_nghttp2_hd_inflate_indname_inc(void); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 568e1153..eccc314c 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -363,7 +363,7 @@ void test_nghttp2_session_recv(void) callbacks.on_frame_recv_callback = on_frame_recv_callback; user_data.df = &df; nghttp2_session_server_new(&session, &callbacks, &user_data); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, @@ -446,7 +446,7 @@ void test_nghttp2_session_recv_invalid_stream_id(void) user_data.df = &df; user_data.invalid_frame_recv_cb_called = 0; nghttp2_session_server_new(&session, &callbacks, &user_data); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2, NGHTTP2_PRI_DEFAULT, NULL, 0); @@ -491,7 +491,7 @@ void test_nghttp2_session_recv_invalid_frame(void) user_data.df = &df; user_data.frame_send_cb_called = 0; nghttp2_session_server_new(&session, &callbacks, &user_data); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); nvlen = nghttp2_nv_array_copy(&nva, nv, ARRLEN(nv)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1, NGHTTP2_PRI_DEFAULT, nva, nvlen); @@ -690,7 +690,7 @@ void test_nghttp2_session_recv_continuation(void) nghttp2_session_server_new(&session, &callbacks, &ud); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); /* Make 1 HEADERS and insert CONTINUATION header */ nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); @@ -746,7 +746,7 @@ void test_nghttp2_session_recv_continuation(void) /* Expecting CONTINUATION, but get the other frame */ nghttp2_session_server_new(&session, &callbacks, &ud); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); /* HEADERS without END_HEADERS flag */ nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); @@ -803,7 +803,7 @@ void test_nghttp2_session_recv_premature_headers(void) nghttp2_session_server_new(&session, &callbacks, &ud); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, @@ -867,7 +867,7 @@ void test_nghttp2_session_continue(void) nghttp2_session_server_new(&session, &callbacks, &user_data); - nghttp2_hd_deflate_init(&deflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_deflate_init(&deflater); /* Make 2 HEADERS frames */ nvlen = nghttp2_nv_array_copy(&nva, nv1, ARRLEN(nv1)); @@ -2255,7 +2255,7 @@ void test_nghttp2_submit_request_without_data(void) callbacks.send_callback = accumulator_send_callback; CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); CU_ASSERT(0 == nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, nva, ARRLEN(nva), &data_prd, NULL)); item = nghttp2_session_get_next_ob_item(session); @@ -2327,7 +2327,7 @@ void test_nghttp2_submit_response_without_data(void) callbacks.send_callback = accumulator_send_callback; CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud)); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_RESPONSE); + nghttp2_hd_inflate_init(&inflater); nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM, NGHTTP2_PRI_DEFAULT, NGHTTP2_STREAM_OPENING, NULL); @@ -2499,7 +2499,7 @@ void test_nghttp2_submit_headers(void) CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud)); - nghttp2_hd_inflate_init(&inflater, NGHTTP2_HD_SIDE_REQUEST); + nghttp2_hd_inflate_init(&inflater); CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 1, NGHTTP2_PRI_DEFAULT, From 7ab4206269bea3b7e33436ae88279fc3ee4dae1f Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 14 Feb 2014 16:08:39 +0900 Subject: [PATCH 46/56] Tear down connection if SETTINGS makes window size overflow --- lib/nghttp2_session.c | 8 ++++---- tests/nghttp2_session_test.c | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 00c4e65f..92941d1d 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -2562,8 +2562,8 @@ static int nghttp2_update_remote_initial_window_size_func arg->new_window_size, arg->old_window_size); if(rv != 0) { - return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, - NGHTTP2_FLOW_CONTROL_ERROR); + return nghttp2_session_terminate_session(arg->session, + NGHTTP2_FLOW_CONTROL_ERROR); } /* If window size gets positive, push deferred DATA frame to outbound queue. */ @@ -2619,8 +2619,8 @@ static int nghttp2_update_local_initial_window_size_func arg->new_window_size, arg->old_window_size); if(rv != 0) { - return nghttp2_session_add_rst_stream(arg->session, stream->stream_id, - NGHTTP2_FLOW_CONTROL_ERROR); + return nghttp2_session_terminate_session(arg->session, + NGHTTP2_FLOW_CONTROL_ERROR); } if(!(arg->session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_STREAM_WINDOW_UPDATE)) { diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index eccc314c..0669ee96 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -2791,7 +2791,10 @@ void test_nghttp2_submit_settings_update_local_window_size(void) CU_ASSERT(0 == nghttp2_session_send(session)); CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0)); - CU_ASSERT(NGHTTP2_STREAM_CLOSING == stream->state); + + item = nghttp2_session_get_next_ob_item(session); + CU_ASSERT(NGHTTP2_GOAWAY == OB_CTRL_TYPE(item)); + CU_ASSERT(NGHTTP2_FLOW_CONTROL_ERROR == OB_CTRL(item)->goaway.error_code); nghttp2_session_del(session); nghttp2_frame_settings_free(&ack_frame.settings); From 622f783675768114bc4d2a7681e1c8a2c75945d6 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 14 Feb 2014 16:12:04 +0900 Subject: [PATCH 47/56] Disallow PUSH_PROMISE from client side --- lib/nghttp2_session.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 92941d1d..b975644f 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -912,6 +912,9 @@ static int nghttp2_session_predicate_push_promise_send { int rv; nghttp2_stream *stream; + if(!session->server) { + return NGHTTP2_ERR_PROTO; + } if(nghttp2_session_is_my_stream_id(session, stream_id)) { /* The associated stream must be initiated by the remote peer */ return NGHTTP2_ERR_PROTO; @@ -2861,7 +2864,8 @@ int nghttp2_session_on_push_promise_received(nghttp2_session *session, return nghttp2_session_inflate_handle_invalid_connection (session, frame, NGHTTP2_PROTOCOL_ERROR); } - if(session->local_settings[NGHTTP2_SETTINGS_ENABLE_PUSH] == 0) { + if(session->server || + session->local_settings[NGHTTP2_SETTINGS_ENABLE_PUSH] == 0) { return nghttp2_session_inflate_handle_invalid_connection (session, frame, NGHTTP2_PROTOCOL_ERROR); } From 1e95c8b3133467043ae78a42c0bda00d6a3034f4 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 15 Feb 2014 01:34:04 +0900 Subject: [PATCH 48/56] Allow always max 1024 padding for HEADERS We need paddings regardless of payload and frame boundary to mitigate certain attacks. Since we handles CONTINUATION internally, we don't show FLAG_PAD_HIGH and PAD_LOW flags of HEADERS in nghttp/nghttpd. We just show the total paddings in HEADERS + CONTINUATION. --- lib/nghttp2_session.c | 71 +++++++++++++++++++++++++++++------- tests/main.c | 2 + tests/nghttp2_session_test.c | 50 ++++++++++++++++++++++++- tests/nghttp2_session_test.h | 1 + 4 files changed, 109 insertions(+), 15 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index b975644f..7fab91f8 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1141,10 +1141,7 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, return framebuflen; } padded_payloadlen = session_call_select_padding - (session, frame, - (frame->hd.length == 0 ? NGHTTP2_MAX_FRAME_LENGTH : - (frame->hd.length + NGHTTP2_MAX_FRAME_LENGTH - 1) - / NGHTTP2_MAX_FRAME_LENGTH * NGHTTP2_MAX_FRAME_LENGTH)); + (session, frame, frame->hd.length + 1024); if(nghttp2_is_fatal(padded_payloadlen)) { return padded_payloadlen; } @@ -1152,13 +1149,46 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, frame->headers.padlen = padded_payloadlen - frame->hd.length; frame->hd.length = padded_payloadlen; + DEBUGF(fprintf(stderr, "payloadlen=%zu, padlen=%zu\n", + frame->hd.length, frame->headers.padlen)); + if(frame->hd.length > NGHTTP2_MAX_FRAME_LENGTH) { - /* PAD_HIGH and PAD_LOW will be added in - nghttp2_session_after_frame_sent(). */ - /* This may make framebuflen > session->aob.framebufmax. But + if(NGHTTP2_MAX_FRAME_LENGTH > + frame->hd.length - frame->headers.padlen) { + size_t padlen = NGHTTP2_MAX_FRAME_LENGTH - + (frame->hd.length - frame->headers.padlen); + nghttp2_frame_hd hd = frame->hd; + + DEBUGF(fprintf(stderr, "padding across 2 frames\n")); + + hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; + hd.length = NGHTTP2_MAX_FRAME_LENGTH; + + DEBUGF(fprintf(stderr, "first HEADERS payloadlen=%zu, padlen=%zu\n", + hd.length, padlen)); + + r = nghttp2_frame_add_pad(&session->aob.framebuf, + &session->aob.framebufmax, + &session->aob.framebufoff, + &hd.flags, + hd.length - padlen, + padlen); + if(nghttp2_is_fatal(r)) { + return r; + } + framebuflen = session->aob.framebufoff + frame->hd.length + + NGHTTP2_FRAME_HEAD_LENGTH; + + nghttp2_frame_pack_frame_hd + (session->aob.framebuf + session->aob.framebufoff, &hd); + } else { + /* PAD_HIGH and PAD_LOW will be added in + nghttp2_session_after_frame_sent(). */ + framebuflen += frame->headers.padlen; + } + /* At this point, framebuflen > session->aob.framebufmax. But before we access the missing part, we will allocate it in nghttp2_session_after_frame_sent(). */ - framebuflen += frame->headers.padlen; } else if(frame->hd.length <= NGHTTP2_MAX_FRAME_LENGTH && frame->headers.padlen > 0) { r = nghttp2_frame_add_pad(&session->aob.framebuf, @@ -1504,17 +1534,24 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) session->aob.framebufoff -= NGHTTP2_FRAME_HEAD_LENGTH; if(cont_hd.length + session->aob.framebufmark == session->aob.framebuflen) { + size_t padlen; + if(cont_hd.length < frame->headers.padlen) { + padlen = cont_hd.length; + } else { + padlen = frame->headers.padlen; + } DEBUGF(fprintf(stderr, "last CONTINUATION payloadlen=%zu, padlen=%zu\n", - cont_hd.length, frame->headers.padlen)); + cont_hd.length, padlen)); cont_hd.flags = NGHTTP2_FLAG_END_HEADERS; + rv = nghttp2_frame_add_pad(&session->aob.framebuf, &session->aob.framebufmax, &session->aob.framebufoff, &cont_hd.flags, - cont_hd.length - frame->headers.padlen, - frame->headers.padlen); + cont_hd.length - padlen, + padlen); if(nghttp2_is_fatal(rv)) { return rv; } @@ -1524,9 +1561,6 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) session->aob.framebuflen = session->aob.framebufmark = session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH + cont_hd.length; - /* Or-ing flags so that we can show these flags in - callback */ - frame->hd.flags |= cont_hd.flags; } else { cont_hd.flags = NGHTTP2_FLAG_NONE; session->aob.framebufmark += cont_hd.length; @@ -3506,6 +3540,8 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->buf); iframe->payloadleft = iframe->frame.hd.length; + DEBUGF(fprintf(stderr, "payloadlen=%zu\n", iframe->payloadleft)); + switch(iframe->frame.hd.type) { case NGHTTP2_DATA: { DEBUGF(fprintf(stderr, "DATA\n")); @@ -3841,6 +3877,10 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, if(iframe->payloadleft) { break; } + /* Clear PAD_HIGH and PAD_LOW, because we rely on those flags + in the next CONTINUATION frame. */ + iframe->frame.hd.flags &= + ~(NGHTTP2_FLAG_PAD_HIGH | NGHTTP2_FLAG_PAD_LOW); if((iframe->frame.hd.flags & NGHTTP2_FLAG_END_HEADERS) == 0) { inbound_frame_reset_left(iframe, NGHTTP2_FRAME_HEAD_LENGTH); iframe->padlen = 0; @@ -3950,6 +3990,9 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, } nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->buf); iframe->payloadleft = cont_hd.length; + + DEBUGF(fprintf(stderr, "payloadlen=%zu\n", iframe->payloadleft)); + if(cont_hd.type != NGHTTP2_CONTINUATION || cont_hd.stream_id != iframe->frame.hd.stream_id) { DEBUGF(fprintf(stderr, "expected stream_id=%d, type=%d, but " diff --git a/tests/main.c b/tests/main.c index 415acc03..2c038721 100644 --- a/tests/main.c +++ b/tests/main.c @@ -199,6 +199,8 @@ int main(int argc, char* argv[]) test_nghttp2_session_data_backoff_by_high_pri_frame) || !CU_add_test(pSuite, "session_pack_data_with_padding", test_nghttp2_session_pack_data_with_padding) || + !CU_add_test(pSuite, "session_pack_headers_with_padding", + test_nghttp2_session_pack_headers_with_padding) || !CU_add_test(pSuite, "pack_settings_payload", test_nghttp2_pack_settings_payload) || !CU_add_test(pSuite, "frame_pack_headers", diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index 0669ee96..dca5ba86 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -40,7 +40,7 @@ #define OB_DATA(ITEM) nghttp2_outbound_item_get_data_frame(ITEM) typedef struct { - uint8_t buf[4096]; + uint8_t buf[65535]; size_t length; } accumulator; @@ -4039,6 +4039,54 @@ void test_nghttp2_session_pack_data_with_padding(void) nghttp2_session_del(session); } +void test_nghttp2_session_pack_headers_with_padding(void) +{ + nghttp2_session *session, *sv_session; + accumulator acc; + my_user_data ud; + nghttp2_session_callbacks callbacks, sv_callbacks; + nghttp2_nv nva[8190]; + size_t i; + + for(i = 0; i < ARRLEN(nva); ++i) { + nva[i].name = (uint8_t*)":path"; + nva[i].namelen = 5; + nva[i].value = (uint8_t*)"/"; + nva[i].valuelen = 1; + } + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.send_callback = accumulator_send_callback; + callbacks.on_frame_send_callback = on_frame_send_callback; + callbacks.select_padding_callback = select_padding_callback; + + acc.length = 0; + ud.acc = &acc; + + memset(&sv_callbacks, 0, sizeof(sv_callbacks)); + sv_callbacks.on_frame_recv_callback = on_frame_recv_callback; + + nghttp2_session_client_new(&session, &callbacks, &ud); + nghttp2_session_server_new(&sv_session, &sv_callbacks, &ud); + + ud.padding_boundary = 16385; + + CU_ASSERT(0 == + nghttp2_submit_request(session, NGHTTP2_PRI_DEFAULT, + nva, ARRLEN(nva), NULL, NULL)); + CU_ASSERT(0 == nghttp2_session_send(session)); + + CU_ASSERT(acc.length > NGHTTP2_MAX_FRAME_LENGTH); + ud.frame_recv_cb_called = 0; + CU_ASSERT((ssize_t)acc.length == + nghttp2_session_mem_recv(sv_session, acc.buf, acc.length)); + CU_ASSERT(1 == ud.frame_recv_cb_called); + CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session)); + + nghttp2_session_del(sv_session); + nghttp2_session_del(session); +} + void test_nghttp2_pack_settings_payload(void) { nghttp2_settings_entry iv[2]; diff --git a/tests/nghttp2_session_test.h b/tests/nghttp2_session_test.h index 626963a4..26680a58 100644 --- a/tests/nghttp2_session_test.h +++ b/tests/nghttp2_session_test.h @@ -90,6 +90,7 @@ void test_nghttp2_session_get_effective_local_window_size(void); void test_nghttp2_session_set_option(void); void test_nghttp2_session_data_backoff_by_high_pri_frame(void); void test_nghttp2_session_pack_data_with_padding(void); +void test_nghttp2_session_pack_headers_with_padding(void); void test_nghttp2_pack_settings_payload(void); #endif /* NGHTTP2_SESSION_TEST_H */ From 3f3f258cd63c59d9c8f179e307c6e1d9fd7fc44a Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 15 Feb 2014 16:30:43 +0900 Subject: [PATCH 49/56] Add padding to PUSH_PROMISE --- lib/nghttp2_frame.c | 38 ++++--- lib/nghttp2_frame.h | 9 ++ lib/nghttp2_session.c | 192 +++++++++++++++++++++++------------ tests/nghttp2_frame_test.c | 15 ++- tests/nghttp2_session_test.c | 22 +++- 5 files changed, 186 insertions(+), 90 deletions(-) diff --git a/lib/nghttp2_frame.c b/lib/nghttp2_frame.c index c6318c1e..680a37b1 100644 --- a/lib/nghttp2_frame.c +++ b/lib/nghttp2_frame.c @@ -266,7 +266,7 @@ ssize_t nghttp2_frame_pack_headers(uint8_t **buf_ptr, if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->pri); } - return frame->hd.length + NGHTTP2_FRAME_HEAD_LENGTH + *bufoff_ptr; + return *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length; } int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, @@ -396,35 +396,45 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr, ssize_t nghttp2_frame_pack_push_promise(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, nghttp2_push_promise *frame, nghttp2_hd_deflater *deflater) { - ssize_t framelen; - size_t nv_offset = NGHTTP2_FRAME_HEAD_LENGTH + 4; + size_t payloadoff = NGHTTP2_FRAME_HEAD_LENGTH + 2; + size_t nv_offset = payloadoff + 4; ssize_t rv; + size_t payloadlen; + rv = nghttp2_hd_deflate_hd(deflater, buf_ptr, buflen_ptr, nv_offset, frame->nva, frame->nvlen); if(rv < 0) { return rv; } - framelen = rv + nv_offset; - if(NGHTTP2_FRAME_HEAD_LENGTH + NGHTTP2_MAX_FRAME_LENGTH < rv + nv_offset) { - frame->hd.length = NGHTTP2_MAX_FRAME_LENGTH; - frame->hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; - } else { - frame->hd.length = framelen - NGHTTP2_FRAME_HEAD_LENGTH; - } + + payloadlen = 4 + rv; + + *bufoff_ptr = 2; + frame->padlen = 0; + frame->hd.length = payloadlen; /* If frame->nvlen == 0, *buflen_ptr may be smaller than nv_offset */ rv = nghttp2_reserve_buffer(buf_ptr, buflen_ptr, nv_offset); if(rv < 0) { return rv; } - memset(*buf_ptr, 0, nv_offset); + memset(*buf_ptr + *bufoff_ptr, 0, NGHTTP2_FRAME_HEAD_LENGTH); /* pack ctrl header after length is determined */ - nghttp2_frame_pack_frame_hd(*buf_ptr, &frame->hd); - nghttp2_put_uint32be(&(*buf_ptr)[8], frame->promised_stream_id); - return framelen; + if(NGHTTP2_MAX_FRAME_LENGTH < payloadlen) { + /* Needs CONTINUATION */ + nghttp2_frame_hd hd = frame->hd; + hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; + hd.length = NGHTTP2_MAX_FRAME_LENGTH; + nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &hd); + } else { + nghttp2_frame_pack_frame_hd(*buf_ptr + *bufoff_ptr, &frame->hd); + } + nghttp2_put_uint32be(&(*buf_ptr)[payloadoff], frame->promised_stream_id); + return *bufoff_ptr + NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length; } int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, diff --git a/lib/nghttp2_frame.h b/lib/nghttp2_frame.h index ee0e0b84..16754d09 100644 --- a/lib/nghttp2_frame.h +++ b/lib/nghttp2_frame.h @@ -256,12 +256,20 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr, * expansion occurred, memory previously pointed by |*buf_ptr| may * change. |*buf_ptr| and |*buflen_ptr| are updated accordingly. * + * The first byte the frame is serialized is returned in the + * |*bufoff_ptr|. Currently, it is always 2 to account for possible + * PAD_HIGH and PAD_LOW. + * * frame->hd.length is assigned after length is determined during * packing process. If payload length is strictly larger than * NGHTTP2_MAX_FRAME_LENGTH, payload data is still serialized as is, * but frame->hd.length is set to NGHTTP2_MAX_FRAME_LENGTH and * NGHTTP2_FLAG_END_HEADERS flag is cleared from frame->hd.flags. * + * This function returns the size of packed frame (which includes + * |*bufoff_ptr| bytes) if it succeeds, or returns one of the + * following negative error codes: + * * This function returns the size of packed frame if it succeeds, or * returns one of the following negative error codes: * @@ -274,6 +282,7 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr, */ ssize_t nghttp2_frame_pack_push_promise(uint8_t **buf_ptr, size_t *buflen_ptr, + size_t *bufoff_ptr, nghttp2_push_promise *frame, nghttp2_hd_deflater *deflater); diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 7fab91f8..8a29304b 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1095,6 +1095,76 @@ static ssize_t session_call_select_padding(nghttp2_session *session, return frame->hd.length; } +/* Add padding to HEADERS or PUSH_PROMISE. We use + frame->headers.padlen in this function to use the fact that + frame->push_promise has also padlen in the same position. */ +static ssize_t session_headers_add_pad(nghttp2_session *session, + nghttp2_frame *frame) +{ + int rv; + ssize_t padded_payloadlen; + + padded_payloadlen = session_call_select_padding(session, frame, + frame->hd.length + 1024); + if(nghttp2_is_fatal(padded_payloadlen)) { + return padded_payloadlen; + } + + frame->headers.padlen = padded_payloadlen - frame->hd.length; + frame->hd.length = padded_payloadlen; + + DEBUGF(fprintf(stderr, "payloadlen=%zu, padlen=%zu\n", + frame->hd.length, frame->headers.padlen)); + + if(frame->hd.length > NGHTTP2_MAX_FRAME_LENGTH) { + nghttp2_frame_hd hd = frame->hd; + hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; + hd.length = NGHTTP2_MAX_FRAME_LENGTH; + + if(NGHTTP2_MAX_FRAME_LENGTH > + frame->hd.length - frame->headers.padlen) { + size_t padlen = NGHTTP2_MAX_FRAME_LENGTH - + (frame->hd.length - frame->headers.padlen); + + DEBUGF(fprintf(stderr, "padding across 2 frames\n")); + DEBUGF(fprintf(stderr, "first HEADERS/PUSH_PROMISE " + "payloadlen=%zu, padlen=%zu\n", hd.length, padlen)); + + rv = nghttp2_frame_add_pad(&session->aob.framebuf, + &session->aob.framebufmax, + &session->aob.framebufoff, + &hd.flags, + hd.length - padlen, + padlen); + if(nghttp2_is_fatal(rv)) { + return rv; + } + } else { + /* PAD_HIGH and PAD_LOW will be added in + nghttp2_session_after_frame_sent(). */ + } + nghttp2_frame_pack_frame_hd + (session->aob.framebuf + session->aob.framebufoff, &hd); + /* At this point, framebuflen > session->aob.framebufmax. But + before we access the missing part, we will allocate it in + nghttp2_session_after_frame_sent(). */ + } else if(frame->headers.padlen > 0) { + rv = nghttp2_frame_add_pad(&session->aob.framebuf, + &session->aob.framebufmax, + &session->aob.framebufoff, + &frame->hd.flags, + frame->hd.length - frame->headers.padlen, + frame->headers.padlen); + if(nghttp2_is_fatal(rv)) { + return rv; + } + nghttp2_frame_pack_frame_hd + (session->aob.framebuf + session->aob.framebufoff, &frame->hd); + } + return session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH + + frame->hd.length; +} + static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, nghttp2_outbound_item *item) { @@ -1106,7 +1176,6 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, case NGHTTP2_HEADERS: { int r; nghttp2_headers_aux_data *aux_data; - ssize_t padded_payloadlen; aux_data = (nghttp2_headers_aux_data*)item->aux_data; if(frame->hd.stream_id == -1) { /* initial HEADERS, which opens stream */ @@ -1140,71 +1209,9 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, if(framebuflen < 0) { return framebuflen; } - padded_payloadlen = session_call_select_padding - (session, frame, frame->hd.length + 1024); - if(nghttp2_is_fatal(padded_payloadlen)) { - return padded_payloadlen; - } - - frame->headers.padlen = padded_payloadlen - frame->hd.length; - frame->hd.length = padded_payloadlen; - - DEBUGF(fprintf(stderr, "payloadlen=%zu, padlen=%zu\n", - frame->hd.length, frame->headers.padlen)); - - if(frame->hd.length > NGHTTP2_MAX_FRAME_LENGTH) { - if(NGHTTP2_MAX_FRAME_LENGTH > - frame->hd.length - frame->headers.padlen) { - size_t padlen = NGHTTP2_MAX_FRAME_LENGTH - - (frame->hd.length - frame->headers.padlen); - nghttp2_frame_hd hd = frame->hd; - - DEBUGF(fprintf(stderr, "padding across 2 frames\n")); - - hd.flags &= ~NGHTTP2_FLAG_END_HEADERS; - hd.length = NGHTTP2_MAX_FRAME_LENGTH; - - DEBUGF(fprintf(stderr, "first HEADERS payloadlen=%zu, padlen=%zu\n", - hd.length, padlen)); - - r = nghttp2_frame_add_pad(&session->aob.framebuf, - &session->aob.framebufmax, - &session->aob.framebufoff, - &hd.flags, - hd.length - padlen, - padlen); - if(nghttp2_is_fatal(r)) { - return r; - } - framebuflen = session->aob.framebufoff + frame->hd.length - + NGHTTP2_FRAME_HEAD_LENGTH; - - nghttp2_frame_pack_frame_hd - (session->aob.framebuf + session->aob.framebufoff, &hd); - } else { - /* PAD_HIGH and PAD_LOW will be added in - nghttp2_session_after_frame_sent(). */ - framebuflen += frame->headers.padlen; - } - /* At this point, framebuflen > session->aob.framebufmax. But - before we access the missing part, we will allocate it in - nghttp2_session_after_frame_sent(). */ - } else if(frame->hd.length <= NGHTTP2_MAX_FRAME_LENGTH && - frame->headers.padlen > 0) { - r = nghttp2_frame_add_pad(&session->aob.framebuf, - &session->aob.framebufmax, - &session->aob.framebufoff, - &frame->hd.flags, - frame->hd.length - frame->headers.padlen, - frame->headers.padlen); - if(nghttp2_is_fatal(r)) { - return r; - } - framebuflen = session->aob.framebufoff + frame->hd.length - + NGHTTP2_FRAME_HEAD_LENGTH; - - nghttp2_frame_pack_frame_hd - (session->aob.framebuf + session->aob.framebufoff, &frame->hd); + framebuflen = session_headers_add_pad(session, frame); + if(framebuflen < 0) { + return framebuflen; } switch(frame->headers.cat) { @@ -1281,11 +1288,17 @@ static ssize_t nghttp2_session_prep_frame(nghttp2_session *session, session->next_stream_id += 2; framebuflen = nghttp2_frame_pack_push_promise(&session->aob.framebuf, &session->aob.framebufmax, + &session->aob.framebufoff, &frame->push_promise, &session->hd_deflater); if(framebuflen < 0) { return framebuflen; } + framebuflen = session_headers_add_pad(session, frame); + if(framebuflen < 0) { + return framebuflen; + } + stream = nghttp2_session_get_stream(session, frame->hd.stream_id); assert(stream); if(nghttp2_session_open_stream @@ -1538,6 +1551,9 @@ static int nghttp2_session_after_frame_sent(nghttp2_session *session) if(cont_hd.length < frame->headers.padlen) { padlen = cont_hd.length; } else { + /* We use frame->headers.padlen for PUSH_PROMISE too. This + is possible because padlen is located in the same + position. */ padlen = frame->headers.padlen; } DEBUGF(fprintf(stderr, @@ -3454,10 +3470,16 @@ static int inbound_frame_handle_pad(nghttp2_inbound_frame *iframe, if((hd->flags & NGHTTP2_FLAG_PAD_LOW) == 0) { return -1; } + if(hd->length < 2) { + return -1; + } inbound_frame_reset_left(iframe, 2); return 1; } if(hd->flags & NGHTTP2_FLAG_PAD_LOW) { + if(hd->length < 1) { + return -1; + } inbound_frame_reset_left(iframe, 1); return 1; } @@ -3657,6 +3679,21 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, break; case NGHTTP2_PUSH_PROMISE: DEBUGF(fprintf(stderr, "PUSH_PROMISE\n")); + rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd); + if(rv < 0) { + busy = 1; + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + break; + } + if(rv == 1) { + iframe->state = NGHTTP2_IB_READ_NBYTE; + break; + } if(iframe->payloadleft < 4) { busy = 1; iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; @@ -3762,6 +3799,29 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, nghttp2_inbound_frame_reset(session); break; case NGHTTP2_PUSH_PROMISE: + if(iframe->padlen == 0 && + iframe->frame.hd.flags & NGHTTP2_FLAG_PAD_LOW) { + rv = inbound_frame_compute_pad(iframe); + if(rv < 0) { + busy = 1; + rv = nghttp2_session_terminate_session(session, + NGHTTP2_PROTOCOL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + iframe->state = NGHTTP2_IB_IGN_PAYLOAD; + break; + } + iframe->frame.push_promise.padlen = rv; + if(iframe->payloadleft < 4) { + busy = 1; + iframe->state = NGHTTP2_IB_FRAME_SIZE_ERROR; + break; + } + iframe->state = NGHTTP2_IB_READ_NBYTE; + inbound_frame_reset_left(iframe, 4); + break; + } rv = session_process_push_promise_frame(session); if(nghttp2_is_fatal(rv)) { return rv; diff --git a/tests/nghttp2_frame_test.c b/tests/nghttp2_frame_test.c index 9fe5cbbb..5580e1a7 100644 --- a/tests/nghttp2_frame_test.c +++ b/tests/nghttp2_frame_test.c @@ -263,10 +263,12 @@ void test_nghttp2_frame_pack_push_promise() nghttp2_push_promise frame, oframe; uint8_t *buf = NULL; size_t buflen = 0; + size_t bufoff; ssize_t framelen; nghttp2_nv *nva; ssize_t nvlen; nva_out out; + ssize_t nv_offset; nva_out_init(&out); nghttp2_hd_deflate_init(&deflater); @@ -276,16 +278,19 @@ void test_nghttp2_frame_pack_push_promise() nvlen = HEADERS_LENGTH; nghttp2_frame_push_promise_init(&frame, NGHTTP2_FLAG_END_PUSH_PROMISE, 1000000007, (1U << 31) - 1, nva, nvlen); - framelen = nghttp2_frame_pack_push_promise(&buf, &buflen, &frame, &deflater); + framelen = nghttp2_frame_pack_push_promise(&buf, &buflen, &bufoff, &frame, + &deflater); - CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, buf, framelen)); - check_frame_header(framelen - NGHTTP2_FRAME_HEAD_LENGTH, + CU_ASSERT(0 == unpack_frame((nghttp2_frame*)&oframe, + buf + bufoff, framelen - bufoff)); + check_frame_header(framelen - bufoff - NGHTTP2_FRAME_HEAD_LENGTH, NGHTTP2_PUSH_PROMISE, NGHTTP2_FLAG_END_PUSH_PROMISE, 1000000007, &oframe.hd); CU_ASSERT((1U << 31) - 1 == oframe.promised_stream_id); - CU_ASSERT(framelen - 12 == - inflate_hd(&inflater, &out, buf + 12, framelen - 12)); + nv_offset = bufoff + NGHTTP2_FRAME_HEAD_LENGTH + 4; + CU_ASSERT(framelen - nv_offset == + inflate_hd(&inflater, &out, buf + nv_offset, framelen - nv_offset)); CU_ASSERT(7 == out.nvlen); CU_ASSERT(nvnameeq("method", &out.nva[0])); diff --git a/tests/nghttp2_session_test.c b/tests/nghttp2_session_test.c index dca5ba86..fdb2c524 100644 --- a/tests/nghttp2_session_test.c +++ b/tests/nghttp2_session_test.c @@ -4044,7 +4044,7 @@ void test_nghttp2_session_pack_headers_with_padding(void) nghttp2_session *session, *sv_session; accumulator acc; my_user_data ud; - nghttp2_session_callbacks callbacks, sv_callbacks; + nghttp2_session_callbacks callbacks; nghttp2_nv nva[8190]; size_t i; @@ -4059,15 +4059,13 @@ void test_nghttp2_session_pack_headers_with_padding(void) callbacks.send_callback = accumulator_send_callback; callbacks.on_frame_send_callback = on_frame_send_callback; callbacks.select_padding_callback = select_padding_callback; + callbacks.on_frame_recv_callback = on_frame_recv_callback; acc.length = 0; ud.acc = &acc; - memset(&sv_callbacks, 0, sizeof(sv_callbacks)); - sv_callbacks.on_frame_recv_callback = on_frame_recv_callback; - nghttp2_session_client_new(&session, &callbacks, &ud); - nghttp2_session_server_new(&sv_session, &sv_callbacks, &ud); + nghttp2_session_server_new(&sv_session, &callbacks, &ud); ud.padding_boundary = 16385; @@ -4083,6 +4081,20 @@ void test_nghttp2_session_pack_headers_with_padding(void) CU_ASSERT(1 == ud.frame_recv_cb_called); CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session)); + /* Check PUSH_PROMISE */ + CU_ASSERT(0 == + nghttp2_submit_push_promise(sv_session, NGHTTP2_FLAG_NONE, 1, + nva, ARRLEN(nva))); + acc.length = 0; + CU_ASSERT(0 == nghttp2_session_send(sv_session)); + + CU_ASSERT(acc.length > NGHTTP2_MAX_FRAME_LENGTH); + ud.frame_recv_cb_called = 0; + CU_ASSERT((ssize_t)acc.length == + nghttp2_session_mem_recv(session, acc.buf, acc.length)); + CU_ASSERT(1 == ud.frame_recv_cb_called); + CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session)); + nghttp2_session_del(sv_session); nghttp2_session_del(session); } From 7504d89f9ba1d77a87e6b005a9fc854bf59079ed Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 15 Feb 2014 16:40:32 +0900 Subject: [PATCH 50/56] src: Add at most N bytes as padding if --padding option is used --- src/HttpServer.cc | 13 +++---------- src/HttpServer.h | 2 +- src/nghttp.cc | 22 +++++++--------------- src/nghttpd.cc | 7 +++---- src/shrpx.cc | 4 ++-- src/shrpx_http.cc | 6 +----- 6 files changed, 17 insertions(+), 37 deletions(-) diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 344fcfd0..209933f5 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -66,7 +66,7 @@ const std::string NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION; Config::Config() : data_ptr(nullptr), output_upper_thres(1024*1024), - padding_boundary(0), + padding(0), header_table_size(-1), port(0), verbose(false), @@ -931,14 +931,7 @@ ssize_t select_padding_callback void *user_data) { auto hd = static_cast(user_data); - auto bd = hd->get_config()->padding_boundary; - if(bd == 0) { - return frame->hd.length; - } - if(frame->hd.length == 0) { - return std::min(max_payload, bd); - } - return std::min(max_payload, (frame->hd.length + bd - 1) / bd * bd); + return std::min(max_payload, frame->hd.length + hd->get_config()->padding); } } // namespace @@ -988,7 +981,7 @@ void fill_callback(nghttp2_session_callbacks& callbacks, const Config *config) callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback; callbacks.on_header_callback = on_header_callback; callbacks.on_begin_headers_callback = on_begin_headers_callback; - if(config->padding_boundary) { + if(config->padding) { callbacks.select_padding_callback = select_padding_callback; } } diff --git a/src/HttpServer.h b/src/HttpServer.h index 308d3b10..f89a1ee2 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -56,7 +56,7 @@ struct Config { std::string cert_file; void *data_ptr; size_t output_upper_thres; - size_t padding_boundary; + size_t padding; ssize_t header_table_size; uint16_t port; bool verbose; diff --git a/src/nghttp.cc b/src/nghttp.cc index 573b3672..59ca75d5 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -82,7 +82,7 @@ struct Config { std::string keyfile; std::string datafile; size_t output_upper_thres; - size_t padding_boundary; + size_t padding; ssize_t peer_max_concurrent_streams; ssize_t header_table_size; int32_t pri; @@ -100,7 +100,7 @@ struct Config { bool continuation; Config() : output_upper_thres(1024*1024), - padding_boundary(0), + padding(0), peer_max_concurrent_streams(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS), header_table_size(-1), pri(NGHTTP2_PRI_DEFAULT), @@ -1131,14 +1131,7 @@ ssize_t select_padding_callback (nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload, void *user_data) { - auto bd = config.padding_boundary; - if(bd == 0) { - return frame->hd.length; - } - if(frame->hd.length == 0) { - return std::min(max_payload, bd); - } - return std::min(max_payload, (frame->hd.length + bd - 1) / bd * bd); + return std::min(max_payload, frame->hd.length + config.padding); } } // namespace @@ -1598,7 +1591,7 @@ int run(char **uris, int n) } callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback; callbacks.on_header_callback = on_header_callback; - if(config.padding_boundary) { + if(config.padding) { callbacks.select_padding_callback = select_padding_callback; } @@ -1723,9 +1716,8 @@ void print_help(std::ostream& out) << " is large enough as it is seen as unlimited.\n" << " -c, --header-table-size=\n" << " Specify decoder header table size.\n" - << " -b, --padding=\n" - << " Padding boundary for frame payload. Specify\n" - << " 0 to disable padding.\n" + << " -b, --padding= Add at most bytes to a frame payload as\n" + << " padding. Specify 0 to disable padding.\n" << " --color Force colored log output.\n" << " --continuation Send large header to test CONTINUATION.\n" << std::endl; @@ -1780,7 +1772,7 @@ int main(int argc, char **argv) print_help(std::cout); exit(EXIT_SUCCESS); case 'b': - config.padding_boundary = strtol(optarg, nullptr, 10); + config.padding = strtol(optarg, nullptr, 10); break; case 'n': config.null_out = true; diff --git a/src/nghttpd.cc b/src/nghttpd.cc index 30bbeb0e..9bb9d2c2 100644 --- a/src/nghttpd.cc +++ b/src/nghttpd.cc @@ -115,9 +115,8 @@ void print_help(std::ostream& out) << " -p/=/foo.png -p/doc=/bar.css\n" << " PATH and PUSH_PATHs are relative to document\n" << " root. See --htdocs option.\n" - << " -b, --padding=\n" - << " Padding boundary for frame payload. Specify\n" - << " 0 to disable padding.\n" + << " -b, --padding= Add at most bytes to a frame payload as\n" + << " padding. Specify 0 to disable padding.\n" << " -h, --help Print this help.\n" << std::endl; } @@ -156,7 +155,7 @@ int main(int argc, char **argv) config.verify_client = true; break; case 'b': - config.padding_boundary = strtol(optarg, nullptr, 10); + config.padding = strtol(optarg, nullptr, 10); break; case 'd': config.htdocs = optarg; diff --git a/src/shrpx.cc b/src/shrpx.cc index 48242dc1..ed551aff 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -676,8 +676,8 @@ void print_help(std::ostream& out) << " --backend-no-tls Disable SSL/TLS on backend connections.\n" << " --http2-no-cookie-crumbling\n" << " Don't crumble cookie header field.\n" - << " --padding=\n" - << " Padding boundary for HTTP/2 frame payload.\n" + << " --padding= Add at most bytes to a HTTP/2 frame payload\n" + << " as padding.\n" << " Specify 0 to disable padding. This option is\n" << " meant for debugging purpose and not intended\n" << " to enhance protocol security.\n" diff --git a/src/shrpx_http.cc b/src/shrpx_http.cc index 0c1db266..5788d09c 100644 --- a/src/shrpx_http.cc +++ b/src/shrpx_http.cc @@ -98,11 +98,7 @@ ssize_t select_padding_callback (nghttp2_session *session, const nghttp2_frame *frame, size_t max_payload, void *user_data) { - auto bd = get_config()->padding; - if(frame->hd.length == 0) { - return std::min(max_payload, bd); - } - return std::min(max_payload, (frame->hd.length + bd - 1) / bd * bd); + return std::min(max_payload, frame->hd.length + get_config()->padding); } } // namespace http From 0da79865b80cc43ca2078c303dec63a15b77418f Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 15 Feb 2014 17:12:17 +0900 Subject: [PATCH 51/56] Don't set PAD_HIGH and PAD_LOW flags to HEADERS/PUSH_PROMISE object to user cb --- lib/nghttp2_session.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/nghttp2_session.c b/lib/nghttp2_session.c index 8a29304b..60adfa18 100644 --- a/lib/nghttp2_session.c +++ b/lib/nghttp2_session.c @@ -1149,17 +1149,18 @@ static ssize_t session_headers_add_pad(nghttp2_session *session, before we access the missing part, we will allocate it in nghttp2_session_after_frame_sent(). */ } else if(frame->headers.padlen > 0) { + nghttp2_frame_hd hd = frame->hd; rv = nghttp2_frame_add_pad(&session->aob.framebuf, &session->aob.framebufmax, &session->aob.framebufoff, - &frame->hd.flags, + &hd.flags, frame->hd.length - frame->headers.padlen, frame->headers.padlen); if(nghttp2_is_fatal(rv)) { return rv; } nghttp2_frame_pack_frame_hd - (session->aob.framebuf + session->aob.framebufoff, &frame->hd); + (session->aob.framebuf + session->aob.framebufoff, &hd); } return session->aob.framebufoff + NGHTTP2_FRAME_HEAD_LENGTH + frame->hd.length; From 652dc250fd99f7dc54477295de3b140a40652a8d Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 15 Feb 2014 17:19:49 +0900 Subject: [PATCH 52/56] Update README.rst --- README.rst | 206 +++++++++++++++++++++++++++-------------------------- 1 file changed, 104 insertions(+), 102 deletions(-) diff --git a/README.rst b/README.rst index 2163422b..31d2e355 100644 --- a/README.rst +++ b/README.rst @@ -7,25 +7,22 @@ version 2.0. Development Status ------------------ -We started to implement HTTP-draft-09/2.0 -(http://tools.ietf.org/html/draft-ietf-httpbis-http2-09) and the +We started to implement HTTP-draft-10/2.0 +(http://tools.ietf.org/html/draft-ietf-httpbis-http2-10) and the header compression -(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-05). +(http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-06). The nghttp2 code base was forked from spdylay project. -========================== ================= -Features HTTP-draft-09/2.0 -========================== ================= -:authority Done -HPACK-draft-05 Done -SETTINGS_HEADER_TABLE_SIZE Done -SETTINGS_ENABLE_PUSH Done -FRAME_SIZE_ERROR Done -SETTINGS with ACK Done -Header Continuation Done -ALPN Done -========================== ================= +========================== ===== +Features h2-10 +========================== ===== +HPACK-draft-06 Done +Strict SETTINGS validation Done +Disallow client to push Done +Padding Done +END_SEGMENT +========================== ===== Public Test Server ------------------ @@ -150,19 +147,21 @@ with prior knowledge, HTTP Upgrade and NPN/ALPN TLS extension. It has verbose output mode for framing information. Here is sample output from ``nghttp`` client:: - $ src/nghttp -vn https://localhost:8443 - [ 0.003] NPN select next protocol: the remote server offers: - * HTTP-draft-09/2.0 + $ src/nghttp -nv https://localhost:8443 + [ 0.004][NPN] server offers: + * h2-10 + * spdy/3.1 * spdy/3 * spdy/2 * http/1.1 - NPN selected the protocol: HTTP-draft-09/2.0 - [ 0.005] send SETTINGS frame + The negotiated protocol: h2-10 + [ 0.006] send SETTINGS frame (niv=2) - [SETTINGS_MAX_CONCURRENT_STREAMS(4):100] - [SETTINGS_INITIAL_WINDOW_SIZE(7):65535] - [ 0.006] send HEADERS frame + [SETTINGS_MAX_CONCURRENT_STREAMS(3):100] + [SETTINGS_INITIAL_WINDOW_SIZE(4):65535] + [ 0.007] send HEADERS frame ; END_STREAM | END_HEADERS + (padlen=0) ; Open new stream :authority: localhost:8443 :method: GET @@ -170,91 +169,91 @@ output from ``nghttp`` client:: :scheme: https accept: */* accept-encoding: gzip, deflate - user-agent: nghttp2/0.1.0-DEV - [ 0.006] recv SETTINGS frame - (niv=2) - [SETTINGS_MAX_CONCURRENT_STREAMS(4):100] - [SETTINGS_INITIAL_WINDOW_SIZE(7):65535] - [ 0.006] send SETTINGS frame + user-agent: nghttp2/0.4.0-DEV + [ 0.007] recv SETTINGS frame + (niv=3) + [SETTINGS_MAX_CONCURRENT_STREAMS(3):100] + [SETTINGS_INITIAL_WINDOW_SIZE(4):65535] + [SETTINGS_ENABLE_PUSH(2):0] + [ 0.007] send SETTINGS frame ; ACK (niv=0) - [ 0.006] recv WINDOW_UPDATE frame - (window_size_increment=1000000007) - [ 0.006] recv SETTINGS frame + [ 0.007] recv SETTINGS frame ; ACK (niv=0) - [ 0.006] recv HEADERS frame + [ 0.008] (stream_id=1) :status: 200 + [ 0.008] (stream_id=1) accept-ranges: bytes + [ 0.008] (stream_id=1) content-encoding: gzip + [ 0.008] (stream_id=1) content-length: 146 + [ 0.008] (stream_id=1) content-type: text/html + [ 0.008] (stream_id=1) date: Sat, 15 Feb 2014 08:14:12 GMT + [ 0.008] (stream_id=1) etag: "b1-4e5535a027780-gzip" + [ 0.008] (stream_id=1) last-modified: Sun, 01 Sep 2013 14:34:22 GMT + [ 0.008] (stream_id=1) server: Apache/2.4.6 (Debian) + [ 0.008] (stream_id=1) vary: Accept-Encoding + [ 0.008] (stream_id=1) via: 1.1 nghttpx + [ 0.008] recv HEADERS frame ; END_HEADERS + (padlen=0) ; First response header - :status: 200 - accept-ranges: bytes - content-encoding: gzip - content-length: 146 - content-type: text/html - date: Sun, 27 Oct 2013 14:23:54 GMT - etag: "b1-4e5535a027780-gzip" - last-modified: Sun, 01 Sep 2013 14:34:22 GMT - server: Apache/2.4.6 (Debian) - vary: Accept-Encoding - via: 1.1 nghttpx - [ 0.006] recv DATA frame - [ 0.006] recv DATA frame + [ 0.008] recv DATA frame + [ 0.008] recv DATA frame ; END_STREAM - [ 0.007] send GOAWAY frame + [ 0.008] send GOAWAY frame (last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[]) The HTTP Upgrade is performed like this:: - $ src/nghttp -vnu http://localhost:8080 + $ src/nghttp -nvu http://localhost:8080 [ 0.000] HTTP Upgrade request GET / HTTP/1.1 Host: localhost:8080 Connection: Upgrade, HTTP2-Settings - Upgrade: HTTP-draft-09/2.0 - HTTP2-Settings: AAAABAAAAGQAAAAHAAD__w + Upgrade: h2-10 + HTTP2-Settings: AwAAAGQEAAD__w Accept: */* - User-Agent: nghttp2/0.1.0-DEV + User-Agent: nghttp2/0.4.0-DEV - [ 0.000] HTTP Upgrade response + [ 0.001] HTTP Upgrade response HTTP/1.1 101 Switching Protocols Connection: Upgrade - Upgrade: HTTP-draft-09/2.0 + Upgrade: h2-10 [ 0.001] HTTP Upgrade success - [ 0.001] send SETTINGS frame + [ 0.001] send SETTINGS frame (niv=2) - [SETTINGS_MAX_CONCURRENT_STREAMS(4):100] - [SETTINGS_INITIAL_WINDOW_SIZE(7):65535] - [ 0.001] recv SETTINGS frame - (niv=2) - [SETTINGS_MAX_CONCURRENT_STREAMS(4):100] - [SETTINGS_INITIAL_WINDOW_SIZE(7):65535] - [ 0.001] recv WINDOW_UPDATE frame - (window_size_increment=1000000007) - [ 0.001] recv HEADERS frame + [SETTINGS_MAX_CONCURRENT_STREAMS(3):100] + [SETTINGS_INITIAL_WINDOW_SIZE(4):65535] + [ 0.001] recv SETTINGS frame + (niv=3) + [SETTINGS_MAX_CONCURRENT_STREAMS(3):100] + [SETTINGS_INITIAL_WINDOW_SIZE(4):65535] + [SETTINGS_ENABLE_PUSH(2):0] + [ 0.001] (stream_id=1) :status: 200 + [ 0.001] (stream_id=1) accept-ranges: bytes + [ 0.001] (stream_id=1) content-length: 177 + [ 0.001] (stream_id=1) content-type: text/html + [ 0.001] (stream_id=1) date: Sat, 15 Feb 2014 08:16:23 GMT + [ 0.001] (stream_id=1) etag: "b1-4e5535a027780" + [ 0.001] (stream_id=1) last-modified: Sun, 01 Sep 2013 14:34:22 GMT + [ 0.001] (stream_id=1) server: Apache/2.4.6 (Debian) + [ 0.001] (stream_id=1) vary: Accept-Encoding + [ 0.001] (stream_id=1) via: 1.1 nghttpx + [ 0.001] recv HEADERS frame ; END_HEADERS + (padlen=0) ; First response header - :status: 200 - accept-ranges: bytes - content-length: 177 - content-type: text/html - date: Sun, 27 Oct 2013 14:26:04 GMT - etag: "b1-4e5535a027780" - last-modified: Sun, 01 Sep 2013 14:34:22 GMT - server: Apache/2.4.6 (Debian) - vary: Accept-Encoding - via: 1.1 nghttpx [ 0.001] recv DATA frame [ 0.001] recv DATA frame ; END_STREAM - [ 0.001] send SETTINGS frame + [ 0.002] send SETTINGS frame ; ACK (niv=0) - [ 0.001] send GOAWAY frame + [ 0.002] send GOAWAY frame (last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[]) - [ 0.001] recv SETTINGS frame + [ 0.002] recv SETTINGS frame ; ACK (niv=0) @@ -278,50 +277,53 @@ information. Here is sample output from ``nghttpd`` server:: $ src/nghttpd --no-tls -v 8080 IPv4: listen on port 8080 IPv6: listen on port 8080 - [id=1] [ 1.189] send SETTINGS frame - (niv=1) - [SETTINGS_MAX_CONCURRENT_STREAMS(4):100] - [id=1] [ 1.191] recv SETTINGS frame + [id=1] [ 1.027] send SETTINGS frame (niv=2) - [SETTINGS_MAX_CONCURRENT_STREAMS(4):100] - [SETTINGS_INITIAL_WINDOW_SIZE(7):65535] - [id=1] [ 1.191] recv HEADERS frame + [SETTINGS_MAX_CONCURRENT_STREAMS(3):100] + [SETTINGS_ENABLE_PUSH(2):0] + [id=1] [ 1.027] recv SETTINGS frame + (niv=2) + [SETTINGS_MAX_CONCURRENT_STREAMS(3):100] + [SETTINGS_INITIAL_WINDOW_SIZE(4):65535] + [id=1] [ 1.027] (stream_id=1) :authority: localhost:8080 + [id=1] [ 1.027] (stream_id=1) :method: GET + [id=1] [ 1.027] (stream_id=1) :path: / + [id=1] [ 1.027] (stream_id=1) :scheme: http + [id=1] [ 1.027] (stream_id=1) accept: */* + [id=1] [ 1.027] (stream_id=1) accept-encoding: gzip, deflate + [id=1] [ 1.027] (stream_id=1) user-agent: nghttp2/0.4.0-DEV + [id=1] [ 1.027] recv HEADERS frame ; END_STREAM | END_HEADERS + (padlen=0) ; Open new stream - :authority: localhost:8080 - :method: GET - :path: / - :scheme: http - accept: */* - accept-encoding: gzip, deflate - user-agent: nghttp2/0.1.0-DEV - [id=1] [ 1.192] send SETTINGS frame + [id=1] [ 1.027] send SETTINGS frame ; ACK (niv=0) - [id=1] [ 1.192] send HEADERS frame + [id=1] [ 1.027] send HEADERS frame ; END_HEADERS + (padlen=0) ; First response header :status: 404 content-encoding: gzip content-type: text/html; charset=UTF-8 - date: Sun, 27 Oct 2013 14:27:53 GMT - server: nghttpd nghttp2/0.1.0-DEV - [id=1] [ 1.192] send DATA frame - [id=1] [ 1.192] send DATA frame + date: Sat, 15 Feb 2014 08:18:53 GMT + server: nghttpd nghttp2/0.4.0-DEV + [id=1] [ 1.028] send DATA frame + [id=1] [ 1.028] send DATA frame ; END_STREAM - [id=1] [ 1.192] stream_id=1 closed - [id=1] [ 1.192] recv SETTINGS frame + [id=1] [ 1.028] stream_id=1 closed + [id=1] [ 1.028] recv SETTINGS frame ; ACK (niv=0) - [id=1] [ 1.192] recv GOAWAY frame + [id=1] [ 1.028] recv GOAWAY frame (last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[]) - [id=1] [ 1.192] closed + [id=1] [ 1.028] closed nghttpx - proxy +++++++++++++++ The ``nghttpx`` is a multi-threaded reverse proxy for -HTTP-draft-09/2.0, SPDY and HTTP/1.1. It has several operation modes: +h2-10, SPDY and HTTP/1.1. It has several operation modes: ================== ============================== ============== ============= Mode option Frontend Backend Note @@ -334,7 +336,7 @@ default mode HTTP/2.0, SPDY, HTTP/1.1 (TLS) HTTP/1.1 Reverse proxy ================== ============================== ============== ============= The interesting mode at the moment is the default mode. It works like -a reverse proxy and listens HTTP-draft-09/2.0, SPDY and HTTP/1.1 and +a reverse proxy and listens h2-10, SPDY and HTTP/1.1 and can be deployed SSL/TLS terminator for existing web server. The default mode, ``--http2-proxy`` and ``--http2-bridge`` modes use From bc0ce40dc2f39383a2c47520d64f21834abea8d1 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 15 Feb 2014 17:20:47 +0900 Subject: [PATCH 53/56] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 31d2e355..7a3e5155 100644 --- a/README.rst +++ b/README.rst @@ -7,7 +7,7 @@ version 2.0. Development Status ------------------ -We started to implement HTTP-draft-10/2.0 +We started to implement h2-10 (http://tools.ietf.org/html/draft-ietf-httpbis-http2-10) and the header compression (http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-06). From 66832e9f4e954f86748ec698641934c069e440b8 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 15 Feb 2014 18:55:52 +0900 Subject: [PATCH 54/56] Allow NGHTTP2_FLAG_END_SEGMENT in nghttp2_submit_headers() --- lib/nghttp2_submit.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index 3ef60ad4..851d2d84 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -75,8 +75,9 @@ static int nghttp2_submit_headers_shared rv = NGHTTP2_ERR_NOMEM; goto fail; } - /* TODO Implement header continuation */ - flags_copy = (flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) | + flags_copy = + (flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY | + NGHTTP2_FLAG_END_SEGMENT)) | NGHTTP2_FLAG_END_HEADERS; nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, pri, From 62b73133e5c78077eea15aad9a254694741317c2 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 15 Feb 2014 18:56:20 +0900 Subject: [PATCH 55/56] Code cleanup --- lib/nghttp2_submit.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index 851d2d84..bdf4fb0b 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -197,7 +197,6 @@ int nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags, free(frame); return rv; } - /* TODO Implement header continuation */ flags_copy = NGHTTP2_FLAG_END_PUSH_PROMISE; nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy, stream_id, -1, nva_copy, nvlen); From 27b3091ab697a0c12aebb5bdd24d251b44953748 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 15 Feb 2014 20:00:51 +0900 Subject: [PATCH 56/56] Update README.rst --- README.rst | 50 ++++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/README.rst b/README.rst index 7a3e5155..8c3ca5e0 100644 --- a/README.rst +++ b/README.rst @@ -442,21 +442,18 @@ deflatehd - header compressor The ``deflatehd`` reads JSON data or HTTP/1-style header fields from stdin and outputs compressed header block in JSON. -For the JSON input, the root JSON object must contain ``context`` key, -which indicates which compression context is used. If it is -``request``, request compression context is used. Otherwise, response -compression context is used. The value of ``cases`` key contains the -sequence of input header set. They share the same compression context -and are processed in the order they appear. Each item in the sequence -is a JSON object and it must have at least ``headers`` key. Its value -is an array of a JSON object containing exactly one name/value pair. +For the JSON input, the root JSON object must include ``cases`` +key. Its value has to include the sequence of input header set. They +share the same compression context and are processed in the order they +appear. Each item in the sequence is a JSON object and it must +include ``headers`` key. Its value is an array of a JSON object , +which includes exactly one name/value pair. Example: .. code-block:: json { - "context": "request", "cases": [ { @@ -487,9 +484,7 @@ Example:: :method: POST user-agent: nghttp2 -The output is JSON object. It contains ``context`` key and its value -is ``request`` if the compression context is request, otherwise -``response``. The root JSON object also contains ``cases`` key and its +The output is JSON object. It should include ``cases`` key and its value is an array of JSON object, which has at least following keys: seq @@ -518,7 +513,6 @@ Examples: .. code-block:: json { - "context": "request", "cases": [ { @@ -580,9 +574,9 @@ The output can be used as the input for ``inflatehd`` and ``deflatehd``. With ``-d`` option, the extra ``header_table`` key is added and its -associated value contains the state of dyanmic header table after the -corresponding header set was processed. The value contains following -keys: +associated value includes the state of dyanmic header table after the +corresponding header set was processed. The value includes at least +following keys: entries The entry in the header table. If ``referenced`` is ``true``, it @@ -618,7 +612,6 @@ Example: .. code-block:: json { - "context": "request", "cases": [ { @@ -774,21 +767,17 @@ inflatehd - header decompressor The ``inflatehd`` reads JSON data from stdin and outputs decompressed name/value pairs in JSON. -The root JSON object must contain ``context`` key, which indicates -which compression context is used. If it is ``request``, request -compression context is used. Otherwise, response compression context -is used. The value of ``cases`` key contains the sequence of -compressed header block. They share the same compression context and -are processed in the order they appear. Each item in the sequence is a -JSON object and it must have at least ``wire`` key. Its value is a -string containing compressed header block in hex string. +The root JSON object must include ``cases`` key. Its value has to +include the sequence of compressed header block. They share the same +compression context and are processed in the order they appear. Each +item in the sequence is a JSON object and it must have at least +``wire`` key. Its value is a compressed header block in hex string. Example: .. code-block:: json { - "context": "request", "cases": [ { "wire": "8285" }, @@ -796,16 +785,14 @@ Example: ] } -The output is JSON object. It contains ``context`` key and its value -is ``request`` if the compression context is request, otherwise -``response``. The root JSON object also contains ``cases`` key and its +The output is JSON object. It should include ``cases`` key and its value is an array of JSON object, which has at least following keys: seq The index of header set in the input. headers - The JSON array contains decompressed name/value pairs. + The JSON array includes decompressed name/value pairs. wire The compressed header block in hex string. @@ -819,7 +806,6 @@ Example: .. code-block:: json { - "context": "request", "cases": [ { @@ -874,7 +860,7 @@ The output can be used as the input for ``deflatehd`` and ``inflatehd``. With ``-d`` option, the extra ``header_table`` key is added and its -associated value contains the state of dyanmic header table after the +associated value includes the state of dyanmic header table after the corresponding header set was processed. The format is the same as ``deflatehd``.