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