LCOV - code coverage report
Current view: top level - netwerk/protocol/http - Http2Push.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 215 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 41 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : // HttpLog.h should generally be included first
       8             : #include "HttpLog.h"
       9             : 
      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()
      15             : 
      16             : #include <algorithm>
      17             : 
      18             : #include "Http2Push.h"
      19             : #include "nsHttpChannel.h"
      20             : #include "nsIHttpPushListener.h"
      21             : #include "nsString.h"
      22             : 
      23             : namespace mozilla {
      24             : namespace net {
      25             : 
      26           0 : class CallChannelOnPush final : public Runnable {
      27             :   public:
      28           0 :     CallChannelOnPush(nsIHttpChannelInternal* associatedChannel,
      29             :                       const nsACString& pushedURI,
      30             :                       Http2PushedStream* pushStream)
      31           0 :       : Runnable("net::CallChannelOnPush")
      32             :       , mAssociatedChannel(associatedChannel)
      33             :       , mPushedURI(pushedURI)
      34           0 :       , mPushedStream(pushStream)
      35             :     {
      36           0 :   }
      37             : 
      38           0 :   NS_IMETHOD Run() override
      39             :   {
      40           0 :     MOZ_ASSERT(NS_IsMainThread());
      41           0 :     RefPtr<nsHttpChannel> channel;
      42           0 :     CallQueryInterface(mAssociatedChannel, channel.StartAssignment());
      43           0 :     MOZ_ASSERT(channel);
      44           0 :     if (channel && NS_SUCCEEDED(channel->OnPush(mPushedURI, mPushedStream))) {
      45           0 :       return NS_OK;
      46             :     }
      47             : 
      48           0 :     LOG3(("Http2PushedStream Orphan %p failed OnPush\n", this));
      49           0 :     mPushedStream->OnPushFailed();
      50           0 :     return NS_OK;
      51             :   }
      52             : 
      53             : private:
      54             :   nsCOMPtr<nsIHttpChannelInternal> mAssociatedChannel;
      55             :   const nsCString mPushedURI;
      56             :   Http2PushedStream *mPushedStream;
      57             : };
      58             : 
      59             : //////////////////////////////////////////
      60             : // Http2PushedStream
      61             : //////////////////////////////////////////
      62             : 
      63           0 : Http2PushedStream::Http2PushedStream(Http2PushTransactionBuffer *aTransaction,
      64             :                                      Http2Session *aSession,
      65             :                                      Http2Stream *aAssociatedStream,
      66           0 :                                      uint32_t aID)
      67             :   :Http2Stream(aTransaction, aSession, 0)
      68             :   , mConsumerStream(nullptr)
      69           0 :   , mAssociatedTransaction(aAssociatedStream->Transaction())
      70             :   , mBufferedPush(aTransaction)
      71             :   , mStatus(NS_OK)
      72             :   , mPushCompleted(false)
      73             :   , mDeferCleanupOnSuccess(true)
      74             :   , mDeferCleanupOnPush(false)
      75           0 :   , mOnPushFailed(false)
      76             : {
      77           0 :   LOG3(("Http2PushedStream ctor this=%p 0x%X\n", this, aID));
      78           0 :   mStreamID = aID;
      79           0 :   MOZ_ASSERT(!(aID & 1)); // must be even to be a pushed stream
      80           0 :   mBufferedPush->SetPushStream(this);
      81           0 :   mRequestContext = aAssociatedStream->RequestContext();
      82           0 :   mLastRead = TimeStamp::Now();
      83           0 :   SetPriority(aAssociatedStream->Priority() + 1);
      84           0 : }
      85             : 
      86             : bool
      87           0 : Http2PushedStream::GetPushComplete()
      88             : {
      89           0 :   return mPushCompleted;
      90             : }
      91             : 
      92             : nsresult
      93           0 : Http2PushedStream::WriteSegments(nsAHttpSegmentWriter *writer,
      94             :                                  uint32_t count, uint32_t *countWritten)
      95             : {
      96           0 :   nsresult rv = Http2Stream::WriteSegments(writer, count, countWritten);
      97           0 :   if (NS_SUCCEEDED(rv) && *countWritten) {
      98           0 :     mLastRead = TimeStamp::Now();
      99             :   }
     100             : 
     101           0 :   if (rv == NS_BASE_STREAM_CLOSED) {
     102           0 :     mPushCompleted = true;
     103           0 :     rv = NS_OK; // this is what a normal HTTP transaction would do
     104             :   }
     105           0 :   if (rv != NS_BASE_STREAM_WOULD_BLOCK && NS_FAILED(rv))
     106           0 :     mStatus = rv;
     107           0 :   return rv;
     108             : }
     109             : 
     110             : bool
     111           0 : Http2PushedStream::DeferCleanup(nsresult status)
     112             : {
     113           0 :   LOG3(("Http2PushedStream::DeferCleanup Query %p %" PRIx32 "\n", this,
     114             :         static_cast<uint32_t>(status)));
     115             : 
     116           0 :   if (NS_SUCCEEDED(status) && mDeferCleanupOnSuccess) {
     117           0 :     LOG3(("Http2PushedStream::DeferCleanup %p %" PRIx32 " defer on success\n", this,
     118             :           static_cast<uint32_t>(status)));
     119           0 :     return true;
     120             :   }
     121           0 :   if (mDeferCleanupOnPush) {
     122           0 :     LOG3(("Http2PushedStream::DeferCleanup %p %" PRIx32 " defer onPush ref\n", this,
     123             :           static_cast<uint32_t>(status)));
     124           0 :     return true;
     125             :   }
     126           0 :   if (mConsumerStream) {
     127           0 :     LOG3(("Http2PushedStream::DeferCleanup %p %" PRIx32 " defer active consumer\n", this,
     128             :           static_cast<uint32_t>(status)));
     129           0 :     return true;
     130             :   }
     131           0 :   LOG3(("Http2PushedStream::DeferCleanup Query %p %" PRIx32 " not deferred\n", this,
     132             :         static_cast<uint32_t>(status)));
     133           0 :   return false;
     134             : }
     135             : 
     136             : // return true if channel implements nsIHttpPushListener
     137             : bool
     138           0 : Http2PushedStream::TryOnPush()
     139             : {
     140           0 :   nsHttpTransaction *trans = mAssociatedTransaction->QueryHttpTransaction();
     141           0 :   if (!trans) {
     142           0 :     return false;
     143             :   }
     144             : 
     145           0 :   nsCOMPtr<nsIHttpChannelInternal> associatedChannel = do_QueryInterface(trans->HttpChannel());
     146           0 :   if (!associatedChannel) {
     147           0 :     return false;
     148             :   }
     149             : 
     150           0 :   if (!(trans->Caps() & NS_HTTP_ONPUSH_LISTENER)) {
     151           0 :     return false;
     152             :   }
     153             : 
     154           0 :   mDeferCleanupOnPush = true;
     155           0 :   nsCString uri = Origin() + Path();
     156           0 :   NS_DispatchToMainThread(new CallChannelOnPush(associatedChannel, uri, this));
     157           0 :   return true;
     158             : }
     159             : 
     160             : // side effect free static method to determine if Http2Stream implements nsIHttpPushListener
     161             : bool
     162           0 : Http2PushedStream::TestOnPush(Http2Stream *stream)
     163             : {
     164           0 :   if (!stream) {
     165           0 :     return false;
     166             :   }
     167           0 :   nsAHttpTransaction *abstractTransaction = stream->Transaction();
     168           0 :   if (!abstractTransaction) {
     169           0 :     return false;
     170             :   }
     171           0 :   nsHttpTransaction *trans = abstractTransaction->QueryHttpTransaction();
     172           0 :   if (!trans) {
     173           0 :     return false;
     174             :   }
     175           0 :   nsCOMPtr<nsIHttpChannelInternal> associatedChannel = do_QueryInterface(trans->HttpChannel());
     176           0 :   if (!associatedChannel) {
     177           0 :     return false;
     178             :   }
     179           0 :   return (trans->Caps() & NS_HTTP_ONPUSH_LISTENER);
     180             : }
     181             : 
     182             : nsresult
     183           0 : Http2PushedStream::ReadSegments(nsAHttpSegmentReader *reader,
     184             :                                 uint32_t, uint32_t *count)
     185             : {
     186           0 :   nsresult rv = NS_OK;
     187           0 :   *count = 0;
     188             : 
     189           0 :   mozilla::OriginAttributes originAttributes;
     190           0 :   switch (mUpstreamState) {
     191             :   case GENERATING_HEADERS:
     192             :     // The request headers for this has been processed, so we need to verify
     193             :     // that :authority, :scheme, and :path MUST be present. :method MUST NOT be
     194             :     // present
     195           0 :     mSocketTransport->GetOriginAttributes(&originAttributes);
     196           0 :     CreatePushHashKey(mHeaderScheme, mHeaderHost, originAttributes,
     197           0 :                       mSession->Serial(), mHeaderPath,
     198           0 :                       mOrigin, mHashKey);
     199             : 
     200           0 :     LOG3(("Http2PushStream 0x%X hash key %s\n", mStreamID, mHashKey.get()));
     201             : 
     202             :     // the write side of a pushed transaction just involves manipulating a little state
     203           0 :     SetSentFin(true);
     204           0 :     Http2Stream::mRequestHeadersDone = 1;
     205           0 :     Http2Stream::mOpenGenerated = 1;
     206           0 :     Http2Stream::ChangeState(UPSTREAM_COMPLETE);
     207           0 :     break;
     208             : 
     209             :   case UPSTREAM_COMPLETE:
     210             :     // Let's just clear the stream's transmit buffer by pushing it into
     211             :     // the session. This is probably a window adjustment.
     212           0 :     LOG3(("Http2Push::ReadSegments 0x%X \n", mStreamID));
     213           0 :     mSegmentReader = reader;
     214           0 :     rv = TransmitFrame(nullptr, nullptr, true);
     215           0 :     mSegmentReader = nullptr;
     216           0 :     break;
     217             : 
     218             :   case GENERATING_BODY:
     219             :   case SENDING_BODY:
     220             :   case SENDING_FIN_STREAM:
     221             :   default:
     222           0 :     break;
     223             :   }
     224             : 
     225           0 :   return rv;
     226             : }
     227             : 
     228             : void
     229           0 : Http2PushedStream::AdjustInitialWindow()
     230             : {
     231           0 :   LOG3(("Http2PushStream %p 0x%X AdjustInitialWindow", this, mStreamID));
     232           0 :   if (mConsumerStream) {
     233           0 :     LOG3(("Http2PushStream::AdjustInitialWindow %p 0x%X "
     234             :           "calling super consumer %p 0x%X\n", this,
     235             :           mStreamID, mConsumerStream, mConsumerStream->StreamID()));
     236           0 :     Http2Stream::AdjustInitialWindow();
     237             :     // Http2PushedStream::ReadSegments is needed to call TransmitFrame()
     238             :     // and actually get this information into the session bytestream
     239           0 :     mSession->TransactionHasDataToWrite(this);
     240             :   }
     241             :   // Otherwise, when we get hooked up, the initial window will get bumped
     242             :   // anyway, so we're good to go.
     243           0 : }
     244             : 
     245             : void
     246           0 : Http2PushedStream::SetConsumerStream(Http2Stream *consumer)
     247             : {
     248           0 :   mConsumerStream = consumer;
     249           0 :   mDeferCleanupOnPush = false;
     250           0 : }
     251             : 
     252             : bool
     253           0 : Http2PushedStream::GetHashKey(nsCString &key)
     254             : {
     255           0 :   if (mHashKey.IsEmpty())
     256           0 :     return false;
     257             : 
     258           0 :   key = mHashKey;
     259           0 :   return true;
     260             : }
     261             : 
     262             : void
     263           0 : Http2PushedStream::ConnectPushedStream(Http2Stream *stream)
     264             : {
     265           0 :   mSession->ConnectPushedStream(stream);
     266           0 : }
     267             : 
     268             : bool
     269           0 : Http2PushedStream::IsOrphaned(TimeStamp now)
     270             : {
     271           0 :   MOZ_ASSERT(!now.IsNull());
     272             : 
     273             :   // if session is not transmitting, and is also not connected to a consumer
     274             :   // stream, and its been like that for too long then it is oprhaned
     275             : 
     276           0 :   if (mConsumerStream || mDeferCleanupOnPush) {
     277           0 :     return false;
     278             :   }
     279             : 
     280           0 :   if (mOnPushFailed) {
     281           0 :     return true;
     282             :   }
     283             : 
     284           0 :   bool rv = ((now - mLastRead).ToSeconds() > 30.0);
     285           0 :   if (rv) {
     286           0 :     LOG3(("Http2PushedStream:IsOrphaned 0x%X IsOrphaned %3.2f\n",
     287             :           mStreamID, (now - mLastRead).ToSeconds()));
     288             :   }
     289           0 :   return rv;
     290             : }
     291             : 
     292             : nsresult
     293           0 : Http2PushedStream::GetBufferedData(char *buf,
     294             :                                    uint32_t count, uint32_t *countWritten)
     295             : {
     296           0 :   if (NS_FAILED(mStatus))
     297           0 :     return mStatus;
     298             : 
     299           0 :   nsresult rv = mBufferedPush->GetBufferedData(buf, count, countWritten);
     300           0 :   if (NS_FAILED(rv))
     301           0 :     return rv;
     302             : 
     303           0 :   if (!*countWritten)
     304           0 :     rv = GetPushComplete() ? NS_BASE_STREAM_CLOSED : NS_BASE_STREAM_WOULD_BLOCK;
     305             : 
     306           0 :   return rv;
     307             : }
     308             : 
     309             : //////////////////////////////////////////
     310             : // Http2PushTransactionBuffer
     311             : // This is the nsAHttpTransction owned by the stream when the pushed
     312             : // stream has not yet been matched with a pull request
     313             : //////////////////////////////////////////
     314             : 
     315           0 : NS_IMPL_ISUPPORTS0(Http2PushTransactionBuffer)
     316             : 
     317           0 : Http2PushTransactionBuffer::Http2PushTransactionBuffer()
     318             :   : mStatus(NS_OK)
     319             :   , mRequestHead(nullptr)
     320             :   , mPushStream(nullptr)
     321             :   , mIsDone(false)
     322             :   , mBufferedHTTP1Size(kDefaultBufferSize)
     323             :   , mBufferedHTTP1Used(0)
     324           0 :   , mBufferedHTTP1Consumed(0)
     325             : {
     326           0 :   mBufferedHTTP1 = MakeUnique<char[]>(mBufferedHTTP1Size);
     327           0 : }
     328             : 
     329           0 : Http2PushTransactionBuffer::~Http2PushTransactionBuffer()
     330             : {
     331           0 :   delete mRequestHead;
     332           0 : }
     333             : 
     334             : void
     335           0 : Http2PushTransactionBuffer::SetConnection(nsAHttpConnection *conn)
     336             : {
     337           0 : }
     338             : 
     339             : nsAHttpConnection *
     340           0 : Http2PushTransactionBuffer::Connection()
     341             : {
     342           0 :   return nullptr;
     343             : }
     344             : 
     345             : void
     346           0 : Http2PushTransactionBuffer::GetSecurityCallbacks(nsIInterfaceRequestor **outCB)
     347             : {
     348           0 :   *outCB = nullptr;
     349           0 : }
     350             : 
     351             : void
     352           0 : Http2PushTransactionBuffer::OnTransportStatus(nsITransport* transport,
     353             :                                               nsresult status, int64_t progress)
     354             : {
     355           0 : }
     356             : 
     357             : nsHttpConnectionInfo *
     358           0 : Http2PushTransactionBuffer::ConnectionInfo()
     359             : {
     360           0 :   if (!mPushStream) {
     361           0 :     return nullptr;
     362             :   }
     363           0 :   if (!mPushStream->Transaction()) {
     364           0 :     return nullptr;
     365             :   }
     366           0 :   MOZ_ASSERT(mPushStream->Transaction() != this);
     367           0 :   return mPushStream->Transaction()->ConnectionInfo();
     368             : }
     369             : 
     370             : bool
     371           0 : Http2PushTransactionBuffer::IsDone()
     372             : {
     373           0 :   return mIsDone;
     374             : }
     375             : 
     376             : nsresult
     377           0 : Http2PushTransactionBuffer::Status()
     378             : {
     379           0 :   return mStatus;
     380             : }
     381             : 
     382             : uint32_t
     383           0 : Http2PushTransactionBuffer::Caps()
     384             : {
     385           0 :   return 0;
     386             : }
     387             : 
     388             : void
     389           0 : Http2PushTransactionBuffer::SetDNSWasRefreshed()
     390             : {
     391           0 : }
     392             : 
     393             : uint64_t
     394           0 : Http2PushTransactionBuffer::Available()
     395             : {
     396           0 :   return mBufferedHTTP1Used - mBufferedHTTP1Consumed;
     397             : }
     398             : 
     399             : nsresult
     400           0 : Http2PushTransactionBuffer::ReadSegments(nsAHttpSegmentReader *reader,
     401             :                                          uint32_t count, uint32_t *countRead)
     402             : {
     403           0 :   *countRead = 0;
     404           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     405             : }
     406             : 
     407             : nsresult
     408           0 : Http2PushTransactionBuffer::WriteSegments(nsAHttpSegmentWriter *writer,
     409             :                                           uint32_t count, uint32_t *countWritten)
     410             : {
     411           0 :   if ((mBufferedHTTP1Size - mBufferedHTTP1Used) < 20480) {
     412           0 :     EnsureBuffer(mBufferedHTTP1,mBufferedHTTP1Size + kDefaultBufferSize,
     413           0 :                  mBufferedHTTP1Used, mBufferedHTTP1Size);
     414             :   }
     415             : 
     416           0 :   count = std::min(count, mBufferedHTTP1Size - mBufferedHTTP1Used);
     417           0 :   nsresult rv = writer->OnWriteSegment(&mBufferedHTTP1[mBufferedHTTP1Used],
     418           0 :                                        count, countWritten);
     419           0 :   if (NS_SUCCEEDED(rv)) {
     420           0 :     mBufferedHTTP1Used += *countWritten;
     421             :   }
     422           0 :   else if (rv == NS_BASE_STREAM_CLOSED) {
     423           0 :     mIsDone = true;
     424             :   }
     425             : 
     426           0 :   if (Available() || mIsDone) {
     427           0 :     Http2Stream *consumer = mPushStream->GetConsumerStream();
     428             : 
     429           0 :     if (consumer) {
     430           0 :       LOG3(("Http2PushTransactionBuffer::WriteSegments notifying connection "
     431             :             "consumer data available 0x%X [%" PRIu64 "] done=%d\n",
     432             :             mPushStream->StreamID(), Available(), mIsDone));
     433           0 :       mPushStream->ConnectPushedStream(consumer);
     434             :     }
     435             :   }
     436             : 
     437           0 :   return rv;
     438             : }
     439             : 
     440             : uint32_t
     441           0 : Http2PushTransactionBuffer::Http1xTransactionCount()
     442             : {
     443           0 :   return 0;
     444             : }
     445             : 
     446             : nsHttpRequestHead *
     447           0 : Http2PushTransactionBuffer::RequestHead()
     448             : {
     449           0 :   if (!mRequestHead)
     450           0 :     mRequestHead = new nsHttpRequestHead();
     451           0 :   return mRequestHead;
     452             : }
     453             : 
     454             : nsresult
     455           0 : Http2PushTransactionBuffer::TakeSubTransactions(
     456             :   nsTArray<RefPtr<nsAHttpTransaction> > &outTransactions)
     457             : {
     458           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     459             : }
     460             : 
     461             : void
     462           0 : Http2PushTransactionBuffer::SetProxyConnectFailed()
     463             : {
     464           0 : }
     465             : 
     466             : void
     467           0 : Http2PushTransactionBuffer::Close(nsresult reason)
     468             : {
     469           0 :   mStatus = reason;
     470           0 :   mIsDone = true;
     471           0 : }
     472             : 
     473             : nsresult
     474           0 : Http2PushTransactionBuffer::GetBufferedData(char *buf,
     475             :                                             uint32_t count,
     476             :                                             uint32_t *countWritten)
     477             : {
     478           0 :   *countWritten = std::min(count, static_cast<uint32_t>(Available()));
     479           0 :   if (*countWritten) {
     480           0 :     memcpy(buf, &mBufferedHTTP1[mBufferedHTTP1Consumed], *countWritten);
     481           0 :     mBufferedHTTP1Consumed += *countWritten;
     482             :   }
     483             : 
     484             :   // If all the data has been consumed then reset the buffer
     485           0 :   if (mBufferedHTTP1Consumed == mBufferedHTTP1Used) {
     486           0 :     mBufferedHTTP1Consumed = 0;
     487           0 :     mBufferedHTTP1Used = 0;
     488             :   }
     489             : 
     490           0 :   return NS_OK;
     491             : }
     492             : 
     493             : } // namespace net
     494             : } // namespace mozilla

Generated by: LCOV version 1.13