netwerk/protocol/http/HttpChannelChild.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/protocol/http/HttpChannelChild.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1661 @@
     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 +
     1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
    1.10 +
    1.11 +// HttpLog.h should generally be included first
    1.12 +#include "HttpLog.h"
    1.13 +
    1.14 +#include "nsHttp.h"
    1.15 +#include "mozilla/unused.h"
    1.16 +#include "mozilla/dom/ContentChild.h"
    1.17 +#include "mozilla/dom/TabChild.h"
    1.18 +#include "mozilla/dom/FileDescriptorSetChild.h"
    1.19 +#include "mozilla/net/NeckoChild.h"
    1.20 +#include "mozilla/net/HttpChannelChild.h"
    1.21 +
    1.22 +#include "nsStringStream.h"
    1.23 +#include "nsHttpHandler.h"
    1.24 +#include "nsNetUtil.h"
    1.25 +#include "nsSerializationHelper.h"
    1.26 +#include "mozilla/Attributes.h"
    1.27 +#include "mozilla/ipc/InputStreamUtils.h"
    1.28 +#include "mozilla/ipc/URIUtils.h"
    1.29 +#include "mozilla/net/ChannelDiverterChild.h"
    1.30 +#include "mozilla/net/DNS.h"
    1.31 +#include "SerializedLoadContext.h"
    1.32 +
    1.33 +using namespace mozilla::dom;
    1.34 +using namespace mozilla::ipc;
    1.35 +
    1.36 +namespace mozilla {
    1.37 +namespace net {
    1.38 +
    1.39 +//-----------------------------------------------------------------------------
    1.40 +// HttpChannelChild
    1.41 +//-----------------------------------------------------------------------------
    1.42 +
    1.43 +HttpChannelChild::HttpChannelChild()
    1.44 +  : HttpAsyncAborter<HttpChannelChild>(MOZ_THIS_IN_INITIALIZER_LIST())
    1.45 +  , mIsFromCache(false)
    1.46 +  , mCacheEntryAvailable(false)
    1.47 +  , mCacheExpirationTime(nsICache::NO_EXPIRATION_TIME)
    1.48 +  , mSendResumeAt(false)
    1.49 +  , mIPCOpen(false)
    1.50 +  , mKeptAlive(false)
    1.51 +  , mDivertingToParent(false)
    1.52 +  , mFlushedForDiversion(false)
    1.53 +  , mSuspendSent(false)
    1.54 +{
    1.55 +  LOG(("Creating HttpChannelChild @%x\n", this));
    1.56 +
    1.57 +  mChannelCreationTime = PR_Now();
    1.58 +  mChannelCreationTimestamp = TimeStamp::Now();
    1.59 +  mAsyncOpenTime = TimeStamp::Now();
    1.60 +  mEventQ = new ChannelEventQueue(static_cast<nsIHttpChannel*>(this));
    1.61 +}
    1.62 +
    1.63 +HttpChannelChild::~HttpChannelChild()
    1.64 +{
    1.65 +  LOG(("Destroying HttpChannelChild @%x\n", this));
    1.66 +}
    1.67 +
    1.68 +//-----------------------------------------------------------------------------
    1.69 +// HttpChannelChild::nsISupports
    1.70 +//-----------------------------------------------------------------------------
    1.71 +
    1.72 +// Override nsHashPropertyBag's AddRef: we don't need thread-safe refcnt
    1.73 +NS_IMPL_ADDREF(HttpChannelChild)
    1.74 +
    1.75 +NS_IMETHODIMP_(MozExternalRefCountType) HttpChannelChild::Release()
    1.76 +{
    1.77 +  NS_PRECONDITION(0 != mRefCnt, "dup release");
    1.78 +  NS_ASSERT_OWNINGTHREAD(HttpChannelChild);
    1.79 +  --mRefCnt;
    1.80 +  NS_LOG_RELEASE(this, mRefCnt, "HttpChannelChild");
    1.81 +
    1.82 +  // Normally we Send_delete in OnStopRequest, but when we need to retain the
    1.83 +  // remote channel for security info IPDL itself holds 1 reference, so we
    1.84 +  // Send_delete when refCnt==1.  But if !mIPCOpen, then there's nobody to send
    1.85 +  // to, so we fall through.
    1.86 +  if (mKeptAlive && mRefCnt == 1 && mIPCOpen) {
    1.87 +    mKeptAlive = false;
    1.88 +    // Send_delete calls NeckoChild::DeallocPHttpChannel, which will release
    1.89 +    // again to refcount==0
    1.90 +    PHttpChannelChild::Send__delete__(this);
    1.91 +    return 0;
    1.92 +  }
    1.93 +
    1.94 +  if (mRefCnt == 0) {
    1.95 +    mRefCnt = 1; /* stabilize */
    1.96 +    delete this;
    1.97 +    return 0;
    1.98 +  }
    1.99 +  return mRefCnt;
   1.100 +}
   1.101 +
   1.102 +NS_INTERFACE_MAP_BEGIN(HttpChannelChild)
   1.103 +  NS_INTERFACE_MAP_ENTRY(nsIRequest)
   1.104 +  NS_INTERFACE_MAP_ENTRY(nsIChannel)
   1.105 +  NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
   1.106 +  NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
   1.107 +  NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
   1.108 +  NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
   1.109 +  NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
   1.110 +  NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
   1.111 +  NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
   1.112 +  NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
   1.113 +  NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
   1.114 +  NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
   1.115 +  NS_INTERFACE_MAP_ENTRY(nsIChildChannel)
   1.116 +  NS_INTERFACE_MAP_ENTRY(nsIHttpChannelChild)
   1.117 +  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAssociatedContentSecurity, GetAssociatedContentSecurity())
   1.118 +  NS_INTERFACE_MAP_ENTRY(nsIDivertableChannel)
   1.119 +NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
   1.120 +
   1.121 +//-----------------------------------------------------------------------------
   1.122 +// HttpChannelChild::PHttpChannelChild
   1.123 +//-----------------------------------------------------------------------------
   1.124 +
   1.125 +void
   1.126 +HttpChannelChild::AddIPDLReference()
   1.127 +{
   1.128 +  MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
   1.129 +  mIPCOpen = true;
   1.130 +  AddRef();
   1.131 +}
   1.132 +
   1.133 +void
   1.134 +HttpChannelChild::ReleaseIPDLReference()
   1.135 +{
   1.136 +  MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
   1.137 +  mIPCOpen = false;
   1.138 +  Release();
   1.139 +}
   1.140 +
   1.141 +class AssociateApplicationCacheEvent : public ChannelEvent
   1.142 +{
   1.143 +  public:
   1.144 +    AssociateApplicationCacheEvent(HttpChannelChild* child,
   1.145 +                                   const nsCString &groupID,
   1.146 +                                   const nsCString &clientID)
   1.147 +    : mChild(child)
   1.148 +    , groupID(groupID)
   1.149 +    , clientID(clientID) {}
   1.150 +
   1.151 +    void Run() { mChild->AssociateApplicationCache(groupID, clientID); }
   1.152 +  private:
   1.153 +    HttpChannelChild* mChild;
   1.154 +    nsCString groupID;
   1.155 +    nsCString clientID;
   1.156 +};
   1.157 +
   1.158 +bool
   1.159 +HttpChannelChild::RecvAssociateApplicationCache(const nsCString &groupID,
   1.160 +                                                const nsCString &clientID)
   1.161 +{
   1.162 +  if (mEventQ->ShouldEnqueue()) {
   1.163 +    mEventQ->Enqueue(new AssociateApplicationCacheEvent(this, groupID, clientID));
   1.164 +  } else {
   1.165 +    AssociateApplicationCache(groupID, clientID);
   1.166 +  }
   1.167 +  return true;
   1.168 +}
   1.169 +
   1.170 +void
   1.171 +HttpChannelChild::AssociateApplicationCache(const nsCString &groupID,
   1.172 +                                            const nsCString &clientID)
   1.173 +{
   1.174 +  nsresult rv;
   1.175 +  mApplicationCache = do_CreateInstance(NS_APPLICATIONCACHE_CONTRACTID, &rv);
   1.176 +  if (NS_FAILED(rv))
   1.177 +    return;
   1.178 +
   1.179 +  mLoadedFromApplicationCache = true;
   1.180 +  mApplicationCache->InitAsHandle(groupID, clientID);
   1.181 +}
   1.182 +
   1.183 +class StartRequestEvent : public ChannelEvent
   1.184 +{
   1.185 + public:
   1.186 +  StartRequestEvent(HttpChannelChild* child,
   1.187 +                    const nsresult& channelStatus,
   1.188 +                    const nsHttpResponseHead& responseHead,
   1.189 +                    const bool& useResponseHead,
   1.190 +                    const nsHttpHeaderArray& requestHeaders,
   1.191 +                    const bool& isFromCache,
   1.192 +                    const bool& cacheEntryAvailable,
   1.193 +                    const uint32_t& cacheExpirationTime,
   1.194 +                    const nsCString& cachedCharset,
   1.195 +                    const nsCString& securityInfoSerialization,
   1.196 +                    const NetAddr& selfAddr,
   1.197 +                    const NetAddr& peerAddr)
   1.198 +  : mChild(child)
   1.199 +  , mChannelStatus(channelStatus)
   1.200 +  , mResponseHead(responseHead)
   1.201 +  , mRequestHeaders(requestHeaders)
   1.202 +  , mUseResponseHead(useResponseHead)
   1.203 +  , mIsFromCache(isFromCache)
   1.204 +  , mCacheEntryAvailable(cacheEntryAvailable)
   1.205 +  , mCacheExpirationTime(cacheExpirationTime)
   1.206 +  , mCachedCharset(cachedCharset)
   1.207 +  , mSecurityInfoSerialization(securityInfoSerialization)
   1.208 +  , mSelfAddr(selfAddr)
   1.209 +  , mPeerAddr(peerAddr)
   1.210 +  {}
   1.211 +
   1.212 +  void Run()
   1.213 +  {
   1.214 +    mChild->OnStartRequest(mChannelStatus, mResponseHead, mUseResponseHead,
   1.215 +                           mRequestHeaders, mIsFromCache, mCacheEntryAvailable,
   1.216 +                           mCacheExpirationTime, mCachedCharset,
   1.217 +                           mSecurityInfoSerialization, mSelfAddr, mPeerAddr);
   1.218 +  }
   1.219 + private:
   1.220 +  HttpChannelChild* mChild;
   1.221 +  nsresult mChannelStatus;
   1.222 +  nsHttpResponseHead mResponseHead;
   1.223 +  nsHttpHeaderArray mRequestHeaders;
   1.224 +  bool mUseResponseHead;
   1.225 +  bool mIsFromCache;
   1.226 +  bool mCacheEntryAvailable;
   1.227 +  uint32_t mCacheExpirationTime;
   1.228 +  nsCString mCachedCharset;
   1.229 +  nsCString mSecurityInfoSerialization;
   1.230 +  NetAddr mSelfAddr;
   1.231 +  NetAddr mPeerAddr;
   1.232 +};
   1.233 +
   1.234 +bool
   1.235 +HttpChannelChild::RecvOnStartRequest(const nsresult& channelStatus,
   1.236 +                                     const nsHttpResponseHead& responseHead,
   1.237 +                                     const bool& useResponseHead,
   1.238 +                                     const nsHttpHeaderArray& requestHeaders,
   1.239 +                                     const bool& isFromCache,
   1.240 +                                     const bool& cacheEntryAvailable,
   1.241 +                                     const uint32_t& cacheExpirationTime,
   1.242 +                                     const nsCString& cachedCharset,
   1.243 +                                     const nsCString& securityInfoSerialization,
   1.244 +                                     const NetAddr& selfAddr,
   1.245 +                                     const NetAddr& peerAddr,
   1.246 +                                     const int16_t& redirectCount)
   1.247 +{
   1.248 +  // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
   1.249 +  // stage, as they are set in the listener's OnStartRequest.
   1.250 +  MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.251 +    "mFlushedForDiversion should be unset before OnStartRequest!");
   1.252 +  MOZ_RELEASE_ASSERT(!mDivertingToParent,
   1.253 +    "mDivertingToParent should be unset before OnStartRequest!");
   1.254 +
   1.255 +
   1.256 +  mRedirectCount = redirectCount;
   1.257 +
   1.258 +  if (mEventQ->ShouldEnqueue()) {
   1.259 +    mEventQ->Enqueue(new StartRequestEvent(this, channelStatus, responseHead,
   1.260 +                                           useResponseHead, requestHeaders,
   1.261 +                                           isFromCache, cacheEntryAvailable,
   1.262 +                                           cacheExpirationTime, cachedCharset,
   1.263 +                                           securityInfoSerialization, selfAddr,
   1.264 +                                           peerAddr));
   1.265 +  } else {
   1.266 +    OnStartRequest(channelStatus, responseHead, useResponseHead, requestHeaders,
   1.267 +                   isFromCache, cacheEntryAvailable, cacheExpirationTime,
   1.268 +                   cachedCharset, securityInfoSerialization, selfAddr,
   1.269 +                   peerAddr);
   1.270 +  }
   1.271 +  return true;
   1.272 +}
   1.273 +
   1.274 +void
   1.275 +HttpChannelChild::OnStartRequest(const nsresult& channelStatus,
   1.276 +                                 const nsHttpResponseHead& responseHead,
   1.277 +                                 const bool& useResponseHead,
   1.278 +                                 const nsHttpHeaderArray& requestHeaders,
   1.279 +                                 const bool& isFromCache,
   1.280 +                                 const bool& cacheEntryAvailable,
   1.281 +                                 const uint32_t& cacheExpirationTime,
   1.282 +                                 const nsCString& cachedCharset,
   1.283 +                                 const nsCString& securityInfoSerialization,
   1.284 +                                 const NetAddr& selfAddr,
   1.285 +                                 const NetAddr& peerAddr)
   1.286 +{
   1.287 +  LOG(("HttpChannelChild::RecvOnStartRequest [this=%p]\n", this));
   1.288 +
   1.289 +  // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
   1.290 +  // stage, as they are set in the listener's OnStartRequest.
   1.291 +  MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.292 +    "mFlushedForDiversion should be unset before OnStartRequest!");
   1.293 +  MOZ_RELEASE_ASSERT(!mDivertingToParent,
   1.294 +    "mDivertingToParent should be unset before OnStartRequest!");
   1.295 +
   1.296 +  if (!mCanceled && NS_SUCCEEDED(mStatus)) {
   1.297 +    mStatus = channelStatus;
   1.298 +  }
   1.299 +
   1.300 +  if (useResponseHead && !mCanceled)
   1.301 +    mResponseHead = new nsHttpResponseHead(responseHead);
   1.302 +
   1.303 +  if (!securityInfoSerialization.IsEmpty()) {
   1.304 +    NS_DeserializeObject(securityInfoSerialization,
   1.305 +                         getter_AddRefs(mSecurityInfo));
   1.306 +  }
   1.307 +
   1.308 +  mIsFromCache = isFromCache;
   1.309 +  mCacheEntryAvailable = cacheEntryAvailable;
   1.310 +  mCacheExpirationTime = cacheExpirationTime;
   1.311 +  mCachedCharset = cachedCharset;
   1.312 +
   1.313 +  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
   1.314 +
   1.315 +  // replace our request headers with what actually got sent in the parent
   1.316 +  mRequestHead.Headers() = requestHeaders;
   1.317 +
   1.318 +  // Note: this is where we would notify "http-on-examine-response" observers.
   1.319 +  // We have deliberately disabled this for child processes (see bug 806753)
   1.320 +  //
   1.321 +  // gHttpHandler->OnExamineResponse(this);
   1.322 +
   1.323 +  mTracingEnabled = false;
   1.324 +
   1.325 +  nsresult rv = mListener->OnStartRequest(this, mListenerContext);
   1.326 +  if (NS_FAILED(rv)) {
   1.327 +    Cancel(rv);
   1.328 +    return;
   1.329 +  }
   1.330 +
   1.331 +  if (mDivertingToParent) {
   1.332 +    mListener = nullptr;
   1.333 +    mListenerContext = nullptr;
   1.334 +    if (mLoadGroup) {
   1.335 +      mLoadGroup->RemoveRequest(this, nullptr, mStatus);
   1.336 +    }
   1.337 +  }
   1.338 +
   1.339 +  if (mResponseHead)
   1.340 +    SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
   1.341 +
   1.342 +  rv = ApplyContentConversions();
   1.343 +  if (NS_FAILED(rv))
   1.344 +    Cancel(rv);
   1.345 +
   1.346 +  mSelfAddr = selfAddr;
   1.347 +  mPeerAddr = peerAddr;
   1.348 +}
   1.349 +
   1.350 +class TransportAndDataEvent : public ChannelEvent
   1.351 +{
   1.352 + public:
   1.353 +  TransportAndDataEvent(HttpChannelChild* child,
   1.354 +                        const nsresult& channelStatus,
   1.355 +                        const nsresult& transportStatus,
   1.356 +                        const uint64_t& progress,
   1.357 +                        const uint64_t& progressMax,
   1.358 +                        const nsCString& data,
   1.359 +                        const uint64_t& offset,
   1.360 +                        const uint32_t& count)
   1.361 +  : mChild(child)
   1.362 +  , mChannelStatus(channelStatus)
   1.363 +  , mTransportStatus(transportStatus)
   1.364 +  , mProgress(progress)
   1.365 +  , mProgressMax(progressMax)
   1.366 +  , mData(data)
   1.367 +  , mOffset(offset)
   1.368 +  , mCount(count) {}
   1.369 +
   1.370 +  void Run()
   1.371 +  {
   1.372 +    mChild->OnTransportAndData(mChannelStatus, mTransportStatus, mProgress,
   1.373 +                               mProgressMax, mData, mOffset, mCount);
   1.374 +  }
   1.375 + private:
   1.376 +  HttpChannelChild* mChild;
   1.377 +  nsresult mChannelStatus;
   1.378 +  nsresult mTransportStatus;
   1.379 +  uint64_t mProgress;
   1.380 +  uint64_t mProgressMax;
   1.381 +  nsCString mData;
   1.382 +  uint64_t mOffset;
   1.383 +  uint32_t mCount;
   1.384 +};
   1.385 +
   1.386 +bool
   1.387 +HttpChannelChild::RecvOnTransportAndData(const nsresult& channelStatus,
   1.388 +                                         const nsresult& transportStatus,
   1.389 +                                         const uint64_t& progress,
   1.390 +                                         const uint64_t& progressMax,
   1.391 +                                         const nsCString& data,
   1.392 +                                         const uint64_t& offset,
   1.393 +                                         const uint32_t& count)
   1.394 +{
   1.395 +  MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.396 +                     "Should not be receiving any more callbacks from parent!");
   1.397 +
   1.398 +  if (mEventQ->ShouldEnqueue()) {
   1.399 +    mEventQ->Enqueue(new TransportAndDataEvent(this, channelStatus,
   1.400 +                                               transportStatus, progress,
   1.401 +                                               progressMax, data, offset,
   1.402 +                                               count));
   1.403 +  } else {
   1.404 +    MOZ_RELEASE_ASSERT(!mDivertingToParent,
   1.405 +                       "ShouldEnqueue when diverting to parent!");
   1.406 +
   1.407 +    OnTransportAndData(channelStatus, transportStatus, progress, progressMax,
   1.408 +                       data, offset, count);
   1.409 +  }
   1.410 +  return true;
   1.411 +}
   1.412 +
   1.413 +void
   1.414 +HttpChannelChild::OnTransportAndData(const nsresult& channelStatus,
   1.415 +                                     const nsresult& transportStatus,
   1.416 +                                     const uint64_t progress,
   1.417 +                                     const uint64_t& progressMax,
   1.418 +                                     const nsCString& data,
   1.419 +                                     const uint64_t& offset,
   1.420 +                                     const uint32_t& count)
   1.421 +{
   1.422 +  LOG(("HttpChannelChild::OnTransportAndData [this=%p]\n", this));
   1.423 +
   1.424 +  if (!mCanceled && NS_SUCCEEDED(mStatus)) {
   1.425 +    mStatus = channelStatus;
   1.426 +  }
   1.427 +
   1.428 +  // For diversion to parent, just SendDivertOnDataAvailable.
   1.429 +  if (mDivertingToParent) {
   1.430 +    MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.431 +      "Should not be processing any more callbacks from parent!");
   1.432 +
   1.433 +    SendDivertOnDataAvailable(data, offset, count);
   1.434 +    return;
   1.435 +  }
   1.436 +
   1.437 +  if (mCanceled)
   1.438 +    return;
   1.439 +
   1.440 +  // cache the progress sink so we don't have to query for it each time.
   1.441 +  if (!mProgressSink)
   1.442 +    GetCallback(mProgressSink);
   1.443 +
   1.444 +  // Hold queue lock throughout all three calls, else we might process a later
   1.445 +  // necko msg in between them.
   1.446 +  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
   1.447 +
   1.448 +  // block status/progress after Cancel or OnStopRequest has been called,
   1.449 +  // or if channel has LOAD_BACKGROUND set.
   1.450 +  // - JDUELL: may not need mStatus/mIsPending checks, given this is always called
   1.451 +  //   during OnDataAvailable, and we've already checked mCanceled.  Code
   1.452 +  //   dupe'd from nsHttpChannel
   1.453 +  if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
   1.454 +      !(mLoadFlags & LOAD_BACKGROUND))
   1.455 +  {
   1.456 +    // OnStatus
   1.457 +    //
   1.458 +    MOZ_ASSERT(transportStatus == NS_NET_STATUS_RECEIVING_FROM ||
   1.459 +               transportStatus == NS_NET_STATUS_READING);
   1.460 +
   1.461 +    nsAutoCString host;
   1.462 +    mURI->GetHost(host);
   1.463 +    mProgressSink->OnStatus(this, nullptr, transportStatus,
   1.464 +                            NS_ConvertUTF8toUTF16(host).get());
   1.465 +    // OnProgress
   1.466 +    //
   1.467 +    if (progress > 0) {
   1.468 +      MOZ_ASSERT(progress <= progressMax, "unexpected progress values");
   1.469 +      mProgressSink->OnProgress(this, nullptr, progress, progressMax);
   1.470 +    }
   1.471 +  }
   1.472 +
   1.473 +  // OnDataAvailable
   1.474 +  //
   1.475 +  // NOTE: the OnDataAvailable contract requires the client to read all the data
   1.476 +  // in the inputstream.  This code relies on that ('data' will go away after
   1.477 +  // this function).  Apparently the previous, non-e10s behavior was to actually
   1.478 +  // support only reading part of the data, allowing later calls to read the
   1.479 +  // rest.
   1.480 +  nsCOMPtr<nsIInputStream> stringStream;
   1.481 +  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
   1.482 +                                      count, NS_ASSIGNMENT_DEPEND);
   1.483 +  if (NS_FAILED(rv)) {
   1.484 +    Cancel(rv);
   1.485 +    return;
   1.486 +  }
   1.487 +
   1.488 +  rv = mListener->OnDataAvailable(this, mListenerContext,
   1.489 +                                  stringStream, offset, count);
   1.490 +  stringStream->Close();
   1.491 +  if (NS_FAILED(rv)) {
   1.492 +    Cancel(rv);
   1.493 +  }
   1.494 +}
   1.495 +
   1.496 +class StopRequestEvent : public ChannelEvent
   1.497 +{
   1.498 + public:
   1.499 +  StopRequestEvent(HttpChannelChild* child,
   1.500 +                   const nsresult& channelStatus)
   1.501 +  : mChild(child)
   1.502 +  , mChannelStatus(channelStatus) {}
   1.503 +
   1.504 +  void Run() { mChild->OnStopRequest(mChannelStatus); }
   1.505 + private:
   1.506 +  HttpChannelChild* mChild;
   1.507 +  nsresult mChannelStatus;
   1.508 +};
   1.509 +
   1.510 +bool
   1.511 +HttpChannelChild::RecvOnStopRequest(const nsresult& channelStatus)
   1.512 +{
   1.513 +  MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.514 +    "Should not be receiving any more callbacks from parent!");
   1.515 +
   1.516 +  if (mEventQ->ShouldEnqueue()) {
   1.517 +    mEventQ->Enqueue(new StopRequestEvent(this, channelStatus));
   1.518 +  } else {
   1.519 +    MOZ_ASSERT(!mDivertingToParent, "ShouldEnqueue when diverting to parent!");
   1.520 +
   1.521 +    OnStopRequest(channelStatus);
   1.522 +  }
   1.523 +  return true;
   1.524 +}
   1.525 +
   1.526 +void
   1.527 +HttpChannelChild::OnStopRequest(const nsresult& channelStatus)
   1.528 +{
   1.529 +  LOG(("HttpChannelChild::OnStopRequest [this=%p status=%x]\n",
   1.530 +           this, channelStatus));
   1.531 +
   1.532 +  if (mDivertingToParent) {
   1.533 +    MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.534 +      "Should not be processing any more callbacks from parent!");
   1.535 +
   1.536 +    SendDivertOnStopRequest(channelStatus);
   1.537 +    return;
   1.538 +  }
   1.539 +
   1.540 +  mIsPending = false;
   1.541 +
   1.542 +  if (!mCanceled && NS_SUCCEEDED(mStatus)) {
   1.543 +    mStatus = channelStatus;
   1.544 +  }
   1.545 +
   1.546 +  { // We must flush the queue before we Send__delete__
   1.547 +    // (although we really shouldn't receive any msgs after OnStop),
   1.548 +    // so make sure this goes out of scope before then.
   1.549 +    AutoEventEnqueuer ensureSerialDispatch(mEventQ);
   1.550 +
   1.551 +    mListener->OnStopRequest(this, mListenerContext, mStatus);
   1.552 +
   1.553 +    mListener = 0;
   1.554 +    mListenerContext = 0;
   1.555 +    mCacheEntryAvailable = false;
   1.556 +    if (mLoadGroup)
   1.557 +      mLoadGroup->RemoveRequest(this, nullptr, mStatus);
   1.558 +  }
   1.559 +
   1.560 +  if (mLoadFlags & LOAD_DOCUMENT_URI) {
   1.561 +    // Keep IPDL channel open, but only for updating security info.
   1.562 +    mKeptAlive = true;
   1.563 +    SendDocumentChannelCleanup();
   1.564 +  } else {
   1.565 +    // This calls NeckoChild::DeallocPHttpChannelChild(), which deletes |this| if IPDL
   1.566 +    // holds the last reference.  Don't rely on |this| existing after here.
   1.567 +    PHttpChannelChild::Send__delete__(this);
   1.568 +  }
   1.569 +}
   1.570 +
   1.571 +class ProgressEvent : public ChannelEvent
   1.572 +{
   1.573 + public:
   1.574 +  ProgressEvent(HttpChannelChild* child,
   1.575 +                const uint64_t& progress,
   1.576 +                const uint64_t& progressMax)
   1.577 +  : mChild(child)
   1.578 +  , mProgress(progress)
   1.579 +  , mProgressMax(progressMax) {}
   1.580 +
   1.581 +  void Run() { mChild->OnProgress(mProgress, mProgressMax); }
   1.582 + private:
   1.583 +  HttpChannelChild* mChild;
   1.584 +  uint64_t mProgress, mProgressMax;
   1.585 +};
   1.586 +
   1.587 +bool
   1.588 +HttpChannelChild::RecvOnProgress(const uint64_t& progress,
   1.589 +                                 const uint64_t& progressMax)
   1.590 +{
   1.591 +  if (mEventQ->ShouldEnqueue())  {
   1.592 +    mEventQ->Enqueue(new ProgressEvent(this, progress, progressMax));
   1.593 +  } else {
   1.594 +    OnProgress(progress, progressMax);
   1.595 +  }
   1.596 +  return true;
   1.597 +}
   1.598 +
   1.599 +void
   1.600 +HttpChannelChild::OnProgress(const uint64_t& progress,
   1.601 +                             const uint64_t& progressMax)
   1.602 +{
   1.603 +  LOG(("HttpChannelChild::OnProgress [this=%p progress=%llu/%llu]\n",
   1.604 +       this, progress, progressMax));
   1.605 +
   1.606 +  if (mCanceled)
   1.607 +    return;
   1.608 +
   1.609 +  // cache the progress sink so we don't have to query for it each time.
   1.610 +  if (!mProgressSink)
   1.611 +    GetCallback(mProgressSink);
   1.612 +
   1.613 +  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
   1.614 +
   1.615 +  // block socket status event after Cancel or OnStopRequest has been called,
   1.616 +  // or if channel has LOAD_BACKGROUND set
   1.617 +  if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
   1.618 +      !(mLoadFlags & LOAD_BACKGROUND))
   1.619 +  {
   1.620 +    if (progress > 0) {
   1.621 +      MOZ_ASSERT(progress <= progressMax, "unexpected progress values");
   1.622 +      mProgressSink->OnProgress(this, nullptr, progress, progressMax);
   1.623 +    }
   1.624 +  }
   1.625 +}
   1.626 +
   1.627 +class StatusEvent : public ChannelEvent
   1.628 +{
   1.629 + public:
   1.630 +  StatusEvent(HttpChannelChild* child,
   1.631 +              const nsresult& status)
   1.632 +  : mChild(child)
   1.633 +  , mStatus(status) {}
   1.634 +
   1.635 +  void Run() { mChild->OnStatus(mStatus); }
   1.636 + private:
   1.637 +  HttpChannelChild* mChild;
   1.638 +  nsresult mStatus;
   1.639 +};
   1.640 +
   1.641 +bool
   1.642 +HttpChannelChild::RecvOnStatus(const nsresult& status)
   1.643 +{
   1.644 +  if (mEventQ->ShouldEnqueue()) {
   1.645 +    mEventQ->Enqueue(new StatusEvent(this, status));
   1.646 +  } else {
   1.647 +    OnStatus(status);
   1.648 +  }
   1.649 +  return true;
   1.650 +}
   1.651 +
   1.652 +void
   1.653 +HttpChannelChild::OnStatus(const nsresult& status)
   1.654 +{
   1.655 +  LOG(("HttpChannelChild::OnStatus [this=%p status=%x]\n", this, status));
   1.656 +
   1.657 +  if (mCanceled)
   1.658 +    return;
   1.659 +
   1.660 +  // cache the progress sink so we don't have to query for it each time.
   1.661 +  if (!mProgressSink)
   1.662 +    GetCallback(mProgressSink);
   1.663 +
   1.664 +  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
   1.665 +
   1.666 +  // block socket status event after Cancel or OnStopRequest has been called,
   1.667 +  // or if channel has LOAD_BACKGROUND set
   1.668 +  if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending &&
   1.669 +      !(mLoadFlags & LOAD_BACKGROUND))
   1.670 +  {
   1.671 +    nsAutoCString host;
   1.672 +    mURI->GetHost(host);
   1.673 +    mProgressSink->OnStatus(this, nullptr, status,
   1.674 +                            NS_ConvertUTF8toUTF16(host).get());
   1.675 +  }
   1.676 +}
   1.677 +
   1.678 +class FailedAsyncOpenEvent : public ChannelEvent
   1.679 +{
   1.680 + public:
   1.681 +  FailedAsyncOpenEvent(HttpChannelChild* child, const nsresult& status)
   1.682 +  : mChild(child)
   1.683 +  , mStatus(status) {}
   1.684 +
   1.685 +  void Run() { mChild->FailedAsyncOpen(mStatus); }
   1.686 + private:
   1.687 +  HttpChannelChild* mChild;
   1.688 +  nsresult mStatus;
   1.689 +};
   1.690 +
   1.691 +bool
   1.692 +HttpChannelChild::RecvFailedAsyncOpen(const nsresult& status)
   1.693 +{
   1.694 +  if (mEventQ->ShouldEnqueue()) {
   1.695 +    mEventQ->Enqueue(new FailedAsyncOpenEvent(this, status));
   1.696 +  } else {
   1.697 +    FailedAsyncOpen(status);
   1.698 +  }
   1.699 +  return true;
   1.700 +}
   1.701 +
   1.702 +// We need to have an implementation of this function just so that we can keep
   1.703 +// all references to mCallOnResume of type HttpChannelChild:  it's not OK in C++
   1.704 +// to set a member function ptr to a base class function.
   1.705 +void
   1.706 +HttpChannelChild::HandleAsyncAbort()
   1.707 +{
   1.708 +  HttpAsyncAborter<HttpChannelChild>::HandleAsyncAbort();
   1.709 +}
   1.710 +
   1.711 +void
   1.712 +HttpChannelChild::FailedAsyncOpen(const nsresult& status)
   1.713 +{
   1.714 +  LOG(("HttpChannelChild::FailedAsyncOpen [this=%p status=%x]\n", this, status));
   1.715 +
   1.716 +  mStatus = status;
   1.717 +  mIsPending = false;
   1.718 +  // We're already being called from IPDL, therefore already "async"
   1.719 +  HandleAsyncAbort();
   1.720 +}
   1.721 +
   1.722 +void
   1.723 +HttpChannelChild::DoNotifyListenerCleanup()
   1.724 +{
   1.725 +  if (mIPCOpen)
   1.726 +    PHttpChannelChild::Send__delete__(this);
   1.727 +}
   1.728 +
   1.729 +class DeleteSelfEvent : public ChannelEvent
   1.730 +{
   1.731 + public:
   1.732 +  DeleteSelfEvent(HttpChannelChild* child) : mChild(child) {}
   1.733 +  void Run() { mChild->DeleteSelf(); }
   1.734 + private:
   1.735 +  HttpChannelChild* mChild;
   1.736 +};
   1.737 +
   1.738 +bool
   1.739 +HttpChannelChild::RecvDeleteSelf()
   1.740 +{
   1.741 +  if (mEventQ->ShouldEnqueue()) {
   1.742 +    mEventQ->Enqueue(new DeleteSelfEvent(this));
   1.743 +  } else {
   1.744 +    DeleteSelf();
   1.745 +  }
   1.746 +  return true;
   1.747 +}
   1.748 +
   1.749 +void
   1.750 +HttpChannelChild::DeleteSelf()
   1.751 +{
   1.752 +  Send__delete__(this);
   1.753 +}
   1.754 +
   1.755 +class Redirect1Event : public ChannelEvent
   1.756 +{
   1.757 + public:
   1.758 +  Redirect1Event(HttpChannelChild* child,
   1.759 +                 const uint32_t& newChannelId,
   1.760 +                 const URIParams& newURI,
   1.761 +                 const uint32_t& redirectFlags,
   1.762 +                 const nsHttpResponseHead& responseHead)
   1.763 +  : mChild(child)
   1.764 +  , mNewChannelId(newChannelId)
   1.765 +  , mNewURI(newURI)
   1.766 +  , mRedirectFlags(redirectFlags)
   1.767 +  , mResponseHead(responseHead) {}
   1.768 +
   1.769 +  void Run()
   1.770 +  {
   1.771 +    mChild->Redirect1Begin(mNewChannelId, mNewURI, mRedirectFlags,
   1.772 +                           mResponseHead);
   1.773 +  }
   1.774 + private:
   1.775 +  HttpChannelChild*   mChild;
   1.776 +  uint32_t            mNewChannelId;
   1.777 +  URIParams           mNewURI;
   1.778 +  uint32_t            mRedirectFlags;
   1.779 +  nsHttpResponseHead  mResponseHead;
   1.780 +};
   1.781 +
   1.782 +bool
   1.783 +HttpChannelChild::RecvRedirect1Begin(const uint32_t& newChannelId,
   1.784 +                                     const URIParams& newUri,
   1.785 +                                     const uint32_t& redirectFlags,
   1.786 +                                     const nsHttpResponseHead& responseHead)
   1.787 +{
   1.788 +  if (mEventQ->ShouldEnqueue()) {
   1.789 +    mEventQ->Enqueue(new Redirect1Event(this, newChannelId, newUri,
   1.790 +                                       redirectFlags, responseHead));
   1.791 +  } else {
   1.792 +    Redirect1Begin(newChannelId, newUri, redirectFlags, responseHead);
   1.793 +  }
   1.794 +  return true;
   1.795 +}
   1.796 +
   1.797 +void
   1.798 +HttpChannelChild::Redirect1Begin(const uint32_t& newChannelId,
   1.799 +                                 const URIParams& newUri,
   1.800 +                                 const uint32_t& redirectFlags,
   1.801 +                                 const nsHttpResponseHead& responseHead)
   1.802 +{
   1.803 +  nsresult rv;
   1.804 +
   1.805 +  nsCOMPtr<nsIIOService> ioService;
   1.806 +  rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
   1.807 +  if (NS_FAILED(rv)) {
   1.808 +    // Veto redirect.  nsHttpChannel decides to cancel or continue.
   1.809 +    OnRedirectVerifyCallback(rv);
   1.810 +    return;
   1.811 +  }
   1.812 +
   1.813 +  nsCOMPtr<nsIURI> uri = DeserializeURI(newUri);
   1.814 +
   1.815 +  nsCOMPtr<nsIChannel> newChannel;
   1.816 +  rv = ioService->NewChannelFromURI(uri, getter_AddRefs(newChannel));
   1.817 +  if (NS_FAILED(rv)) {
   1.818 +    // Veto redirect.  nsHttpChannel decides to cancel or continue.
   1.819 +    OnRedirectVerifyCallback(rv);
   1.820 +    return;
   1.821 +  }
   1.822 +
   1.823 +  // We won't get OnStartRequest, set cookies here.
   1.824 +  mResponseHead = new nsHttpResponseHead(responseHead);
   1.825 +  SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
   1.826 +
   1.827 +  bool rewriteToGET = HttpBaseChannel::ShouldRewriteRedirectToGET(mResponseHead->Status(),
   1.828 +                                                                  mRequestHead.ParsedMethod());
   1.829 +
   1.830 +  rv = SetupReplacementChannel(uri, newChannel, !rewriteToGET);
   1.831 +  if (NS_FAILED(rv)) {
   1.832 +    // Veto redirect.  nsHttpChannel decides to cancel or continue.
   1.833 +    OnRedirectVerifyCallback(rv);
   1.834 +    return;
   1.835 +  }
   1.836 +
   1.837 +  mRedirectChannelChild = do_QueryInterface(newChannel);
   1.838 +  if (mRedirectChannelChild) {
   1.839 +    mRedirectChannelChild->ConnectParent(newChannelId);
   1.840 +    rv = gHttpHandler->AsyncOnChannelRedirect(this,
   1.841 +                                              newChannel,
   1.842 +                                              redirectFlags);
   1.843 +  } else {
   1.844 +    LOG(("  redirecting to a protocol that doesn't implement"
   1.845 +         " nsIChildChannel"));
   1.846 +    rv = NS_ERROR_FAILURE;
   1.847 +  }
   1.848 +
   1.849 +  if (NS_FAILED(rv))
   1.850 +    OnRedirectVerifyCallback(rv);
   1.851 +}
   1.852 +
   1.853 +class Redirect3Event : public ChannelEvent
   1.854 +{
   1.855 + public:
   1.856 +  Redirect3Event(HttpChannelChild* child) : mChild(child) {}
   1.857 +  void Run() { mChild->Redirect3Complete(); }
   1.858 + private:
   1.859 +  HttpChannelChild* mChild;
   1.860 +};
   1.861 +
   1.862 +bool
   1.863 +HttpChannelChild::RecvRedirect3Complete()
   1.864 +{
   1.865 +  if (mEventQ->ShouldEnqueue()) {
   1.866 +    mEventQ->Enqueue(new Redirect3Event(this));
   1.867 +  } else {
   1.868 +    Redirect3Complete();
   1.869 +  }
   1.870 +  return true;
   1.871 +}
   1.872 +
   1.873 +class HttpFlushedForDiversionEvent : public ChannelEvent
   1.874 +{
   1.875 + public:
   1.876 +  HttpFlushedForDiversionEvent(HttpChannelChild* aChild)
   1.877 +  : mChild(aChild)
   1.878 +  {
   1.879 +    MOZ_RELEASE_ASSERT(aChild);
   1.880 +  }
   1.881 +
   1.882 +  void Run()
   1.883 +  {
   1.884 +    mChild->FlushedForDiversion();
   1.885 +  }
   1.886 + private:
   1.887 +  HttpChannelChild* mChild;
   1.888 +};
   1.889 +
   1.890 +bool
   1.891 +HttpChannelChild::RecvFlushedForDiversion()
   1.892 +{
   1.893 +  MOZ_RELEASE_ASSERT(mDivertingToParent);
   1.894 +  MOZ_RELEASE_ASSERT(mEventQ->ShouldEnqueue());
   1.895 +
   1.896 +  mEventQ->Enqueue(new HttpFlushedForDiversionEvent(this));
   1.897 +
   1.898 +  return true;
   1.899 +}
   1.900 +
   1.901 +void
   1.902 +HttpChannelChild::FlushedForDiversion()
   1.903 +{
   1.904 +  MOZ_RELEASE_ASSERT(mDivertingToParent);
   1.905 +
   1.906 +  // Once this is set, it should not be unset before HttpChannelChild is taken
   1.907 +  // down. After it is set, no OnStart/OnData/OnStop callbacks should be
   1.908 +  // received from the parent channel, nor dequeued from the ChannelEventQueue.
   1.909 +  mFlushedForDiversion = true;
   1.910 +
   1.911 +  SendDivertComplete();
   1.912 +}
   1.913 +
   1.914 +bool
   1.915 +HttpChannelChild::RecvDivertMessages()
   1.916 +{
   1.917 +  MOZ_RELEASE_ASSERT(mDivertingToParent);
   1.918 +  MOZ_RELEASE_ASSERT(mSuspendCount > 0);
   1.919 +
   1.920 +  // DivertTo() has been called on parent, so we can now start sending queued
   1.921 +  // IPDL messages back to parent listener.
   1.922 +  MOZ_RELEASE_ASSERT(NS_SUCCEEDED(Resume()));
   1.923 +
   1.924 +  return true;
   1.925 +}
   1.926 +
   1.927 +void
   1.928 +HttpChannelChild::Redirect3Complete()
   1.929 +{
   1.930 +  nsresult rv = NS_OK;
   1.931 +
   1.932 +  // Chrome channel has been AsyncOpen'd.  Reflect this in child.
   1.933 +  if (mRedirectChannelChild)
   1.934 +    rv = mRedirectChannelChild->CompleteRedirectSetup(mListener,
   1.935 +                                                      mListenerContext);
   1.936 +
   1.937 +  // Redirecting to new channel: shut this down and init new channel
   1.938 +  if (mLoadGroup)
   1.939 +    mLoadGroup->RemoveRequest(this, nullptr, NS_BINDING_ABORTED);
   1.940 +
   1.941 +  if (NS_FAILED(rv))
   1.942 +    NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?");
   1.943 +
   1.944 +  // Release ref to new channel.
   1.945 +  mRedirectChannelChild = nullptr;
   1.946 +}
   1.947 +
   1.948 +//-----------------------------------------------------------------------------
   1.949 +// HttpChannelChild::nsIChildChannel
   1.950 +//-----------------------------------------------------------------------------
   1.951 +
   1.952 +NS_IMETHODIMP
   1.953 +HttpChannelChild::ConnectParent(uint32_t id)
   1.954 +{
   1.955 +  mozilla::dom::TabChild* tabChild = nullptr;
   1.956 +  nsCOMPtr<nsITabChild> iTabChild;
   1.957 +  GetCallback(iTabChild);
   1.958 +  if (iTabChild) {
   1.959 +    tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
   1.960 +  }
   1.961 +  if (MissingRequiredTabChild(tabChild, "http")) {
   1.962 +    return NS_ERROR_ILLEGAL_VALUE;
   1.963 +  }
   1.964 +
   1.965 +  // The socket transport in the chrome process now holds a logical ref to us
   1.966 +  // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
   1.967 +  AddIPDLReference();
   1.968 +
   1.969 +  HttpChannelConnectArgs connectArgs(id);
   1.970 +  if (!gNeckoChild->
   1.971 +        SendPHttpChannelConstructor(this, tabChild,
   1.972 +                                    IPC::SerializedLoadContext(this),
   1.973 +                                    connectArgs)) {
   1.974 +    return NS_ERROR_FAILURE;
   1.975 +  }
   1.976 +
   1.977 +  return NS_OK;
   1.978 +}
   1.979 +
   1.980 +NS_IMETHODIMP
   1.981 +HttpChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
   1.982 +                                        nsISupports *aContext)
   1.983 +{
   1.984 +  LOG(("HttpChannelChild::FinishRedirectSetup [this=%p]\n", this));
   1.985 +
   1.986 +  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
   1.987 +  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
   1.988 +
   1.989 +  /*
   1.990 +   * No need to check for cancel: we don't get here if nsHttpChannel canceled
   1.991 +   * before AsyncOpen(); if it's canceled after that, OnStart/Stop will just
   1.992 +   * get called with error code as usual.  So just setup mListener and make the
   1.993 +   * channel reflect AsyncOpen'ed state.
   1.994 +   */
   1.995 +
   1.996 +  mIsPending = true;
   1.997 +  mWasOpened = true;
   1.998 +  mListener = listener;
   1.999 +  mListenerContext = aContext;
  1.1000 +
  1.1001 +  // add ourselves to the load group.
  1.1002 +  if (mLoadGroup)
  1.1003 +    mLoadGroup->AddRequest(this, nullptr);
  1.1004 +
  1.1005 +  // We already have an open IPDL connection to the parent. If on-modify-request
  1.1006 +  // listeners or load group observers canceled us, let the parent handle it
  1.1007 +  // and send it back to us naturally.
  1.1008 +  return NS_OK;
  1.1009 +}
  1.1010 +
  1.1011 +//-----------------------------------------------------------------------------
  1.1012 +// HttpChannelChild::nsIAsyncVerifyRedirectCallback
  1.1013 +//-----------------------------------------------------------------------------
  1.1014 +
  1.1015 +NS_IMETHODIMP
  1.1016 +HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
  1.1017 +{
  1.1018 +  OptionalURIParams redirectURI;
  1.1019 +  nsCOMPtr<nsIHttpChannel> newHttpChannel =
  1.1020 +      do_QueryInterface(mRedirectChannelChild);
  1.1021 +
  1.1022 +  if (newHttpChannel) {
  1.1023 +    // Must not be called until after redirect observers called.
  1.1024 +    newHttpChannel->SetOriginalURI(mOriginalURI);
  1.1025 +  }
  1.1026 +
  1.1027 +  RequestHeaderTuples emptyHeaders;
  1.1028 +  RequestHeaderTuples* headerTuples = &emptyHeaders;
  1.1029 +
  1.1030 +  nsCOMPtr<nsIHttpChannelChild> newHttpChannelChild =
  1.1031 +      do_QueryInterface(mRedirectChannelChild);
  1.1032 +  if (newHttpChannelChild && NS_SUCCEEDED(result)) {
  1.1033 +    newHttpChannelChild->AddCookiesToRequest();
  1.1034 +    newHttpChannelChild->GetClientSetRequestHeaders(&headerTuples);
  1.1035 +  }
  1.1036 +
  1.1037 +  /* If the redirect was canceled, bypass OMR and send an empty API
  1.1038 +   * redirect URI */
  1.1039 +  SerializeURI(nullptr, redirectURI);
  1.1040 +
  1.1041 +  if (NS_SUCCEEDED(result)) {
  1.1042 +    // Note: this is where we would notify "http-on-modify-response" observers.
  1.1043 +    // We have deliberately disabled this for child processes (see bug 806753)
  1.1044 +    //
  1.1045 +    // After we verify redirect, nsHttpChannel may hit the network: must give
  1.1046 +    // "http-on-modify-request" observers the chance to cancel before that.
  1.1047 +    //base->CallOnModifyRequestObservers();
  1.1048 +
  1.1049 +    nsCOMPtr<nsIHttpChannelInternal> newHttpChannelInternal =
  1.1050 +      do_QueryInterface(mRedirectChannelChild);
  1.1051 +    if (newHttpChannelInternal) {
  1.1052 +      nsCOMPtr<nsIURI> apiRedirectURI;
  1.1053 +      nsresult rv = newHttpChannelInternal->GetApiRedirectToURI(
  1.1054 +        getter_AddRefs(apiRedirectURI));
  1.1055 +      if (NS_SUCCEEDED(rv) && apiRedirectURI) {
  1.1056 +        /* If there was an API redirect of this channel, we need to send it
  1.1057 +         * up here, since it can't be sent via SendAsyncOpen. */
  1.1058 +        SerializeURI(apiRedirectURI, redirectURI);
  1.1059 +      }
  1.1060 +    }
  1.1061 +  }
  1.1062 +
  1.1063 +  if (mIPCOpen)
  1.1064 +    SendRedirect2Verify(result, *headerTuples, redirectURI);
  1.1065 +
  1.1066 +  return NS_OK;
  1.1067 +}
  1.1068 +
  1.1069 +//-----------------------------------------------------------------------------
  1.1070 +// HttpChannelChild::nsIRequest
  1.1071 +//-----------------------------------------------------------------------------
  1.1072 +
  1.1073 +NS_IMETHODIMP
  1.1074 +HttpChannelChild::Cancel(nsresult status)
  1.1075 +{
  1.1076 +  MOZ_ASSERT(NS_IsMainThread());
  1.1077 +
  1.1078 +  if (!mCanceled) {
  1.1079 +    // If this cancel occurs before nsHttpChannel has been set up, AsyncOpen
  1.1080 +    // is responsible for cleaning up.
  1.1081 +    mCanceled = true;
  1.1082 +    mStatus = status;
  1.1083 +    if (RemoteChannelExists())
  1.1084 +      SendCancel(status);
  1.1085 +  }
  1.1086 +  return NS_OK;
  1.1087 +}
  1.1088 +
  1.1089 +NS_IMETHODIMP
  1.1090 +HttpChannelChild::Suspend()
  1.1091 +{
  1.1092 +  NS_ENSURE_TRUE(RemoteChannelExists(), NS_ERROR_NOT_AVAILABLE);
  1.1093 +
  1.1094 +  // SendSuspend only once, when suspend goes from 0 to 1.
  1.1095 +  // Don't SendSuspend at all if we're diverting callbacks to the parent;
  1.1096 +  // suspend will be called at the correct time in the parent itself.
  1.1097 +  if (!mSuspendCount++ && !mDivertingToParent) {
  1.1098 +    SendSuspend();
  1.1099 +    mSuspendSent = true;
  1.1100 +  }
  1.1101 +  mEventQ->Suspend();
  1.1102 +
  1.1103 +  return NS_OK;
  1.1104 +}
  1.1105 +
  1.1106 +NS_IMETHODIMP
  1.1107 +HttpChannelChild::Resume()
  1.1108 +{
  1.1109 +  NS_ENSURE_TRUE(RemoteChannelExists(), NS_ERROR_NOT_AVAILABLE);
  1.1110 +  NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
  1.1111 +
  1.1112 +  nsresult rv = NS_OK;
  1.1113 +
  1.1114 +  // SendResume only once, when suspend count drops to 0.
  1.1115 +  // Don't SendResume at all if we're diverting callbacks to the parent (unless
  1.1116 +  // suspend was sent earlier); otherwise, resume will be called at the correct
  1.1117 +  // time in the parent itself.
  1.1118 +  if (!--mSuspendCount && (!mDivertingToParent || mSuspendSent)) {
  1.1119 +    SendResume();
  1.1120 +    if (mCallOnResume) {
  1.1121 +      AsyncCall(mCallOnResume);
  1.1122 +      mCallOnResume = nullptr;
  1.1123 +    }
  1.1124 +  }
  1.1125 +  mEventQ->Resume();
  1.1126 +
  1.1127 +  return rv;
  1.1128 +}
  1.1129 +
  1.1130 +//-----------------------------------------------------------------------------
  1.1131 +// HttpChannelChild::nsIChannel
  1.1132 +//-----------------------------------------------------------------------------
  1.1133 +
  1.1134 +NS_IMETHODIMP
  1.1135 +HttpChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
  1.1136 +{
  1.1137 +  NS_ENSURE_ARG_POINTER(aSecurityInfo);
  1.1138 +  NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
  1.1139 +  return NS_OK;
  1.1140 +}
  1.1141 +
  1.1142 +NS_IMETHODIMP
  1.1143 +HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
  1.1144 +{
  1.1145 +  LOG(("HttpChannelChild::AsyncOpen [this=%p uri=%s]\n", this, mSpec.get()));
  1.1146 +
  1.1147 +  if (mCanceled)
  1.1148 +    return mStatus;
  1.1149 +
  1.1150 +  NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
  1.1151 +  NS_ENSURE_ARG_POINTER(listener);
  1.1152 +  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
  1.1153 +  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
  1.1154 +
  1.1155 +  mAsyncOpenTime = TimeStamp::Now();
  1.1156 +
  1.1157 +  // Port checked in parent, but duplicate here so we can return with error
  1.1158 +  // immediately
  1.1159 +  nsresult rv;
  1.1160 +  rv = NS_CheckPortSafety(mURI);
  1.1161 +  if (NS_FAILED(rv))
  1.1162 +    return rv;
  1.1163 +
  1.1164 +  const char *cookieHeader = mRequestHead.PeekHeader(nsHttp::Cookie);
  1.1165 +  if (cookieHeader) {
  1.1166 +    mUserSetCookieHeader = cookieHeader;
  1.1167 +  }
  1.1168 +
  1.1169 +  AddCookiesToRequest();
  1.1170 +
  1.1171 +  //
  1.1172 +  // NOTE: From now on we must return NS_OK; all errors must be handled via
  1.1173 +  // OnStart/OnStopRequest
  1.1174 +  //
  1.1175 +
  1.1176 +  // Note: this is where we would notify "http-on-modify-request" observers.
  1.1177 +  // We have deliberately disabled this for child processes (see bug 806753)
  1.1178 +  //
  1.1179 +  // notify "http-on-modify-request" observers
  1.1180 +  //CallOnModifyRequestObservers();
  1.1181 +
  1.1182 +  mIsPending = true;
  1.1183 +  mWasOpened = true;
  1.1184 +  mListener = listener;
  1.1185 +  mListenerContext = aContext;
  1.1186 +
  1.1187 +  // add ourselves to the load group.
  1.1188 +  if (mLoadGroup)
  1.1189 +    mLoadGroup->AddRequest(this, nullptr);
  1.1190 +
  1.1191 +  if (mCanceled) {
  1.1192 +    // We may have been canceled already, either by on-modify-request
  1.1193 +    // listeners or by load group observers; in that case, don't create IPDL
  1.1194 +    // connection. See nsHttpChannel::AsyncOpen().
  1.1195 +    AsyncAbort(mStatus);
  1.1196 +    return NS_OK;
  1.1197 +  }
  1.1198 +
  1.1199 +  nsCString appCacheClientId;
  1.1200 +  if (mInheritApplicationCache) {
  1.1201 +    // Pick up an application cache from the notification
  1.1202 +    // callbacks if available
  1.1203 +    nsCOMPtr<nsIApplicationCacheContainer> appCacheContainer;
  1.1204 +    GetCallback(appCacheContainer);
  1.1205 +
  1.1206 +    if (appCacheContainer) {
  1.1207 +      nsCOMPtr<nsIApplicationCache> appCache;
  1.1208 +      rv = appCacheContainer->GetApplicationCache(getter_AddRefs(appCache));
  1.1209 +      if (NS_SUCCEEDED(rv) && appCache) {
  1.1210 +        appCache->GetClientID(appCacheClientId);
  1.1211 +      }
  1.1212 +    }
  1.1213 +  }
  1.1214 +
  1.1215 +  //
  1.1216 +  // Send request to the chrome process...
  1.1217 +  //
  1.1218 +
  1.1219 +  mozilla::dom::TabChild* tabChild = nullptr;
  1.1220 +  nsCOMPtr<nsITabChild> iTabChild;
  1.1221 +  GetCallback(iTabChild);
  1.1222 +  if (iTabChild) {
  1.1223 +    tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
  1.1224 +  }
  1.1225 +  if (MissingRequiredTabChild(tabChild, "http")) {
  1.1226 +    return NS_ERROR_ILLEGAL_VALUE;
  1.1227 +  }
  1.1228 +
  1.1229 +  HttpChannelOpenArgs openArgs;
  1.1230 +  // No access to HttpChannelOpenArgs members, but they each have a
  1.1231 +  // function with the struct name that returns a ref.
  1.1232 +  SerializeURI(mURI, openArgs.uri());
  1.1233 +  SerializeURI(mOriginalURI, openArgs.original());
  1.1234 +  SerializeURI(mDocumentURI, openArgs.doc());
  1.1235 +  SerializeURI(mReferrer, openArgs.referrer());
  1.1236 +  SerializeURI(mAPIRedirectToURI, openArgs.apiRedirectTo());
  1.1237 +  openArgs.loadFlags() = mLoadFlags;
  1.1238 +  openArgs.requestHeaders() = mClientSetRequestHeaders;
  1.1239 +  openArgs.requestMethod() = mRequestHead.Method();
  1.1240 +
  1.1241 +  nsTArray<mozilla::ipc::FileDescriptor> fds;
  1.1242 +  SerializeInputStream(mUploadStream, openArgs.uploadStream(), fds);
  1.1243 +
  1.1244 +  PFileDescriptorSetChild* fdSet = nullptr;
  1.1245 +  if (!fds.IsEmpty()) {
  1.1246 +    MOZ_ASSERT(gNeckoChild->Manager());
  1.1247 +
  1.1248 +    fdSet = gNeckoChild->Manager()->SendPFileDescriptorSetConstructor(fds[0]);
  1.1249 +    for (uint32_t i = 1; i < fds.Length(); ++i) {
  1.1250 +      unused << fdSet->SendAddFileDescriptor(fds[i]);
  1.1251 +    }
  1.1252 +  }
  1.1253 +
  1.1254 +  OptionalFileDescriptorSet optionalFDs;
  1.1255 +  if (fdSet) {
  1.1256 +    optionalFDs = fdSet;
  1.1257 +  } else {
  1.1258 +    optionalFDs = mozilla::void_t();
  1.1259 +  }
  1.1260 +
  1.1261 +  openArgs.fds() = optionalFDs;
  1.1262 +
  1.1263 +  openArgs.uploadStreamHasHeaders() = mUploadStreamHasHeaders;
  1.1264 +  openArgs.priority() = mPriority;
  1.1265 +  openArgs.redirectionLimit() = mRedirectionLimit;
  1.1266 +  openArgs.allowPipelining() = mAllowPipelining;
  1.1267 +  openArgs.forceAllowThirdPartyCookie() = mForceAllowThirdPartyCookie;
  1.1268 +  openArgs.resumeAt() = mSendResumeAt;
  1.1269 +  openArgs.startPos() = mStartPos;
  1.1270 +  openArgs.entityID() = mEntityID;
  1.1271 +  openArgs.chooseApplicationCache() = mChooseApplicationCache;
  1.1272 +  openArgs.appCacheClientID() = appCacheClientId;
  1.1273 +  openArgs.allowSpdy() = mAllowSpdy;
  1.1274 +
  1.1275 +  // The socket transport in the chrome process now holds a logical ref to us
  1.1276 +  // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
  1.1277 +  AddIPDLReference();
  1.1278 +
  1.1279 +  gNeckoChild->SendPHttpChannelConstructor(this, tabChild,
  1.1280 +                                           IPC::SerializedLoadContext(this),
  1.1281 +                                           openArgs);
  1.1282 +
  1.1283 +  if (fdSet) {
  1.1284 +    FileDescriptorSetChild* fdSetActor =
  1.1285 +      static_cast<FileDescriptorSetChild*>(fdSet);
  1.1286 +
  1.1287 +    fdSetActor->ForgetFileDescriptors(fds);
  1.1288 +  }
  1.1289 +
  1.1290 +  return NS_OK;
  1.1291 +}
  1.1292 +
  1.1293 +//-----------------------------------------------------------------------------
  1.1294 +// HttpChannelChild::nsIHttpChannel
  1.1295 +//-----------------------------------------------------------------------------
  1.1296 +
  1.1297 +NS_IMETHODIMP
  1.1298 +HttpChannelChild::SetRequestHeader(const nsACString& aHeader,
  1.1299 +                                   const nsACString& aValue,
  1.1300 +                                   bool aMerge)
  1.1301 +{
  1.1302 +  nsresult rv = HttpBaseChannel::SetRequestHeader(aHeader, aValue, aMerge);
  1.1303 +  if (NS_FAILED(rv))
  1.1304 +    return rv;
  1.1305 +
  1.1306 +  RequestHeaderTuple* tuple = mClientSetRequestHeaders.AppendElement();
  1.1307 +  if (!tuple)
  1.1308 +    return NS_ERROR_OUT_OF_MEMORY;
  1.1309 +
  1.1310 +  tuple->mHeader = aHeader;
  1.1311 +  tuple->mValue = aValue;
  1.1312 +  tuple->mMerge = aMerge;
  1.1313 +  return NS_OK;
  1.1314 +}
  1.1315 +
  1.1316 +NS_IMETHODIMP
  1.1317 +HttpChannelChild::RedirectTo(nsIURI *newURI)
  1.1318 +{
  1.1319 +  // disabled until/unless addons run in child or something else needs this
  1.1320 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.1321 +}
  1.1322 +
  1.1323 +//-----------------------------------------------------------------------------
  1.1324 +// HttpChannelChild::nsIHttpChannelInternal
  1.1325 +//-----------------------------------------------------------------------------
  1.1326 +
  1.1327 +NS_IMETHODIMP
  1.1328 +HttpChannelChild::SetupFallbackChannel(const char *aFallbackKey)
  1.1329 +{
  1.1330 +  DROP_DEAD();
  1.1331 +}
  1.1332 +
  1.1333 +// The next four _should_ be implemented, but we need to figure out how
  1.1334 +// to transfer the data from the chrome process first.
  1.1335 +
  1.1336 +NS_IMETHODIMP
  1.1337 +HttpChannelChild::GetRemoteAddress(nsACString & _result)
  1.1338 +{
  1.1339 +  return NS_ERROR_NOT_AVAILABLE;
  1.1340 +}
  1.1341 +
  1.1342 +NS_IMETHODIMP
  1.1343 +HttpChannelChild::GetRemotePort(int32_t * _result)
  1.1344 +{
  1.1345 +  NS_ENSURE_ARG_POINTER(_result);
  1.1346 +  return NS_ERROR_NOT_AVAILABLE;
  1.1347 +}
  1.1348 +
  1.1349 +NS_IMETHODIMP
  1.1350 +HttpChannelChild::GetLocalAddress(nsACString & _result)
  1.1351 +{
  1.1352 +  return NS_ERROR_NOT_AVAILABLE;
  1.1353 +}
  1.1354 +
  1.1355 +NS_IMETHODIMP
  1.1356 +HttpChannelChild::GetLocalPort(int32_t * _result)
  1.1357 +{
  1.1358 +  NS_ENSURE_ARG_POINTER(_result);
  1.1359 +  return NS_ERROR_NOT_AVAILABLE;
  1.1360 +}
  1.1361 +
  1.1362 +
  1.1363 +//-----------------------------------------------------------------------------
  1.1364 +// HttpChannelChild::nsICacheInfoChannel
  1.1365 +//-----------------------------------------------------------------------------
  1.1366 +
  1.1367 +NS_IMETHODIMP
  1.1368 +HttpChannelChild::GetCacheTokenExpirationTime(uint32_t *_retval)
  1.1369 +{
  1.1370 +  NS_ENSURE_ARG_POINTER(_retval);
  1.1371 +  if (!mCacheEntryAvailable)
  1.1372 +    return NS_ERROR_NOT_AVAILABLE;
  1.1373 +
  1.1374 +  *_retval = mCacheExpirationTime;
  1.1375 +  return NS_OK;
  1.1376 +}
  1.1377 +
  1.1378 +NS_IMETHODIMP
  1.1379 +HttpChannelChild::GetCacheTokenCachedCharset(nsACString &_retval)
  1.1380 +{
  1.1381 +  if (!mCacheEntryAvailable)
  1.1382 +    return NS_ERROR_NOT_AVAILABLE;
  1.1383 +
  1.1384 +  _retval = mCachedCharset;
  1.1385 +  return NS_OK;
  1.1386 +}
  1.1387 +NS_IMETHODIMP
  1.1388 +HttpChannelChild::SetCacheTokenCachedCharset(const nsACString &aCharset)
  1.1389 +{
  1.1390 +  if (!mCacheEntryAvailable || !RemoteChannelExists())
  1.1391 +    return NS_ERROR_NOT_AVAILABLE;
  1.1392 +
  1.1393 +  mCachedCharset = aCharset;
  1.1394 +  if (!SendSetCacheTokenCachedCharset(PromiseFlatCString(aCharset))) {
  1.1395 +    return NS_ERROR_FAILURE;
  1.1396 +  }
  1.1397 +  return NS_OK;
  1.1398 +}
  1.1399 +
  1.1400 +NS_IMETHODIMP
  1.1401 +HttpChannelChild::IsFromCache(bool *value)
  1.1402 +{
  1.1403 +  if (!mIsPending)
  1.1404 +    return NS_ERROR_NOT_AVAILABLE;
  1.1405 +
  1.1406 +  *value = mIsFromCache;
  1.1407 +  return NS_OK;
  1.1408 +}
  1.1409 +
  1.1410 +//-----------------------------------------------------------------------------
  1.1411 +// HttpChannelChild::nsIResumableChannel
  1.1412 +//-----------------------------------------------------------------------------
  1.1413 +
  1.1414 +NS_IMETHODIMP
  1.1415 +HttpChannelChild::ResumeAt(uint64_t startPos, const nsACString& entityID)
  1.1416 +{
  1.1417 +  ENSURE_CALLED_BEFORE_CONNECT();
  1.1418 +  mStartPos = startPos;
  1.1419 +  mEntityID = entityID;
  1.1420 +  mSendResumeAt = true;
  1.1421 +  return NS_OK;
  1.1422 +}
  1.1423 +
  1.1424 +// GetEntityID is shared in HttpBaseChannel
  1.1425 +
  1.1426 +//-----------------------------------------------------------------------------
  1.1427 +// HttpChannelChild::nsISupportsPriority
  1.1428 +//-----------------------------------------------------------------------------
  1.1429 +
  1.1430 +NS_IMETHODIMP
  1.1431 +HttpChannelChild::SetPriority(int32_t aPriority)
  1.1432 +{
  1.1433 +  int16_t newValue = clamped<int32_t>(aPriority, INT16_MIN, INT16_MAX);
  1.1434 +  if (mPriority == newValue)
  1.1435 +    return NS_OK;
  1.1436 +  mPriority = newValue;
  1.1437 +  if (RemoteChannelExists())
  1.1438 +    SendSetPriority(mPriority);
  1.1439 +  return NS_OK;
  1.1440 +}
  1.1441 +
  1.1442 +//-----------------------------------------------------------------------------
  1.1443 +// HttpChannelChild::nsIProxiedChannel
  1.1444 +//-----------------------------------------------------------------------------
  1.1445 +
  1.1446 +NS_IMETHODIMP
  1.1447 +HttpChannelChild::GetProxyInfo(nsIProxyInfo **aProxyInfo)
  1.1448 +{
  1.1449 +  DROP_DEAD();
  1.1450 +}
  1.1451 +
  1.1452 +//-----------------------------------------------------------------------------
  1.1453 +// HttpChannelChild::nsIApplicationCacheContainer
  1.1454 +//-----------------------------------------------------------------------------
  1.1455 +
  1.1456 +NS_IMETHODIMP
  1.1457 +HttpChannelChild::GetApplicationCache(nsIApplicationCache **aApplicationCache)
  1.1458 +{
  1.1459 +  NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
  1.1460 +  return NS_OK;
  1.1461 +}
  1.1462 +NS_IMETHODIMP
  1.1463 +HttpChannelChild::SetApplicationCache(nsIApplicationCache *aApplicationCache)
  1.1464 +{
  1.1465 +  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
  1.1466 +
  1.1467 +  mApplicationCache = aApplicationCache;
  1.1468 +  return NS_OK;
  1.1469 +}
  1.1470 +
  1.1471 +//-----------------------------------------------------------------------------
  1.1472 +// HttpChannelChild::nsIApplicationCacheChannel
  1.1473 +//-----------------------------------------------------------------------------
  1.1474 +
  1.1475 +NS_IMETHODIMP
  1.1476 +HttpChannelChild::GetApplicationCacheForWrite(nsIApplicationCache **aApplicationCache)
  1.1477 +{
  1.1478 +  *aApplicationCache = nullptr;
  1.1479 +  return NS_OK;
  1.1480 +}
  1.1481 +NS_IMETHODIMP
  1.1482 +HttpChannelChild::SetApplicationCacheForWrite(nsIApplicationCache *aApplicationCache)
  1.1483 +{
  1.1484 +  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
  1.1485 +
  1.1486 +  // Child channels are not intended to be used for cache writes
  1.1487 +  return NS_ERROR_NOT_IMPLEMENTED;
  1.1488 +}
  1.1489 +
  1.1490 +NS_IMETHODIMP
  1.1491 +HttpChannelChild::GetLoadedFromApplicationCache(bool *aLoadedFromApplicationCache)
  1.1492 +{
  1.1493 +  *aLoadedFromApplicationCache = mLoadedFromApplicationCache;
  1.1494 +  return NS_OK;
  1.1495 +}
  1.1496 +
  1.1497 +NS_IMETHODIMP
  1.1498 +HttpChannelChild::GetInheritApplicationCache(bool *aInherit)
  1.1499 +{
  1.1500 +  *aInherit = mInheritApplicationCache;
  1.1501 +  return NS_OK;
  1.1502 +}
  1.1503 +NS_IMETHODIMP
  1.1504 +HttpChannelChild::SetInheritApplicationCache(bool aInherit)
  1.1505 +{
  1.1506 +  mInheritApplicationCache = aInherit;
  1.1507 +  return NS_OK;
  1.1508 +}
  1.1509 +
  1.1510 +NS_IMETHODIMP
  1.1511 +HttpChannelChild::GetChooseApplicationCache(bool *aChoose)
  1.1512 +{
  1.1513 +  *aChoose = mChooseApplicationCache;
  1.1514 +  return NS_OK;
  1.1515 +}
  1.1516 +
  1.1517 +NS_IMETHODIMP
  1.1518 +HttpChannelChild::SetChooseApplicationCache(bool aChoose)
  1.1519 +{
  1.1520 +  mChooseApplicationCache = aChoose;
  1.1521 +  return NS_OK;
  1.1522 +}
  1.1523 +
  1.1524 +NS_IMETHODIMP
  1.1525 +HttpChannelChild::MarkOfflineCacheEntryAsForeign()
  1.1526 +{
  1.1527 +  SendMarkOfflineCacheEntryAsForeign();
  1.1528 +  return NS_OK;
  1.1529 +}
  1.1530 +
  1.1531 +//-----------------------------------------------------------------------------
  1.1532 +// HttpChannelChild::nsIAssociatedContentSecurity
  1.1533 +//-----------------------------------------------------------------------------
  1.1534 +
  1.1535 +bool
  1.1536 +HttpChannelChild::GetAssociatedContentSecurity(
  1.1537 +                    nsIAssociatedContentSecurity** _result)
  1.1538 +{
  1.1539 +  if (!mSecurityInfo)
  1.1540 +    return false;
  1.1541 +
  1.1542 +  nsCOMPtr<nsIAssociatedContentSecurity> assoc =
  1.1543 +      do_QueryInterface(mSecurityInfo);
  1.1544 +  if (!assoc)
  1.1545 +    return false;
  1.1546 +
  1.1547 +  if (_result)
  1.1548 +    assoc.forget(_result);
  1.1549 +  return true;
  1.1550 +}
  1.1551 +
  1.1552 +/* attribute unsigned long countSubRequestsBrokenSecurity; */
  1.1553 +NS_IMETHODIMP
  1.1554 +HttpChannelChild::GetCountSubRequestsBrokenSecurity(
  1.1555 +                    int32_t *aSubRequestsBrokenSecurity)
  1.1556 +{
  1.1557 +  nsCOMPtr<nsIAssociatedContentSecurity> assoc;
  1.1558 +  if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
  1.1559 +    return NS_OK;
  1.1560 +
  1.1561 +  return assoc->GetCountSubRequestsBrokenSecurity(aSubRequestsBrokenSecurity);
  1.1562 +}
  1.1563 +NS_IMETHODIMP
  1.1564 +HttpChannelChild::SetCountSubRequestsBrokenSecurity(
  1.1565 +                    int32_t aSubRequestsBrokenSecurity)
  1.1566 +{
  1.1567 +  nsCOMPtr<nsIAssociatedContentSecurity> assoc;
  1.1568 +  if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
  1.1569 +    return NS_OK;
  1.1570 +
  1.1571 +  return assoc->SetCountSubRequestsBrokenSecurity(aSubRequestsBrokenSecurity);
  1.1572 +}
  1.1573 +
  1.1574 +/* attribute unsigned long countSubRequestsNoSecurity; */
  1.1575 +NS_IMETHODIMP
  1.1576 +HttpChannelChild::GetCountSubRequestsNoSecurity(int32_t *aSubRequestsNoSecurity)
  1.1577 +{
  1.1578 +  nsCOMPtr<nsIAssociatedContentSecurity> assoc;
  1.1579 +  if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
  1.1580 +    return NS_OK;
  1.1581 +
  1.1582 +  return assoc->GetCountSubRequestsNoSecurity(aSubRequestsNoSecurity);
  1.1583 +}
  1.1584 +NS_IMETHODIMP
  1.1585 +HttpChannelChild::SetCountSubRequestsNoSecurity(int32_t aSubRequestsNoSecurity)
  1.1586 +{
  1.1587 +  nsCOMPtr<nsIAssociatedContentSecurity> assoc;
  1.1588 +  if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
  1.1589 +    return NS_OK;
  1.1590 +
  1.1591 +  return assoc->SetCountSubRequestsNoSecurity(aSubRequestsNoSecurity);
  1.1592 +}
  1.1593 +
  1.1594 +NS_IMETHODIMP
  1.1595 +HttpChannelChild::Flush()
  1.1596 +{
  1.1597 +  nsCOMPtr<nsIAssociatedContentSecurity> assoc;
  1.1598 +  if (!GetAssociatedContentSecurity(getter_AddRefs(assoc)))
  1.1599 +    return NS_OK;
  1.1600 +
  1.1601 +  nsresult rv;
  1.1602 +  int32_t broken, no;
  1.1603 +
  1.1604 +  rv = assoc->GetCountSubRequestsBrokenSecurity(&broken);
  1.1605 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1606 +  rv = assoc->GetCountSubRequestsNoSecurity(&no);
  1.1607 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1608 +
  1.1609 +  if (mIPCOpen)
  1.1610 +    SendUpdateAssociatedContentSecurity(broken, no);
  1.1611 +
  1.1612 +  return NS_OK;
  1.1613 +}
  1.1614 +
  1.1615 +//-----------------------------------------------------------------------------
  1.1616 +// HttpChannelChild::nsIHttpChannelChild
  1.1617 +//-----------------------------------------------------------------------------
  1.1618 +
  1.1619 +NS_IMETHODIMP HttpChannelChild::AddCookiesToRequest()
  1.1620 +{
  1.1621 +  HttpBaseChannel::AddCookiesToRequest();
  1.1622 +  return NS_OK;
  1.1623 +}
  1.1624 +
  1.1625 +NS_IMETHODIMP HttpChannelChild::GetClientSetRequestHeaders(RequestHeaderTuples **aRequestHeaders)
  1.1626 +{
  1.1627 +  *aRequestHeaders = &mClientSetRequestHeaders;
  1.1628 +  return NS_OK;
  1.1629 +}
  1.1630 +
  1.1631 +//-----------------------------------------------------------------------------
  1.1632 +// HttpChannelChild::nsIDivertableChannel
  1.1633 +//-----------------------------------------------------------------------------
  1.1634 +NS_IMETHODIMP
  1.1635 +HttpChannelChild::DivertToParent(ChannelDiverterChild **aChild)
  1.1636 +{
  1.1637 +  MOZ_RELEASE_ASSERT(aChild);
  1.1638 +  MOZ_RELEASE_ASSERT(gNeckoChild);
  1.1639 +  MOZ_RELEASE_ASSERT(!mDivertingToParent);
  1.1640 +
  1.1641 +  // We must fail DivertToParent() if there's no parent end of the channel (and
  1.1642 +  // won't be!) due to early failure.
  1.1643 +  if (NS_FAILED(mStatus) && !RemoteChannelExists()) {
  1.1644 +    return mStatus;
  1.1645 +  }
  1.1646 +
  1.1647 +  nsresult rv = Suspend();
  1.1648 +  if (NS_WARN_IF(NS_FAILED(rv))) {
  1.1649 +    return rv;
  1.1650 +  }
  1.1651 +
  1.1652 +  // Once this is set, it should not be unset before the child is taken down.
  1.1653 +  mDivertingToParent = true;
  1.1654 +
  1.1655 +  PChannelDiverterChild* diverter =
  1.1656 +    gNeckoChild->SendPChannelDiverterConstructor(this);
  1.1657 +  MOZ_RELEASE_ASSERT(diverter);
  1.1658 +
  1.1659 +  *aChild = static_cast<ChannelDiverterChild*>(diverter);
  1.1660 +
  1.1661 +  return NS_OK;
  1.1662 +}
  1.1663 +
  1.1664 +}} // mozilla::net

mercurial