netwerk/protocol/http/SpdyStream31.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set sw=2 ts=8 et tw=80 : */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 // HttpLog.h should generally be included first
     8 #include "HttpLog.h"
    10 // Log on level :5, instead of default :4.
    11 #undef LOG
    12 #define LOG(args) LOG5(args)
    13 #undef LOG_ENABLED
    14 #define LOG_ENABLED() LOG5_ENABLED()
    16 #include "mozilla/Telemetry.h"
    17 #include "nsAlgorithm.h"
    18 #include "nsHttp.h"
    19 #include "nsHttpHandler.h"
    20 #include "nsHttpRequestHead.h"
    21 #include "nsISocketTransport.h"
    22 #include "nsISupportsPriority.h"
    23 #include "prnetdb.h"
    24 #include "SpdyPush31.h"
    25 #include "SpdySession31.h"
    26 #include "SpdyStream31.h"
    28 #include <algorithm>
    30 #ifdef DEBUG
    31 // defined by the socket transport service while active
    32 extern PRThread *gSocketThread;
    33 #endif
    35 namespace mozilla {
    36 namespace net {
    38 SpdyStream31::SpdyStream31(nsAHttpTransaction *httpTransaction,
    39                            SpdySession31 *spdySession,
    40                            int32_t priority)
    41   : mStreamID(0),
    42   mSession(spdySession),
    43   mUpstreamState(GENERATING_SYN_STREAM),
    44   mSynFrameComplete(0),
    45   mSentFinOnData(0),
    46   mTransaction(httpTransaction),
    47   mSocketTransport(spdySession->SocketTransport()),
    48   mSegmentReader(nullptr),
    49   mSegmentWriter(nullptr),
    50   mChunkSize(spdySession->SendingChunkSize()),
    51   mRequestBlockedOnRead(0),
    52   mRecvdFin(0),
    53   mFullyOpen(0),
    54   mSentWaitingFor(0),
    55   mReceivedData(0),
    56   mSetTCPSocketBuffer(0),
    57   mTxInlineFrameSize(SpdySession31::kDefaultBufferSize),
    58   mTxInlineFrameUsed(0),
    59   mTxStreamFrameSize(0),
    60   mZlib(spdySession->UpstreamZlib()),
    61   mDecompressBufferSize(SpdySession31::kDefaultBufferSize),
    62   mDecompressBufferUsed(0),
    63   mDecompressedBytes(0),
    64   mRequestBodyLenRemaining(0),
    65   mPriority(priority),
    66   mLocalUnacked(0),
    67   mBlockedOnRwin(false),
    68   mTotalSent(0),
    69   mTotalRead(0),
    70   mPushSource(nullptr)
    71 {
    72   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
    74   LOG3(("SpdyStream31::SpdyStream31 %p", this));
    76   mRemoteWindow = spdySession->GetServerInitialStreamWindow();
    77   mLocalWindow = spdySession->PushAllowance();
    79   mTxInlineFrame = new uint8_t[mTxInlineFrameSize];
    80   mDecompressBuffer = new char[mDecompressBufferSize];
    81 }
    83 SpdyStream31::~SpdyStream31()
    84 {
    85   mStreamID = SpdySession31::kDeadStreamID;
    86 }
    88 // ReadSegments() is used to write data down the socket. Generally, HTTP
    89 // request data is pulled from the approriate transaction and
    90 // converted to SPDY data. Sometimes control data like a window-update is
    91 // generated instead.
    93 nsresult
    94 SpdyStream31::ReadSegments(nsAHttpSegmentReader *reader,
    95                            uint32_t count,
    96                            uint32_t *countRead)
    97 {
    98   LOG3(("SpdyStream31 %p ReadSegments reader=%p count=%d state=%x",
    99         this, reader, count, mUpstreamState));
   101   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
   103   nsresult rv = NS_ERROR_UNEXPECTED;
   104   mRequestBlockedOnRead = 0;
   106   // avoid runt chunks if possible by anticipating
   107   // full data frames
   108   if (count > (mChunkSize + 8)) {
   109     uint32_t numchunks = count / (mChunkSize + 8);
   110     count = numchunks * (mChunkSize + 8);
   111   }
   113   switch (mUpstreamState) {
   114   case GENERATING_SYN_STREAM:
   115   case GENERATING_REQUEST_BODY:
   116   case SENDING_REQUEST_BODY:
   117     // Call into the HTTP Transaction to generate the HTTP request
   118     // stream. That stream will show up in OnReadSegment().
   119     mSegmentReader = reader;
   120     rv = mTransaction->ReadSegments(this, count, countRead);
   121     mSegmentReader = nullptr;
   123     // Check to see if the transaction's request could be written out now.
   124     // If not, mark the stream for callback when writing can proceed.
   125     if (NS_SUCCEEDED(rv) &&
   126         mUpstreamState == GENERATING_SYN_STREAM &&
   127         !mSynFrameComplete)
   128       mSession->TransactionHasDataToWrite(this);
   130     // mTxinlineFrameUsed represents any queued un-sent frame. It might
   131     // be 0 if there is no such frame, which is not a gurantee that we
   132     // don't have more request body to send - just that any data that was
   133     // sent comprised a complete SPDY frame. Likewise, a non 0 value is
   134     // a queued, but complete, spdy frame length.
   136     // Mark that we are blocked on read if the http transaction needs to
   137     // provide more of the request message body and there is nothing queued
   138     // for writing
   139     if (rv == NS_BASE_STREAM_WOULD_BLOCK && !mTxInlineFrameUsed)
   140       mRequestBlockedOnRead = 1;
   142     // If the sending flow control window is open (!mBlockedOnRwin) then
   143     // continue sending the request
   144     if (!mBlockedOnRwin &&
   145         !mTxInlineFrameUsed && NS_SUCCEEDED(rv) && (!*countRead)) {
   146       LOG3(("SpdyStream31::ReadSegments %p 0x%X: Sending request data complete, "
   147             "mUpstreamState=%x",this, mStreamID, mUpstreamState));
   148       if (mSentFinOnData) {
   149         ChangeState(UPSTREAM_COMPLETE);
   150       }
   151       else {
   152         GenerateDataFrameHeader(0, true);
   153         ChangeState(SENDING_FIN_STREAM);
   154         mSession->TransactionHasDataToWrite(this);
   155         rv = NS_BASE_STREAM_WOULD_BLOCK;
   156       }
   157     }
   158     break;
   160   case SENDING_FIN_STREAM:
   161     // We were trying to send the FIN-STREAM but were blocked from
   162     // sending it out - try again.
   163     if (!mSentFinOnData) {
   164       mSegmentReader = reader;
   165       rv = TransmitFrame(nullptr, nullptr, false);
   166       mSegmentReader = nullptr;
   167       MOZ_ASSERT(NS_FAILED(rv) || !mTxInlineFrameUsed,
   168                  "Transmit Frame should be all or nothing");
   169       if (NS_SUCCEEDED(rv))
   170         ChangeState(UPSTREAM_COMPLETE);
   171     }
   172     else {
   173       rv = NS_OK;
   174       mTxInlineFrameUsed = 0;         // cancel fin data packet
   175       ChangeState(UPSTREAM_COMPLETE);
   176     }
   178     *countRead = 0;
   180     // don't change OK to WOULD BLOCK. we are really done sending if OK
   181     break;
   183   case UPSTREAM_COMPLETE:
   184     *countRead = 0;
   185     rv = NS_OK;
   186     break;
   188   default:
   189     MOZ_ASSERT(false, "SpdyStream31::ReadSegments unknown state");
   190     break;
   191   }
   193   return rv;
   194 }
   196 // WriteSegments() is used to read data off the socket. Generally this is
   197 // just the SPDY frame header and from there the appropriate SPDYStream
   198 // is identified from the Stream-ID. The http transaction associated with
   199 // that read then pulls in the data directly.
   201 nsresult
   202 SpdyStream31::WriteSegments(nsAHttpSegmentWriter *writer,
   203                             uint32_t count,
   204                             uint32_t *countWritten)
   205 {
   206   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
   207   MOZ_ASSERT(!mSegmentWriter, "segment writer in progress");
   209   LOG3(("SpdyStream31::WriteSegments %p count=%d state=%x",
   210         this, count, mUpstreamState));
   212   mSegmentWriter = writer;
   213   nsresult rv = mTransaction->WriteSegments(this, count, countWritten);
   214   mSegmentWriter = nullptr;
   216   return rv;
   217 }
   219 PLDHashOperator
   220 SpdyStream31::hdrHashEnumerate(const nsACString &key,
   221                                nsAutoPtr<nsCString> &value,
   222                                void *closure)
   223 {
   224   SpdyStream31 *self = static_cast<SpdyStream31 *>(closure);
   226   self->CompressToFrame(key);
   227   self->CompressToFrame(value.get());
   228   return PL_DHASH_NEXT;
   229 }
   231 void
   232 SpdyStream31::CreatePushHashKey(const nsCString &scheme,
   233                                 const nsCString &hostHeader,
   234                                 uint64_t serial,
   235                                 const nsCSubstring &pathInfo,
   236                                 nsCString &outOrigin,
   237                                 nsCString &outKey)
   238 {
   239   outOrigin = scheme;
   240   outOrigin.Append(NS_LITERAL_CSTRING("://"));
   241   outOrigin.Append(hostHeader);
   243   outKey = outOrigin;
   244   outKey.Append(NS_LITERAL_CSTRING("/[spdy3_1."));
   245   outKey.AppendInt(serial);
   246   outKey.Append(NS_LITERAL_CSTRING("]"));
   247   outKey.Append(pathInfo);
   248 }
   251 nsresult
   252 SpdyStream31::ParseHttpRequestHeaders(const char *buf,
   253                                       uint32_t avail,
   254                                       uint32_t *countUsed)
   255 {
   256   // Returns NS_OK even if the headers are incomplete
   257   // set mSynFrameComplete flag if they are complete
   259   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
   260   MOZ_ASSERT(mUpstreamState == GENERATING_SYN_STREAM);
   262   LOG3(("SpdyStream31::ParseHttpRequestHeaders %p avail=%d state=%x",
   263         this, avail, mUpstreamState));
   265   mFlatHttpRequestHeaders.Append(buf, avail);
   267   // We can use the simple double crlf because firefox is the
   268   // only client we are parsing
   269   int32_t endHeader = mFlatHttpRequestHeaders.Find("\r\n\r\n");
   271   if (endHeader == kNotFound) {
   272     // We don't have all the headers yet
   273     LOG3(("SpdyStream31::ParseHttpRequestHeaders %p "
   274           "Need more header bytes. Len = %d",
   275           this, mFlatHttpRequestHeaders.Length()));
   276     *countUsed = avail;
   277     return NS_OK;
   278   }
   280   // We have recvd all the headers, trim the local
   281   // buffer of the final empty line, and set countUsed to reflect
   282   // the whole header has been consumed.
   283   uint32_t oldLen = mFlatHttpRequestHeaders.Length();
   284   mFlatHttpRequestHeaders.SetLength(endHeader + 2);
   285   *countUsed = avail - (oldLen - endHeader) + 4;
   286   mSynFrameComplete = 1;
   288   nsCString hostHeader;
   289   nsCString hashkey;
   290   mTransaction->RequestHead()->GetHeader(nsHttp::Host, hostHeader);
   292   CreatePushHashKey(NS_LITERAL_CSTRING("https"),
   293                     hostHeader, mSession->Serial(),
   294                     mTransaction->RequestHead()->RequestURI(),
   295                     mOrigin, hashkey);
   297   // check the push cache for GET
   298   if (mTransaction->RequestHead()->IsGet()) {
   299     // from :scheme, :host, :path
   300     nsILoadGroupConnectionInfo *loadGroupCI = mTransaction->LoadGroupConnectionInfo();
   301     SpdyPushCache *cache = nullptr;
   302     if (loadGroupCI)
   303       loadGroupCI->GetSpdyPushCache(&cache);
   305     SpdyPushedStream31 *pushedStream = nullptr;
   306     // we remove the pushedstream from the push cache so that
   307     // it will not be used for another GET. This does not destroy the
   308     // stream itself - that is done when the transactionhash is done with it.
   309     if (cache)
   310       pushedStream = cache->RemovePushedStreamSpdy31(hashkey);
   312     if (pushedStream) {
   313       LOG3(("Pushed Stream Match located id=0x%X key=%s\n",
   314             pushedStream->StreamID(), hashkey.get()));
   315       pushedStream->SetConsumerStream(this);
   316       mPushSource = pushedStream;
   317       mSentFinOnData = 1;
   319       // This stream has been activated (and thus counts against the concurrency
   320       // limit intentionally), but will not be registered via
   321       // RegisterStreamID (below) because of the push match. Therefore the
   322       // concurrency sempahore needs to be balanced.
   323       mSession->DecrementConcurrent(this);
   325       // There is probably pushed data buffered so trigger a read manually
   326       // as we can't rely on future network events to do it
   327       mSession->ConnectPushedStream(this);
   328       return NS_OK;
   329     }
   330   }
   332   // It is now OK to assign a streamID that we are assured will
   333   // be monotonically increasing amongst syn-streams on this
   334   // session
   335   mStreamID = mSession->RegisterStreamID(this);
   336   MOZ_ASSERT(mStreamID & 1, "Spdy Stream Channel ID must be odd");
   338   if (mStreamID >= 0x80000000) {
   339     // streamID must fit in 31 bits. This is theoretically possible
   340     // because stream ID assignment is asynchronous to stream creation
   341     // because of the protocol requirement that the ID in syn-stream
   342     // be monotonically increasing. In reality this is really not possible
   343     // because new streams stop being added to a session with 0x10000000 / 2
   344     // IDs still available and no race condition is going to bridge that gap,
   345     // so we can be comfortable on just erroring out for correctness in that
   346     // case.
   347     LOG3(("Stream assigned out of range ID: 0x%X", mStreamID));
   348     return NS_ERROR_UNEXPECTED;
   349   }
   351   // Now we need to convert the flat http headers into a set
   352   // of SPDY headers..  writing to mTxInlineFrame{sz}
   354   mTxInlineFrame[0] = SpdySession31::kFlag_Control;
   355   mTxInlineFrame[1] = SpdySession31::kVersion;
   356   mTxInlineFrame[2] = 0;
   357   mTxInlineFrame[3] = SpdySession31::CONTROL_TYPE_SYN_STREAM;
   358   // 4 to 7 are length and flags, we'll fill that in later
   360   uint32_t networkOrderID = PR_htonl(mStreamID);
   361   memcpy(mTxInlineFrame + 8, &networkOrderID, 4);
   363   // this is the associated-to field, which is not used sending
   364   // from the client in the http binding
   365   memset (mTxInlineFrame + 12, 0, 4);
   367   // Priority flags are the E0 mask of byte 16.
   368   // 0 is highest priority, 7 is lowest.
   369   // The other 5 bits of byte 16 are unused.
   371   if (mPriority >= nsISupportsPriority::PRIORITY_LOWEST)
   372     mTxInlineFrame[16] = 7 << 5;
   373   else if (mPriority <= nsISupportsPriority::PRIORITY_HIGHEST)
   374     mTxInlineFrame[16] = 0 << 5;
   375   else {
   376     // The priority mapping relies on the unfiltered ranged to be
   377     // between -20 .. +20
   378     PR_STATIC_ASSERT(nsISupportsPriority::PRIORITY_LOWEST == 20);
   379     PR_STATIC_ASSERT(nsISupportsPriority::PRIORITY_HIGHEST == -20);
   381     // Add one to the priority so that values such as -10 and -11
   382     // get different spdy priorities - this appears to be an important
   383     // breaking line in the priorities content assigns to
   384     // transactions.
   385     uint8_t calculatedPriority = 3 + ((mPriority + 1) / 5);
   386     MOZ_ASSERT (!(calculatedPriority & 0xf8),
   387                 "Calculated Priority Out Of Range");
   388     mTxInlineFrame[16] = calculatedPriority << 5;
   389   }
   391   // The client cert "slot". Right now we don't send client certs
   392   mTxInlineFrame[17] = 0;
   394   nsCString versionHeader;
   395   if (mTransaction->RequestHead()->Version() == NS_HTTP_VERSION_1_1)
   396     versionHeader = NS_LITERAL_CSTRING("HTTP/1.1");
   397   else
   398     versionHeader = NS_LITERAL_CSTRING("HTTP/1.0");
   400   // use mRequestHead() to get a sense of how big to make the hash,
   401   // even though we are parsing the actual text stream because
   402   // it is legit to append headers.
   403   nsClassHashtable<nsCStringHashKey, nsCString>
   404     hdrHash(1 + (mTransaction->RequestHead()->Headers().Count() * 2));
   406   const char *beginBuffer = mFlatHttpRequestHeaders.BeginReading();
   408   // need to hash all the headers together to remove duplicates, special
   409   // headers, etc..
   411   int32_t crlfIndex = mFlatHttpRequestHeaders.Find("\r\n");
   412   while (true) {
   413     int32_t startIndex = crlfIndex + 2;
   415     crlfIndex = mFlatHttpRequestHeaders.Find("\r\n", false, startIndex);
   416     if (crlfIndex == -1)
   417       break;
   419     int32_t colonIndex = mFlatHttpRequestHeaders.Find(":", false, startIndex,
   420                                                       crlfIndex - startIndex);
   421     if (colonIndex == -1)
   422       break;
   424     nsDependentCSubstring name = Substring(beginBuffer + startIndex,
   425                                            beginBuffer + colonIndex);
   426     // all header names are lower case in spdy
   427     ToLowerCase(name);
   429     // exclusions.. mostly from 3.2.1
   430     if (name.Equals("connection") ||
   431         name.Equals("keep-alive") ||
   432         name.Equals("host") ||
   433         name.Equals("accept-encoding") ||
   434         name.Equals("te") ||
   435         name.Equals("transfer-encoding"))
   436       continue;
   438     nsCString *val = hdrHash.Get(name);
   439     if (!val) {
   440       val = new nsCString();
   441       hdrHash.Put(name, val);
   442     }
   444     int32_t valueIndex = colonIndex + 1;
   445     while (valueIndex < crlfIndex && beginBuffer[valueIndex] == ' ')
   446       ++valueIndex;
   448     nsDependentCSubstring v = Substring(beginBuffer + valueIndex,
   449                                         beginBuffer + crlfIndex);
   450     if (!val->IsEmpty())
   451       val->Append(static_cast<char>(0));
   452     val->Append(v);
   454     if (name.Equals("content-length")) {
   455       int64_t len;
   456       if (nsHttp::ParseInt64(val->get(), nullptr, &len))
   457         mRequestBodyLenRemaining = len;
   458     }
   459   }
   461   mTxInlineFrameUsed = 18;
   463   // Do not naively log the request headers here beacuse they might
   464   // contain auth. The http transaction already logs the sanitized request
   465   // headers at this same level so it is not necessary to do so here.
   467   const char *methodHeader = mTransaction->RequestHead()->Method().get();
   469   // The header block length
   470   uint16_t count = hdrHash.Count() + 5; /* method, path, version, host, scheme */
   471   CompressToFrame(count);
   473   // :method, :path, :version comprise a HTTP/1 request line, so send those first
   474   // to make life easy for any gateways
   475   CompressToFrame(NS_LITERAL_CSTRING(":method"));
   476   CompressToFrame(methodHeader, strlen(methodHeader));
   477   CompressToFrame(NS_LITERAL_CSTRING(":path"));
   478   CompressToFrame(mTransaction->RequestHead()->RequestURI());
   479   CompressToFrame(NS_LITERAL_CSTRING(":version"));
   480   CompressToFrame(versionHeader);
   482   CompressToFrame(NS_LITERAL_CSTRING(":host"));
   483   CompressToFrame(hostHeader);
   484   CompressToFrame(NS_LITERAL_CSTRING(":scheme"));
   485   CompressToFrame(NS_LITERAL_CSTRING("https"));
   487   hdrHash.Enumerate(hdrHashEnumerate, this);
   488   CompressFlushFrame();
   490   // 4 to 7 are length and flags, which we can now fill in
   491   (reinterpret_cast<uint32_t *>(mTxInlineFrame.get()))[1] =
   492     PR_htonl(mTxInlineFrameUsed - 8);
   494   MOZ_ASSERT(!mTxInlineFrame[4], "Size greater than 24 bits");
   496   // Determine whether to put the fin bit on the syn stream frame or whether
   497   // to wait for a data packet to put it on.
   499   if (mTransaction->RequestHead()->IsGet() ||
   500       mTransaction->RequestHead()->IsConnect() ||
   501       mTransaction->RequestHead()->IsHead()) {
   502     // for GET, CONNECT, and HEAD place the fin bit right on the
   503     // syn stream packet
   505     mSentFinOnData = 1;
   506     mTxInlineFrame[4] = SpdySession31::kFlag_Data_FIN;
   507   }
   508   else if (mTransaction->RequestHead()->IsPost() ||
   509            mTransaction->RequestHead()->IsPut() ||
   510            mTransaction->RequestHead()->IsOptions()) {
   511     // place fin in a data frame even for 0 length messages, I've seen
   512     // the google gateway be unhappy with fin-on-syn for 0 length POST
   513   }
   514   else if (!mRequestBodyLenRemaining) {
   515     // for other HTTP extension methods, rely on the content-length
   516     // to determine whether or not to put fin on syn
   517     mSentFinOnData = 1;
   518     mTxInlineFrame[4] = SpdySession31::kFlag_Data_FIN;
   519   }
   521   Telemetry::Accumulate(Telemetry::SPDY_SYN_SIZE, mTxInlineFrameUsed - 18);
   523   // The size of the input headers is approximate
   524   uint32_t ratio =
   525     (mTxInlineFrameUsed - 18) * 100 /
   526     (11 + mTransaction->RequestHead()->RequestURI().Length() +
   527      mFlatHttpRequestHeaders.Length());
   529   Telemetry::Accumulate(Telemetry::SPDY_SYN_RATIO, ratio);
   530   return NS_OK;
   531 }
   533 void
   534 SpdyStream31::AdjustInitialWindow()
   535 {
   536   MOZ_ASSERT(mSession->PushAllowance() <= ASpdySession::kInitialRwin);
   538   // The session initial_window is sized for serverpushed streams. When we
   539   // generate a client pulled stream we want to adjust the initial window
   540   // to a huge value in a pipeline with that SYN_STREAM.
   542   // >0 even numbered IDs are pushed streams.
   543   // odd numbered IDs are pulled streams.
   544   // 0 is the sink for a pushed stream.
   545   SpdyStream31 *stream = this;
   546   if (!mStreamID) {
   547     MOZ_ASSERT(mPushSource);
   548     if (!mPushSource)
   549       return;
   550     stream = mPushSource;
   551     MOZ_ASSERT(stream->mStreamID);
   552     MOZ_ASSERT(!(stream->mStreamID & 1)); // is a push stream
   554     // If the pushed stream has sent a FIN, there is no reason to update
   555     // the window
   556     if (stream->RecvdFin())
   557       return;
   558   }
   560   // For server pushes we also want to include in the ack any data that has been
   561   // buffered but unacknowledged.
   563   // mLocalUnacked is technically 64 bits, but because it can never grow larger than
   564   // our window size (which is closer to 29bits max) we know it fits comfortably in 32.
   565   // However we don't really enforce that, and track it as a 64 so that broken senders
   566   // can still interoperate. That means we have to be careful with this calculation.
   567   uint64_t toack64 = (ASpdySession::kInitialRwin - mSession->PushAllowance()) +
   568     stream->mLocalUnacked;
   569   stream->mLocalUnacked = 0;
   570   if (toack64 > 0x7fffffff) {
   571     stream->mLocalUnacked = toack64 - 0x7fffffff;
   572     toack64 = 0x7fffffff;
   573   }
   574   uint32_t toack = static_cast<uint32_t>(toack64);
   575   if (!toack)
   576     return;
   577   toack = PR_htonl(toack);
   579   SpdySession31::EnsureBuffer(mTxInlineFrame,
   580                               mTxInlineFrameUsed + 16,
   581                               mTxInlineFrameUsed,
   582                               mTxInlineFrameSize);
   584   unsigned char *packet = mTxInlineFrame.get() + mTxInlineFrameUsed;
   585   mTxInlineFrameUsed += 16;
   587   memset(packet, 0, 8);
   588   packet[0] = SpdySession31::kFlag_Control;
   589   packet[1] = SpdySession31::kVersion;
   590   packet[3] = SpdySession31::CONTROL_TYPE_WINDOW_UPDATE;
   591   packet[7] = 8; // 8 data bytes after 8 byte header
   593   uint32_t id = PR_htonl(stream->mStreamID);
   594   memcpy(packet + 8, &id, 4);
   595   memcpy(packet + 12, &toack, 4);
   597   stream->mLocalWindow += PR_ntohl(toack);
   598   LOG3(("AdjustInitialwindow %p 0x%X %u\n",
   599         this, stream->mStreamID, PR_ntohl(toack)));
   600 }
   602 void
   603 SpdyStream31::UpdateTransportReadEvents(uint32_t count)
   604 {
   605   mTotalRead += count;
   607   mTransaction->OnTransportStatus(mSocketTransport,
   608                                   NS_NET_STATUS_RECEIVING_FROM,
   609                                   mTotalRead);
   610 }
   612 void
   613 SpdyStream31::UpdateTransportSendEvents(uint32_t count)
   614 {
   615   mTotalSent += count;
   617   // normally on non-windows platform we use TCP autotuning for
   618   // the socket buffers, and this works well (managing enough
   619   // buffers for BDP while conserving memory) for HTTP even when
   620   // it creates really deep queues. However this 'buffer bloat' is
   621   // a problem for spdy because it ruins the low latency properties
   622   // necessary for PING and cancel to work meaningfully.
   623   //
   624   // If this stream represents a large upload, disable autotuning for
   625   // the session and cap the send buffers by default at 128KB.
   626   // (10Mbit/sec @ 100ms)
   627   //
   628   uint32_t bufferSize = gHttpHandler->SpdySendBufferSize();
   629   if ((mTotalSent > bufferSize) && !mSetTCPSocketBuffer) {
   630     mSetTCPSocketBuffer = 1;
   631     mSocketTransport->SetSendBufferSize(bufferSize);
   632   }
   634   if (mUpstreamState != SENDING_FIN_STREAM)
   635     mTransaction->OnTransportStatus(mSocketTransport,
   636                                     NS_NET_STATUS_SENDING_TO,
   637                                     mTotalSent);
   639   if (!mSentWaitingFor && !mRequestBodyLenRemaining) {
   640     mSentWaitingFor = 1;
   641     mTransaction->OnTransportStatus(mSocketTransport,
   642                                     NS_NET_STATUS_WAITING_FOR,
   643                                     0);
   644   }
   645 }
   647 nsresult
   648 SpdyStream31::TransmitFrame(const char *buf,
   649                             uint32_t *countUsed,
   650                             bool forceCommitment)
   651 {
   652   // If TransmitFrame returns SUCCESS than all the data is sent (or at least
   653   // buffered at the session level), if it returns WOULD_BLOCK then none of
   654   // the data is sent.
   656   // You can call this function with no data and no out parameter in order to
   657   // flush internal buffers that were previously blocked on writing. You can
   658   // of course feed new data to it as well.
   660   LOG3(("SpdyStream31::TransmitFrame %p inline=%d stream=%d",
   661         this, mTxInlineFrameUsed, mTxStreamFrameSize));
   662   if (countUsed)
   663     *countUsed = 0;
   665   if (!mTxInlineFrameUsed) {
   666     MOZ_ASSERT(!buf);
   667     return NS_OK;
   668   }
   670   MOZ_ASSERT(mTxInlineFrameUsed, "empty stream frame in transmit");
   671   MOZ_ASSERT(mSegmentReader, "TransmitFrame with null mSegmentReader");
   672   MOZ_ASSERT((buf && countUsed) || (!buf && !countUsed),
   673              "TransmitFrame arguments inconsistent");
   675   uint32_t transmittedCount;
   676   nsresult rv;
   678   // In the (relatively common) event that we have a small amount of data
   679   // split between the inlineframe and the streamframe, then move the stream
   680   // data into the inlineframe via copy in order to coalesce into one write.
   681   // Given the interaction with ssl this is worth the small copy cost.
   682   if (mTxStreamFrameSize && mTxInlineFrameUsed &&
   683       mTxStreamFrameSize < SpdySession31::kDefaultBufferSize &&
   684       mTxInlineFrameUsed + mTxStreamFrameSize < mTxInlineFrameSize) {
   685     LOG3(("Coalesce Transmit"));
   686     memcpy (mTxInlineFrame + mTxInlineFrameUsed,
   687             buf, mTxStreamFrameSize);
   688     if (countUsed)
   689       *countUsed += mTxStreamFrameSize;
   690     mTxInlineFrameUsed += mTxStreamFrameSize;
   691     mTxStreamFrameSize = 0;
   692   }
   694   rv =
   695     mSegmentReader->CommitToSegmentSize(mTxStreamFrameSize + mTxInlineFrameUsed,
   696                                         forceCommitment);
   698   if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
   699     MOZ_ASSERT(!forceCommitment, "forceCommitment with WOULD_BLOCK");
   700     mSession->TransactionHasDataToWrite(this);
   701   }
   702   if (NS_FAILED(rv))     // this will include WOULD_BLOCK
   703     return rv;
   705   // This function calls mSegmentReader->OnReadSegment to report the actual SPDY
   706   // bytes through to the SpdySession31 and then the HttpConnection which calls
   707   // the socket write function. It will accept all of the inline and stream
   708   // data because of the above 'commitment' even if it has to buffer
   710   rv = mSession->BufferOutput(reinterpret_cast<char*>(mTxInlineFrame.get()),
   711                               mTxInlineFrameUsed,
   712                               &transmittedCount);
   713   LOG3(("SpdyStream31::TransmitFrame for inline BufferOutput session=%p "
   714         "stream=%p result %x len=%d",
   715         mSession, this, rv, transmittedCount));
   717   MOZ_ASSERT(rv != NS_BASE_STREAM_WOULD_BLOCK,
   718              "inconsistent inline commitment result");
   720   if (NS_FAILED(rv))
   721     return rv;
   723   MOZ_ASSERT(transmittedCount == mTxInlineFrameUsed,
   724              "inconsistent inline commitment count");
   726   SpdySession31::LogIO(mSession, this, "Writing from Inline Buffer",
   727                        reinterpret_cast<char*>(mTxInlineFrame.get()),
   728                        transmittedCount);
   730   if (mTxStreamFrameSize) {
   731     if (!buf) {
   732       // this cannot happen
   733       MOZ_ASSERT(false, "Stream transmit with null buf argument to "
   734                  "TransmitFrame()");
   735       LOG(("Stream transmit with null buf argument to TransmitFrame()\n"));
   736       return NS_ERROR_UNEXPECTED;
   737     }
   739     // If there is already data buffered, just add to that to form
   740     // a single TLS Application Data Record - otherwise skip the memcpy
   741     if (mSession->AmountOfOutputBuffered()) {
   742       rv = mSession->BufferOutput(buf, mTxStreamFrameSize,
   743                                   &transmittedCount);
   744     } else {
   745       rv = mSession->OnReadSegment(buf, mTxStreamFrameSize,
   746                                    &transmittedCount);
   747     }
   749     LOG3(("SpdyStream31::TransmitFrame for regular session=%p "
   750           "stream=%p result %x len=%d",
   751           mSession, this, rv, transmittedCount));
   753     MOZ_ASSERT(rv != NS_BASE_STREAM_WOULD_BLOCK,
   754                "inconsistent stream commitment result");
   756     if (NS_FAILED(rv))
   757       return rv;
   759     MOZ_ASSERT(transmittedCount == mTxStreamFrameSize,
   760                "inconsistent stream commitment count");
   762     SpdySession31::LogIO(mSession, this, "Writing from Transaction Buffer",
   763                          buf, transmittedCount);
   765     *countUsed += mTxStreamFrameSize;
   766   }
   768   mSession->FlushOutputQueue();
   770   // calling this will trigger waiting_for if mRequestBodyLenRemaining is 0
   771   UpdateTransportSendEvents(mTxInlineFrameUsed + mTxStreamFrameSize);
   773   mTxInlineFrameUsed = 0;
   774   mTxStreamFrameSize = 0;
   776   return NS_OK;
   777 }
   779 void
   780 SpdyStream31::ChangeState(enum stateType newState)
   781 {
   782   LOG3(("SpdyStream31::ChangeState() %p from %X to %X",
   783         this, mUpstreamState, newState));
   784   mUpstreamState = newState;
   785   return;
   786 }
   788 void
   789 SpdyStream31::GenerateDataFrameHeader(uint32_t dataLength, bool lastFrame)
   790 {
   791   LOG3(("SpdyStream31::GenerateDataFrameHeader %p len=%d last=%d",
   792         this, dataLength, lastFrame));
   794   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
   795   MOZ_ASSERT(!mTxInlineFrameUsed, "inline frame not empty");
   796   MOZ_ASSERT(!mTxStreamFrameSize, "stream frame not empty");
   797   MOZ_ASSERT(!(dataLength & 0xff000000), "datalength > 24 bits");
   799   (reinterpret_cast<uint32_t *>(mTxInlineFrame.get()))[0] = PR_htonl(mStreamID);
   800   (reinterpret_cast<uint32_t *>(mTxInlineFrame.get()))[1] =
   801     PR_htonl(dataLength);
   803   MOZ_ASSERT(!(mTxInlineFrame[0] & 0x80), "control bit set unexpectedly");
   804   MOZ_ASSERT(!mTxInlineFrame[4], "flag bits set unexpectedly");
   806   mTxInlineFrameUsed = 8;
   807   mTxStreamFrameSize = dataLength;
   809   if (lastFrame) {
   810     mTxInlineFrame[4] |= SpdySession31::kFlag_Data_FIN;
   811     if (dataLength)
   812       mSentFinOnData = 1;
   813   }
   814 }
   816 void
   817 SpdyStream31::CompressToFrame(const nsACString &str)
   818 {
   819   CompressToFrame(str.BeginReading(), str.Length());
   820 }
   822 void
   823 SpdyStream31::CompressToFrame(const nsACString *str)
   824 {
   825   CompressToFrame(str->BeginReading(), str->Length());
   826 }
   828 // Dictionary taken from
   829 // http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3
   831 const unsigned char SpdyStream31::kDictionary[] = {
   832   0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69,   // - - - - o p t i
   833   0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68,   // o n s - - - - h
   834   0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70,   // e a d - - - - p
   835   0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70,   // o s t - - - - p
   836   0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65,   // u t - - - - d e
   837   0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05,   // l e t e - - - -
   838   0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,   // t r a c e - - -
   839   0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00,   // - a c c e p t -
   840   0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70,   // - - - a c c e p
   841   0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,   // t - c h a r s e
   842   0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63,   // t - - - - a c c
   843   0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,   // e p t - e n c o
   844   0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f,   // d i n g - - - -
   845   0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c,   // a c c e p t - l
   846   0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00,   // a n g u a g e -
   847   0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70,   // - - - a c c e p
   848   0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,   // t - r a n g e s
   849   0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00,   // - - - - a g e -
   850   0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77,   // - - - a l l o w
   851   0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68,   // - - - - a u t h
   852   0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,   // o r i z a t i o
   853   0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63,   // n - - - - c a c
   854   0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72,   // h e - c o n t r
   855   0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f,   // o l - - - - c o
   856   0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,   // n n e c t i o n
   857   0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74,   // - - - - c o n t
   858   0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65,   // e n t - b a s e
   859   0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74,   // - - - - c o n t
   860   0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,   // e n t - e n c o
   861   0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10,   // d i n g - - - -
   862   0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,   // c o n t e n t -
   863   0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,   // l a n g u a g e
   864   0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74,   // - - - - c o n t
   865   0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67,   // e n t - l e n g
   866   0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f,   // t h - - - - c o
   867   0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,   // n t e n t - l o
   868   0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,   // c a t i o n - -
   869   0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,   // - - c o n t e n
   870   0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00,   // t - m d 5 - - -
   871   0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,   // - c o n t e n t
   872   0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00,   // - r a n g e - -
   873   0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,   // - - c o n t e n
   874   0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00,   // t - t y p e - -
   875   0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00,   // - - d a t e - -
   876   0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00,   // - - e t a g - -
   877   0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,   // - - e x p e c t
   878   0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69,   // - - - - e x p i
   879   0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66,   // r e s - - - - f
   880   0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68,   // r o m - - - - h
   881   0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69,   // o s t - - - - i
   882   0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00,   // f - m a t c h -
   883   0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f,   // - - - i f - m o
   884   0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,   // d i f i e d - s
   885   0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d,   // i n c e - - - -
   886   0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d,   // i f - n o n e -
   887   0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00,   // m a t c h - - -
   888   0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,   // - i f - r a n g
   889   0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d,   // e - - - - i f -
   890   0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,   // u n m o d i f i
   891   0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65,   // e d - s i n c e
   892   0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74,   // - - - - l a s t
   893   0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,   // - m o d i f i e
   894   0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63,   // d - - - - l o c
   895   0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,   // a t i o n - - -
   896   0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72,   // - m a x - f o r
   897   0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00,   // w a r d s - - -
   898   0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00,   // - p r a g m a -
   899   0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79,   // - - - p r o x y
   900   0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,   // - a u t h e n t
   901   0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,   // i c a t e - - -
   902   0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61,   // - p r o x y - a
   903   0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,   // u t h o r i z a
   904   0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05,   // t i o n - - - -
   905   0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00,   // r a n g e - - -
   906   0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72,   // - r e f e r e r
   907   0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72,   // - - - - r e t r
   908   0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,   // y - a f t e r -
   909   0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,   // - - - s e r v e
   910   0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00,   // r - - - - t e -
   911   0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c,   // - - - t r a i l
   912   0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72,   // e r - - - - t r
   913   0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65,   // a n s f e r - e
   914   0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00,   // n c o d i n g -
   915   0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61,   // - - - u p g r a
   916   0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73,   // d e - - - - u s
   917   0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74,   // e r - a g e n t
   918   0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79,   // - - - - v a r y
   919   0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00,   // - - - - v i a -
   920   0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69,   // - - - w a r n i
   921   0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,   // n g - - - - w w
   922   0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,   // w - a u t h e n
   923   0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00,   // t i c a t e - -
   924   0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,   // - - m e t h o d
   925   0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00,   // - - - - g e t -
   926   0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,   // - - - s t a t u
   927   0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30,   // s - - - - 2 0 0
   928   0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76,   // - O K - - - - v
   929   0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,   // e r s i o n - -
   930   0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,   // - - H T T P - 1
   931   0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72,   // - 1 - - - - u r
   932   0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62,   // l - - - - p u b
   933   0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73,   // l i c - - - - s
   934   0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69,   // e t - c o o k i
   935   0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65,   // e - - - - k e e
   936   0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00,   // p - a l i v e -
   937   0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,   // - - - o r i g i
   938   0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32,   // n 1 0 0 1 0 1 2
   939   0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35,   // 0 1 2 0 2 2 0 5
   940   0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30,   // 2 0 6 3 0 0 3 0
   941   0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33,   // 2 3 0 3 3 0 4 3
   942   0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37,   // 0 5 3 0 6 3 0 7
   943   0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30,   // 4 0 2 4 0 5 4 0
   944   0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34,   // 6 4 0 7 4 0 8 4
   945   0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31,   // 0 9 4 1 0 4 1 1
   946   0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31,   // 4 1 2 4 1 3 4 1
   947   0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34,   // 4 4 1 5 4 1 6 4
   948   0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34,   // 1 7 5 0 2 5 0 4
   949   0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e,   // 5 0 5 2 0 3 - N
   950   0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f,   // o n - A u t h o
   951   0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65,   // r i t a t i v e
   952   0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61,   // - I n f o r m a
   953   0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20,   // t i o n 2 0 4 -
   954   0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65,   // N o - C o n t e
   955   0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f,   // n t 3 0 1 - M o
   956   0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d,   // v e d - P e r m
   957   0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34,   // a n e n t l y 4
   958   0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52,   // 0 0 - B a d - R
   959   0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30,   // e q u e s t 4 0
   960   0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,   // 1 - U n a u t h
   961   0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30,   // o r i z e d 4 0
   962   0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64,   // 3 - F o r b i d
   963   0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e,   // d e n 4 0 4 - N
   964   0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64,   // o t - F o u n d
   965   0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65,   // 5 0 0 - I n t e
   966   0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72,   // r n a l - S e r
   967   0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f,   // v e r - E r r o
   968   0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74,   // r 5 0 1 - N o t
   969   0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,   // - I m p l e m e
   970   0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20,   // n t e d 5 0 3 -
   971   0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20,   // S e r v i c e -
   972   0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,   // U n a v a i l a
   973   0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46,   // b l e J a n - F
   974   0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41,   // e b - M a r - A
   975   0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a,   // p r - M a y - J
   976   0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41,   // u n - J u l - A
   977   0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20,   // u g - S e p t -
   978   0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20,   // O c t - N o v -
   979   0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30,   // D e c - 0 0 - 0
   980   0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e,   // 0 - 0 0 - M o n
   981   0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57,   // - - T u e - - W
   982   0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c,   // e d - - T h u -
   983   0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61,   // - F r i - - S a
   984   0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20,   // t - - S u n - -
   985   0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b,   // G M T c h u n k
   986   0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f,   // e d - t e x t -
   987   0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61,   // h t m l - i m a
   988   0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69,   // g e - p n g - i
   989   0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67,   // m a g e - j p g
   990   0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67,   // - i m a g e - g
   991   0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,   // i f - a p p l i
   992   0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,   // c a t i o n - x
   993   0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,   // m l - a p p l i
   994   0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,   // c a t i o n - x
   995   0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c,   // h t m l - x m l
   996   0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c,   // - t e x t - p l
   997   0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74,   // a i n - t e x t
   998   0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72,   // - j a v a s c r
   999   0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c,   // i p t - p u b l
  1000   0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,   // i c p r i v a t
  1001   0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65,   // e m a x - a g e
  1002   0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65,   // - g z i p - d e
  1003   0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64,   // f l a t e - s d
  1004   0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,   // c h c h a r s e
  1005   0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63,   // t - u t f - 8 c
  1006   0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69,   // h a r s e t - i
  1007   0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,   // s o - 8 8 5 9 -
  1008   0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a,   // 1 - u t f - - -
  1009   0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e          // - e n q - 0 -
  1010 };
  1012 // This can be called N times.. 1 for syn_reply and 0->N for headers
  1013 nsresult
  1014 SpdyStream31::Uncompress(z_stream *context,
  1015                          char *blockStart,
  1016                          uint32_t blockLen)
  1018   mDecompressedBytes += blockLen;
  1020   context->avail_in = blockLen;
  1021   context->next_in = reinterpret_cast<unsigned char *>(blockStart);
  1022   bool triedDictionary = false;
  1024   do {
  1025     context->next_out =
  1026       reinterpret_cast<unsigned char *>(mDecompressBuffer.get()) +
  1027       mDecompressBufferUsed;
  1028     context->avail_out = mDecompressBufferSize - mDecompressBufferUsed;
  1029     int zlib_rv = inflate(context, Z_NO_FLUSH);
  1031     if (zlib_rv == Z_NEED_DICT) {
  1032       if (triedDictionary) {
  1033         LOG3(("SpdySession31::Uncompress %p Dictionary Error\n", this));
  1034         return NS_ERROR_ILLEGAL_VALUE;
  1037       triedDictionary = true;
  1038       inflateSetDictionary(context, kDictionary, sizeof(kDictionary));
  1041     if (zlib_rv == Z_DATA_ERROR)
  1042       return NS_ERROR_ILLEGAL_VALUE;
  1044     if (zlib_rv == Z_MEM_ERROR)
  1045       return NS_ERROR_FAILURE;
  1047     // zlib's inflate() decreases context->avail_out by the amount it places
  1048     // in the output buffer
  1050     mDecompressBufferUsed += mDecompressBufferSize - mDecompressBufferUsed -
  1051       context->avail_out;
  1053     // When there is no more output room, but input still available then
  1054     // increase the output space
  1055     if (zlib_rv == Z_OK &&
  1056         !context->avail_out && context->avail_in) {
  1057       LOG3(("SpdyStream31::Uncompress %p Large Headers - so far %d",
  1058             this, mDecompressBufferSize));
  1059       SpdySession31::EnsureBuffer(mDecompressBuffer,
  1060                                   mDecompressBufferSize + 4096,
  1061                                   mDecompressBufferUsed,
  1062                                   mDecompressBufferSize);
  1065   while (context->avail_in);
  1066   return NS_OK;
  1069 // mDecompressBuffer contains 0 to N uncompressed Name/Value Header blocks
  1070 nsresult
  1071 SpdyStream31::FindHeader(nsCString name,
  1072                          nsDependentCSubstring &value)
  1074   const unsigned char *nvpair = reinterpret_cast<unsigned char *>
  1075     (mDecompressBuffer.get()) + 4;
  1076   const unsigned char *lastHeaderByte = reinterpret_cast<unsigned char *>
  1077     (mDecompressBuffer.get()) + mDecompressBufferUsed;
  1078   if (lastHeaderByte < nvpair)
  1079     return NS_ERROR_ILLEGAL_VALUE;
  1081   do {
  1082     uint32_t numPairs = PR_ntohl(reinterpret_cast<const uint32_t *>(nvpair)[-1]);
  1084     for (uint32_t index = 0; index < numPairs; ++index) {
  1085       if (lastHeaderByte < nvpair + 4)
  1086         return NS_ERROR_ILLEGAL_VALUE;
  1087       uint32_t nameLen = (nvpair[0] << 24) + (nvpair[1] << 16) +
  1088         (nvpair[2] << 8) + nvpair[3];
  1089       if (lastHeaderByte < nvpair + 4 + nameLen)
  1090         return NS_ERROR_ILLEGAL_VALUE;
  1091       nsDependentCSubstring nameString =
  1092         Substring(reinterpret_cast<const char *>(nvpair) + 4,
  1093                   reinterpret_cast<const char *>(nvpair) + 4 + nameLen);
  1094       if (lastHeaderByte < nvpair + 8 + nameLen)
  1095         return NS_ERROR_ILLEGAL_VALUE;
  1096       uint32_t valueLen = (nvpair[4 + nameLen] << 24) + (nvpair[5 + nameLen] << 16) +
  1097         (nvpair[6 + nameLen] << 8) + nvpair[7 + nameLen];
  1098       if (lastHeaderByte < nvpair + 8 + nameLen + valueLen)
  1099         return NS_ERROR_ILLEGAL_VALUE;
  1100       if (nameString.Equals(name)) {
  1101         value.Assign(((char *)nvpair) + 8 + nameLen, valueLen);
  1102         return NS_OK;
  1105       // that pair didn't match - try the next one in this block
  1106       nvpair += 8 + nameLen + valueLen;
  1109     // move to the next name/value header block (if there is one) - the
  1110     // first pair is offset 4 bytes into it
  1111     nvpair += 4;
  1112   } while (lastHeaderByte >= nvpair);
  1114   return NS_ERROR_NOT_AVAILABLE;
  1117 // ConvertHeaders is used to convert the response headers
  1118 // in a syn_reply or in 0..N headers frames that follow it into
  1119 // HTTP/1 format
  1120 nsresult
  1121 SpdyStream31::ConvertHeaders(nsACString &aHeadersOut)
  1123   // :status and :version are required.
  1124   nsDependentCSubstring status, version;
  1125   nsresult rv = FindHeader(NS_LITERAL_CSTRING(":status"),
  1126                            status);
  1127   if (NS_FAILED(rv))
  1128     return (rv == NS_ERROR_NOT_AVAILABLE) ? NS_ERROR_ILLEGAL_VALUE : rv;
  1130   rv = FindHeader(NS_LITERAL_CSTRING(":version"),
  1131                   version);
  1132   if (NS_FAILED(rv))
  1133     return (rv == NS_ERROR_NOT_AVAILABLE) ? NS_ERROR_ILLEGAL_VALUE : rv;
  1135   if (mDecompressedBytes && mDecompressBufferUsed) {
  1136     Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_SIZE, mDecompressedBytes);
  1137     uint32_t ratio =
  1138       mDecompressedBytes * 100 / mDecompressBufferUsed;
  1139     Telemetry::Accumulate(Telemetry::SPDY_SYN_REPLY_RATIO, ratio);
  1142   aHeadersOut.Truncate();
  1143   aHeadersOut.SetCapacity(mDecompressBufferUsed + 64);
  1145   // Connection, Keep-Alive and chunked transfer encodings are to be
  1146   // removed.
  1148   // Content-Length is 'advisory'.. we will not strip it because it can
  1149   // create UI feedback.
  1151   aHeadersOut.Append(version);
  1152   aHeadersOut.Append(NS_LITERAL_CSTRING(" "));
  1153   aHeadersOut.Append(status);
  1154   aHeadersOut.Append(NS_LITERAL_CSTRING("\r\n"));
  1156   const unsigned char *nvpair = reinterpret_cast<unsigned char *>
  1157     (mDecompressBuffer.get()) + 4;
  1158   const unsigned char *lastHeaderByte = reinterpret_cast<unsigned char *>
  1159     (mDecompressBuffer.get()) + mDecompressBufferUsed;
  1160   if (lastHeaderByte < nvpair)
  1161     return NS_ERROR_ILLEGAL_VALUE;
  1163   do {
  1164     uint32_t numPairs = PR_ntohl(reinterpret_cast<const uint32_t *>(nvpair)[-1]);
  1166     for (uint32_t index = 0; index < numPairs; ++index) {
  1167       if (lastHeaderByte < nvpair + 4)
  1168         return NS_ERROR_ILLEGAL_VALUE;
  1170       uint32_t nameLen = (nvpair[0] << 24) + (nvpair[1] << 16) +
  1171         (nvpair[2] << 8) + nvpair[3];
  1172       if (lastHeaderByte < nvpair + 4 + nameLen)
  1173         return NS_ERROR_ILLEGAL_VALUE;
  1175       nsDependentCSubstring nameString =
  1176         Substring(reinterpret_cast<const char *>(nvpair) + 4,
  1177                   reinterpret_cast<const char *>(nvpair) + 4 + nameLen);
  1179       if (lastHeaderByte < nvpair + 8 + nameLen)
  1180         return NS_ERROR_ILLEGAL_VALUE;
  1182       // Look for illegal characters in the nameString.
  1183       // This includes upper case characters and nulls (as they will
  1184       // break the fixup-nulls-in-value-string algorithm)
  1185       // Look for upper case characters in the name. They are illegal.
  1186       for (char *cPtr = nameString.BeginWriting();
  1187            cPtr && cPtr < nameString.EndWriting();
  1188            ++cPtr) {
  1189         if (*cPtr <= 'Z' && *cPtr >= 'A') {
  1190           nsCString toLog(nameString);
  1192           LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p "
  1193                 "upper case response header found. [%s]\n",
  1194                 mSession, this, toLog.get()));
  1196           return NS_ERROR_ILLEGAL_VALUE;
  1199         // check for null characters
  1200         if (*cPtr == '\0')
  1201           return NS_ERROR_ILLEGAL_VALUE;
  1204       // HTTP Chunked responses are not legal over spdy. We do not need
  1205       // to look for chunked specifically because it is the only HTTP
  1206       // allowed default encoding and we did not negotiate further encodings
  1207       // via TE
  1208       if (nameString.Equals(NS_LITERAL_CSTRING("transfer-encoding"))) {
  1209         LOG3(("SpdyStream31::ConvertHeaders session=%p stream=%p "
  1210               "transfer-encoding found. Chunked is invalid and no TE sent.",
  1211               mSession, this));
  1213         return NS_ERROR_ILLEGAL_VALUE;
  1216       uint32_t valueLen =
  1217         (nvpair[4 + nameLen] << 24) + (nvpair[5 + nameLen] << 16) +
  1218         (nvpair[6 + nameLen] << 8)  +   nvpair[7 + nameLen];
  1220       if (lastHeaderByte < nvpair + 8 + nameLen + valueLen)
  1221         return NS_ERROR_ILLEGAL_VALUE;
  1223       // spdy transport level headers shouldn't be gatewayed into http/1
  1224       if (!nameString.IsEmpty() && nameString[0] != ':' &&
  1225           !nameString.Equals(NS_LITERAL_CSTRING("connection")) &&
  1226           !nameString.Equals(NS_LITERAL_CSTRING("keep-alive"))) {
  1227         nsDependentCSubstring valueString =
  1228           Substring(reinterpret_cast<const char *>(nvpair) + 8 + nameLen,
  1229                     reinterpret_cast<const char *>(nvpair) + 8 + nameLen +
  1230                     valueLen);
  1232         aHeadersOut.Append(nameString);
  1233         aHeadersOut.Append(NS_LITERAL_CSTRING(": "));
  1235         // expand NULL bytes in the value string
  1236         for (char *cPtr = valueString.BeginWriting();
  1237              cPtr && cPtr < valueString.EndWriting();
  1238              ++cPtr) {
  1239           if (*cPtr != 0) {
  1240             aHeadersOut.Append(*cPtr);
  1241             continue;
  1244           // NULLs are really "\r\nhdr: "
  1245           aHeadersOut.Append(NS_LITERAL_CSTRING("\r\n"));
  1246           aHeadersOut.Append(nameString);
  1247           aHeadersOut.Append(NS_LITERAL_CSTRING(": "));
  1250         aHeadersOut.Append(NS_LITERAL_CSTRING("\r\n"));
  1252       // move to the next name/value pair in this block
  1253       nvpair += 8 + nameLen + valueLen;
  1256     // move to the next name/value header block (if there is one) - the
  1257     // first pair is offset 4 bytes into it
  1258     nvpair += 4;
  1259   } while (lastHeaderByte >= nvpair);
  1261   aHeadersOut.Append(NS_LITERAL_CSTRING("X-Firefox-Spdy: 3.1\r\n\r\n"));
  1262   LOG (("decoded response headers are:\n%s",
  1263         aHeadersOut.BeginReading()));
  1265   // The spdy formatted buffer isnt needed anymore - free it up
  1266   mDecompressBuffer = nullptr;
  1267   mDecompressBufferSize = 0;
  1268   mDecompressBufferUsed = 0;
  1270   return NS_OK;
  1273 void
  1274 SpdyStream31::ExecuteCompress(uint32_t flushMode)
  1276   // Expect mZlib->avail_in and mZlib->next_in to be set.
  1277   // Append the compressed version of next_in to mTxInlineFrame
  1279   do
  1281     uint32_t avail = mTxInlineFrameSize - mTxInlineFrameUsed;
  1282     if (avail < 1) {
  1283       SpdySession31::EnsureBuffer(mTxInlineFrame,
  1284                                   mTxInlineFrameSize + 2000,
  1285                                   mTxInlineFrameUsed,
  1286                                   mTxInlineFrameSize);
  1287       avail = mTxInlineFrameSize - mTxInlineFrameUsed;
  1290     mZlib->next_out = mTxInlineFrame + mTxInlineFrameUsed;
  1291     mZlib->avail_out = avail;
  1292     deflate(mZlib, flushMode);
  1293     mTxInlineFrameUsed += avail - mZlib->avail_out;
  1294   } while (mZlib->avail_in > 0 || !mZlib->avail_out);
  1297 void
  1298 SpdyStream31::CompressToFrame(uint32_t data)
  1300   // convert the data to 4 byte network byte order and write that
  1301   // to the compressed stream
  1302   data = PR_htonl(data);
  1304   mZlib->next_in = reinterpret_cast<unsigned char *> (&data);
  1305   mZlib->avail_in = 4;
  1306   ExecuteCompress(Z_NO_FLUSH);
  1310 void
  1311 SpdyStream31::CompressToFrame(const char *data, uint32_t len)
  1313   // Format calls for a network ordered 32 bit length
  1314   // followed by the utf8 string
  1316   uint32_t networkLen = PR_htonl(len);
  1318   // write out the length
  1319   mZlib->next_in = reinterpret_cast<unsigned char *> (&networkLen);
  1320   mZlib->avail_in = 4;
  1321   ExecuteCompress(Z_NO_FLUSH);
  1323   // write out the data
  1324   mZlib->next_in = (unsigned char *)data;
  1325   mZlib->avail_in = len;
  1326   ExecuteCompress(Z_NO_FLUSH);
  1329 void
  1330 SpdyStream31::CompressFlushFrame()
  1332   mZlib->next_in = (unsigned char *) "";
  1333   mZlib->avail_in = 0;
  1334   ExecuteCompress(Z_SYNC_FLUSH);
  1337 void
  1338 SpdyStream31::Close(nsresult reason)
  1340   mTransaction->Close(reason);
  1343 void
  1344 SpdyStream31::UpdateRemoteWindow(int32_t delta)
  1346   mRemoteWindow += delta;
  1348   // If the stream had a <=0 window, that has now opened
  1349   // schedule it for writing again
  1350   if (mBlockedOnRwin && mSession->RemoteSessionWindow() > 0 &&
  1351       mRemoteWindow > 0) {
  1352     // the window has been opened :)
  1353     mSession->TransactionHasDataToWrite(this);
  1357 //-----------------------------------------------------------------------------
  1358 // nsAHttpSegmentReader
  1359 //-----------------------------------------------------------------------------
  1361 nsresult
  1362 SpdyStream31::OnReadSegment(const char *buf,
  1363                             uint32_t count,
  1364                             uint32_t *countRead)
  1366   LOG3(("SpdyStream31::OnReadSegment %p count=%d state=%x",
  1367         this, count, mUpstreamState));
  1369   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
  1370   MOZ_ASSERT(mSegmentReader, "OnReadSegment with null mSegmentReader");
  1372   nsresult rv = NS_ERROR_UNEXPECTED;
  1373   uint32_t dataLength;
  1375   switch (mUpstreamState) {
  1376   case GENERATING_SYN_STREAM:
  1377     // The buffer is the HTTP request stream, including at least part of the
  1378     // HTTP request header. This state's job is to build a SYN_STREAM frame
  1379     // from the header information. count is the number of http bytes available
  1380     // (which may include more than the header), and in countRead we return
  1381     // the number of those bytes that we consume (i.e. the portion that are
  1382     // header bytes)
  1384     rv = ParseHttpRequestHeaders(buf, count, countRead);
  1385     if (NS_FAILED(rv))
  1386       return rv;
  1387     LOG3(("ParseHttpRequestHeaders %p used %d of %d. complete = %d",
  1388           this, *countRead, count, mSynFrameComplete));
  1389     if (mSynFrameComplete) {
  1390       AdjustInitialWindow();
  1391       rv = TransmitFrame(nullptr, nullptr, true);
  1392       if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
  1393         // this can't happen
  1394         MOZ_ASSERT(false, "Transmit Frame SYN_FRAME must at least buffer data");
  1395         rv = NS_ERROR_UNEXPECTED;
  1398       ChangeState(GENERATING_REQUEST_BODY);
  1399       break;
  1401     MOZ_ASSERT(*countRead == count, "Header parsing not complete but unused data");
  1402     break;
  1404   case GENERATING_REQUEST_BODY:
  1405     if ((mRemoteWindow <= 0) || (mSession->RemoteSessionWindow() <= 0)) {
  1406       *countRead = 0;
  1407       LOG3(("SpdyStream31 this=%p, id 0x%X request body suspended because "
  1408             "remote window is stream=%ld session=%ld.\n", this, mStreamID,
  1409             mRemoteWindow, mSession->RemoteSessionWindow()));
  1410       mBlockedOnRwin = true;
  1411       return NS_BASE_STREAM_WOULD_BLOCK;
  1413     mBlockedOnRwin = false;
  1415     dataLength = std::min(count, mChunkSize);
  1417     if (dataLength > mRemoteWindow)
  1418       dataLength = static_cast<uint32_t>(mRemoteWindow);
  1420     if (dataLength > mSession->RemoteSessionWindow())
  1421       dataLength = static_cast<uint32_t>(mSession->RemoteSessionWindow());
  1423     LOG3(("SpdyStream31 this=%p id 0x%X remote window is stream %ld and "
  1424           "session %ld. Chunk is %d\n",
  1425           this, mStreamID, mRemoteWindow, mSession->RemoteSessionWindow(),
  1426           dataLength));
  1427     mRemoteWindow -= dataLength;
  1428     mSession->DecrementRemoteSessionWindow(dataLength);
  1430     LOG3(("SpdyStream31 %p id %x request len remaining %d, "
  1431           "count avail %d, chunk used %d",
  1432           this, mStreamID, mRequestBodyLenRemaining, count, dataLength));
  1433     if (dataLength > mRequestBodyLenRemaining)
  1434       return NS_ERROR_UNEXPECTED;
  1435     mRequestBodyLenRemaining -= dataLength;
  1436     GenerateDataFrameHeader(dataLength, !mRequestBodyLenRemaining);
  1437     ChangeState(SENDING_REQUEST_BODY);
  1438     // NO BREAK
  1440   case SENDING_REQUEST_BODY:
  1441     MOZ_ASSERT(mTxInlineFrameUsed, "OnReadSegment Send Data Header 0b");
  1442     rv = TransmitFrame(buf, countRead, false);
  1443     MOZ_ASSERT(NS_FAILED(rv) || !mTxInlineFrameUsed,
  1444                "Transmit Frame should be all or nothing");
  1446     LOG3(("TransmitFrame() rv=%x returning %d data bytes. "
  1447           "Header is %d Body is %d.",
  1448           rv, *countRead, mTxInlineFrameUsed, mTxStreamFrameSize));
  1450     // normalize a partial write with a WOULD_BLOCK into just a partial write
  1451     // as some code will take WOULD_BLOCK to mean an error with nothing
  1452     // written (e.g. nsHttpTransaction::ReadRequestSegment()
  1453     if (rv == NS_BASE_STREAM_WOULD_BLOCK && *countRead)
  1454       rv = NS_OK;
  1456     // If that frame was all sent, look for another one
  1457     if (!mTxInlineFrameUsed)
  1458       ChangeState(GENERATING_REQUEST_BODY);
  1459     break;
  1461   case SENDING_FIN_STREAM:
  1462     MOZ_ASSERT(false, "resuming partial fin stream out of OnReadSegment");
  1463     break;
  1465   default:
  1466     MOZ_ASSERT(false, "SpdyStream31::OnReadSegment non-write state");
  1467     break;
  1470   return rv;
  1473 //-----------------------------------------------------------------------------
  1474 // nsAHttpSegmentWriter
  1475 //-----------------------------------------------------------------------------
  1477 nsresult
  1478 SpdyStream31::OnWriteSegment(char *buf,
  1479                              uint32_t count,
  1480                              uint32_t *countWritten)
  1482   LOG3(("SpdyStream31::OnWriteSegment %p count=%d state=%x 0x%X\n",
  1483         this, count, mUpstreamState, mStreamID));
  1485   MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
  1486   MOZ_ASSERT(mSegmentWriter);
  1488   if (!mPushSource)
  1489     return mSegmentWriter->OnWriteSegment(buf, count, countWritten);
  1491   nsresult rv;
  1492   rv = mPushSource->GetBufferedData(buf, count, countWritten);
  1493   if (NS_FAILED(rv))
  1494     return rv;
  1496   mSession->ConnectPushedStream(this);
  1497   return NS_OK;
  1500 } // namespace mozilla::net
  1501 } // namespace mozilla

mercurial