netwerk/protocol/http/HttpChannelParent.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/protocol/http/HttpChannelParent.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,988 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set sw=2 ts=8 et tw=80 : */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +// HttpLog.h should generally be included first
    1.11 +#include "HttpLog.h"
    1.12 +
    1.13 +#include "mozilla/dom/FileDescriptorSetParent.h"
    1.14 +#include "mozilla/net/HttpChannelParent.h"
    1.15 +#include "mozilla/dom/TabParent.h"
    1.16 +#include "mozilla/net/NeckoParent.h"
    1.17 +#include "mozilla/unused.h"
    1.18 +#include "HttpChannelParentListener.h"
    1.19 +#include "nsHttpHandler.h"
    1.20 +#include "nsNetUtil.h"
    1.21 +#include "nsISupportsPriority.h"
    1.22 +#include "nsIAuthPromptProvider.h"
    1.23 +#include "nsIScriptSecurityManager.h"
    1.24 +#include "nsSerializationHelper.h"
    1.25 +#include "nsISerializable.h"
    1.26 +#include "nsIAssociatedContentSecurity.h"
    1.27 +#include "nsIApplicationCacheService.h"
    1.28 +#include "mozilla/ipc/InputStreamUtils.h"
    1.29 +#include "mozilla/ipc/URIUtils.h"
    1.30 +#include "SerializedLoadContext.h"
    1.31 +
    1.32 +using namespace mozilla::dom;
    1.33 +using namespace mozilla::ipc;
    1.34 +
    1.35 +namespace mozilla {
    1.36 +namespace net {
    1.37 +
    1.38 +HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding,
    1.39 +                                     nsILoadContext* aLoadContext,
    1.40 +                                     PBOverrideStatus aOverrideStatus)
    1.41 +  : mIPCClosed(false)
    1.42 +  , mStoredStatus(NS_OK)
    1.43 +  , mStoredProgress(0)
    1.44 +  , mStoredProgressMax(0)
    1.45 +  , mSentRedirect1Begin(false)
    1.46 +  , mSentRedirect1BeginFailed(false)
    1.47 +  , mReceivedRedirect2Verify(false)
    1.48 +  , mPBOverride(aOverrideStatus)
    1.49 +  , mLoadContext(aLoadContext)
    1.50 +  , mStatus(NS_OK)
    1.51 +  , mDivertingFromChild(false)
    1.52 +  , mDivertedOnStartRequest(false)
    1.53 +  , mSuspendedForDiversion(false)
    1.54 +{
    1.55 +  // Ensure gHttpHandler is initialized: we need the atom table up and running.
    1.56 +  nsCOMPtr<nsIHttpProtocolHandler> dummyInitializer =
    1.57 +    do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http");
    1.58 +
    1.59 +  MOZ_ASSERT(gHttpHandler);
    1.60 +  mHttpHandler = gHttpHandler;
    1.61 +
    1.62 +  mTabParent = static_cast<mozilla::dom::TabParent*>(iframeEmbedding);
    1.63 +}
    1.64 +
    1.65 +HttpChannelParent::~HttpChannelParent()
    1.66 +{
    1.67 +}
    1.68 +
    1.69 +void
    1.70 +HttpChannelParent::ActorDestroy(ActorDestroyReason why)
    1.71 +{
    1.72 +  // We may still have refcount>0 if nsHttpChannel hasn't called OnStopRequest
    1.73 +  // yet, but child process has crashed.  We must not try to send any more msgs
    1.74 +  // to child, or IPDL will kill chrome process, too.
    1.75 +  mIPCClosed = true;
    1.76 +}
    1.77 +
    1.78 +bool
    1.79 +HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
    1.80 +{
    1.81 +  switch (aArgs.type()) {
    1.82 +  case HttpChannelCreationArgs::THttpChannelOpenArgs:
    1.83 +  {
    1.84 +    const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs();
    1.85 +    return DoAsyncOpen(a.uri(), a.original(), a.doc(), a.referrer(),
    1.86 +                       a.apiRedirectTo(), a.loadFlags(), a.requestHeaders(),
    1.87 +                       a.requestMethod(), a.uploadStream(),
    1.88 +                       a.uploadStreamHasHeaders(), a.priority(),
    1.89 +                       a.redirectionLimit(), a.allowPipelining(),
    1.90 +                       a.forceAllowThirdPartyCookie(), a.resumeAt(),
    1.91 +                       a.startPos(), a.entityID(), a.chooseApplicationCache(),
    1.92 +                       a.appCacheClientID(), a.allowSpdy(), a.fds());
    1.93 +  }
    1.94 +  case HttpChannelCreationArgs::THttpChannelConnectArgs:
    1.95 +  {
    1.96 +    const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
    1.97 +    return ConnectChannel(cArgs.channelId());
    1.98 +  }
    1.99 +  default:
   1.100 +    NS_NOTREACHED("unknown open type");
   1.101 +    return false;
   1.102 +  }
   1.103 +}
   1.104 +
   1.105 +//-----------------------------------------------------------------------------
   1.106 +// HttpChannelParent::nsISupports
   1.107 +//-----------------------------------------------------------------------------
   1.108 +
   1.109 +NS_IMPL_ISUPPORTS(HttpChannelParent,
   1.110 +                  nsIInterfaceRequestor,
   1.111 +                  nsIProgressEventSink,
   1.112 +                  nsIRequestObserver,
   1.113 +                  nsIStreamListener,
   1.114 +                  nsIParentChannel,
   1.115 +                  nsIParentRedirectingChannel)
   1.116 +
   1.117 +//-----------------------------------------------------------------------------
   1.118 +// HttpChannelParent::nsIInterfaceRequestor
   1.119 +//-----------------------------------------------------------------------------
   1.120 +
   1.121 +NS_IMETHODIMP
   1.122 +HttpChannelParent::GetInterface(const nsIID& aIID, void **result)
   1.123 +{
   1.124 +  if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
   1.125 +      aIID.Equals(NS_GET_IID(nsISecureBrowserUI))) {
   1.126 +    if (!mTabParent)
   1.127 +      return NS_NOINTERFACE;
   1.128 +
   1.129 +    return mTabParent->QueryInterface(aIID, result);
   1.130 +  }
   1.131 +
   1.132 +  // Only support nsILoadContext if child channel's callbacks did too
   1.133 +  if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
   1.134 +    NS_ADDREF(mLoadContext);
   1.135 +    *result = static_cast<nsILoadContext*>(mLoadContext);
   1.136 +    return NS_OK;
   1.137 +  }
   1.138 +
   1.139 +  return QueryInterface(aIID, result);
   1.140 +}
   1.141 +
   1.142 +//-----------------------------------------------------------------------------
   1.143 +// HttpChannelParent::PHttpChannelParent
   1.144 +//-----------------------------------------------------------------------------
   1.145 +
   1.146 +bool
   1.147 +HttpChannelParent::DoAsyncOpen(  const URIParams&           aURI,
   1.148 +                                 const OptionalURIParams&   aOriginalURI,
   1.149 +                                 const OptionalURIParams&   aDocURI,
   1.150 +                                 const OptionalURIParams&   aReferrerURI,
   1.151 +                                 const OptionalURIParams&   aAPIRedirectToURI,
   1.152 +                                 const uint32_t&            loadFlags,
   1.153 +                                 const RequestHeaderTuples& requestHeaders,
   1.154 +                                 const nsCString&           requestMethod,
   1.155 +                                 const OptionalInputStreamParams& uploadStream,
   1.156 +                                 const bool&              uploadStreamHasHeaders,
   1.157 +                                 const uint16_t&            priority,
   1.158 +                                 const uint8_t&             redirectionLimit,
   1.159 +                                 const bool&              allowPipelining,
   1.160 +                                 const bool&              forceAllowThirdPartyCookie,
   1.161 +                                 const bool&                doResumeAt,
   1.162 +                                 const uint64_t&            startPos,
   1.163 +                                 const nsCString&           entityID,
   1.164 +                                 const bool&                chooseApplicationCache,
   1.165 +                                 const nsCString&           appCacheClientID,
   1.166 +                                 const bool&                allowSpdy,
   1.167 +                                 const OptionalFileDescriptorSet& aFds)
   1.168 +{
   1.169 +  nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
   1.170 +  if (!uri) {
   1.171 +    // URIParams does MOZ_ASSERT if null, but we need to protect opt builds from
   1.172 +    // null deref here.
   1.173 +    return false;
   1.174 +  }
   1.175 +  nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
   1.176 +  nsCOMPtr<nsIURI> docUri = DeserializeURI(aDocURI);
   1.177 +  nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
   1.178 +  nsCOMPtr<nsIURI> apiRedirectToUri = DeserializeURI(aAPIRedirectToURI);
   1.179 +
   1.180 +  nsCString uriSpec;
   1.181 +  uri->GetSpec(uriSpec);
   1.182 +  LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s]\n",
   1.183 +       this, uriSpec.get()));
   1.184 +
   1.185 +  nsresult rv;
   1.186 +
   1.187 +  nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
   1.188 +  if (NS_FAILED(rv))
   1.189 +    return SendFailedAsyncOpen(rv);
   1.190 +
   1.191 +  nsCOMPtr<nsIChannel> channel;
   1.192 +  rv = NS_NewChannel(getter_AddRefs(channel), uri, ios, nullptr, nullptr, loadFlags);
   1.193 +  if (NS_FAILED(rv))
   1.194 +    return SendFailedAsyncOpen(rv);
   1.195 +
   1.196 +  mChannel = static_cast<nsHttpChannel *>(channel.get());
   1.197 +  if (mPBOverride != kPBOverride_Unset) {
   1.198 +    mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
   1.199 +  }
   1.200 +
   1.201 +  if (doResumeAt)
   1.202 +    mChannel->ResumeAt(startPos, entityID);
   1.203 +
   1.204 +  if (originalUri)
   1.205 +    mChannel->SetOriginalURI(originalUri);
   1.206 +  if (docUri)
   1.207 +    mChannel->SetDocumentURI(docUri);
   1.208 +  if (referrerUri)
   1.209 +    mChannel->SetReferrerInternal(referrerUri);
   1.210 +  if (apiRedirectToUri)
   1.211 +    mChannel->RedirectTo(apiRedirectToUri);
   1.212 +  if (loadFlags != nsIRequest::LOAD_NORMAL)
   1.213 +    mChannel->SetLoadFlags(loadFlags);
   1.214 +
   1.215 +  for (uint32_t i = 0; i < requestHeaders.Length(); i++) {
   1.216 +    mChannel->SetRequestHeader(requestHeaders[i].mHeader,
   1.217 +                               requestHeaders[i].mValue,
   1.218 +                               requestHeaders[i].mMerge);
   1.219 +  }
   1.220 +
   1.221 +  mParentListener = new HttpChannelParentListener(this);
   1.222 +
   1.223 +  mChannel->SetNotificationCallbacks(mParentListener);
   1.224 +
   1.225 +  mChannel->SetRequestMethod(nsDependentCString(requestMethod.get()));
   1.226 +
   1.227 +  nsTArray<mozilla::ipc::FileDescriptor> fds;
   1.228 +  if (aFds.type() == OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
   1.229 +    FileDescriptorSetParent* fdSetActor =
   1.230 +      static_cast<FileDescriptorSetParent*>(aFds.get_PFileDescriptorSetParent());
   1.231 +    MOZ_ASSERT(fdSetActor);
   1.232 +
   1.233 +    fdSetActor->ForgetFileDescriptors(fds);
   1.234 +    MOZ_ASSERT(!fds.IsEmpty());
   1.235 +
   1.236 +    unused << fdSetActor->Send__delete__(fdSetActor);
   1.237 +  }
   1.238 +
   1.239 +  nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(uploadStream, fds);
   1.240 +  if (stream) {
   1.241 +    mChannel->InternalSetUploadStream(stream);
   1.242 +    mChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
   1.243 +  }
   1.244 +
   1.245 +  if (priority != nsISupportsPriority::PRIORITY_NORMAL)
   1.246 +    mChannel->SetPriority(priority);
   1.247 +  mChannel->SetRedirectionLimit(redirectionLimit);
   1.248 +  mChannel->SetAllowPipelining(allowPipelining);
   1.249 +  mChannel->SetForceAllowThirdPartyCookie(forceAllowThirdPartyCookie);
   1.250 +  mChannel->SetAllowSpdy(allowSpdy);
   1.251 +
   1.252 +  nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
   1.253 +    do_QueryObject(mChannel);
   1.254 +  nsCOMPtr<nsIApplicationCacheService> appCacheService =
   1.255 +    do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID);
   1.256 +
   1.257 +  bool setChooseApplicationCache = chooseApplicationCache;
   1.258 +  if (appCacheChan && appCacheService) {
   1.259 +    // We might potentially want to drop this flag (that is TRUE by default)
   1.260 +    // after we successfully associate the channel with an application cache
   1.261 +    // reported by the channel child.  Dropping it here may be too early.
   1.262 +    appCacheChan->SetInheritApplicationCache(false);
   1.263 +    if (!appCacheClientID.IsEmpty()) {
   1.264 +      nsCOMPtr<nsIApplicationCache> appCache;
   1.265 +      rv = appCacheService->GetApplicationCache(appCacheClientID,
   1.266 +                                                getter_AddRefs(appCache));
   1.267 +      if (NS_SUCCEEDED(rv)) {
   1.268 +        appCacheChan->SetApplicationCache(appCache);
   1.269 +        setChooseApplicationCache = false;
   1.270 +      }
   1.271 +    }
   1.272 +
   1.273 +    if (setChooseApplicationCache) {
   1.274 +      bool inBrowser = false;
   1.275 +      uint32_t appId = NECKO_NO_APP_ID;
   1.276 +      if (mLoadContext) {
   1.277 +        mLoadContext->GetIsInBrowserElement(&inBrowser);
   1.278 +        mLoadContext->GetAppId(&appId);
   1.279 +      }
   1.280 +
   1.281 +      bool chooseAppCache = false;
   1.282 +      nsCOMPtr<nsIScriptSecurityManager> secMan =
   1.283 +        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
   1.284 +      if (secMan) {
   1.285 +        nsCOMPtr<nsIPrincipal> principal;
   1.286 +        secMan->GetAppCodebasePrincipal(uri, appId, inBrowser, getter_AddRefs(principal));
   1.287 +
   1.288 +        // This works because we've already called SetNotificationCallbacks and
   1.289 +        // done mPBOverride logic by this point.
   1.290 +        chooseAppCache = NS_ShouldCheckAppCache(principal, NS_UsePrivateBrowsing(mChannel));
   1.291 +      }
   1.292 +
   1.293 +      appCacheChan->SetChooseApplicationCache(chooseAppCache);
   1.294 +    }
   1.295 +  }
   1.296 +
   1.297 +  rv = mChannel->AsyncOpen(mParentListener, nullptr);
   1.298 +  if (NS_FAILED(rv))
   1.299 +    return SendFailedAsyncOpen(rv);
   1.300 +
   1.301 +  return true;
   1.302 +}
   1.303 +
   1.304 +bool
   1.305 +HttpChannelParent::ConnectChannel(const uint32_t& channelId)
   1.306 +{
   1.307 +  nsresult rv;
   1.308 +
   1.309 +  LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId));
   1.310 +  nsCOMPtr<nsIChannel> channel;
   1.311 +  rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
   1.312 +  mChannel = static_cast<nsHttpChannel*>(channel.get());
   1.313 +  LOG(("  found channel %p, rv=%08x", mChannel.get(), rv));
   1.314 +
   1.315 +  if (mPBOverride != kPBOverride_Unset) {
   1.316 +    // redirected-to channel may not support PB
   1.317 +    nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryObject(mChannel);
   1.318 +    if (pbChannel) {
   1.319 +      pbChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
   1.320 +    }
   1.321 +  }
   1.322 +
   1.323 +  return true;
   1.324 +}
   1.325 +
   1.326 +bool
   1.327 +HttpChannelParent::RecvSetPriority(const uint16_t& priority)
   1.328 +{
   1.329 +  if (mChannel) {
   1.330 +    mChannel->SetPriority(priority);
   1.331 +  }
   1.332 +
   1.333 +  nsCOMPtr<nsISupportsPriority> priorityRedirectChannel =
   1.334 +      do_QueryInterface(mRedirectChannel);
   1.335 +  if (priorityRedirectChannel)
   1.336 +    priorityRedirectChannel->SetPriority(priority);
   1.337 +
   1.338 +  return true;
   1.339 +}
   1.340 +
   1.341 +bool
   1.342 +HttpChannelParent::RecvSuspend()
   1.343 +{
   1.344 +  if (mChannel) {
   1.345 +    mChannel->Suspend();
   1.346 +  }
   1.347 +  return true;
   1.348 +}
   1.349 +
   1.350 +bool
   1.351 +HttpChannelParent::RecvResume()
   1.352 +{
   1.353 +  if (mChannel) {
   1.354 +    mChannel->Resume();
   1.355 +  }
   1.356 +  return true;
   1.357 +}
   1.358 +
   1.359 +bool
   1.360 +HttpChannelParent::RecvCancel(const nsresult& status)
   1.361 +{
   1.362 +  // May receive cancel before channel has been constructed!
   1.363 +  if (mChannel) {
   1.364 +    mChannel->Cancel(status);
   1.365 +  }
   1.366 +  return true;
   1.367 +}
   1.368 +
   1.369 +
   1.370 +bool
   1.371 +HttpChannelParent::RecvSetCacheTokenCachedCharset(const nsCString& charset)
   1.372 +{
   1.373 +  if (mCacheEntry)
   1.374 +    mCacheEntry->SetMetaDataElement("charset", charset.get());
   1.375 +  return true;
   1.376 +}
   1.377 +
   1.378 +bool
   1.379 +HttpChannelParent::RecvUpdateAssociatedContentSecurity(const int32_t& broken,
   1.380 +                                                       const int32_t& no)
   1.381 +{
   1.382 +  if (mAssociatedContentSecurity) {
   1.383 +    mAssociatedContentSecurity->SetCountSubRequestsBrokenSecurity(broken);
   1.384 +    mAssociatedContentSecurity->SetCountSubRequestsNoSecurity(no);
   1.385 +  }
   1.386 +  return true;
   1.387 +}
   1.388 +
   1.389 +bool
   1.390 +HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
   1.391 +                                       const RequestHeaderTuples& changedHeaders,
   1.392 +                                       const OptionalURIParams&   aAPIRedirectURI)
   1.393 +{
   1.394 +  if (NS_SUCCEEDED(result)) {
   1.395 +    nsCOMPtr<nsIHttpChannel> newHttpChannel =
   1.396 +        do_QueryInterface(mRedirectChannel);
   1.397 +
   1.398 +    if (newHttpChannel) {
   1.399 +      nsCOMPtr<nsIURI> apiRedirectUri = DeserializeURI(aAPIRedirectURI);
   1.400 +
   1.401 +      if (apiRedirectUri)
   1.402 +        newHttpChannel->RedirectTo(apiRedirectUri);
   1.403 +
   1.404 +      for (uint32_t i = 0; i < changedHeaders.Length(); i++) {
   1.405 +        newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader,
   1.406 +                                         changedHeaders[i].mValue,
   1.407 +                                         changedHeaders[i].mMerge);
   1.408 +      }
   1.409 +    }
   1.410 +  }
   1.411 +
   1.412 +  if (!mRedirectCallback) {
   1.413 +    // This should according the logic never happen, log the situation.
   1.414 +    if (mReceivedRedirect2Verify)
   1.415 +      LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this));
   1.416 +    if (mSentRedirect1BeginFailed)
   1.417 +      LOG(("RecvRedirect2Verify[%p]: Send to child failed", this));
   1.418 +    if (mSentRedirect1Begin && NS_FAILED(result))
   1.419 +      LOG(("RecvRedirect2Verify[%p]: Redirect failed", this));
   1.420 +    if (mSentRedirect1Begin && NS_SUCCEEDED(result))
   1.421 +      LOG(("RecvRedirect2Verify[%p]: Redirect succeeded", this));
   1.422 +    if (!mRedirectChannel)
   1.423 +      LOG(("RecvRedirect2Verify[%p]: Missing redirect channel", this));
   1.424 +
   1.425 +    NS_ERROR("Unexpcted call to HttpChannelParent::RecvRedirect2Verify, "
   1.426 +             "mRedirectCallback null");
   1.427 +  }
   1.428 +
   1.429 +  mReceivedRedirect2Verify = true;
   1.430 +
   1.431 +  if (mRedirectCallback) {
   1.432 +    mRedirectCallback->OnRedirectVerifyCallback(result);
   1.433 +    mRedirectCallback = nullptr;
   1.434 +  }
   1.435 +
   1.436 +  return true;
   1.437 +}
   1.438 +
   1.439 +bool
   1.440 +HttpChannelParent::RecvDocumentChannelCleanup()
   1.441 +{
   1.442 +  // From now on only using mAssociatedContentSecurity.  Free everything else.
   1.443 +  mChannel = 0;          // Reclaim some memory sooner.
   1.444 +  mCacheEntry = 0;  // Else we'll block other channels reading same URI
   1.445 +  return true;
   1.446 +}
   1.447 +
   1.448 +bool
   1.449 +HttpChannelParent::RecvMarkOfflineCacheEntryAsForeign()
   1.450 +{
   1.451 +  if (mOfflineForeignMarker) {
   1.452 +    mOfflineForeignMarker->MarkAsForeign();
   1.453 +    mOfflineForeignMarker = 0;
   1.454 +  }
   1.455 +
   1.456 +  return true;
   1.457 +}
   1.458 +
   1.459 +bool
   1.460 +HttpChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
   1.461 +                                             const uint64_t& offset,
   1.462 +                                             const uint32_t& count)
   1.463 +{
   1.464 +  MOZ_ASSERT(mParentListener);
   1.465 +  if (NS_WARN_IF(!mDivertingFromChild)) {
   1.466 +    MOZ_ASSERT(mDivertingFromChild,
   1.467 +               "Cannot RecvDivertOnDataAvailable if diverting is not set!");
   1.468 +    FailDiversion(NS_ERROR_UNEXPECTED);
   1.469 +    return false;
   1.470 +  }
   1.471 +
   1.472 +  // Drop OnDataAvailables if the parent was canceled already.
   1.473 +  if (NS_FAILED(mStatus)) {
   1.474 +    return true;
   1.475 +  }
   1.476 +
   1.477 +  nsCOMPtr<nsIInputStream> stringStream;
   1.478 +  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
   1.479 +                                      count, NS_ASSIGNMENT_DEPEND);
   1.480 +  if (NS_FAILED(rv)) {
   1.481 +    if (mChannel) {
   1.482 +      mChannel->Cancel(rv);
   1.483 +    }
   1.484 +    mStatus = rv;
   1.485 +    return true;
   1.486 +  }
   1.487 +
   1.488 +  rv = mParentListener->OnDataAvailable(mChannel, nullptr, stringStream,
   1.489 +                                        offset, count);
   1.490 +  stringStream->Close();
   1.491 +  if (NS_FAILED(rv)) {
   1.492 +    if (mChannel) {
   1.493 +      mChannel->Cancel(rv);
   1.494 +    }
   1.495 +    mStatus = rv;
   1.496 +    return true;
   1.497 +  }
   1.498 +  return true;
   1.499 +}
   1.500 +
   1.501 +bool
   1.502 +HttpChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
   1.503 +{
   1.504 +  MOZ_ASSERT(mParentListener);
   1.505 +  if (NS_WARN_IF(!mDivertingFromChild)) {
   1.506 +    MOZ_ASSERT(mDivertingFromChild,
   1.507 +               "Cannot RecvDivertOnStopRequest if diverting is not set!");
   1.508 +    FailDiversion(NS_ERROR_UNEXPECTED);
   1.509 +    return false;
   1.510 +  }
   1.511 +
   1.512 +  // Honor the channel's status even if the underlying transaction completed.
   1.513 +  nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode;
   1.514 +
   1.515 +  // Reset fake pending status in case OnStopRequest has already been called.
   1.516 +  if (mChannel) {
   1.517 +    mChannel->ForcePending(false);
   1.518 +  }
   1.519 +
   1.520 +  mParentListener->OnStopRequest(mChannel, nullptr, status);
   1.521 +  return true;
   1.522 +}
   1.523 +
   1.524 +bool
   1.525 +HttpChannelParent::RecvDivertComplete()
   1.526 +{
   1.527 +  MOZ_ASSERT(mParentListener);
   1.528 +  mParentListener = nullptr;
   1.529 +  if (NS_WARN_IF(!mDivertingFromChild)) {
   1.530 +    MOZ_ASSERT(mDivertingFromChild,
   1.531 +               "Cannot RecvDivertComplete if diverting is not set!");
   1.532 +    FailDiversion(NS_ERROR_UNEXPECTED);
   1.533 +    return false;
   1.534 +  }
   1.535 +
   1.536 +  nsresult rv = ResumeForDiversion();
   1.537 +  if (NS_WARN_IF(NS_FAILED(rv))) {
   1.538 +    FailDiversion(NS_ERROR_UNEXPECTED);
   1.539 +    return false;
   1.540 +  }
   1.541 +
   1.542 +  return true;
   1.543 +}
   1.544 +
   1.545 +//-----------------------------------------------------------------------------
   1.546 +// HttpChannelParent::nsIRequestObserver
   1.547 +//-----------------------------------------------------------------------------
   1.548 +
   1.549 +NS_IMETHODIMP
   1.550 +HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
   1.551 +{
   1.552 +  LOG(("HttpChannelParent::OnStartRequest [this=%p]\n", this));
   1.553 +
   1.554 +  MOZ_RELEASE_ASSERT(!mDivertingFromChild,
   1.555 +    "Cannot call OnStartRequest if diverting is set!");
   1.556 +
   1.557 +  nsHttpChannel *chan = static_cast<nsHttpChannel *>(aRequest);
   1.558 +  nsHttpResponseHead *responseHead = chan->GetResponseHead();
   1.559 +  nsHttpRequestHead  *requestHead = chan->GetRequestHead();
   1.560 +  bool isFromCache = false;
   1.561 +  chan->IsFromCache(&isFromCache);
   1.562 +  uint32_t expirationTime = nsICache::NO_EXPIRATION_TIME;
   1.563 +  chan->GetCacheTokenExpirationTime(&expirationTime);
   1.564 +  nsCString cachedCharset;
   1.565 +  chan->GetCacheTokenCachedCharset(cachedCharset);
   1.566 +
   1.567 +  bool loadedFromApplicationCache;
   1.568 +  chan->GetLoadedFromApplicationCache(&loadedFromApplicationCache);
   1.569 +  if (loadedFromApplicationCache) {
   1.570 +    mOfflineForeignMarker = chan->GetOfflineCacheEntryAsForeignMarker();
   1.571 +    nsCOMPtr<nsIApplicationCache> appCache;
   1.572 +    chan->GetApplicationCache(getter_AddRefs(appCache));
   1.573 +    nsCString appCacheGroupId;
   1.574 +    nsCString appCacheClientId;
   1.575 +    appCache->GetGroupID(appCacheGroupId);
   1.576 +    appCache->GetClientID(appCacheClientId);
   1.577 +    if (mIPCClosed ||
   1.578 +        !SendAssociateApplicationCache(appCacheGroupId, appCacheClientId))
   1.579 +    {
   1.580 +      return NS_ERROR_UNEXPECTED;
   1.581 +    }
   1.582 +  }
   1.583 +
   1.584 +  nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(aRequest);
   1.585 +  if (encodedChannel)
   1.586 +    encodedChannel->SetApplyConversion(false);
   1.587 +
   1.588 +  // Keep the cache entry for future use in RecvSetCacheTokenCachedCharset().
   1.589 +  // It could be already released by nsHttpChannel at that time.
   1.590 +  nsCOMPtr<nsISupports> cacheEntry;
   1.591 +  chan->GetCacheToken(getter_AddRefs(cacheEntry));
   1.592 +  mCacheEntry = do_QueryInterface(cacheEntry);
   1.593 +
   1.594 +  nsresult channelStatus = NS_OK;
   1.595 +  chan->GetStatus(&channelStatus);
   1.596 +
   1.597 +  nsCString secInfoSerialization;
   1.598 +  nsCOMPtr<nsISupports> secInfoSupp;
   1.599 +  chan->GetSecurityInfo(getter_AddRefs(secInfoSupp));
   1.600 +  if (secInfoSupp) {
   1.601 +    mAssociatedContentSecurity = do_QueryInterface(secInfoSupp);
   1.602 +    nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(secInfoSupp);
   1.603 +    if (secInfoSer)
   1.604 +      NS_SerializeToString(secInfoSer, secInfoSerialization);
   1.605 +  }
   1.606 +
   1.607 +  uint16_t redirectCount = 0;
   1.608 +  mChannel->GetRedirectCount(&redirectCount);
   1.609 +  if (mIPCClosed ||
   1.610 +      !SendOnStartRequest(channelStatus,
   1.611 +                          responseHead ? *responseHead : nsHttpResponseHead(),
   1.612 +                          !!responseHead,
   1.613 +                          requestHead->Headers(),
   1.614 +                          isFromCache,
   1.615 +                          mCacheEntry ? true : false,
   1.616 +                          expirationTime, cachedCharset, secInfoSerialization,
   1.617 +                          mChannel->GetSelfAddr(), mChannel->GetPeerAddr(),
   1.618 +                          redirectCount))
   1.619 +  {
   1.620 +    return NS_ERROR_UNEXPECTED;
   1.621 +  }
   1.622 +  return NS_OK;
   1.623 +}
   1.624 +
   1.625 +NS_IMETHODIMP
   1.626 +HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
   1.627 +                                 nsISupports *aContext,
   1.628 +                                 nsresult aStatusCode)
   1.629 +{
   1.630 +  LOG(("HttpChannelParent::OnStopRequest: [this=%p status=%x]\n",
   1.631 +       this, aStatusCode));
   1.632 +
   1.633 +  MOZ_RELEASE_ASSERT(!mDivertingFromChild,
   1.634 +    "Cannot call OnStopRequest if diverting is set!");
   1.635 +
   1.636 +  if (mIPCClosed || !SendOnStopRequest(aStatusCode))
   1.637 +    return NS_ERROR_UNEXPECTED;
   1.638 +  return NS_OK;
   1.639 +}
   1.640 +
   1.641 +//-----------------------------------------------------------------------------
   1.642 +// HttpChannelParent::nsIStreamListener
   1.643 +//-----------------------------------------------------------------------------
   1.644 +
   1.645 +NS_IMETHODIMP
   1.646 +HttpChannelParent::OnDataAvailable(nsIRequest *aRequest,
   1.647 +                                   nsISupports *aContext,
   1.648 +                                   nsIInputStream *aInputStream,
   1.649 +                                   uint64_t aOffset,
   1.650 +                                   uint32_t aCount)
   1.651 +{
   1.652 +  LOG(("HttpChannelParent::OnDataAvailable [this=%p]\n", this));
   1.653 +
   1.654 +  MOZ_RELEASE_ASSERT(!mDivertingFromChild,
   1.655 +    "Cannot call OnDataAvailable if diverting is set!");
   1.656 +
   1.657 +  nsCString data;
   1.658 +  nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
   1.659 +  if (NS_FAILED(rv))
   1.660 +    return rv;
   1.661 +
   1.662 +  nsresult channelStatus = NS_OK;
   1.663 +  mChannel->GetStatus(&channelStatus);
   1.664 +
   1.665 +  // OnDataAvailable is always preceded by OnStatus/OnProgress calls that set
   1.666 +  // mStoredStatus/mStoredProgress(Max) to appropriate values, unless
   1.667 +  // LOAD_BACKGROUND set.  In that case, they'll have garbage values, but
   1.668 +  // child doesn't use them.
   1.669 +  if (mIPCClosed || !SendOnTransportAndData(channelStatus, mStoredStatus,
   1.670 +                                            mStoredProgress, mStoredProgressMax,
   1.671 +                                            data, aOffset, aCount)) {
   1.672 +    return NS_ERROR_UNEXPECTED;
   1.673 +  }
   1.674 +  return NS_OK;
   1.675 +}
   1.676 +
   1.677 +//-----------------------------------------------------------------------------
   1.678 +// HttpChannelParent::nsIProgressEventSink
   1.679 +//-----------------------------------------------------------------------------
   1.680 +
   1.681 +NS_IMETHODIMP
   1.682 +HttpChannelParent::OnProgress(nsIRequest *aRequest,
   1.683 +                              nsISupports *aContext,
   1.684 +                              uint64_t aProgress,
   1.685 +                              uint64_t aProgressMax)
   1.686 +{
   1.687 +  // OnStatus has always just set mStoredStatus. If it indicates this precedes
   1.688 +  // OnDataAvailable, store and ODA will send to child.
   1.689 +  if (mStoredStatus == NS_NET_STATUS_RECEIVING_FROM ||
   1.690 +      mStoredStatus == NS_NET_STATUS_READING)
   1.691 +  {
   1.692 +    mStoredProgress = aProgress;
   1.693 +    mStoredProgressMax = aProgressMax;
   1.694 +  } else {
   1.695 +    // Send to child now.  The only case I've observed that this handles (i.e.
   1.696 +    // non-ODA status with progress > 0) is data upload progress notification
   1.697 +    // (status == NS_NET_STATUS_SENDING_TO)
   1.698 +    if (mIPCClosed || !SendOnProgress(aProgress, aProgressMax))
   1.699 +      return NS_ERROR_UNEXPECTED;
   1.700 +  }
   1.701 +
   1.702 +  return NS_OK;
   1.703 +}
   1.704 +
   1.705 +NS_IMETHODIMP
   1.706 +HttpChannelParent::OnStatus(nsIRequest *aRequest,
   1.707 +                            nsISupports *aContext,
   1.708 +                            nsresult aStatus,
   1.709 +                            const char16_t *aStatusArg)
   1.710 +{
   1.711 +  // If this precedes OnDataAvailable, store and ODA will send to child.
   1.712 +  if (aStatus == NS_NET_STATUS_RECEIVING_FROM ||
   1.713 +      aStatus == NS_NET_STATUS_READING)
   1.714 +  {
   1.715 +    mStoredStatus = aStatus;
   1.716 +    return NS_OK;
   1.717 +  }
   1.718 +  // Otherwise, send to child now
   1.719 +  if (mIPCClosed || !SendOnStatus(aStatus))
   1.720 +    return NS_ERROR_UNEXPECTED;
   1.721 +  return NS_OK;
   1.722 +}
   1.723 +
   1.724 +//-----------------------------------------------------------------------------
   1.725 +// HttpChannelParent::nsIParentChannel
   1.726 +//-----------------------------------------------------------------------------
   1.727 +
   1.728 +NS_IMETHODIMP
   1.729 +HttpChannelParent::SetParentListener(HttpChannelParentListener* aListener)
   1.730 +{
   1.731 +  MOZ_ASSERT(aListener);
   1.732 +  MOZ_ASSERT(!mParentListener, "SetParentListener should only be called for "
   1.733 +                               "new HttpChannelParents after a redirect, when "
   1.734 +                               "mParentListener is null.");
   1.735 +  mParentListener = aListener;
   1.736 +  return NS_OK;
   1.737 +}
   1.738 +
   1.739 +NS_IMETHODIMP
   1.740 +HttpChannelParent::Delete()
   1.741 +{
   1.742 +  if (!mIPCClosed)
   1.743 +    unused << SendDeleteSelf();
   1.744 +
   1.745 +  return NS_OK;
   1.746 +}
   1.747 +
   1.748 +//-----------------------------------------------------------------------------
   1.749 +// HttpChannelParent::nsIParentRedirectingChannel
   1.750 +//-----------------------------------------------------------------------------
   1.751 +
   1.752 +NS_IMETHODIMP
   1.753 +HttpChannelParent::StartRedirect(uint32_t newChannelId,
   1.754 +                                 nsIChannel* newChannel,
   1.755 +                                 uint32_t redirectFlags,
   1.756 +                                 nsIAsyncVerifyRedirectCallback* callback)
   1.757 +{
   1.758 +  if (mIPCClosed)
   1.759 +    return NS_BINDING_ABORTED;
   1.760 +
   1.761 +  nsCOMPtr<nsIURI> newURI;
   1.762 +  newChannel->GetURI(getter_AddRefs(newURI));
   1.763 +
   1.764 +  URIParams uriParams;
   1.765 +  SerializeURI(newURI, uriParams);
   1.766 +
   1.767 +  nsHttpResponseHead *responseHead = mChannel->GetResponseHead();
   1.768 +  bool result = SendRedirect1Begin(newChannelId, uriParams, redirectFlags,
   1.769 +                                   responseHead ? *responseHead
   1.770 +                                                : nsHttpResponseHead());
   1.771 +  if (!result) {
   1.772 +    // Bug 621446 investigation
   1.773 +    mSentRedirect1BeginFailed = true;
   1.774 +    return NS_BINDING_ABORTED;
   1.775 +  }
   1.776 +
   1.777 +  // Bug 621446 investigation
   1.778 +  mSentRedirect1Begin = true;
   1.779 +
   1.780 +  // Result is handled in RecvRedirect2Verify above
   1.781 +
   1.782 +  mRedirectChannel = newChannel;
   1.783 +  mRedirectCallback = callback;
   1.784 +  return NS_OK;
   1.785 +}
   1.786 +
   1.787 +NS_IMETHODIMP
   1.788 +HttpChannelParent::CompleteRedirect(bool succeeded)
   1.789 +{
   1.790 +  if (succeeded && !mIPCClosed) {
   1.791 +    // TODO: check return value: assume child dead if failed
   1.792 +    unused << SendRedirect3Complete();
   1.793 +  }
   1.794 +
   1.795 +  mRedirectChannel = nullptr;
   1.796 +  return NS_OK;
   1.797 +}
   1.798 +
   1.799 +//-----------------------------------------------------------------------------
   1.800 +// HttpChannelParent::ADivertableParentChannel
   1.801 +//-----------------------------------------------------------------------------
   1.802 +nsresult
   1.803 +HttpChannelParent::SuspendForDiversion()
   1.804 +{
   1.805 +  MOZ_ASSERT(mChannel);
   1.806 +  MOZ_ASSERT(mParentListener);
   1.807 +  if (NS_WARN_IF(mDivertingFromChild)) {
   1.808 +    MOZ_ASSERT(!mDivertingFromChild, "Already suspended for diversion!");
   1.809 +    return NS_ERROR_UNEXPECTED;
   1.810 +  }
   1.811 +
   1.812 +  // Try suspending the channel. Allow it to fail, since OnStopRequest may have
   1.813 +  // been called and thus the channel may not be pending.
   1.814 +  nsresult rv = mChannel->Suspend();
   1.815 +  MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE);
   1.816 +  mSuspendedForDiversion = NS_SUCCEEDED(rv);
   1.817 +
   1.818 +  rv = mParentListener->SuspendForDiversion();
   1.819 +  MOZ_ASSERT(NS_SUCCEEDED(rv));
   1.820 +
   1.821 +  // Once this is set, no more OnStart/OnData/OnStop callbacks should be sent
   1.822 +  // to the child.
   1.823 +  mDivertingFromChild = true;
   1.824 +
   1.825 +  return NS_OK;
   1.826 +}
   1.827 +
   1.828 +/* private, supporting function for ADivertableParentChannel */
   1.829 +nsresult
   1.830 +HttpChannelParent::ResumeForDiversion()
   1.831 +{
   1.832 +  MOZ_ASSERT(mChannel);
   1.833 +  if (NS_WARN_IF(!mDivertingFromChild)) {
   1.834 +    MOZ_ASSERT(mDivertingFromChild,
   1.835 +               "Cannot ResumeForDiversion if not diverting!");
   1.836 +    return NS_ERROR_UNEXPECTED;
   1.837 +  }
   1.838 +
   1.839 +  if (mSuspendedForDiversion) {
   1.840 +    // The nsHttpChannel will deliver remaining OnData/OnStop for the transfer.
   1.841 +    nsresult rv = mChannel->Resume();
   1.842 +    if (NS_WARN_IF(NS_FAILED(rv))) {
   1.843 +      FailDiversion(NS_ERROR_UNEXPECTED, true);
   1.844 +      return rv;
   1.845 +    }
   1.846 +    mSuspendedForDiversion = false;
   1.847 +  }
   1.848 +
   1.849 +  if (NS_WARN_IF(mIPCClosed || !SendDeleteSelf())) {
   1.850 +    FailDiversion(NS_ERROR_UNEXPECTED);
   1.851 +    return NS_ERROR_UNEXPECTED;
   1.852 +  }
   1.853 +  return NS_OK;
   1.854 +}
   1.855 +
   1.856 +void
   1.857 +HttpChannelParent::DivertTo(nsIStreamListener *aListener)
   1.858 +{
   1.859 +  MOZ_ASSERT(mParentListener);
   1.860 +  if (NS_WARN_IF(!mDivertingFromChild)) {
   1.861 +    MOZ_ASSERT(mDivertingFromChild,
   1.862 +               "Cannot DivertTo new listener if diverting is not set!");
   1.863 +    return;
   1.864 +  }
   1.865 +
   1.866 +  DebugOnly<nsresult> rv = mParentListener->DivertTo(aListener);
   1.867 +  MOZ_ASSERT(NS_SUCCEEDED(rv));
   1.868 +
   1.869 +  if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) {
   1.870 +    FailDiversion(NS_ERROR_UNEXPECTED);
   1.871 +    return;
   1.872 +  }
   1.873 +
   1.874 +  // Call OnStartRequest and SendDivertMessages asynchronously to avoid
   1.875 +  // reentering client context.
   1.876 +  NS_DispatchToCurrentThread(
   1.877 +    NS_NewRunnableMethod(this, &HttpChannelParent::StartDiversion));
   1.878 +  return;
   1.879 +}
   1.880 +
   1.881 +void
   1.882 +HttpChannelParent::StartDiversion()
   1.883 +{
   1.884 +  if (NS_WARN_IF(!mDivertingFromChild)) {
   1.885 +    MOZ_ASSERT(mDivertingFromChild,
   1.886 +               "Cannot StartDiversion if diverting is not set!");
   1.887 +    return;
   1.888 +  }
   1.889 +
   1.890 +  // Fake pending status in case OnStopRequest has already been called.
   1.891 +  if (mChannel) {
   1.892 +    mChannel->ForcePending(true);
   1.893 +  }
   1.894 +
   1.895 +  // Call OnStartRequest for the "DivertTo" listener.
   1.896 +  nsresult rv = mParentListener->OnStartRequest(mChannel, nullptr);
   1.897 +  if (NS_FAILED(rv)) {
   1.898 +    if (mChannel) {
   1.899 +      mChannel->Cancel(rv);
   1.900 +    }
   1.901 +    mStatus = rv;
   1.902 +  }
   1.903 +  mDivertedOnStartRequest = true;
   1.904 +
   1.905 +  // After OnStartRequest has been called, tell HttpChannelChild to divert the
   1.906 +  // OnDataAvailables and OnStopRequest to this HttpChannelParent.
   1.907 +  if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) {
   1.908 +    FailDiversion(NS_ERROR_UNEXPECTED);
   1.909 +    return;
   1.910 +  }
   1.911 +}
   1.912 +
   1.913 +class HTTPFailDiversionEvent : public nsRunnable
   1.914 +{
   1.915 +public:
   1.916 +  HTTPFailDiversionEvent(HttpChannelParent *aChannelParent,
   1.917 +                         nsresult aErrorCode,
   1.918 +                         bool aSkipResume)
   1.919 +    : mChannelParent(aChannelParent)
   1.920 +    , mErrorCode(aErrorCode)
   1.921 +    , mSkipResume(aSkipResume)
   1.922 +  {
   1.923 +    MOZ_RELEASE_ASSERT(aChannelParent);
   1.924 +    MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
   1.925 +  }
   1.926 +  NS_IMETHOD Run()
   1.927 +  {
   1.928 +    mChannelParent->NotifyDiversionFailed(mErrorCode, mSkipResume);
   1.929 +    return NS_OK;
   1.930 +  }
   1.931 +private:
   1.932 +  nsRefPtr<HttpChannelParent> mChannelParent;
   1.933 +  nsresult mErrorCode;
   1.934 +  bool mSkipResume;
   1.935 +};
   1.936 +
   1.937 +void
   1.938 +HttpChannelParent::FailDiversion(nsresult aErrorCode,
   1.939 +                                 bool aSkipResume)
   1.940 +{
   1.941 +  MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
   1.942 +  MOZ_RELEASE_ASSERT(mDivertingFromChild);
   1.943 +  MOZ_RELEASE_ASSERT(mParentListener);
   1.944 +  MOZ_RELEASE_ASSERT(mChannel);
   1.945 +
   1.946 +  NS_DispatchToCurrentThread(
   1.947 +    new HTTPFailDiversionEvent(this, aErrorCode, aSkipResume));
   1.948 +}
   1.949 +
   1.950 +void
   1.951 +HttpChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
   1.952 +                                         bool aSkipResume)
   1.953 +{
   1.954 +  MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
   1.955 +  MOZ_RELEASE_ASSERT(mDivertingFromChild);
   1.956 +  MOZ_RELEASE_ASSERT(mParentListener);
   1.957 +  MOZ_RELEASE_ASSERT(mChannel);
   1.958 +
   1.959 +  mChannel->Cancel(aErrorCode);
   1.960 +
   1.961 +  mChannel->ForcePending(false);
   1.962 +
   1.963 +  bool isPending = false;
   1.964 +  nsresult rv = mChannel->IsPending(&isPending);
   1.965 +  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
   1.966 +
   1.967 +  // Resume only if we suspended earlier.
   1.968 +  if (mSuspendedForDiversion) {
   1.969 +    mChannel->Resume();
   1.970 +  }
   1.971 +  // Channel has already sent OnStartRequest to the child, so ensure that we
   1.972 +  // call it here if it hasn't already been called.
   1.973 +  if (!mDivertedOnStartRequest) {
   1.974 +    mChannel->ForcePending(true);
   1.975 +    mParentListener->OnStartRequest(mChannel, nullptr);
   1.976 +    mChannel->ForcePending(false);
   1.977 +  }
   1.978 +  // If the channel is pending, it will call OnStopRequest itself; otherwise, do
   1.979 +  // it here.
   1.980 +  if (!isPending) {
   1.981 +    mParentListener->OnStopRequest(mChannel, nullptr, aErrorCode);
   1.982 +  }
   1.983 +  mParentListener = nullptr;
   1.984 +  mChannel = nullptr;
   1.985 +
   1.986 +  if (!mIPCClosed) {
   1.987 +    unused << SendDeleteSelf();
   1.988 +  }
   1.989 +}
   1.990 +
   1.991 +}} // mozilla::net

mercurial