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