netwerk/protocol/http/HttpChannelParent.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial