LCOV - code coverage report
Current view: top level - netwerk/protocol/http - HttpChannelParentListener.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 45 173 26.0 %
Date: 2017-07-14 16:53:18 Functions: 11 30 36.7 %
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             : #include "HttpChannelParentListener.h"
      11             : #include "mozilla/net/HttpChannelParent.h"
      12             : #include "mozilla/Unused.h"
      13             : #include "nsIAuthPrompt.h"
      14             : #include "nsIAuthPrompt2.h"
      15             : #include "nsIHttpEventSink.h"
      16             : #include "nsIHttpHeaderVisitor.h"
      17             : #include "nsIRedirectChannelRegistrar.h"
      18             : #include "nsIPromptFactory.h"
      19             : #include "nsIWindowWatcher.h"
      20             : #include "nsQueryObject.h"
      21             : 
      22             : using mozilla::Unused;
      23             : 
      24             : namespace mozilla {
      25             : namespace net {
      26             : 
      27           3 : HttpChannelParentListener::HttpChannelParentListener(HttpChannelParent* aInitialChannel)
      28             :   : mNextListener(aInitialChannel)
      29             :   , mRedirectChannelId(0)
      30             :   , mSuspendedForDiversion(false)
      31             :   , mShouldIntercept(false)
      32           3 :   , mShouldSuspendIntercept(false)
      33             : {
      34           3 :   LOG(("HttpChannelParentListener::HttpChannelParentListener [this=%p, next=%p]",
      35             :        this, aInitialChannel));
      36           3 : }
      37             : 
      38           4 : HttpChannelParentListener::~HttpChannelParentListener()
      39             : {
      40           6 : }
      41             : 
      42             : //-----------------------------------------------------------------------------
      43             : // HttpChannelParentListener::nsISupports
      44             : //-----------------------------------------------------------------------------
      45             : 
      46          91 : NS_IMPL_ADDREF(HttpChannelParentListener)
      47          90 : NS_IMPL_RELEASE(HttpChannelParentListener)
      48          47 : NS_INTERFACE_MAP_BEGIN(HttpChannelParentListener)
      49          47 :   NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
      50          13 :   NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
      51           6 :   NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
      52           6 :   NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
      53           6 :   NS_INTERFACE_MAP_ENTRY(nsIRedirectResultListener)
      54           6 :   NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController)
      55           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInterfaceRequestor)
      56           0 :   if (aIID.Equals(NS_GET_IID(HttpChannelParentListener))) {
      57           0 :     foundInterface = static_cast<nsIInterfaceRequestor*>(this);
      58             :   } else
      59           0 : NS_INTERFACE_MAP_END
      60             : 
      61             : //-----------------------------------------------------------------------------
      62             : // HttpChannelParentListener::nsIRequestObserver
      63             : //-----------------------------------------------------------------------------
      64             : 
      65             : NS_IMETHODIMP
      66           3 : HttpChannelParentListener::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
      67             : {
      68           3 :   MOZ_RELEASE_ASSERT(!mSuspendedForDiversion,
      69             :     "Cannot call OnStartRequest if suspended for diversion!");
      70             : 
      71           3 :   if (!mNextListener)
      72           0 :     return NS_ERROR_UNEXPECTED;
      73             : 
      74           3 :   LOG(("HttpChannelParentListener::OnStartRequest [this=%p]\n", this));
      75           3 :   return mNextListener->OnStartRequest(aRequest, aContext);
      76             : }
      77             : 
      78             : NS_IMETHODIMP
      79           3 : HttpChannelParentListener::OnStopRequest(nsIRequest *aRequest,
      80             :                                          nsISupports *aContext,
      81             :                                          nsresult aStatusCode)
      82             : {
      83           3 :   MOZ_RELEASE_ASSERT(!mSuspendedForDiversion,
      84             :     "Cannot call OnStopRequest if suspended for diversion!");
      85             : 
      86           3 :   if (!mNextListener)
      87           0 :     return NS_ERROR_UNEXPECTED;
      88             : 
      89           3 :   LOG(("HttpChannelParentListener::OnStopRequest: [this=%p status=%" PRIu32 "]\n",
      90             :        this, static_cast<uint32_t>(aStatusCode)));
      91           3 :   nsresult rv = mNextListener->OnStopRequest(aRequest, aContext, aStatusCode);
      92             : 
      93           3 :   mNextListener = nullptr;
      94           3 :   return rv;
      95             : }
      96             : 
      97             : //-----------------------------------------------------------------------------
      98             : // HttpChannelParentListener::nsIStreamListener
      99             : //-----------------------------------------------------------------------------
     100             : 
     101             : NS_IMETHODIMP
     102           3 : HttpChannelParentListener::OnDataAvailable(nsIRequest *aRequest,
     103             :                                            nsISupports *aContext,
     104             :                                            nsIInputStream *aInputStream,
     105             :                                            uint64_t aOffset,
     106             :                                            uint32_t aCount)
     107             : {
     108           3 :   MOZ_RELEASE_ASSERT(!mSuspendedForDiversion,
     109             :     "Cannot call OnDataAvailable if suspended for diversion!");
     110             : 
     111           3 :   if (!mNextListener)
     112           0 :     return NS_ERROR_UNEXPECTED;
     113             : 
     114           3 :   LOG(("HttpChannelParentListener::OnDataAvailable [this=%p]\n", this));
     115           3 :   return mNextListener->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
     116             : }
     117             : 
     118             : //-----------------------------------------------------------------------------
     119             : // HttpChannelParentListener::nsIInterfaceRequestor
     120             : //-----------------------------------------------------------------------------
     121             : 
     122             : NS_IMETHODIMP
     123          37 : HttpChannelParentListener::GetInterface(const nsIID& aIID, void **result)
     124             : {
     125         111 :   if (aIID.Equals(NS_GET_IID(nsIChannelEventSink)) ||
     126          74 :       aIID.Equals(NS_GET_IID(nsIHttpEventSink))  ||
     127         108 :       aIID.Equals(NS_GET_IID(nsINetworkInterceptController))  ||
     128          34 :       aIID.Equals(NS_GET_IID(nsIRedirectResultListener)))
     129             :   {
     130           3 :     return QueryInterface(aIID, result);
     131             :   }
     132             : 
     133          68 :   nsCOMPtr<nsIInterfaceRequestor> ir;
     134         170 :   if (mNextListener &&
     135         170 :       NS_SUCCEEDED(CallQueryInterface(mNextListener.get(),
     136             :                                       getter_AddRefs(ir))))
     137             :   {
     138          34 :     return ir->GetInterface(aIID, result);
     139             :   }
     140             : 
     141           0 :   if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
     142           0 :       aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
     143             :     nsresult rv;
     144             :     nsCOMPtr<nsIPromptFactory> wwatch =
     145           0 :       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     146           0 :     NS_ENSURE_SUCCESS(rv, rv);
     147             : 
     148           0 :     return wwatch->GetPrompt(nullptr, aIID,
     149           0 :                              reinterpret_cast<void**>(result));
     150             :   }
     151             : 
     152           0 :   return NS_NOINTERFACE;
     153             : }
     154             : 
     155             : //-----------------------------------------------------------------------------
     156             : // HttpChannelParentListener::nsIChannelEventSink
     157             : //-----------------------------------------------------------------------------
     158             : 
     159             : NS_IMETHODIMP
     160           0 : HttpChannelParentListener::AsyncOnChannelRedirect(
     161             :                                     nsIChannel *oldChannel,
     162             :                                     nsIChannel *newChannel,
     163             :                                     uint32_t redirectFlags,
     164             :                                     nsIAsyncVerifyRedirectCallback* callback)
     165             : {
     166           0 :   LOG(("HttpChannelParentListener::AsyncOnChannelRedirect [this=%p, old=%p, new=%p, flags=%u]",
     167             :        this, oldChannel, newChannel, redirectFlags));
     168             : 
     169             :   nsresult rv;
     170             : 
     171             :   nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel =
     172           0 :       do_QueryInterface(mNextListener);
     173           0 :   if (!activeRedirectingChannel) {
     174           0 :     NS_ERROR("Channel got a redirect response, but doesn't implement "
     175             :              "nsIParentRedirectingChannel to handle it.");
     176           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     177             :   }
     178             : 
     179             :   // Register the new channel and obtain id for it
     180             :   nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
     181           0 :       do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
     182           0 :   NS_ENSURE_SUCCESS(rv, rv);
     183             : 
     184           0 :   rv = registrar->RegisterChannel(newChannel, &mRedirectChannelId);
     185           0 :   NS_ENSURE_SUCCESS(rv, rv);
     186             : 
     187           0 :   LOG(("Registered %p channel under id=%d", newChannel, mRedirectChannelId));
     188             : 
     189           0 :   return activeRedirectingChannel->StartRedirect(mRedirectChannelId,
     190             :                                                  newChannel,
     191             :                                                  redirectFlags,
     192           0 :                                                  callback);
     193             : }
     194             : 
     195             : //-----------------------------------------------------------------------------
     196             : // HttpChannelParentListener::nsIRedirectResultListener
     197             : //-----------------------------------------------------------------------------
     198             : 
     199             : NS_IMETHODIMP
     200           0 : HttpChannelParentListener::OnRedirectResult(bool succeeded)
     201             : {
     202           0 :   LOG(("HttpChannelParentListener::OnRedirectResult [this=%p, suc=%d]",
     203             :        this, succeeded));
     204             : 
     205             :   nsresult rv;
     206             : 
     207           0 :   nsCOMPtr<nsIParentChannel> redirectChannel;
     208           0 :   if (mRedirectChannelId) {
     209             :     nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
     210           0 :         do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
     211           0 :     NS_ENSURE_SUCCESS(rv, rv);
     212             : 
     213           0 :     rv = registrar->GetParentChannel(mRedirectChannelId,
     214           0 :                                      getter_AddRefs(redirectChannel));
     215           0 :     if (NS_FAILED(rv) || !redirectChannel) {
     216             :       // Redirect might get canceled before we got AsyncOnChannelRedirect
     217           0 :       LOG(("Registered parent channel not found under id=%d", mRedirectChannelId));
     218             : 
     219           0 :       nsCOMPtr<nsIChannel> newChannel;
     220           0 :       rv = registrar->GetRegisteredChannel(mRedirectChannelId,
     221           0 :                                            getter_AddRefs(newChannel));
     222           0 :       MOZ_ASSERT(newChannel, "Already registered channel not found");
     223             : 
     224           0 :       if (NS_SUCCEEDED(rv))
     225           0 :         newChannel->Cancel(NS_BINDING_ABORTED);
     226             :     }
     227             : 
     228             :     // Release all previously registered channels, they are no longer need to be
     229             :     // kept in the registrar from this moment.
     230           0 :     registrar->DeregisterChannels(mRedirectChannelId);
     231             : 
     232           0 :     mRedirectChannelId = 0;
     233             :   }
     234             : 
     235           0 :   if (!redirectChannel) {
     236           0 :     succeeded = false;
     237             :   }
     238             : 
     239             :   nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel =
     240           0 :       do_QueryInterface(mNextListener);
     241           0 :   MOZ_ASSERT(activeRedirectingChannel,
     242             :     "Channel finished a redirect response, but doesn't implement "
     243             :     "nsIParentRedirectingChannel to complete it.");
     244             : 
     245           0 :   if (activeRedirectingChannel) {
     246           0 :     activeRedirectingChannel->CompleteRedirect(succeeded);
     247             :   } else {
     248           0 :     succeeded = false;
     249             :   }
     250             : 
     251           0 :   if (succeeded) {
     252             :     // Switch to redirect channel and delete the old one.
     253           0 :     nsCOMPtr<nsIParentChannel> parent;
     254           0 :     parent = do_QueryInterface(mNextListener);
     255           0 :     MOZ_ASSERT(parent);
     256           0 :     parent->Delete();
     257           0 :     mNextListener = do_QueryInterface(redirectChannel);
     258           0 :     MOZ_ASSERT(mNextListener);
     259           0 :     redirectChannel->SetParentListener(this);
     260           0 :   } else if (redirectChannel) {
     261             :     // Delete the redirect target channel: continue using old channel
     262           0 :     redirectChannel->Delete();
     263             :   }
     264             : 
     265           0 :   return NS_OK;
     266             : }
     267             : 
     268             : //-----------------------------------------------------------------------------
     269             : // HttpChannelParentListener::nsINetworkInterceptController
     270             : //-----------------------------------------------------------------------------
     271             : 
     272             : NS_IMETHODIMP
     273           0 : HttpChannelParentListener::ShouldPrepareForIntercept(nsIURI* aURI,
     274             :                                                      bool aIsNonSubresourceRequest,
     275             :                                                      bool* aShouldIntercept)
     276             : {
     277           0 :   *aShouldIntercept = mShouldIntercept;
     278           0 :   return NS_OK;
     279             : }
     280             : 
     281             : class HeaderVisitor final : public nsIHttpHeaderVisitor
     282             : {
     283             :   nsCOMPtr<nsIInterceptedChannel> mChannel;
     284           0 :   ~HeaderVisitor()
     285           0 :   {
     286           0 :   }
     287             : public:
     288           0 :   explicit HeaderVisitor(nsIInterceptedChannel* aChannel) : mChannel(aChannel)
     289             :   {
     290           0 :   }
     291             : 
     292             :   NS_DECL_ISUPPORTS
     293             : 
     294           0 :   NS_IMETHOD VisitHeader(const nsACString& aHeader, const nsACString& aValue) override
     295             :   {
     296           0 :     mChannel->SynthesizeHeader(aHeader, aValue);
     297           0 :     return NS_OK;
     298             :   }
     299             : };
     300             : 
     301           0 : NS_IMPL_ISUPPORTS(HeaderVisitor, nsIHttpHeaderVisitor)
     302             : 
     303           0 : class FinishSynthesizedResponse : public Runnable
     304             : {
     305             :   nsCOMPtr<nsIInterceptedChannel> mChannel;
     306             : public:
     307           0 :   explicit FinishSynthesizedResponse(nsIInterceptedChannel* aChannel)
     308           0 :     : Runnable("net::FinishSynthesizedResponse")
     309           0 :     , mChannel(aChannel)
     310             :   {
     311           0 :   }
     312             : 
     313           0 :   NS_IMETHOD Run() override
     314             :   {
     315             :     // The URL passed as an argument here doesn't matter, since the child will
     316             :     // receive a redirection notification as a result of this synthesized response.
     317           0 :     mChannel->FinishSynthesizedResponse(EmptyCString());
     318           0 :     return NS_OK;
     319             :   }
     320             : };
     321             : 
     322             : NS_IMETHODIMP
     323           0 : HttpChannelParentListener::ChannelIntercepted(nsIInterceptedChannel* aChannel)
     324             : {
     325           0 :   if (mShouldSuspendIntercept) {
     326           0 :     mInterceptedChannel = aChannel;
     327           0 :     return NS_OK;
     328             :   }
     329             : 
     330           0 :   nsAutoCString statusText;
     331           0 :   mSynthesizedResponseHead->StatusText(statusText);
     332           0 :   aChannel->SynthesizeStatus(mSynthesizedResponseHead->Status(), statusText);
     333           0 :   nsCOMPtr<nsIHttpHeaderVisitor> visitor = new HeaderVisitor(aChannel);
     334             :   DebugOnly<nsresult> rv =
     335           0 :     mSynthesizedResponseHead->VisitHeaders(visitor,
     336           0 :                                            nsHttpHeaderArray::eFilterResponse);
     337           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
     338             : 
     339           0 :   nsCOMPtr<nsIRunnable> event = new FinishSynthesizedResponse(aChannel);
     340           0 :   NS_DispatchToCurrentThread(event);
     341             : 
     342           0 :   mSynthesizedResponseHead = nullptr;
     343             : 
     344           0 :   MOZ_ASSERT(mNextListener);
     345           0 :   RefPtr<HttpChannelParent> channel = do_QueryObject(mNextListener);
     346           0 :   MOZ_ASSERT(channel);
     347           0 :   channel->ResponseSynthesized();
     348             : 
     349           0 :   return NS_OK;
     350             : }
     351             : 
     352             : //-----------------------------------------------------------------------------
     353             : 
     354             : nsresult
     355           0 : HttpChannelParentListener::SuspendForDiversion()
     356             : {
     357           0 :   if (NS_WARN_IF(mSuspendedForDiversion)) {
     358           0 :     MOZ_ASSERT(!mSuspendedForDiversion, "Cannot SuspendForDiversion twice!");
     359           0 :     return NS_ERROR_UNEXPECTED;
     360             :   }
     361             : 
     362             :   // While this is set, no OnStart/OnData/OnStop callbacks should be forwarded
     363             :   // to mNextListener.
     364           0 :   mSuspendedForDiversion = true;
     365             : 
     366           0 :   return NS_OK;
     367             : }
     368             : 
     369             : nsresult
     370           0 : HttpChannelParentListener::ResumeForDiversion()
     371             : {
     372           0 :   MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!");
     373             : 
     374             :   // Allow OnStart/OnData/OnStop callbacks to be forwarded to mNextListener.
     375           0 :   mSuspendedForDiversion = false;
     376             : 
     377           0 :   return NS_OK;
     378             : }
     379             : 
     380             : nsresult
     381           0 : HttpChannelParentListener::DivertTo(nsIStreamListener* aListener)
     382             : {
     383           0 :   MOZ_ASSERT(aListener);
     384           0 :   MOZ_RELEASE_ASSERT(mSuspendedForDiversion, "Must already be suspended!");
     385             : 
     386           0 :   mNextListener = aListener;
     387             : 
     388           0 :   return ResumeForDiversion();
     389             : }
     390             : 
     391             : void
     392           0 : HttpChannelParentListener::SetupInterception(const nsHttpResponseHead& aResponseHead)
     393             : {
     394           0 :   mSynthesizedResponseHead = new nsHttpResponseHead(aResponseHead);
     395           0 :   mShouldIntercept = true;
     396           0 : }
     397             : 
     398             : void
     399           0 : HttpChannelParentListener::SetupInterceptionAfterRedirect(bool aShouldIntercept)
     400             : {
     401           0 :   mShouldIntercept = aShouldIntercept;
     402           0 :   if (mShouldIntercept) {
     403             :     // When an interception occurs, this channel should suspend all further activity.
     404             :     // It will be torn down and recreated if necessary.
     405           0 :     mShouldSuspendIntercept = true;
     406             :   }
     407           0 : }
     408             : 
     409             : void
     410           2 : HttpChannelParentListener::ClearInterceptedChannel()
     411             : {
     412           2 :   if (mInterceptedChannel) {
     413           0 :     mInterceptedChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
     414           0 :     mInterceptedChannel = nullptr;
     415             :   }
     416           2 : }
     417             : 
     418             : } // namespace net
     419             : } // namespace mozilla

Generated by: LCOV version 1.13