Bug 1001022 part 1 - http/2 draft 12 client implementation. r=mcmanus
authorNicholas Hurley <hurley@todesschaf.org>
Tue, 29 Apr 2014 18:46:03 -0700
changeset 180906 3125aa54ca3efa8015fcae12ffb5ead3db50d215
parent 180905 7e0fe75355879100c4be21001a0682ec9ae62dce
child 180907 b5e2228862e84b2c6437ed478648ab157434326b
push id26686
push usercbook@mozilla.com
push dateWed, 30 Apr 2014 13:00:57 +0000
treeherdermozilla-central@c8b374bf936b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus
bugs1001022
milestone32.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 1001022 part 1 - http/2 draft 12 client implementation. r=mcmanus
netwerk/protocol/http/Http2Push.cpp
netwerk/protocol/http/Http2Session.cpp
netwerk/protocol/http/Http2Session.h
netwerk/protocol/http/Http2Stream.cpp
netwerk/protocol/http/Http2Stream.h
netwerk/protocol/http/nsHttp.h
--- a/netwerk/protocol/http/Http2Push.cpp
+++ b/netwerk/protocol/http/Http2Push.cpp
@@ -38,20 +38,17 @@ Http2PushedStream::Http2PushedStream(Htt
   , mDeferCleanupOnSuccess(true)
 {
   LOG3(("Http2PushedStream ctor this=%p 0x%X\n", this, aID));
   mStreamID = aID;
   MOZ_ASSERT(!(aID & 1)); // must be even to be a pushed stream
   mBufferedPush->SetPushStream(this);
   mLoadGroupCI = aAssociatedStream->LoadGroupConnectionInfo();
   mLastRead = TimeStamp::Now();
-  uint32_t priorityGroup = aAssociatedStream->Priority() + 1;
-  uint8_t priorityGroupWeight = (nsISupportsPriority::PRIORITY_LOWEST + 1) -
-    (priorityGroup - kNormalPriority);
-  SetPriorityGroup(priorityGroup, priorityGroupWeight);
+  SetPriority(aAssociatedStream->Priority() + 1);
 }
 
 bool
 Http2PushedStream::GetPushComplete()
 {
   return mPushCompleted;
 }
 
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -225,17 +225,18 @@ static Http2ControlFx sControlFunctions[
   Http2Session::RecvPriority,
   Http2Session::RecvRstStream,
   Http2Session::RecvSettings,
   Http2Session::RecvPushPromise,
   Http2Session::RecvPing,
   Http2Session::RecvGoAway,
   Http2Session::RecvWindowUpdate,
   Http2Session::RecvContinuation,
-  Http2Session::RecvAltSvc
+  Http2Session::RecvAltSvc,
+  Http2Session::RecvBlocked
 };
 
 bool
 Http2Session::RoomForMoreConcurrent()
 {
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
   return (mConcurrent < mMaxConcurrent);
 }
@@ -694,30 +695,28 @@ Http2Session::GenerateSettingsAck()
   char *packet = EnsureOutputBuffer(8);
   mOutputQueueUsed += 8;
   CreateFrameHeader(packet, 0, FRAME_TYPE_SETTINGS, kFlag_ACK, 0);
   LogIO(this, nullptr, "Generate Settings ACK", packet, 8);
   FlushOutputQueue();
 }
 
 void
-Http2Session::GeneratePriority(uint32_t aID, uint32_t aPriorityGroup,
-                               uint8_t aPriorityGroupWeight)
+Http2Session::GeneratePriority(uint32_t aID, uint8_t aPriorityWeight)
 {
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
-  LOG3(("Http2Session::GeneratePriority %p %X %X %X\n",
-        this, aID, aPriorityGroup, aPriorityGroupWeight));
+  LOG3(("Http2Session::GeneratePriority %p %X %X\n",
+        this, aID, aPriorityWeight));
 
   char *packet = EnsureOutputBuffer(13);
   mOutputQueueUsed += 13;
 
-  CreateFrameHeader(packet, 5, FRAME_TYPE_PRIORITY, kFlag_PRIORITY_GROUP, aID);
-  aPriorityGroup = PR_htonl(aPriorityGroup);
-  memcpy(packet + 8, &aPriorityGroup, 4);
-  memcpy(packet + 12, &aPriorityGroupWeight, 1);
+  CreateFrameHeader(packet, 5, FRAME_TYPE_PRIORITY, 0, aID);
+  memset(packet + 8, 0, 4);
+  memcpy(packet + 12, &aPriorityWeight, 1);
   LogIO(this, nullptr, "Generate Priority", packet, 13);
   FlushOutputQueue();
 }
 
 void
 Http2Session::GenerateRstStream(uint32_t aStatusCode, uint32_t aID)
 {
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
@@ -775,33 +774,34 @@ Http2Session::GenerateGoAway(uint32_t aS
 void
 Http2Session::SendHello()
 {
   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
   LOG3(("Http2Session::SendHello %p\n", this));
 
   // sized for magic + 2 settings and a session window update to follow
   // 24 magic, 23 for settings (8 header + 3 settings @5), 12 for window update
-  static const uint32_t maxSettings = 3;
+  static const uint32_t maxSettings = 4;
   static const uint32_t maxDataLen = 24 + 8 + maxSettings * 5 + 12;
   char *packet = EnsureOutputBuffer(maxDataLen);
   memcpy(packet, kMagicHello, 24);
   mOutputQueueUsed += 24;
   LogIO(this, nullptr, "Magic Connection Header", packet, 24);
 
   packet = mOutputQueueBuffer.get() + mOutputQueueUsed;
   memset(packet, 0, maxDataLen - 24);
 
   // frame header will be filled in after we know how long the frame is
   uint8_t numberOfEntries = 0;
 
   // entries need to be listed in order by ID
   // 1st entry is bytes 8 to 12
   // 2nd entry is bytes 13 to 17
   // 3rd entry is bytes 18 to 22
+  // 4th entry is bytes 23 to 17
 
   if (!gHttpHandler->AllowPush()) {
     // If we don't support push then set MAX_CONCURRENT to 0 and also
     // set ENABLE_PUSH to 0
     packet[8 + 5 * numberOfEntries] = SETTINGS_TYPE_ENABLE_PUSH;
     // The value portion of the setting pair is already initialized to 0
     numberOfEntries++;
 
@@ -812,16 +812,22 @@ Http2Session::SendHello()
 
   // Advertise the Push RWIN for the session, and on each new pull stream
   // send a window update with END_FLOW_CONTROL
   packet[8 + 5 * numberOfEntries] = SETTINGS_TYPE_INITIAL_WINDOW;
   uint32_t rwin = PR_htonl(mPushAllowance);
   memcpy(packet + 9 + 5 * numberOfEntries, &rwin, 4);
   numberOfEntries++;
 
+  // Explicitly signal that we do NOT support compressed data frames, even
+  // though the default is to not support anyway.
+  packet[8 + 5 * numberOfEntries] = SETTINGS_TYPE_COMPRESS_DATA;
+  // The value portion of the setting pair is already initialized to 0
+  numberOfEntries++;
+
   MOZ_ASSERT(numberOfEntries <= maxSettings);
   uint32_t dataLen = 5 * numberOfEntries;
   CreateFrameHeader(packet, dataLen, FRAME_TYPE_SETTINGS, 0, 0);
   mOutputQueueUsed += 8 + dataLen;
 
   LogIO(this, nullptr, "Generate Settings", packet, 8 + dataLen);
 
   // now bump the local session window from 64KB
@@ -1051,47 +1057,39 @@ Http2Session::RecvHeaders(Http2Session *
   // frame to be HEADERS of the same ID
   bool endHeadersFlag = self->mInputFrameFlags & kFlag_END_HEADERS;
 
   if (endHeadersFlag)
     self->mExpectedHeaderID = 0;
   else
     self->mExpectedHeaderID = self->mInputFrameID;
 
-  if ((self->mInputFrameFlags & kFlag_PRIORITY_GROUP) &&
-      (self->mInputFrameFlags & kFlag_PRIORITY_DEPENDENCY)) {
-    RETURN_SESSION_ERROR(self, PROTOCOL_ERROR);
-  }
-
   uint32_t priorityLen = 0;
-  if (self->mInputFrameFlags & kFlag_PRIORITY_GROUP) {
+  if (self->mInputFrameFlags & kFlag_PRIORITY) {
     priorityLen = 5;
-  } else if (self->mInputFrameFlags & kFlag_PRIORITY_DEPENDENCY) {
-    priorityLen = 4;
   }
   self->SetInputFrameDataStream(self->mInputFrameID);
 
   // Find out how much padding this frame has, so we can only extract the real
   // header data from the frame.
   uint16_t paddingLength = 0;
   uint8_t paddingControlBytes = 0;
 
   nsresult rv = self->ParsePadding(paddingControlBytes, paddingLength);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   LOG3(("Http2Session::RecvHeaders %p stream 0x%X priorityLen=%d stream=%p "
-        "end_stream=%d end_headers=%d priority_group=%d priority_dependency=%d "
+        "end_stream=%d end_headers=%d priority_group=%d "
         "paddingLength=%d pad_high_flag=%d pad_low_flag=%d\n",
         self, self->mInputFrameID, priorityLen, self->mInputFrameDataStream,
         self->mInputFrameFlags & kFlag_END_STREAM,
         self->mInputFrameFlags & kFlag_END_HEADERS,
-        self->mInputFrameFlags & kFlag_PRIORITY_GROUP,
-        self->mInputFrameFlags & kFlag_PRIORITY_DEPENDENCY,
+        self->mInputFrameFlags & kFlag_PRIORITY,
         paddingLength,
         self->mInputFrameFlags & kFlag_PAD_HIGH,
         self->mInputFrameFlags & kFlag_PAD_LOW));
 
   if (!self->mInputFrameDataStream) {
     // Cannot find stream. We can continue the session, but we need to
     // uncompress the header block to maintain the correct compression context
 
@@ -1172,69 +1170,40 @@ Http2Session::ResponseHeadersComplete()
   return NS_OK;
 }
 
 nsresult
 Http2Session::RecvPriority(Http2Session *self)
 {
   MOZ_ASSERT(self->mInputFrameType == FRAME_TYPE_PRIORITY);
 
-  if ((self->mInputFrameFlags & kFlag_PRIORITY_GROUP) &&
-      (self->mInputFrameFlags & kFlag_PRIORITY_DEPENDENCY)) {
-    self->GenerateRstStream(PROTOCOL_ERROR, self->mInputFrameID);
-    self->ResetDownstreamState();
-    return NS_OK;
-  }
-
-  if (!(self->mInputFrameFlags & (kFlag_PRIORITY_GROUP | kFlag_PRIORITY_DEPENDENCY))) {
-    self->GenerateRstStream(PROTOCOL_ERROR, self->mInputFrameID);
-    self->ResetDownstreamState();
-    return NS_OK;
-  }
-
-  uint32_t dataLength = 0;
-  if (self->mInputFrameFlags & kFlag_PRIORITY_GROUP) {
-    dataLength = 5;
-  } else { // self->mInputFrameFlags & kFlag_PRIORITY_DEPENDENCY
-    dataLength = 4;
-  }
-
-  if (self->mInputFrameDataSize != dataLength) {
+  if (self->mInputFrameDataSize != 5) {
     LOG3(("Http2Session::RecvPriority %p wrong length data=%d\n",
           self, self->mInputFrameDataSize));
     RETURN_SESSION_ERROR(self, PROTOCOL_ERROR);
   }
 
   if (!self->mInputFrameID) {
     LOG3(("Http2Session::RecvPriority %p stream ID of 0.\n", self));
     RETURN_SESSION_ERROR(self, PROTOCOL_ERROR);
   }
 
   nsresult rv = self->SetInputFrameDataStream(self->mInputFrameID);
   if (NS_FAILED(rv))
     return rv;
 
-  if (self->mInputFrameFlags & kFlag_PRIORITY_GROUP) {
-    uint32_t newPriorityGroup =
-      PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
-    newPriorityGroup &= 0x7fffffff;
-    uint8_t newPriorityGroupWeight = *(self->mInputFrameBuffer.get() + 12);
-    if (self->mInputFrameDataStream) {
-      self->mInputFrameDataStream->SetPriorityGroup(newPriorityGroup,
-                                                    newPriorityGroupWeight);
-    }
-  } else { // self->mInputFrameFlags & kFlag_PRIORITY_DEPENDENCY
-    uint32_t newPriorityDependency =
-      PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
-    bool exclusive = !!(newPriorityDependency & 0x80000000);
-    newPriorityDependency &= 0x7fffffff;
-    if (self->mInputFrameDataStream) {
-      self->mInputFrameDataStream->SetPriorityDependency(newPriorityDependency,
-                                                         exclusive);
-    }
+  uint32_t newPriorityDependency =
+    PR_ntohl(reinterpret_cast<uint32_t *>(self->mInputFrameBuffer.get())[2]);
+  bool exclusive = !!(newPriorityDependency & 0x80000000);
+  newPriorityDependency &= 0x7fffffff;
+  uint8_t newPriorityWeight = *(self->mInputFrameBuffer.get() + 12);
+  if (self->mInputFrameDataStream) {
+    self->mInputFrameDataStream->SetPriorityDependency(newPriorityDependency,
+                                                       newPriorityWeight,
+                                                       exclusive);
   }
 
   self->ResetDownstreamState();
   return NS_OK;
 }
 
 nsresult
 Http2Session::RecvRstStream(Http2Session *self)
@@ -1343,16 +1312,21 @@ Http2Session::RecvSettings(Http2Session 
 
         // SETTINGS only adjusts stream windows. Leave the sesison window alone.
         // we need to add the delta to all open streams (delta can be negative)
         self->mStreamTransactionHash.Enumerate(UpdateServerRwinEnumerator,
                                                &delta);
       }
       break;
 
+    case SETTINGS_TYPE_COMPRESS_DATA:
+      LOG3(("Received DATA compression setting: %d\n", value));
+      // nop
+      break;
+
     default:
       break;
     }
   }
 
   self->ResetDownstreamState();
 
   if (!(self->mInputFrameFlags & kFlag_ACK))
@@ -1552,21 +1526,20 @@ Http2Session::RecvPushPromise(Http2Sessi
     LOG3(("Http2Session::RecvPushPromise registerPushedStream Failed\n"));
     self->CleanupStream(pushedStream, NS_ERROR_FAILURE, INTERNAL_ERROR);
     self->ResetDownstreamState();
     return NS_OK;
   }
 
   static_assert(Http2Stream::kWorstPriority >= 0,
                 "kWorstPriority out of range");
-  uint32_t unsignedPriorityGroup = static_cast<uint32_t>(Http2Stream::kWorstPriority);
-  uint8_t priorityGroupWeight = (nsISupportsPriority::PRIORITY_LOWEST + 1) -
+  uint8_t priorityWeight = (nsISupportsPriority::PRIORITY_LOWEST + 1) -
     (Http2Stream::kWorstPriority - Http2Stream::kNormalPriority);
-  pushedStream->SetPriority(unsignedPriorityGroup);
-  self->GeneratePriority(promisedID, unsignedPriorityGroup, priorityGroupWeight);
+  pushedStream->SetPriority(Http2Stream::kWorstPriority);
+  self->GeneratePriority(promisedID, priorityWeight);
   self->ResetDownstreamState();
   return NS_OK;
 }
 
 nsresult
 Http2Session::RecvPing(Http2Session *self)
 {
   MOZ_ASSERT(self->mInputFrameType == FRAME_TYPE_PING);
@@ -1771,18 +1744,17 @@ Http2Session::RecvContinuation(Http2Sess
   if (!self->mInputFrameDataStream) {
     LOG3(("Http2Session::RecvContination stream ID 0x%X not found.",
           self->mInputFrameID));
     RETURN_SESSION_ERROR(self, PROTOCOL_ERROR);
   }
 
   // continued headers
   if (self->mExpectedHeaderID) {
-    self->mInputFrameFlags &= ~kFlag_PRIORITY_GROUP;
-    self->mInputFrameFlags &= ~kFlag_PRIORITY_DEPENDENCY;
+    self->mInputFrameFlags &= ~kFlag_PRIORITY;
     return RecvHeaders(self);
   }
 
   // continued push promise
   if (self->mInputFrameFlags & kFlag_END_HEADERS) {
     self->mInputFrameFlags &= ~kFlag_END_HEADERS;
     self->mInputFrameFlags |= kFlag_END_PUSH_PROMISE;
   }
@@ -1796,16 +1768,31 @@ Http2Session::RecvAltSvc(Http2Session *s
   LOG3(("Http2Session::RecvAltSvc %p Flags 0x%X id 0x%X\n", self,
         self->mInputFrameFlags, self->mInputFrameID));
 
   // For now, we don't do anything with ALTSVC frames
   self->ResetDownstreamState();
   return NS_OK;
 }
 
+nsresult
+Http2Session::RecvBlocked(Http2Session *self)
+{
+  MOZ_ASSERT(self->mInputFrameType == FRAME_TYPE_BLOCKED);
+  LOG3(("Http2Session::RecvBlocked %p id 0x%X\n", self, self->mInputFrameID));
+
+  if (self->mInputFrameDataSize) {
+    RETURN_SESSION_ERROR(self, FRAME_SIZE_ERROR);
+  }
+
+  // Logging is all we do with BLOCKED for now
+  self->ResetDownstreamState();
+  return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 // nsAHttpTransaction. It is expected that nsHttpConnection is the caller
 // of these methods
 //-----------------------------------------------------------------------------
 
 void
 Http2Session::OnTransportStatus(nsITransport* aTransport,
                                 nsresult aStatus, uint64_t aProgress)
@@ -1969,16 +1956,22 @@ Http2Session::ReadyToProcessDataFrame(en
   mLastDataReadEpoch = mLastReadEpoch;
 
   if (!mInputFrameID) {
     LOG3(("Http2Session::ReadyToProcessDataFrame %p data frame stream 0\n",
           this));
     RETURN_SESSION_ERROR(this, PROTOCOL_ERROR);
   }
 
+  if (mInputFrameFlags & kFlag_COMPRESSED) {
+    LOG3(("Http2Session::ReadyToProcessDataFrame %p streamID 0x%X compressed\n",
+          this, mInputFrameID));
+    RETURN_SESSION_ERROR(this, PROTOCOL_ERROR);
+  }
+
   nsresult rv = SetInputFrameDataStream(mInputFrameID);
   if (NS_FAILED(rv)) {
     LOG3(("Http2Session::ReadyToProcessDataFrame %p lookup streamID 0x%X "
           "failed. probably due to verification.\n", this, mInputFrameID));
     return rv;
   }
   if (!mInputFrameDataStream) {
     LOG3(("Http2Session::ReadyToProcessDataFrame %p lookup streamID 0x%X "
--- a/netwerk/protocol/http/Http2Session.h
+++ b/netwerk/protocol/http/Http2Session.h
@@ -78,17 +78,18 @@ public:
     FRAME_TYPE_RST_STREAM = 3,
     FRAME_TYPE_SETTINGS = 4,
     FRAME_TYPE_PUSH_PROMISE = 5,
     FRAME_TYPE_PING = 6,
     FRAME_TYPE_GOAWAY = 7,
     FRAME_TYPE_WINDOW_UPDATE = 8,
     FRAME_TYPE_CONTINUATION = 9,
     FRAME_TYPE_ALTSVC = 10,
-    FRAME_TYPE_LAST = 11
+    FRAME_TYPE_BLOCKED = 11,
+    FRAME_TYPE_LAST = 12
   };
 
   // NO_ERROR is a macro defined on windows, so we'll name the HTTP2 goaway
   // code NO_ERROR to be NO_HTTP_ERROR
   enum errorType {
     NO_HTTP_ERROR = 0,
     PROTOCOL_ERROR = 1,
     INTERNAL_ERROR = 2,
@@ -108,24 +109,25 @@ public:
   // used on frames other than the comments indicate they MUST be ignored.
   const static uint8_t kFlag_END_STREAM = 0x01; // data, headers
   const static uint8_t kFlag_END_HEADERS = 0x04; // headers, continuation
   const static uint8_t kFlag_END_PUSH_PROMISE = 0x04; // push promise
   const static uint8_t kFlag_ACK = 0x01; // ping and settings
   const static uint8_t kFlag_END_SEGMENT = 0x02; // data
   const static uint8_t kFlag_PAD_LOW = 0x08; // data, headers, push promise, continuation
   const static uint8_t kFlag_PAD_HIGH = 0x10; // data, headers, push promise, continuation
-  const static uint8_t kFlag_PRIORITY_GROUP = 0x20; // headers, priority
-  const static uint8_t kFlag_PRIORITY_DEPENDENCY = 0x40; // headers, priority
+  const static uint8_t kFlag_COMPRESSED = 0x20; // data
+  const static uint8_t kFlag_PRIORITY = 0x20; // headers
 
   enum {
     SETTINGS_TYPE_HEADER_TABLE_SIZE = 1, // compression table size
     SETTINGS_TYPE_ENABLE_PUSH = 2,     // can be used to disable push
     SETTINGS_TYPE_MAX_CONCURRENT = 3,  // streams recvr allowed to initiate
-    SETTINGS_TYPE_INITIAL_WINDOW = 4  // bytes for flow control default
+    SETTINGS_TYPE_INITIAL_WINDOW = 4,  // bytes for flow control default
+    SETTINGS_TYPE_COMPRESS_DATA = 5 // whether other side allowes compressed DATA
   };
 
   // This should be big enough to hold all of your control packets,
   // but if it needs to grow for huge headers it can do so dynamically.
   const static uint32_t kDefaultBufferSize = 2048;
 
   // kDefaultQueueSize must be >= other queue size constants
   const static uint32_t kDefaultQueueSize =  32768;
@@ -157,16 +159,17 @@ public:
   static nsresult RecvRstStream(Http2Session *);
   static nsresult RecvSettings(Http2Session *);
   static nsresult RecvPushPromise(Http2Session *);
   static nsresult RecvPing(Http2Session *);
   static nsresult RecvGoAway(Http2Session *);
   static nsresult RecvWindowUpdate(Http2Session *);
   static nsresult RecvContinuation(Http2Session *);
   static nsresult RecvAltSvc(Http2Session *);
+  static nsresult RecvBlocked(Http2Session *);
 
   template<typename T>
   static void EnsureBuffer(nsAutoArrayPtr<T> &,
                            uint32_t, uint32_t, uint32_t &);
   char       *EnsureOutputBuffer(uint32_t needed);
 
   template<typename charType>
   void CreateFrameHeader(charType dest, uint16_t frameLength,
@@ -228,17 +231,17 @@ private:
   nsresult    ResponseHeadersComplete();
   uint32_t    GetWriteQueueSize();
   void        ChangeDownstreamState(enum internalStateType);
   void        ResetDownstreamState();
   nsresult    ReadyToProcessDataFrame(enum internalStateType);
   nsresult    UncompressAndDiscard();
   void        GeneratePing(bool);
   void        GenerateSettingsAck();
-  void        GeneratePriority(uint32_t, uint32_t, uint8_t);
+  void        GeneratePriority(uint32_t, uint8_t);
   void        GenerateRstStream(uint32_t, uint32_t);
   void        GenerateGoAway(uint32_t);
   void        CleanupStream(Http2Stream *, nsresult, errorType);
   void        CloseStream(Http2Stream *, nsresult);
   void        SendHello();
   void        RemoveStreamFromQueues(Http2Stream *);
   nsresult    ParsePadding(uint8_t &, uint16_t &);
 
--- a/netwerk/protocol/http/Http2Stream.cpp
+++ b/netwerk/protocol/http/Http2Stream.cpp
@@ -370,17 +370,17 @@ Http2Stream::ParseHttpRequestHeaders(con
                                             mTransaction->RequestHead()->Method(),
                                             mTransaction->RequestHead()->RequestURI(),
                                             hostHeader,
                                             NS_LITERAL_CSTRING("https"),
                                             compressedData);
 
   // Determine whether to put the fin bit on the header frame or whether
   // to wait for a data packet to put it on.
-  uint8_t firstFrameFlags =  Http2Session::kFlag_PRIORITY_GROUP;
+  uint8_t firstFrameFlags =  Http2Session::kFlag_PRIORITY;
 
   if (mTransaction->RequestHead()->IsGet() ||
       mTransaction->RequestHead()->IsConnect() ||
       mTransaction->RequestHead()->IsHead()) {
     // for GET, CONNECT, and HEAD place the fin bit right on the
     // header packet
 
     SetSentFin(true);
@@ -422,19 +422,18 @@ Http2Stream::ParseHttpRequestHeaders(con
   messageSize += (numFrames - 1) * 8; // frame header overhead in CONTINUATION frames
 
   Http2Session::EnsureBuffer(mTxInlineFrame,
                              dataLength + messageSize,
                              mTxInlineFrameUsed,
                              mTxInlineFrameSize);
 
   mTxInlineFrameUsed += messageSize;
-  LOG3(("%p Generating %d bytes of HEADERS for stream 0x%X with priority group %u weight %u frames %u\n",
-        this, mTxInlineFrameUsed, mStreamID, mPriorityGroup,
-        mPriorityGroupWeight, numFrames));
+  LOG3(("%p Generating %d bytes of HEADERS for stream 0x%X with priority weight %u frames %u\n",
+        this, mTxInlineFrameUsed, mStreamID, mPriorityWeight, numFrames));
 
   uint32_t outputOffset = 0;
   uint32_t compressedDataOffset = 0;
   for (uint32_t idx = 0; idx < numFrames; ++idx) {
     uint32_t flags, frameLen;
     bool lastFrame = (idx == numFrames - 1);
 
     flags = 0;
@@ -453,19 +452,20 @@ Http2Stream::ParseHttpRequestHeaders(con
     mSession->CreateFrameHeader(
       mTxInlineFrame.get() + outputOffset,
       frameLen + (idx ? 0 : 5),
       (idx) ? Http2Session::FRAME_TYPE_CONTINUATION : Http2Session::FRAME_TYPE_HEADERS,
       flags, mStreamID);
     outputOffset += 8;
 
     if (!idx) {
-      uint32_t priorityGroup = PR_htonl(mPriorityGroup);
-      memcpy(mTxInlineFrame.get() + outputOffset, &priorityGroup, 4);
-      memcpy(mTxInlineFrame.get() + outputOffset + 4, &mPriorityGroupWeight, 1);
+      // Priority - Dependency is 0, weight is our gecko-calculated weight,
+      // non-exclusive dependency
+      memset(mTxInlineFrame.get() + outputOffset, 0, 4);
+      memcpy(mTxInlineFrame.get() + outputOffset + 4, &mPriorityWeight, 1);
       outputOffset += 5;
     }
 
     memcpy(mTxInlineFrame.get() + outputOffset,
            compressedData.BeginReading() + compressedDataOffset, frameLen);
     compressedDataOffset += frameLen;
     outputOffset += frameLen;
   }
@@ -585,26 +585,25 @@ Http2Stream::AdjustPushedPriority()
   Http2Session::EnsureBuffer(mTxInlineFrame,
                              mTxInlineFrameUsed + 13,
                              mTxInlineFrameUsed,
                              mTxInlineFrameSize);
   mTxInlineFrameUsed += 13;
 
   mSession->CreateFrameHeader(packet, 5,
                               Http2Session::FRAME_TYPE_PRIORITY,
-                              Http2Session::kFlag_PRIORITY_GROUP,
+                              Http2Session::kFlag_PRIORITY,
                               mPushSource->mStreamID);
 
-  mPushSource->SetPriority(mPriorityGroup);
-  uint32_t newPriority = PR_htonl(mPriorityGroup);
-  memcpy(packet + 8, &newPriority, 4);
-  memcpy(packet + 12, &mPriorityGroupWeight, 1);
+  mPushSource->SetPriority(mPriority);
+  memset(packet + 8, 0, 4);
+  memcpy(packet + 12, &mPriorityWeight, 1);
 
-  LOG3(("AdjustPushedPriority %p id 0x%X to %X\n", this, mPushSource->mStreamID,
-        newPriority));
+  LOG3(("AdjustPushedPriority %p id 0x%X to weight %X\n", this, mPushSource->mStreamID,
+        mPriorityWeight));
 }
 
 void
 Http2Stream::UpdateTransportReadEvents(uint32_t count)
 {
   mTotalRead += count;
   mTransaction->OnTransportStatus(mSocketTransport,
                                   NS_NET_STATUS_RECEIVING_FROM,
@@ -911,35 +910,37 @@ Http2Stream::UpdateServerReceiveWindow(i
 
   if (mBlockedOnRwin && AllowFlowControlledWrite()) {
     LOG3(("Http2Stream::UpdateServerReceived UnPause %p 0x%X "
           "Open stream window\n", this, mStreamID));
     mSession->TransactionHasDataToWrite(this);  }
 }
 
 void
-Http2Stream::SetPriority(uint32_t newGroup)
+Http2Stream::SetPriority(uint32_t newPriority)
 {
-  int32_t httpPriority = static_cast<int32_t>(newGroup);
-  uint8_t newWeight = (nsISupportsPriority::PRIORITY_LOWEST + 1) -
+  int32_t httpPriority = static_cast<int32_t>(newPriority);
+  if (httpPriority > kWorstPriority) {
+    httpPriority = kWorstPriority;
+  } else if (httpPriority < kBestPriority) {
+    httpPriority = kBestPriority;
+  }
+  mPriority = static_cast<uint32_t>(httpPriority);
+  mPriorityWeight = (nsISupportsPriority::PRIORITY_LOWEST + 1) -
     (httpPriority - kNormalPriority);
-  SetPriorityGroup(newGroup, newWeight);
 }
 
 void
-Http2Stream::SetPriorityGroup(uint32_t newGroup, uint8_t newWeight)
+Http2Stream::SetPriorityDependency(uint32_t newDependency, uint8_t newWeight,
+                                   bool exclusive)
 {
-  mPriorityGroup = newGroup;
-  mPriorityGroupWeight = newWeight;
-}
-
-void
-Http2Stream::SetPriorityDependency(uint32_t newDependency, bool exclusive)
-{
-  // TODO
+  // XXX - we ignore this for now... why is the server sending priority frames?!
+  LOG3(("Http2Stream::SetPriorityDependency %p 0x%X received dependency=0x%X "
+        "weight=%u exclusive=%d", this, mStreamID, newDependency, newWeight,
+        exclusive));
 }
 
 void
 Http2Stream::SetRecvdFin(bool aStatus)
 {
   mRecvdFin = aStatus ? 1 : 0;
   if (!aStatus)
     return;
--- a/netwerk/protocol/http/Http2Stream.h
+++ b/netwerk/protocol/http/Http2Stream.h
@@ -104,20 +104,19 @@ public:
     mLocalUnacked -= delta;
   }
 
   uint64_t LocalUnAcked() { return mLocalUnacked; }
   int64_t  ClientReceiveWindow()  { return mClientReceiveWindow; }
 
   bool     BlockedOnRwin() { return mBlockedOnRwin; }
 
-  uint32_t Priority() { return mPriorityGroup; }
+  uint32_t Priority() { return mPriority; }
   void SetPriority(uint32_t);
-  void SetPriorityGroup(uint32_t, uint8_t);
-  void SetPriorityDependency(uint32_t, bool);
+  void SetPriorityDependency(uint32_t, uint8_t, bool);
 
   // A pull stream has an implicit sink, a pushed stream has a sink
   // once it is matched to a pull stream.
   virtual bool HasSink() { return true; }
 
   virtual ~Http2Stream();
 
 protected:
@@ -233,18 +232,18 @@ private:
 
   // Track the content-length of a request body so that we can
   // place the fin flag on the last data packet instead of waiting
   // for a stream closed indication. Relying on stream close results
   // in an extra 0-length runt packet and seems to have some interop
   // problems with the google servers.
   int64_t                      mRequestBodyLenRemaining;
 
-  uint32_t                     mPriorityGroup;
-  uint8_t                      mPriorityGroupWeight;
+  uint32_t                     mPriority;
+  uint8_t                      mPriorityWeight;
 
   // mClientReceiveWindow, mServerReceiveWindow, and mLocalUnacked are for flow control.
   // *window are signed because the race conditions in asynchronous SETTINGS
   // messages can force them temporarily negative.
 
   // mClientReceiveWindow is how much data the server will send without getting a
   //   window update
   int64_t                      mClientReceiveWindow;
--- a/netwerk/protocol/http/nsHttp.h
+++ b/netwerk/protocol/http/nsHttp.h
@@ -28,24 +28,24 @@ namespace net {
         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
         // 26 was http/2-draft08 and http/2-draft07 (they were the same)
-        // 27 was also http/2-draft09 and h2-10
-        HTTP2_VERSION_DRAFT11 = 27
+        // 27 was http/2-draft09, h2-10, and h2-11
+        HTTP2_VERSION_DRAFT12 = 28
     };
 
 typedef uint8_t nsHttpVersion;
 
-#define NS_HTTP2_DRAFT_VERSION HTTP2_VERSION_DRAFT11
-#define NS_HTTP2_DRAFT_TOKEN "h2-11"
+#define NS_HTTP2_DRAFT_VERSION HTTP2_VERSION_DRAFT12
+#define NS_HTTP2_DRAFT_TOKEN "h2-12"
 
 //-----------------------------------------------------------------------------
 // http connection capabilities
 //-----------------------------------------------------------------------------
 
 #define NS_HTTP_ALLOW_KEEPALIVE      (1<<0)
 #define NS_HTTP_ALLOW_PIPELINING     (1<<1)