Author: rhuijben Date: Sun Nov 1 00:42:46 2015 New Revision: 1711710 URL: http://svn.apache.org/viewvc?rev=1711710&view=rev Log: In the hpack bucket decoder: start applying table cleanups.
* buckets/hpack_buckets.c (serf_hpack_entry_t): Add don't index flag. (serf_hpack_table_t): Use apr_size_t. (serf__hpack_table_create): Store sizes. (hpack_shrink_table): Helper function to shrink a table. (serf__hpack_table_set_max_table_size, hpack_table_size_update): New function. (serf__bucket_hpack_setc): Update caller. (serf__bucket_hpack_setx): Add arguments to specify indexing behavior. (handle_read_entry_and_clear): Set last. (hpack_process): Forward size updates. Shrink table when done. * protocols/http2_buckets.h (serf__bucket_hpack_setx): Add two arguments. (serf__hpack_table_set_max_table_size): New function. * protocols/http2_protocol.c (serf_http2_protocol_t): Add tablesizes. (serf__http2_protocol_init): Store tablesizes. Initialize hpack table with the right (smaller) default value. Remove unused variable. (http2_handle_settings): Resolve todo. * protocols/http2_protocol.h (HTTP2_DEFAULT_HPACK_TABLE_SIZE): New define. Modified: serf/trunk/buckets/hpack_buckets.c serf/trunk/protocols/http2_buckets.h serf/trunk/protocols/http2_protocol.c serf/trunk/protocols/http2_protocol.h Modified: serf/trunk/buckets/hpack_buckets.c URL: http://svn.apache.org/viewvc/serf/trunk/buckets/hpack_buckets.c?rev=1711710&r1=1711709&r2=1711710&view=diff ============================================================================== --- serf/trunk/buckets/hpack_buckets.c (original) +++ serf/trunk/buckets/hpack_buckets.c Sun Nov 1 00:42:46 2015 @@ -255,6 +255,7 @@ typedef struct serf_hpack_entry_t char free_key; /* Key must be freed */ char free_val; /* Value must be freed */ + char dont_index; /* 0=index, 1=no-index, 2=never-index */ } serf_hpack_entry_t; static void hpack_free_entry(serf_hpack_entry_t *entry, @@ -289,14 +290,16 @@ struct serf_hpack_table_t serf_hpack_entry_t *lr_first, *lr_last, *lr_start; unsigned int lr_count; /* Number of items (first..last) */ unsigned int lr_indexable; /* Number of items (start..last) */ - unsigned int lr_size; /* 'Bytes' in list, calculated by HPACK_ENTRY_SIZE() */ - unsigned int lr_max_table_size; + apr_size_t lr_size; /* 'Bytes' in list, calculated by HPACK_ENTRY_SIZE() */ + apr_size_t lr_max_table_size; + apr_size_t lr_sys_table_size; serf_hpack_entry_t *rl_first, *rl_last, *rl_start; unsigned int rl_count; /* Number of items (first..last) */ unsigned int rl_indexable; /* Number of items (start..last) */ - unsigned int rl_size; /* 'Bytes' in list, calculated by HPACK_ENTRY_SIZE() */ - unsigned int rl_max_table_size; + apr_size_t rl_size; /* 'Bytes' in list, calculated by HPACK_ENTRY_SIZE() */ + apr_size_t rl_max_table_size; + apr_size_t rl_sys_table_size; }; /* The staticly defined list of pre-encoded entries. All numbers above @@ -382,8 +385,8 @@ serf__hpack_table_create(int for_http2, tbl->pool = result_pool; tbl->alloc = serf_bucket_allocator_create(result_pool, NULL, NULL); - tbl->lr_max_table_size = default_max_table_size; - tbl->rl_max_table_size = default_max_table_size; + tbl->lr_sys_table_size = tbl->lr_max_table_size = default_max_table_size; + tbl->rl_sys_table_size = tbl->rl_max_table_size = default_max_table_size; tbl->lowercase_keys = FALSE; tbl->send_tablesize_update = FALSE; @@ -401,6 +404,77 @@ serf__hpack_table_create(int for_http2, return tbl; } +static void +hpack_shrink_table(serf_hpack_entry_t **first, + serf_hpack_entry_t **start, + serf_hpack_entry_t **last, + apr_size_t *size, + apr_size_t max_size, + serf_bucket_alloc_t *allocator) +{ + while (*last && (*size > max_size)) + { + serf_hpack_entry_t *entry = *last; + + *last = entry->prev; + + if (start && (*start == entry)) + *start = NULL; + if (first && (*first == entry)) + *first = NULL; + + if (entry->prev) + entry->prev->next = NULL; + + *size -= HPACK_ENTRY_SIZE(entry); + hpack_free_entry(entry, allocator); + } +} + +void +serf__hpack_table_set_max_table_size(serf_hpack_table_t *hpack_tbl, + apr_size_t max_decoder_size, + apr_size_t max_encoder_size) +{ + if (max_decoder_size != hpack_tbl->rl_sys_table_size) + { + hpack_tbl->rl_sys_table_size = max_decoder_size; + } + + if (max_encoder_size != hpack_tbl->lr_max_table_size) + { + hpack_tbl->lr_sys_table_size = max_encoder_size; + + if (max_encoder_size > (128 * 1024)) + max_encoder_size = (128 * 1024); + + if (max_encoder_size < hpack_tbl->lr_max_table_size) + hpack_tbl->send_tablesize_update = TRUE; + + hpack_shrink_table(&hpack_tbl->lr_first, &hpack_tbl->lr_start, + &hpack_tbl->lr_last, &hpack_tbl->lr_size, + hpack_tbl->lr_max_table_size, hpack_tbl->alloc); + } +} + +static apr_status_t +hpack_table_size_update(serf_hpack_table_t *hpack_tbl, + apr_size_t size) +{ + if (size <= hpack_tbl->rl_sys_table_size) + { + hpack_tbl->rl_max_table_size = size; + + hpack_shrink_table(&hpack_tbl->rl_first, &hpack_tbl->rl_start, + &hpack_tbl->rl_last, &hpack_tbl->rl_size, + hpack_tbl->rl_max_table_size, hpack_tbl->alloc); + } + else + return SERF_ERROR_HTTP2_COMPRESSION_ERROR; + + return APR_SUCCESS; +} + static apr_status_t hpack_table_get(apr_uint64_t v, serf_hpack_table_t *tbl, @@ -532,7 +606,8 @@ serf__bucket_hpack_setc(serf_bucket_t *h { serf__bucket_hpack_setx(hpack_bucket, key, strlen(key), TRUE, - value, strlen(value), TRUE); + value, strlen(value), TRUE, + FALSE, FALSE); } void @@ -542,7 +617,9 @@ serf__bucket_hpack_setx(serf_bucket_t *h int key_copy, const char *value, apr_size_t value_size, - int value_copy) + int value_copy, + int dont_index, + int never_index) { serf_hpack_context_t *ctx = hpack_bucket->data; serf_hpack_entry_t *entry; @@ -567,6 +644,7 @@ serf__bucket_hpack_setx(serf_bucket_t *h entry->value = serf_bstrmemdup(ctx->alloc, value, value_size); entry->value_len = value_size; entry->free_val = TRUE; + entry->dont_index = never_index ? 2 : (dont_index ? 1 : 0); return; } @@ -618,6 +696,7 @@ serf__bucket_hpack_setx(serf_bucket_t *h entry->free_val = FALSE; } entry->value_len = value_size; + entry->dont_index = never_index ? 2 : (dont_index ? 1 : 0); entry->prev = ctx->last; entry->next = NULL; @@ -1138,6 +1217,8 @@ handle_read_entry_and_clear(serf_hpack_d tbl->rl_size += HPACK_ENTRY_SIZE(entry); if (entry->next) entry->next->prev = entry; + else + tbl->rl_last = entry; /* We don't update lr_start... that is the idea */ } @@ -1444,11 +1525,11 @@ hpack_process(serf_bucket_t *bucket) if (status) continue; - /* TODO: Store max size - Verify if it is in allowed range, etc. - The current code works, until we announce that we support - a bigger table size. We might store too much data though - */ + /* Send remote tablesize update to our table */ + if (v >= APR_SIZE_MAX) + return SERF_ERROR_HTTP2_COMPRESSION_ERROR; + status = hpack_table_size_update(ctx->tbl, (apr_size_t)v); + ctx->state = HPACK_DECODE_STATE_KIND; continue; } @@ -1465,8 +1546,13 @@ hpack_process(serf_bucket_t *bucket) if (!ctx->hit_eof) { + serf_hpack_table_t *tbl = ctx->tbl; ctx->hit_eof = TRUE; + hpack_shrink_table(&tbl->rl_first, &tbl->rl_start, + &tbl->rl_last, &tbl->rl_size, + tbl->rl_max_table_size, tbl->alloc); + if (!ctx->item_callback) { /* Write the final "\r\n" for http/1.1 compatibility */ Modified: serf/trunk/protocols/http2_buckets.h URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_buckets.h?rev=1711710&r1=1711709&r2=1711710&view=diff ============================================================================== --- serf/trunk/protocols/http2_buckets.h (original) +++ serf/trunk/protocols/http2_buckets.h Sun Nov 1 00:42:46 2015 @@ -130,7 +130,9 @@ serf__bucket_hpack_setx(serf_bucket_t *h int header_copy, const char *value, apr_size_t value_size, - int value_copy); + int value_copy, + int dont_index, + int never_index); const char * serf__bucket_hpack_getc(serf_bucket_t *hpack_bucket, @@ -167,6 +169,12 @@ serf__hpack_table_create(int for_http2, apr_size_t default_max_table_size, apr_pool_t *result_pool); +void +serf__hpack_table_set_max_table_size(serf_hpack_table_t *hpack_tbl, + apr_size_t max_decoder_size, + apr_size_t max_encoder_size); + + /* ==================================================================== */ extern const serf_bucket_type_t serf_bucket_type__hpack_decode; #define SERF_BUCKET_IS_HPACK_DECODE(b) SERF_BUCKET_CHECK((b), hpack_decode) Modified: serf/trunk/protocols/http2_protocol.c URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.c?rev=1711710&r1=1711709&r2=1711710&view=diff ============================================================================== --- serf/trunk/protocols/http2_protocol.c (original) +++ serf/trunk/protocols/http2_protocol.c Sun Nov 1 00:42:46 2015 @@ -151,6 +151,7 @@ struct serf_http2_protocol_t apr_uint32_t lr_max_framesize; apr_uint32_t lr_max_headersize; apr_uint32_t lr_max_concurrent; + apr_uint32_t lr_hpack_table_size; apr_int32_t lr_next_streamid; char lr_push_enabled; @@ -160,6 +161,7 @@ struct serf_http2_protocol_t apr_uint32_t rl_max_framesize; apr_uint32_t rl_max_headersize; apr_uint32_t rl_max_concurrent; + apr_uint32_t rl_hpack_table_size; apr_int32_t rl_next_streamid; char rl_push_enabled; @@ -216,6 +218,7 @@ void serf__http2_protocol_init(serf_conn h2->rl_max_framesize = HTTP2_DEFAULT_MAX_FRAMESIZE; h2->rl_max_headersize = APR_UINT32_MAX; h2->rl_max_concurrent = HTTP2_DEFAULT_MAX_CONCURRENT; + h2->rl_hpack_table_size = HTTP2_DEFAULT_HPACK_TABLE_SIZE; h2->rl_push_enabled = TRUE; h2->lr_default_window = HTTP2_DEFAULT_WINDOW_SIZE; @@ -224,6 +227,7 @@ void serf__http2_protocol_init(serf_conn h2->lr_max_framesize = HTTP2_DEFAULT_MAX_FRAMESIZE; h2->lr_max_headersize = APR_UINT32_MAX; h2->lr_max_concurrent = HTTP2_DEFAULT_MAX_CONCURRENT; + h2->lr_hpack_table_size = HTTP2_DEFAULT_HPACK_TABLE_SIZE; h2->lr_push_enabled = TRUE; h2->setting_acks = 0; @@ -233,7 +237,9 @@ void serf__http2_protocol_init(serf_conn h2->first = h2->last = NULL; - h2->hpack_tbl = serf__hpack_table_create(TRUE, 16384, protocol_pool); + h2->hpack_tbl = serf__hpack_table_create(TRUE, + HTTP2_DEFAULT_HPACK_TABLE_SIZE, + protocol_pool); apr_pool_cleanup_register(protocol_pool, conn, http2_protocol_cleanup, apr_pool_cleanup_null); @@ -255,7 +261,6 @@ void serf__http2_protocol_init(serf_conn /* And now a settings frame and a huge window */ { - serf_bucket_t *settings; serf_bucket_t *window_size; tmp = serf__bucket_http2_frame_create(NULL, HTTP2_FRAME_TYPE_SETTINGS, 0, @@ -623,9 +628,11 @@ http2_handle_settings(void *baton, switch (id) { case HTTP2_SETTING_HEADER_TABLE_SIZE: - /* TODO: Send to hpack table */ serf__log(LOGLVL_INFO, SERF_LOGHTTP2, h2->config, "Setting HPACK Table size to %u\n", value); + serf__hpack_table_set_max_table_size(h2->hpack_tbl, + h2->rl_hpack_table_size, + value); break; case HTTP2_SETTING_ENABLE_PUSH: serf__log(LOGLVL_INFO, SERF_LOGHTTP2, h2->config, Modified: serf/trunk/protocols/http2_protocol.h URL: http://svn.apache.org/viewvc/serf/trunk/protocols/http2_protocol.h?rev=1711710&r1=1711709&r2=1711710&view=diff ============================================================================== --- serf/trunk/protocols/http2_protocol.h (original) +++ serf/trunk/protocols/http2_protocol.h Sun Nov 1 00:42:46 2015 @@ -45,6 +45,7 @@ extern "C" { /* The default stream and connection window size before updates */ #define HTTP2_DEFAULT_WINDOW_SIZE 65535 #define HTTP2_DEFAULT_MAX_CONCURRENT 0xFFFFFFFF +#define HTTP2_DEFAULT_HPACK_TABLE_SIZE 4096 #define HTTP2_PRIORITY_DATA_SIZE 5 #define HTTP2_RST_DATA_SIZE 4