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


Reply via email to