netwerk/protocol/http/HttpChannelParent.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 #include "mozilla/dom/FileDescriptorSetParent.h"
    11 #include "mozilla/net/HttpChannelParent.h"
    12 #include "mozilla/dom/TabParent.h"
    13 #include "mozilla/net/NeckoParent.h"
    14 #include "mozilla/unused.h"
    15 #include "HttpChannelParentListener.h"
    16 #include "nsHttpHandler.h"
    17 #include "nsNetUtil.h"
    18 #include "nsISupportsPriority.h"
    19 #include "nsIAuthPromptProvider.h"
    20 #include "nsIScriptSecurityManager.h"
    21 #include "nsSerializationHelper.h"
    22 #include "nsISerializable.h"
    23 #include "nsIAssociatedContentSecurity.h"
    24 #include "nsIApplicationCacheService.h"
    25 #include "mozilla/ipc/InputStreamUtils.h"
    26 #include "mozilla/ipc/URIUtils.h"
    27 #include "SerializedLoadContext.h"
    29 using namespace mozilla::dom;
    30 using namespace mozilla::ipc;
    32 namespace mozilla {
    33 namespace net {
    35 HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding,
    36                                      nsILoadContext* aLoadContext,
    37                                      PBOverrideStatus aOverrideStatus)
    38   : mIPCClosed(false)
    39   , mStoredStatus(NS_OK)
    40   , mStoredProgress(0)
    41   , mStoredProgressMax(0)
    42   , mSentRedirect1Begin(false)
    43   , mSentRedirect1BeginFailed(false)
    44   , mReceivedRedirect2Verify(false)
    45   , mPBOverride(aOverrideStatus)
    46   , mLoadContext(aLoadContext)
    47   , mStatus(NS_OK)
    48   , mDivertingFromChild(false)
    49   , mDivertedOnStartRequest(false)
    50   , mSuspendedForDiversion(false)
    51 {
    52   // Ensure gHttpHandler is initialized: we need the atom table up and running.
    53   nsCOMPtr<nsIHttpProtocolHandler> dummyInitializer =
    54     do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http");
    56   MOZ_ASSERT(gHttpHandler);
    57   mHttpHandler = gHttpHandler;
    59   mTabParent = static_cast<mozilla::dom::TabParent*>(iframeEmbedding);
    60 }
    62 HttpChannelParent::~HttpChannelParent()
    63 {
    64 }
    66 void
    67 HttpChannelParent::ActorDestroy(ActorDestroyReason why)
    68 {
    69   // We may still have refcount>0 if nsHttpChannel hasn't called OnStopRequest
    70   // yet, but child process has crashed.  We must not try to send any more msgs
    71   // to child, or IPDL will kill chrome process, too.
    72   mIPCClosed = true;
    73 }
    75 bool
    76 HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
    77 {
    78   switch (aArgs.type()) {
    79   case HttpChannelCreationArgs::THttpChannelOpenArgs:
    80   {
    81     const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs();
    82     return DoAsyncOpen(a.uri(), a.original(), a.doc(), a.referrer(),
    83                        a.apiRedirectTo(), a.loadFlags(), a.requestHeaders(),
    84                        a.requestMethod(), a.uploadStream(),
    85                        a.uploadStreamHasHeaders(), a.priority(),
    86                        a.redirectionLimit(), a.allowPipelining(),
    87                        a.forceAllowThirdPartyCookie(), a.resumeAt(),
    88                        a.startPos(), a.entityID(), a.chooseApplicationCache(),
    89                        a.appCacheClientID(), a.allowSpdy(), a.fds());
    90   }
    91   case HttpChannelCreationArgs::THttpChannelConnectArgs:
    92   {
    93     const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
    94     return ConnectChannel(cArgs.channelId());
    95   }
    96   default:
    97     NS_NOTREACHED("unknown open type");
    98     return false;
    99   }
   100 }
   102 //-----------------------------------------------------------------------------
   103 // HttpChannelParent::nsISupports
   104 //-----------------------------------------------------------------------------
   106 NS_IMPL_ISUPPORTS(HttpChannelParent,
   107                   nsIInterfaceRequestor,
   108                   nsIProgressEventSink,
   109                   nsIRequestObserver,
   110                   nsIStreamListener,
   111                   nsIParentChannel,
   112                   nsIParentRedirectingChannel)
   114 //-----------------------------------------------------------------------------
   115 // HttpChannelParent::nsIInterfaceRequestor
   116 //-----------------------------------------------------------------------------
   118 NS_IMETHODIMP
   119 HttpChannelParent::GetInterface(const nsIID& aIID, void **result)
   120 {
   121   if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
   122       aIID.Equals(NS_GET_IID(nsISecureBrowserUI))) {
   123     if (!mTabParent)
   124       return NS_NOINTERFACE;
   126     return mTabParent->QueryInterface(aIID, result);
   127   }
   129   // Only support nsILoadContext if child channel's callbacks did too
   130   if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
   131     NS_ADDREF(mLoadContext);
   132     *result = static_cast<nsILoadContext*>(mLoadContext);
   133     return NS_OK;
   134   }
   136   return QueryInterface(aIID, result);
   137 }
   139 //-----------------------------------------------------------------------------
   140 // HttpChannelParent::PHttpChannelParent
   141 //-----------------------------------------------------------------------------
   143 bool
   144 HttpChannelParent::DoAsyncOpen(  const URIParams&           aURI,
   145                                  const OptionalURIParams&   aOriginalURI,
   146                                  const OptionalURIParams&   aDocURI,
   147                                  const OptionalURIParams&   aReferrerURI,
   148                                  const OptionalURIParams&   aAPIRedirectToURI,
   149                                  const uint32_t&            loadFlags,
   150                                  const RequestHeaderTuples& requestHeaders,
   151                                  const nsCString&           requestMethod,
   152                                  const OptionalInputStreamParams& uploadStream,
   153                                  const bool&              uploadStreamHasHeaders,
   154                                  const uint16_t&            priority,
   155                                  const uint8_t&             redirectionLimit,
   156                                  const bool&              allowPipelining,
   157                                  const bool&              forceAllowThirdPartyCookie,
   158                                  const bool&                doResumeAt,
   159                                  const uint64_t&            startPos,
   160                                  const nsCString&           entityID,
   161                                  const bool&                chooseApplicationCache,
   162                                  const nsCString&           appCacheClientID,
   163                                  const bool&                allowSpdy,
   164                                  const OptionalFileDescriptorSet& aFds)
   165 {
   166   nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
   167   if (!uri) {
   168     // URIParams does MOZ_ASSERT if null, but we need to protect opt builds from
   169     // null deref here.
   170     return false;
   171   }
   172   nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
   173   nsCOMPtr<nsIURI> docUri = DeserializeURI(aDocURI);
   174   nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
   175   nsCOMPtr<nsIURI> apiRedirectToUri = DeserializeURI(aAPIRedirectToURI);
   177   nsCString uriSpec;
   178   uri->GetSpec(uriSpec);
   179   LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s]\n",
   180        this, uriSpec.get()));
   182   nsresult rv;
   184   nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
   185   if (NS_FAILED(rv))
   186     return SendFailedAsyncOpen(rv);
   188   nsCOMPtr<nsIChannel> channel;
   189   rv = NS_NewChannel(getter_AddRefs(channel), uri, ios, nullptr, nullptr, loadFlags);
   190   if (NS_FAILED(rv))
   191     return SendFailedAsyncOpen(rv);
   193   mChannel = static_cast<nsHttpChannel *>(channel.get());
   194   if (mPBOverride != kPBOverride_Unset) {
   195     mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
   196   }
   198   if (doResumeAt)
   199     mChannel->ResumeAt(startPos, entityID);
   201   if (originalUri)
   202     mChannel->SetOriginalURI(originalUri);
   203   if (docUri)
   204     mChannel->SetDocumentURI(docUri);
   205   if (referrerUri)
   206     mChannel->SetReferrerInternal(referrerUri);
   207   if (apiRedirectToUri)
   208     mChannel->RedirectTo(apiRedirectToUri);
   209   if (loadFlags != nsIRequest::LOAD_NORMAL)
   210     mChannel->SetLoadFlags(loadFlags);
   212   for (uint32_t i = 0; i < requestHeaders.Length(); i++) {
   213     mChannel->SetRequestHeader(requestHeaders[i].mHeader,
   214                                requestHeaders[i].mValue,
   215                                requestHeaders[i].mMerge);
   216   }
   218   mParentListener = new HttpChannelParentListener(this);
   220   mChannel->SetNotificationCallbacks(mParentListener);
   222   mChannel->SetRequestMethod(nsDependentCString(requestMethod.get()));
   224   nsTArray<mozilla::ipc::FileDescriptor> fds;
   225   if (aFds.type() == OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
   226     FileDescriptorSetParent* fdSetActor =
   227       static_cast<FileDescriptorSetParent*>(aFds.get_PFileDescriptorSetParent());
   228     MOZ_ASSERT(fdSetActor);
   230     fdSetActor->ForgetFileDescriptors(fds);
   231     MOZ_ASSERT(!fds.IsEmpty());
   233     unused << fdSetActor->Send__delete__(fdSetActor);
   234   }
   236   nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(uploadStream, fds);
   237   if (stream) {
   238     mChannel->InternalSetUploadStream(stream);
   239     mChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
   240   }
   242   if (priority != nsISupportsPriority::PRIORITY_NORMAL)
   243     mChannel->SetPriority(priority);
   244   mChannel->SetRedirectionLimit(redirectionLimit);
   245   mChannel->SetAllowPipelining(allowPipelining);
   246   mChannel->SetForceAllowThirdPartyCookie(forceAllowThirdPartyCookie);
   247   mChannel->SetAllowSpdy(allowSpdy);
   249   nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
   250     do_QueryObject(mChannel);
   251   nsCOMPtr<nsIApplicationCacheService> appCacheService =
   252     do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID);
   254   bool setChooseApplicationCache = chooseApplicationCache;
   255   if (appCacheChan && appCacheService) {
   256     // We might potentially want to drop this flag (that is TRUE by default)
   257     // after we successfully associate the channel with an application cache
   258     // reported by the channel child.  Dropping it here may be too early.
   259     appCacheChan->SetInheritApplicationCache(false);
   260     if (!appCacheClientID.IsEmpty()) {
   261       nsCOMPtr<nsIApplicationCache> appCache;
   262       rv = appCacheService->GetApplicationCache(appCacheClientID,
   263                                                 getter_AddRefs(appCache));
   264       if (NS_SUCCEEDED(rv)) {
   265         appCacheChan->SetApplicationCache(appCache);
   266         setChooseApplicationCache = false;
   267       }
   268     }
   270     if (setChooseApplicationCache) {
   271       bool inBrowser = false;
   272       uint32_t appId = NECKO_NO_APP_ID;
   273       if (mLoadContext) {
   274         mLoadContext->GetIsInBrowserElement(&inBrowser);
   275         mLoadContext->GetAppId(&appId);
   276       }
   278       bool chooseAppCache = false;
   279       nsCOMPtr<nsIScriptSecurityManager> secMan =
   280         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
   281       if (secMan) {
   282         nsCOMPtr<nsIPrincipal> principal;
   283         secMan->GetAppCodebasePrincipal(uri, appId, inBrowser, getter_AddRefs(principal));
   285         // This works because we've already called SetNotificationCallbacks and
   286         // done mPBOverride logic by this point.
   287         chooseAppCache = NS_ShouldCheckAppCache(principal, NS_UsePrivateBrowsing(mChannel));
   288       }
   290       appCacheChan->SetChooseApplicationCache(chooseAppCache);
   291     }
   292   }
   294   rv = mChannel->AsyncOpen(mParentListener, nullptr);
   295   if (NS_FAILED(rv))
   296     return SendFailedAsyncOpen(rv);
   298   return true;
   299 }
   301 bool
   302 HttpChannelParent::ConnectChannel(const uint32_t& channelId)
   303 {
   304   nsresult rv;
   306   LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId));
   307   nsCOMPtr<nsIChannel> channel;
   308   rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
   309   mChannel = static_cast<nsHttpChannel*>(channel.get());
   310   LOG(("  found channel %p, rv=%08x", mChannel.get(), rv));
   312   if (mPBOverride != kPBOverride_Unset) {
   313     // redirected-to channel may not support PB
   314     nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryObject(mChannel);
   315     if (pbChannel) {
   316       pbChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
   317     }
   318   }
   320   return true;
   321 }
   323 bool
   324 HttpChannelParent::RecvSetPriority(const uint16_t& priority)
   325 {
   326   if (mChannel) {
   327     mChannel->SetPriority(priority);
   328   }
   330   nsCOMPtr<nsISupportsPriority> priorityRedirectChannel =
   331       do_QueryInterface(mRedirectChannel);
   332   if (priorityRedirectChannel)
   333     priorityRedirectChannel->SetPriority(priority);
   335   return true;
   336 }
   338 bool
   339 HttpChannelParent::RecvSuspend()
   340 {
   341   if (mChannel) {
   342     mChannel->Suspend();
   343   }
   344   return true;
   345 }
   347 bool
   348 HttpChannelParent::RecvResume()
   349 {
   350   if (mChannel) {
   351     mChannel->Resume();
   352   }
   353   return true;
   354 }
   356 bool
   357 HttpChannelParent::RecvCancel(const nsresult& status)
   358 {
   359   // May receive cancel before channel has been constructed!
   360   if (mChannel) {
   361     mChannel->Cancel(status);
   362   }
   363   return true;
   364 }
   367 bool
   368 HttpChannelParent::RecvSetCacheTokenCachedCharset(const nsCString& charset)
   369 {
   370   if (mCacheEntry)
   371     mCacheEntry->SetMetaDataElement("charset", charset.get());
   372   return true;
   373 }
   375 bool
   376 HttpChannelParent::RecvUpdateAssociatedContentSecurity(const int32_t& broken,
   377                                                        const int32_t& no)
   378 {
   379   if (mAssociatedContentSecurity) {
   380     mAssociatedContentSecurity->SetCountSubRequestsBrokenSecurity(broken);
   381     mAssociatedContentSecurity->SetCountSubRequestsNoSecurity(no);
   382   }
   383   return true;
   384 }
   386 bool
   387 HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
   388                                        const RequestHeaderTuples& changedHeaders,
   389                                        const OptionalURIParams&   aAPIRedirectURI)
   390 {
   391   if (NS_SUCCEEDED(result)) {
   392     nsCOMPtr<nsIHttpChannel> newHttpChannel =
   393         do_QueryInterface(mRedirectChannel);
   395     if (newHttpChannel) {
   396       nsCOMPtr<nsIURI> apiRedirectUri = DeserializeURI(aAPIRedirectURI);
   398       if (apiRedirectUri)
   399         newHttpChannel->RedirectTo(apiRedirectUri);
   401       for (uint32_t i = 0; i < changedHeaders.Length(); i++) {
   402         newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader,
   403                                          changedHeaders[i].mValue,
   404                                          changedHeaders[i].mMerge);
   405       }
   406     }
   407   }
   409   if (!mRedirectCallback) {
   410     // This should according the logic never happen, log the situation.
   411     if (mReceivedRedirect2Verify)
   412       LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this));
   413     if (mSentRedirect1BeginFailed)
   414       LOG(("RecvRedirect2Verify[%p]: Send to child failed", this));
   415     if (mSentRedirect1Begin && NS_FAILED(result))
   416       LOG(("RecvRedirect2Verify[%p]: Redirect failed", this));
   417     if (mSentRedirect1Begin && NS_SUCCEEDED(result))
   418       LOG(("RecvRedirect2Verify[%p]: Redirect succeeded", this));
   419     if (!mRedirectChannel)
   420       LOG(("RecvRedirect2Verify[%p]: Missing redirect channel", this));
   422     NS_ERROR("Unexpcted call to HttpChannelParent::RecvRedirect2Verify, "
   423              "mRedirectCallback null");
   424   }
   426   mReceivedRedirect2Verify = true;
   428   if (mRedirectCallback) {
   429     mRedirectCallback->OnRedirectVerifyCallback(result);
   430     mRedirectCallback = nullptr;
   431   }
   433   return true;
   434 }
   436 bool
   437 HttpChannelParent::RecvDocumentChannelCleanup()
   438 {
   439   // From now on only using mAssociatedContentSecurity.  Free everything else.
   440   mChannel = 0;          // Reclaim some memory sooner.
   441   mCacheEntry = 0;  // Else we'll block other channels reading same URI
   442   return true;
   443 }
   445 bool
   446 HttpChannelParent::RecvMarkOfflineCacheEntryAsForeign()
   447 {
   448   if (mOfflineForeignMarker) {
   449     mOfflineForeignMarker->MarkAsForeign();
   450     mOfflineForeignMarker = 0;
   451   }
   453   return true;
   454 }
   456 bool
   457 HttpChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
   458                                              const uint64_t& offset,
   459                                              const uint32_t& count)
   460 {
   461   MOZ_ASSERT(mParentListener);
   462   if (NS_WARN_IF(!mDivertingFromChild)) {
   463     MOZ_ASSERT(mDivertingFromChild,
   464                "Cannot RecvDivertOnDataAvailable if diverting is not set!");
   465     FailDiversion(NS_ERROR_UNEXPECTED);
   466     return false;
   467   }
   469   // Drop OnDataAvailables if the parent was canceled already.
   470   if (NS_FAILED(mStatus)) {
   471     return true;
   472   }
   474   nsCOMPtr<nsIInputStream> stringStream;
   475   nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
   476                                       count, NS_ASSIGNMENT_DEPEND);
   477   if (NS_FAILED(rv)) {
   478     if (mChannel) {
   479       mChannel->Cancel(rv);
   480     }
   481     mStatus = rv;
   482     return true;
   483   }
   485   rv = mParentListener->OnDataAvailable(mChannel, nullptr, stringStream,
   486                                         offset, count);
   487   stringStream->Close();
   488   if (NS_FAILED(rv)) {
   489     if (mChannel) {
   490       mChannel->Cancel(rv);
   491     }
   492     mStatus = rv;
   493     return true;
   494   }
   495   return true;
   496 }
   498 bool
   499 HttpChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
   500 {
   501   MOZ_ASSERT(mParentListener);
   502   if (NS_WARN_IF(!mDivertingFromChild)) {
   503     MOZ_ASSERT(mDivertingFromChild,
   504                "Cannot RecvDivertOnStopRequest if diverting is not set!");
   505     FailDiversion(NS_ERROR_UNEXPECTED);
   506     return false;
   507   }
   509   // Honor the channel's status even if the underlying transaction completed.
   510   nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode;
   512   // Reset fake pending status in case OnStopRequest has already been called.
   513   if (mChannel) {
   514     mChannel->ForcePending(false);
   515   }
   517   mParentListener->OnStopRequest(mChannel, nullptr, status);
   518   return true;
   519 }
   521 bool
   522 HttpChannelParent::RecvDivertComplete()
   523 {
   524   MOZ_ASSERT(mParentListener);
   525   mParentListener = nullptr;
   526   if (NS_WARN_IF(!mDivertingFromChild)) {
   527     MOZ_ASSERT(mDivertingFromChild,
   528                "Cannot RecvDivertComplete if diverting is not set!");
   529     FailDiversion(NS_ERROR_UNEXPECTED);
   530     return false;
   531   }
   533   nsresult rv = ResumeForDiversion();
   534   if (NS_WARN_IF(NS_FAILED(rv))) {
   535     FailDiversion(NS_ERROR_UNEXPECTED);
   536     return false;
   537   }
   539   return true;
   540 }
   542 //-----------------------------------------------------------------------------
   543 // HttpChannelParent::nsIRequestObserver
   544 //-----------------------------------------------------------------------------
   546 NS_IMETHODIMP
   547 HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
   548 {
   549   LOG(("HttpChannelParent::OnStartRequest [this=%p]\n", this));
   551   MOZ_RELEASE_ASSERT(!mDivertingFromChild,
   552     "Cannot call OnStartRequest if diverting is set!");
   554   nsHttpChannel *chan = static_cast<nsHttpChannel *>(aRequest);
   555   nsHttpResponseHead *responseHead = chan->GetResponseHead();
   556   nsHttpRequestHead  *requestHead = chan->GetRequestHead();
   557   bool isFromCache = false;
   558   chan->IsFromCache(&isFromCache);
   559   uint32_t expirationTime = nsICache::NO_EXPIRATION_TIME;
   560   chan->GetCacheTokenExpirationTime(&expirationTime);
   561   nsCString cachedCharset;
   562   chan->GetCacheTokenCachedCharset(cachedCharset);
   564   bool loadedFromApplicationCache;
   565   chan->GetLoadedFromApplicationCache(&loadedFromApplicationCache);
   566   if (loadedFromApplicationCache) {
   567     mOfflineForeignMarker = chan->GetOfflineCacheEntryAsForeignMarker();
   568     nsCOMPtr<nsIApplicationCache> appCache;
   569     chan->GetApplicationCache(getter_AddRefs(appCache));
   570     nsCString appCacheGroupId;
   571     nsCString appCacheClientId;
   572     appCache->GetGroupID(appCacheGroupId);
   573     appCache->GetClientID(appCacheClientId);
   574     if (mIPCClosed ||
   575         !SendAssociateApplicationCache(appCacheGroupId, appCacheClientId))
   576     {
   577       return NS_ERROR_UNEXPECTED;
   578     }
   579   }
   581   nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(aRequest);
   582   if (encodedChannel)
   583     encodedChannel->SetApplyConversion(false);
   585   // Keep the cache entry for future use in RecvSetCacheTokenCachedCharset().
   586   // It could be already released by nsHttpChannel at that time.
   587   nsCOMPtr<nsISupports> cacheEntry;
   588   chan->GetCacheToken(getter_AddRefs(cacheEntry));
   589   mCacheEntry = do_QueryInterface(cacheEntry);
   591   nsresult channelStatus = NS_OK;
   592   chan->GetStatus(&channelStatus);
   594   nsCString secInfoSerialization;
   595   nsCOMPtr<nsISupports> secInfoSupp;
   596   chan->GetSecurityInfo(getter_AddRefs(secInfoSupp));
   597   if (secInfoSupp) {
   598     mAssociatedContentSecurity = do_QueryInterface(secInfoSupp);
   599     nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(secInfoSupp);
   600     if (secInfoSer)
   601       NS_SerializeToString(secInfoSer, secInfoSerialization);
   602   }
   604   uint16_t redirectCount = 0;
   605   mChannel->GetRedirectCount(&redirectCount);
   606   if (mIPCClosed ||
   607       !SendOnStartRequest(channelStatus,
   608                           responseHead ? *responseHead : nsHttpResponseHead(),
   609                           !!responseHead,
   610                           requestHead->Headers(),
   611                           isFromCache,
   612                           mCacheEntry ? true : false,
   613                           expirationTime, cachedCharset, secInfoSerialization,
   614                           mChannel->GetSelfAddr(), mChannel->GetPeerAddr(),
   615                           redirectCount))
   616   {
   617     return NS_ERROR_UNEXPECTED;
   618   }
   619   return NS_OK;
   620 }
   622 NS_IMETHODIMP
   623 HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
   624                                  nsISupports *aContext,
   625                                  nsresult aStatusCode)
   626 {
   627   LOG(("HttpChannelParent::OnStopRequest: [this=%p status=%x]\n",
   628        this, aStatusCode));
   630   MOZ_RELEASE_ASSERT(!mDivertingFromChild,
   631     "Cannot call OnStopRequest if diverting is set!");
   633   if (mIPCClosed || !SendOnStopRequest(aStatusCode))
   634     return NS_ERROR_UNEXPECTED;
   635   return NS_OK;
   636 }
   638 //-----------------------------------------------------------------------------
   639 // HttpChannelParent::nsIStreamListener
   640 //-----------------------------------------------------------------------------
   642 NS_IMETHODIMP
   643 HttpChannelParent::OnDataAvailable(nsIRequest *aRequest,
   644                                    nsISupports *aContext,
   645                                    nsIInputStream *aInputStream,
   646                                    uint64_t aOffset,
   647                                    uint32_t aCount)
   648 {
   649   LOG(("HttpChannelParent::OnDataAvailable [this=%p]\n", this));
   651   MOZ_RELEASE_ASSERT(!mDivertingFromChild,
   652     "Cannot call OnDataAvailable if diverting is set!");
   654   nsCString data;
   655   nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
   656   if (NS_FAILED(rv))
   657     return rv;
   659   nsresult channelStatus = NS_OK;
   660   mChannel->GetStatus(&channelStatus);
   662   // OnDataAvailable is always preceded by OnStatus/OnProgress calls that set
   663   // mStoredStatus/mStoredProgress(Max) to appropriate values, unless
   664   // LOAD_BACKGROUND set.  In that case, they'll have garbage values, but
   665   // child doesn't use them.
   666   if (mIPCClosed || !SendOnTransportAndData(channelStatus, mStoredStatus,
   667                                             mStoredProgress, mStoredProgressMax,
   668                                             data, aOffset, aCount)) {
   669     return NS_ERROR_UNEXPECTED;
   670   }
   671   return NS_OK;
   672 }
   674 //-----------------------------------------------------------------------------
   675 // HttpChannelParent::nsIProgressEventSink
   676 //-----------------------------------------------------------------------------
   678 NS_IMETHODIMP
   679 HttpChannelParent::OnProgress(nsIRequest *aRequest,
   680                               nsISupports *aContext,
   681                               uint64_t aProgress,
   682                               uint64_t aProgressMax)
   683 {
   684   // OnStatus has always just set mStoredStatus. If it indicates this precedes
   685   // OnDataAvailable, store and ODA will send to child.
   686   if (mStoredStatus == NS_NET_STATUS_RECEIVING_FROM ||
   687       mStoredStatus == NS_NET_STATUS_READING)
   688   {
   689     mStoredProgress = aProgress;
   690     mStoredProgressMax = aProgressMax;
   691   } else {
   692     // Send to child now.  The only case I've observed that this handles (i.e.
   693     // non-ODA status with progress > 0) is data upload progress notification
   694     // (status == NS_NET_STATUS_SENDING_TO)
   695     if (mIPCClosed || !SendOnProgress(aProgress, aProgressMax))
   696       return NS_ERROR_UNEXPECTED;
   697   }
   699   return NS_OK;
   700 }
   702 NS_IMETHODIMP
   703 HttpChannelParent::OnStatus(nsIRequest *aRequest,
   704                             nsISupports *aContext,
   705                             nsresult aStatus,
   706                             const char16_t *aStatusArg)
   707 {
   708   // If this precedes OnDataAvailable, store and ODA will send to child.
   709   if (aStatus == NS_NET_STATUS_RECEIVING_FROM ||
   710       aStatus == NS_NET_STATUS_READING)
   711   {
   712     mStoredStatus = aStatus;
   713     return NS_OK;
   714   }
   715   // Otherwise, send to child now
   716   if (mIPCClosed || !SendOnStatus(aStatus))
   717     return NS_ERROR_UNEXPECTED;
   718   return NS_OK;
   719 }
   721 //-----------------------------------------------------------------------------
   722 // HttpChannelParent::nsIParentChannel
   723 //-----------------------------------------------------------------------------
   725 NS_IMETHODIMP
   726 HttpChannelParent::SetParentListener(HttpChannelParentListener* aListener)
   727 {
   728   MOZ_ASSERT(aListener);
   729   MOZ_ASSERT(!mParentListener, "SetParentListener should only be called for "
   730                                "new HttpChannelParents after a redirect, when "
   731                                "mParentListener is null.");
   732   mParentListener = aListener;
   733   return NS_OK;
   734 }
   736 NS_IMETHODIMP
   737 HttpChannelParent::Delete()
   738 {
   739   if (!mIPCClosed)
   740     unused << SendDeleteSelf();
   742   return NS_OK;
   743 }
   745 //-----------------------------------------------------------------------------
   746 // HttpChannelParent::nsIParentRedirectingChannel
   747 //-----------------------------------------------------------------------------
   749 NS_IMETHODIMP
   750 HttpChannelParent::StartRedirect(uint32_t newChannelId,
   751                                  nsIChannel* newChannel,
   752                                  uint32_t redirectFlags,
   753                                  nsIAsyncVerifyRedirectCallback* callback)
   754 {
   755   if (mIPCClosed)
   756     return NS_BINDING_ABORTED;
   758   nsCOMPtr<nsIURI> newURI;
   759   newChannel->GetURI(getter_AddRefs(newURI));
   761   URIParams uriParams;
   762   SerializeURI(newURI, uriParams);
   764   nsHttpResponseHead *responseHead = mChannel->GetResponseHead();
   765   bool result = SendRedirect1Begin(newChannelId, uriParams, redirectFlags,
   766                                    responseHead ? *responseHead
   767                                                 : nsHttpResponseHead());
   768   if (!result) {
   769     // Bug 621446 investigation
   770     mSentRedirect1BeginFailed = true;
   771     return NS_BINDING_ABORTED;
   772   }
   774   // Bug 621446 investigation
   775   mSentRedirect1Begin = true;
   777   // Result is handled in RecvRedirect2Verify above
   779   mRedirectChannel = newChannel;
   780   mRedirectCallback = callback;
   781   return NS_OK;
   782 }
   784 NS_IMETHODIMP
   785 HttpChannelParent::CompleteRedirect(bool succeeded)
   786 {
   787   if (succeeded && !mIPCClosed) {
   788     // TODO: check return value: assume child dead if failed
   789     unused << SendRedirect3Complete();
   790   }
   792   mRedirectChannel = nullptr;
   793   return NS_OK;
   794 }
   796 //-----------------------------------------------------------------------------
   797 // HttpChannelParent::ADivertableParentChannel
   798 //-----------------------------------------------------------------------------
   799 nsresult
   800 HttpChannelParent::SuspendForDiversion()
   801 {
   802   MOZ_ASSERT(mChannel);
   803   MOZ_ASSERT(mParentListener);
   804   if (NS_WARN_IF(mDivertingFromChild)) {
   805     MOZ_ASSERT(!mDivertingFromChild, "Already suspended for diversion!");
   806     return NS_ERROR_UNEXPECTED;
   807   }
   809   // Try suspending the channel. Allow it to fail, since OnStopRequest may have
   810   // been called and thus the channel may not be pending.
   811   nsresult rv = mChannel->Suspend();
   812   MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE);
   813   mSuspendedForDiversion = NS_SUCCEEDED(rv);
   815   rv = mParentListener->SuspendForDiversion();
   816   MOZ_ASSERT(NS_SUCCEEDED(rv));
   818   // Once this is set, no more OnStart/OnData/OnStop callbacks should be sent
   819   // to the child.
   820   mDivertingFromChild = true;
   822   return NS_OK;
   823 }
   825 /* private, supporting function for ADivertableParentChannel */
   826 nsresult
   827 HttpChannelParent::ResumeForDiversion()
   828 {
   829   MOZ_ASSERT(mChannel);
   830   if (NS_WARN_IF(!mDivertingFromChild)) {
   831     MOZ_ASSERT(mDivertingFromChild,
   832                "Cannot ResumeForDiversion if not diverting!");
   833     return NS_ERROR_UNEXPECTED;
   834   }
   836   if (mSuspendedForDiversion) {
   837     // The nsHttpChannel will deliver remaining OnData/OnStop for the transfer.
   838     nsresult rv = mChannel->Resume();
   839     if (NS_WARN_IF(NS_FAILED(rv))) {
   840       FailDiversion(NS_ERROR_UNEXPECTED, true);
   841       return rv;
   842     }
   843     mSuspendedForDiversion = false;
   844   }
   846   if (NS_WARN_IF(mIPCClosed || !SendDeleteSelf())) {
   847     FailDiversion(NS_ERROR_UNEXPECTED);
   848     return NS_ERROR_UNEXPECTED;
   849   }
   850   return NS_OK;
   851 }
   853 void
   854 HttpChannelParent::DivertTo(nsIStreamListener *aListener)
   855 {
   856   MOZ_ASSERT(mParentListener);
   857   if (NS_WARN_IF(!mDivertingFromChild)) {
   858     MOZ_ASSERT(mDivertingFromChild,
   859                "Cannot DivertTo new listener if diverting is not set!");
   860     return;
   861   }
   863   DebugOnly<nsresult> rv = mParentListener->DivertTo(aListener);
   864   MOZ_ASSERT(NS_SUCCEEDED(rv));
   866   if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) {
   867     FailDiversion(NS_ERROR_UNEXPECTED);
   868     return;
   869   }
   871   // Call OnStartRequest and SendDivertMessages asynchronously to avoid
   872   // reentering client context.
   873   NS_DispatchToCurrentThread(
   874     NS_NewRunnableMethod(this, &HttpChannelParent::StartDiversion));
   875   return;
   876 }
   878 void
   879 HttpChannelParent::StartDiversion()
   880 {
   881   if (NS_WARN_IF(!mDivertingFromChild)) {
   882     MOZ_ASSERT(mDivertingFromChild,
   883                "Cannot StartDiversion if diverting is not set!");
   884     return;
   885   }
   887   // Fake pending status in case OnStopRequest has already been called.
   888   if (mChannel) {
   889     mChannel->ForcePending(true);
   890   }
   892   // Call OnStartRequest for the "DivertTo" listener.
   893   nsresult rv = mParentListener->OnStartRequest(mChannel, nullptr);
   894   if (NS_FAILED(rv)) {
   895     if (mChannel) {
   896       mChannel->Cancel(rv);
   897     }
   898     mStatus = rv;
   899   }
   900   mDivertedOnStartRequest = true;
   902   // After OnStartRequest has been called, tell HttpChannelChild to divert the
   903   // OnDataAvailables and OnStopRequest to this HttpChannelParent.
   904   if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) {
   905     FailDiversion(NS_ERROR_UNEXPECTED);
   906     return;
   907   }
   908 }
   910 class HTTPFailDiversionEvent : public nsRunnable
   911 {
   912 public:
   913   HTTPFailDiversionEvent(HttpChannelParent *aChannelParent,
   914                          nsresult aErrorCode,
   915                          bool aSkipResume)
   916     : mChannelParent(aChannelParent)
   917     , mErrorCode(aErrorCode)
   918     , mSkipResume(aSkipResume)
   919   {
   920     MOZ_RELEASE_ASSERT(aChannelParent);
   921     MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
   922   }
   923   NS_IMETHOD Run()
   924   {
   925     mChannelParent->NotifyDiversionFailed(mErrorCode, mSkipResume);
   926     return NS_OK;
   927   }
   928 private:
   929   nsRefPtr<HttpChannelParent> mChannelParent;
   930   nsresult mErrorCode;
   931   bool mSkipResume;
   932 };
   934 void
   935 HttpChannelParent::FailDiversion(nsresult aErrorCode,
   936                                  bool aSkipResume)
   937 {
   938   MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
   939   MOZ_RELEASE_ASSERT(mDivertingFromChild);
   940   MOZ_RELEASE_ASSERT(mParentListener);
   941   MOZ_RELEASE_ASSERT(mChannel);
   943   NS_DispatchToCurrentThread(
   944     new HTTPFailDiversionEvent(this, aErrorCode, aSkipResume));
   945 }
   947 void
   948 HttpChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
   949                                          bool aSkipResume)
   950 {
   951   MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
   952   MOZ_RELEASE_ASSERT(mDivertingFromChild);
   953   MOZ_RELEASE_ASSERT(mParentListener);
   954   MOZ_RELEASE_ASSERT(mChannel);
   956   mChannel->Cancel(aErrorCode);
   958   mChannel->ForcePending(false);
   960   bool isPending = false;
   961   nsresult rv = mChannel->IsPending(&isPending);
   962   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   964   // Resume only if we suspended earlier.
   965   if (mSuspendedForDiversion) {
   966     mChannel->Resume();
   967   }
   968   // Channel has already sent OnStartRequest to the child, so ensure that we
   969   // call it here if it hasn't already been called.
   970   if (!mDivertedOnStartRequest) {
   971     mChannel->ForcePending(true);
   972     mParentListener->OnStartRequest(mChannel, nullptr);
   973     mChannel->ForcePending(false);
   974   }
   975   // If the channel is pending, it will call OnStopRequest itself; otherwise, do
   976   // it here.
   977   if (!isPending) {
   978     mParentListener->OnStopRequest(mChannel, nullptr, aErrorCode);
   979   }
   980   mParentListener = nullptr;
   981   mChannel = nullptr;
   983   if (!mIPCClosed) {
   984     unused << SendDeleteSelf();
   985   }
   986 }
   988 }} // mozilla::net

mercurial