Author: rhuijben
Date: Fri Nov 20 00:44:20 2015
New Revision: 1715309

URL: http://svn.apache.org/viewvc?rev=1715309&view=rev
Log:
Extend the hpack encoder with the first bits of dynamic table compression.

* buckets/hpack_buckets.c
  (hpack_int): Fix indentation.
  (serialize): Find existing item we can reuse and use that to optimize
    item encoding. Document that the dynamic table update is still
    missing.

Modified:
    serf/trunk/buckets/hpack_buckets.c

Modified: serf/trunk/buckets/hpack_buckets.c
URL: 
http://svn.apache.org/viewvc/serf/trunk/buckets/hpack_buckets.c?rev=1715309&r1=1715308&r2=1715309&view=diff
==============================================================================
--- serf/trunk/buckets/hpack_buckets.c (original)
+++ serf/trunk/buckets/hpack_buckets.c Fri Nov 20 00:44:20 2015
@@ -777,10 +777,10 @@ void serf__bucket_hpack_do(serf_bucket_t
 }
 
 static void hpack_int(unsigned char flags,
-                      int bits,
-                      apr_uint32_t value,
-                      char to[6],
-                      apr_size_t *used)
+                       int bits,
+                       apr_uint32_t value,
+                       char to[6],
+                       apr_size_t *used)
 {
     unsigned char max_direct;
     apr_size_t u;
@@ -813,13 +813,6 @@ static void hpack_int(unsigned char flag
 static apr_status_t
 serialize(serf_bucket_t *bucket)
 {
-  /* Quick and dirty write out headers for V2
-
-     Needs A LOT of improvement.
-
-     Currently implements a complete in memory copy to the least
-     efficient HTTP2 / HPACK header format
-   */
     serf_hpack_context_t *ctx = bucket->data;
     serf_bucket_alloc_t *alloc = bucket->allocator;
     serf_hpack_table_t *tbl = ctx->tbl;
@@ -850,11 +843,15 @@ serialize(serf_bucket_t *bucket)
     {
         apr_status_t status;
         apr_size_t len;
+        apr_uint32_t reuse = 0;
+        const serf_hpack_entry_t *e;
+        bool reuseVal = false;
+        apr_uint32_t i;
 
         next = entry->next;
 
         /* Make 100% sure the next entry will fit.
-           ### Temporarily wastes ram
+           ### Using the actual size later on is far more memory efficient
          */
         if (!buffer || (HPACK_ENTRY_SIZE(entry) > chunksize - offset))
         {
@@ -871,74 +868,137 @@ serialize(serf_bucket_t *bucket)
             offset = 0;
         }
 
-      /* Literal header, no indexing (=has a name) */
-        hpack_int(0x40, 6, 0, buffer + offset, &len);
-        offset += len;
+        for (i = 0; i < hpack_static_table_count; i++) {
+            e = &hpack_static_table[i];
 
-        /* ### TODO: Check if we can refer key or key+value by index */
+            if (e->key_len == entry->key_len
+                && !memcmp(e->key, entry->key, e->key_len))
+            {
+                if (e->value_len == entry->value_len
+                    && !memcmp(e->value, entry->value, e->value_len))
+                {
+                    reuse = i+1;
+                    reuseVal = true;
+                    break;
+                }
+                if (!reuse)
+                    reuse = i+1;
+            }
+        }
+        if (!reuseVal) {
+            for (e = tbl->lr_first; e; e = e->next) {
 
-        /* To huff or not... */
-        status = serf__hpack_huffman_encode(entry->key, entry->key_len,
-                                            0, NULL, &len);
-        if (!status && len < entry->key_len)
-        {
-            apr_size_t int_len;
+                i++;
 
-            /* It is more efficient to huffman encode */
-            hpack_int(0x80, 7, len, buffer + offset, &int_len);
-            offset += int_len;
+                if (e->key_len == entry->key_len
+                    && !memcmp(e->key, entry->key, e->key_len))
+                {
+                    if (e->value_len == entry->value_len
+                        && !memcmp(e->value, entry->value, e->value_len))
+                    {
+                        reuse = i;
+                        reuseVal = true;
+                        break;
+                    }
+                    if (!reuse)
+                        reuse = i;
+                }
+            }
+        }
 
-            status = serf__hpack_huffman_encode(entry->key, entry->key_len,
-                                                len,
-                                                (void*)(buffer + offset),
-                                                &len);
+        if (reuseVal) {
+            /* Nice, we have an exact match of key+value. We can
+               use those, but never index them. */
+            hpack_int(0x80, 7, reuse, buffer + offset, &len);
             offset += len;
-
-            if (status)
-                return status;
         }
-        else
-        {
-          /* It is more efficient not to encode */
-            hpack_int(0, 7, entry->key_len, buffer + offset, &len);
+        else if (!entry->dont_index) {
+            /* We reuse the header name, but will add our own value.
+               Or we don't reuse, but do index (value 0) */
+            hpack_int(0x40, 6, reuse, buffer + offset, &len);
+            offset += len;
+        }
+        else if (entry->dont_index == 2) {
+            /* Never index the value */
+            hpack_int(0x10, 4, reuse, buffer + offset, &len);
+            offset += len;
+        }
+        else {
+            hpack_int(0x00, 4, reuse, buffer + offset, &len);
             offset += len;
-
-            memcpy(buffer + offset, entry->key, entry->key_len);
-            offset += entry->key_len;
         }
 
-      /* To huff or not... */
-        status = serf__hpack_huffman_encode(entry->value, entry->value_len,
-                                            0, NULL, &len);
-        if (!status && len < entry->key_len)
-        {
-            apr_size_t int_len;
+        if (!reuse) {
 
-            /* It is more efficient to huffman encode */
-            hpack_int(0x80, 7, len, buffer + offset, &int_len);
-            offset += int_len;
-
-            status = serf__hpack_huffman_encode(entry->value,
-                                                entry->value_len,
-                                                len,
-                                                (void*)(buffer + offset),
-                                                &len);
-            offset += len;
+            /* To huff or not... */
+            status = serf__hpack_huffman_encode(entry->key, entry->key_len,
+                                                0, NULL, &len);
+            if (!status && len < entry->key_len)
+            {
+                apr_size_t int_len;
+
+                /* It is more efficient to huffman encode */
+                hpack_int(0x80, 7, len, buffer + offset, &int_len);
+                offset += int_len;
+
+                status = serf__hpack_huffman_encode(entry->key, entry->key_len,
+                                                    len,
+                                                    (void*)(buffer + offset),
+                                                    &len);
+                offset += len;
+
+                if (status)
+                    return status;
+            }
+            else
+            {
+              /* It is more efficient not to encode */
+                hpack_int(0x00, 7, entry->key_len, buffer + offset, &len);
+                offset += len;
+
+                memcpy(buffer + offset, entry->key, entry->key_len);
+                offset += entry->key_len;
+            }
 
-            if (status)
-                return status;
         }
-        else
-        {
-          /* It is more efficient not to encode */
-            hpack_int(0, 7, entry->value_len, buffer + offset, &len);
-            offset += len;
+        if (!reuseVal) {
+            /* To huff or not... */
+            status = serf__hpack_huffman_encode(entry->value, entry->value_len,
+                                                0, NULL, &len);
+            if (!status && len < entry->key_len)
+            {
+                apr_size_t int_len;
 
-            memcpy(buffer + offset, entry->value, entry->value_len);
-            offset += entry->value_len;
+                /* It is more efficient to huffman encode */
+                hpack_int(0x80, 7, len, buffer + offset, &int_len);
+                offset += int_len;
+
+                status = serf__hpack_huffman_encode(entry->value,
+                                                    entry->value_len,
+                                                    len,
+                                                    (void*)(buffer + offset),
+                                                    &len);
+                offset += len;
+
+                if (status)
+                    return status;
+            }
+            else
+            {
+              /* It is more efficient not to encode */
+                hpack_int(0x00, 7, entry->value_len, buffer + offset, &len);
+                offset += len;
+
+                memcpy(buffer + offset, entry->value, entry->value_len);
+                offset += entry->value_len;
+            }
         }
 
-      /* And now free the item */
+        /* ### TODO: Store the item in the lr dynamic table if we are allowed
+                     to do that. We currently 'forget' that step, so we only
+                     use pre-cached values */
+
+        /* And now free the item */
         hpack_free_entry(entry, alloc);
     }
     ctx->first = ctx->last = NULL;


Reply via email to