Cache-Cache and Binary Encoding

Just one more for the day... Looking at Cache-Control.. Currently the
cache-control header consists of a list of named directives that optionally
have associated values. The format is extensible which is great, but makes
things a bit more difficult to optimize. Let's look at a few random
examples...

  Cache-Control: public (6 bytes)
  Cache-Control: public, max-age=1600 (21 bytes)
  Cache-Control: no-store, no-transform, must-revalidate (39 bytes)

Let's see if we can do better.

First off, let's assume that Cache-Control on requests can have a different
encoding than Cache-Control on responses. For requests, let's make it:

 +----------+----------+---------------------+
 | no-cache | no-store |   no-transform      |
 +----------+-----+----+---------+-----------+
 | only-if-cached |xxxx| max-age | max-stale |
 +-----------+----+----+---------+-----------+
 | min-fresh | num-ext | repeating ext block |
 +-----------+-----+---+---------+-----------+

   no-cache       = 1 bit
   no-store       = 1 bit
   no-transform   = 1 bit
   only-of-cached = 1 bit
   xxx            = 4 reserved bits

   max-age        = uintvar
   max-stale      = uintvar
   min-fresh      = uintvar
   num-ext        = 1 byte

 repeating ext block =

 +---------------------------+
 |TYP|XXXXXX|len(key)|key|val|
 +---------------------------+

   TYP = 2 bit type code
         00 = Boolean, no val
         01 = Numeric, val is uintvar
         10 = Text, val is encoded text
         11 = Reserved
   XXXXXX = Reserved Bits

   if TYP is 00, then val is omitted. The idea is that this is a boolean
flag, like no-cache, no-store, etc. The key identifies the flag. Key is a
text label.

   if TYP is 01, then val is uintvar.

   if TYP is 02, then val is 2-byte length followed by encoded text

So if we look at examples, then,

  Cache-Control: no-cache  encodes as five-bytes
  Cache-Control: only-if-cached, max-age=1600, encodes as seven-bytes

Looking at the Cache-Control header for Responses we can do:

 +--------+---------+----------+-------------+
 | public | private | no-cache | no-transform|
 +--------+-+-------+----------+-----------+-+
 | no-store | must-revalidate  |proxy-reval|X|
 +----------+----------+-------+-----------+-+
 | max-age  | s-maxage | num-no-cache-headers|
 +----------+-------+--+---------------------+
 | no-cache-headers | num-private-headers    |
 +------------------+------------------------+
 |private-headers|num-ext|repeating ext block|
 +------------------+------------------------+

Same idea,

  public               = 1 bit
  private              = 1 bit
  no-cache             = 1 bit
  no-transform         = 1 bit
  no-store             = 1 bit
  must-revalidate      = 1 bit
  proxy-reval          = 1 bit
  X                    = reserved
  max-age              = uintvar
  s-maxage             = uintvar
  num-no-cache-headers = 1-byte
  no-cache-headers     = null-byte separated list of header names
  num-private-headers  = 1-byte
  private-headers      = null-byte separated list of header names

Examples...

  Cache-Control: public (encodes as 6 bytes)
  Cache-Control: public, max-age=1600 (encodes as 6 bytes, saving 17 bytes)
  Cache-Control: no-store, no-transform, must-revalidate (encodes as 6
bytes, saving 33 bytes)

So looking at these examples, it is definitely possible to save a lot of
space but at the cost of quite a bit of encoding-complexity. I'm sure we
could possibly do better but this provides a good starting point, and, it's
bidirectionally compatible with 1.1. Whether or not it's worth the effort
is a different question entirely.

- James

Received on Friday, 18 January 2013 19:59:44 UTC