Bug 958992 - http/2 draft09 support. r=mcmanus
authorNicholas Hurley <hurley@todesschaf.org>
Mon, 13 Jan 2014 17:16:26 -0800
changeset 163232 5475b2719136aa2d4d319a20d63fcd03983b19bf
parent 163231 79595e16949f7a7e3d6aeb1e2ac409f0be4fee5b
child 163233 b114534a9386a426a8e95075c15690fc2fb06750
push id25986
push userkwierso@gmail.com
push dateTue, 14 Jan 2014 04:44:33 +0000
treeherdermozilla-central@b114534a9386 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs958992
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 958992 - http/2 draft09 support. r=mcmanus
netwerk/protocol/http/Http2Compression.cpp
netwerk/protocol/http/nsHttp.h
--- a/netwerk/protocol/http/Http2Compression.cpp
+++ b/netwerk/protocol/http/Http2Compression.cpp
@@ -76,16 +76,17 @@ InitializeStaticHeaders()
     AddStaticElement(NS_LITERAL_CSTRING("content-range"));
     AddStaticElement(NS_LITERAL_CSTRING("content-type"));
     AddStaticElement(NS_LITERAL_CSTRING("cookie"));
     AddStaticElement(NS_LITERAL_CSTRING("date"));
     AddStaticElement(NS_LITERAL_CSTRING("etag"));
     AddStaticElement(NS_LITERAL_CSTRING("expect"));
     AddStaticElement(NS_LITERAL_CSTRING("expires"));
     AddStaticElement(NS_LITERAL_CSTRING("from"));
+    AddStaticElement(NS_LITERAL_CSTRING("host"));
     AddStaticElement(NS_LITERAL_CSTRING("if-match"));
     AddStaticElement(NS_LITERAL_CSTRING("if-modified-since"));
     AddStaticElement(NS_LITERAL_CSTRING("if-none-match"));
     AddStaticElement(NS_LITERAL_CSTRING("if-range"));
     AddStaticElement(NS_LITERAL_CSTRING("if-unmodified-since"));
     AddStaticElement(NS_LITERAL_CSTRING("last-modified"));
     AddStaticElement(NS_LITERAL_CSTRING("link"));
     AddStaticElement(NS_LITERAL_CSTRING("location"));
@@ -429,17 +430,32 @@ Http2Decompressor::OutputHeader(const ns
   if(*(name.BeginReading()) == ':') {
     LOG3(("HTTP Decompressor not gatewaying %s into http/1",
           name.BeginReading()));
     return NS_OK;
   }
 
   mOutput->Append(name);
   mOutput->Append(NS_LITERAL_CSTRING(": "));
-  mOutput->Append(value);
+  // Special handling for set-cookie according to the spec
+  bool isSetCookie = name.Equals(NS_LITERAL_CSTRING("set-cookie"));
+  int32_t valueLen = value.Length();
+  for (int32_t i = 0; i < valueLen; ++i) {
+    if (value[i] == '\0') {
+      if (isSetCookie) {
+        mOutput->Append(NS_LITERAL_CSTRING("\r\n"));
+        mOutput->Append(name);
+        mOutput->Append(NS_LITERAL_CSTRING(": "));
+      } else {
+        mOutput->Append(NS_LITERAL_CSTRING(", "));
+      }
+    } else {
+      mOutput->Append(value[i]);
+    }
+  }
   mOutput->Append(NS_LITERAL_CSTRING("\r\n"));
   return NS_OK;
 }
 
 nsresult
 Http2Decompressor::OutputHeader(uint32_t index)
 {
   // bounds check
@@ -683,16 +699,24 @@ Http2Decompressor::DoIndexed()
 
   uint32_t index;
   nsresult rv = DecodeInteger(7, index);
   if (NS_FAILED(rv))
     return rv;
 
   LOG3(("HTTP decompressor indexed entry %u\n", index));
 
+  if (index == 0) {
+    // Index 0 is a special case - it clear out the reference set
+    mReferenceSet.Clear();
+    mAlternateReferenceSet.Clear();
+    return NS_OK;
+  }
+  index--; // Internally, we 0-index everything, since this is, y'know, C++
+
   // Toggle this in the reference set..
   // if its not currently in the reference set then add it and
   // also emit it. If it is currently in the reference set then just
   // remove it from there.
   if (mReferenceSet.RemoveElement(index)) {
     mAlternateReferenceSet.RemoveElement(index);
     return NS_OK;
   }
@@ -917,17 +941,35 @@ Http2Compressor::EncodeHeaderBlock(const
 
     if (name.Equals("content-length")) {
       int64_t len;
       nsCString tmp(value);
       if (nsHttp::ParseInt64(tmp.get(), nullptr, &len))
         mParsedContentLength = len;
     }
 
-    ProcessHeader(nvPair(name, value));
+    if (name.Equals("cookie")) {
+      // cookie crumbling
+      bool haveMoreCookies = true;
+      int32_t nextCookie = valueIndex;
+      while (haveMoreCookies) {
+        int32_t semiSpaceIndex = nvInput.Find("; ", false, nextCookie,
+                                              crlfIndex - nextCookie);
+        if (semiSpaceIndex == -1) {
+          haveMoreCookies = false;
+          semiSpaceIndex = crlfIndex;
+        }
+        nsDependentCSubstring cookie = Substring(beginBuffer + nextCookie,
+                                                 beginBuffer + semiSpaceIndex);
+        ProcessHeader(nvPair(name, cookie));
+        nextCookie = semiSpaceIndex + 2;
+      }
+    } else {
+      ProcessHeader(nvPair(name, value));
+    }
   }
 
   // iterate mreference set and if !alternate.contains(old[i])
   // toggle off
   uint32_t setLen = mReferenceSet.Length();
   for (uint32_t index = 0; index < setLen; ++index) {
     if (!mAlternateReferenceSet.Contains(mReferenceSet[index])) {
       DoOutput(kToggleOff, mHeaderTable[mReferenceSet[index]],
@@ -952,48 +994,54 @@ Http2Compressor::DoOutput(Http2Compresso
   uint32_t offset = mOutput->Length();
   uint8_t *startByte;
 
   switch (code) {
   case kPlainLiteral:
     LOG3(("HTTP compressor %p noindex literal with name reference %u %s: %s\n",
           this, index, pair->mName.get(), pair->mValue.get()));
 
+    // In this case, the index will have already been adjusted to be 1-based
+    // instead of 0-based.
     EncodeInteger(6, index); // 01 2 bit prefix
     startByte = reinterpret_cast<unsigned char *>(mOutput->BeginWriting()) + offset;
     *startByte = (*startByte & 0x3f) | 0x40;
 
     if (!index) {
       HuffmanAppend(pair->mName);
     }
 
     HuffmanAppend(pair->mValue);
     break;
 
   case kIndexedLiteral:
     LOG3(("HTTP compressor %p literal with name reference %u %s: %s\n",
           this, index, pair->mName.get(), pair->mValue.get()));
 
+    // In this case, the index will have already been adjusted to be 1-based
+    // instead of 0-based.
     EncodeInteger(6, index); // 00 2 bit prefix
     startByte = reinterpret_cast<unsigned char *>(mOutput->BeginWriting()) + offset;
     *startByte = *startByte & 0x3f;
 
     if (!index) {
       HuffmanAppend(pair->mName);
     }
 
     HuffmanAppend(pair->mValue);
     break;
 
   case kToggleOff:
   case kToggleOn:
     LOG3(("HTTP compressor %p toggle %s index %u %s\n",
           this, (code == kToggleOff) ? "off" : "on",
           index, pair->mName.get()));
-    EncodeInteger(7, index);
+    // In this case, we are passed the raw 0-based C index, and need to
+    // increment to make it 1-based and comply with the spec
+    EncodeInteger(7, index + 1);
     startByte = reinterpret_cast<unsigned char *>(mOutput->BeginWriting()) + offset;
     *startByte = *startByte | 0x80; // 1 1 bit prefix
     break;
 
   case kNop:
     LOG3(("HTTP compressor %p implied in reference set index %u %s\n",
           this, index, pair->mName.get()));
     break;
--- a/netwerk/protocol/http/nsHttp.h
+++ b/netwerk/protocol/http/nsHttp.h
@@ -26,23 +26,24 @@ namespace net {
     enum {
         SPDY_VERSION_2_REMOVED = 2,
         SPDY_VERSION_3 = 3,
         SPDY_VERSION_31 = 4,
 
         // leave room for official versions. telem goes to 48
         // 24 was a internal spdy/3.1
         // 25 was spdy/4a2
-        HTTP2_VERSION_DRAFT08 = 26
+        // 26 was http/2-draft08 and http/2-draft07 (they were the same)
+        HTTP2_VERSION_DRAFT09 = 27
     };
 
 typedef uint8_t nsHttpVersion;
 
-#define NS_HTTP2_DRAFT_VERSION HTTP2_VERSION_DRAFT08
-#define NS_HTTP2_DRAFT_TOKEN "HTTP-draft-08/2.0"
+#define NS_HTTP2_DRAFT_VERSION HTTP2_VERSION_DRAFT09
+#define NS_HTTP2_DRAFT_TOKEN "HTTP-draft-09/2.0"
 
 //-----------------------------------------------------------------------------
 // http connection capabilities
 //-----------------------------------------------------------------------------
 
 #define NS_HTTP_ALLOW_KEEPALIVE      (1<<0)
 #define NS_HTTP_ALLOW_PIPELINING     (1<<1)