1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,604 @@ 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 +#include "mozilla/net/FTPChannelParent.h" 1.12 +#include "nsFTPChannel.h" 1.13 +#include "nsNetUtil.h" 1.14 +#include "nsFtpProtocolHandler.h" 1.15 +#include "mozilla/ipc/InputStreamUtils.h" 1.16 +#include "mozilla/ipc/URIUtils.h" 1.17 +#include "mozilla/unused.h" 1.18 +#include "SerializedLoadContext.h" 1.19 + 1.20 +using namespace mozilla::ipc; 1.21 + 1.22 +#undef LOG 1.23 +#define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args) 1.24 + 1.25 +namespace mozilla { 1.26 +namespace net { 1.27 + 1.28 +FTPChannelParent::FTPChannelParent(nsILoadContext* aLoadContext, PBOverrideStatus aOverrideStatus) 1.29 + : mIPCClosed(false) 1.30 + , mLoadContext(aLoadContext) 1.31 + , mPBOverride(aOverrideStatus) 1.32 + , mStatus(NS_OK) 1.33 + , mDivertingFromChild(false) 1.34 + , mDivertedOnStartRequest(false) 1.35 + , mSuspendedForDiversion(false) 1.36 +{ 1.37 + nsIProtocolHandler* handler; 1.38 + CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &handler); 1.39 + NS_ASSERTION(handler, "no ftp handler"); 1.40 +} 1.41 + 1.42 +FTPChannelParent::~FTPChannelParent() 1.43 +{ 1.44 + gFtpHandler->Release(); 1.45 +} 1.46 + 1.47 +void 1.48 +FTPChannelParent::ActorDestroy(ActorDestroyReason why) 1.49 +{ 1.50 + // We may still have refcount>0 if the channel hasn't called OnStopRequest 1.51 + // yet, but we must not send any more msgs to child. 1.52 + mIPCClosed = true; 1.53 +} 1.54 + 1.55 +//----------------------------------------------------------------------------- 1.56 +// FTPChannelParent::nsISupports 1.57 +//----------------------------------------------------------------------------- 1.58 + 1.59 +NS_IMPL_ISUPPORTS(FTPChannelParent, 1.60 + nsIStreamListener, 1.61 + nsIParentChannel, 1.62 + nsIInterfaceRequestor, 1.63 + nsIRequestObserver) 1.64 + 1.65 +//----------------------------------------------------------------------------- 1.66 +// FTPChannelParent::PFTPChannelParent 1.67 +//----------------------------------------------------------------------------- 1.68 + 1.69 +//----------------------------------------------------------------------------- 1.70 +// FTPChannelParent methods 1.71 +//----------------------------------------------------------------------------- 1.72 + 1.73 +bool 1.74 +FTPChannelParent::Init(const FTPChannelCreationArgs& aArgs) 1.75 +{ 1.76 + switch (aArgs.type()) { 1.77 + case FTPChannelCreationArgs::TFTPChannelOpenArgs: 1.78 + { 1.79 + const FTPChannelOpenArgs& a = aArgs.get_FTPChannelOpenArgs(); 1.80 + return DoAsyncOpen(a.uri(), a.startPos(), a.entityID(), a.uploadStream()); 1.81 + } 1.82 + case FTPChannelCreationArgs::TFTPChannelConnectArgs: 1.83 + { 1.84 + const FTPChannelConnectArgs& cArgs = aArgs.get_FTPChannelConnectArgs(); 1.85 + return ConnectChannel(cArgs.channelId()); 1.86 + } 1.87 + default: 1.88 + NS_NOTREACHED("unknown open type"); 1.89 + return false; 1.90 + } 1.91 +} 1.92 + 1.93 +bool 1.94 +FTPChannelParent::DoAsyncOpen(const URIParams& aURI, 1.95 + const uint64_t& aStartPos, 1.96 + const nsCString& aEntityID, 1.97 + const OptionalInputStreamParams& aUploadStream) 1.98 +{ 1.99 + nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); 1.100 + if (!uri) 1.101 + return false; 1.102 + 1.103 +#ifdef DEBUG 1.104 + nsCString uriSpec; 1.105 + uri->GetSpec(uriSpec); 1.106 + LOG(("FTPChannelParent DoAsyncOpen [this=%p uri=%s]\n", 1.107 + this, uriSpec.get())); 1.108 +#endif 1.109 + 1.110 + nsresult rv; 1.111 + nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv)); 1.112 + if (NS_FAILED(rv)) 1.113 + return SendFailedAsyncOpen(rv); 1.114 + 1.115 + nsCOMPtr<nsIChannel> chan; 1.116 + rv = NS_NewChannel(getter_AddRefs(chan), uri, ios); 1.117 + if (NS_FAILED(rv)) 1.118 + return SendFailedAsyncOpen(rv); 1.119 + 1.120 + mChannel = static_cast<nsFtpChannel*>(chan.get()); 1.121 + 1.122 + if (mPBOverride != kPBOverride_Unset) { 1.123 + mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false); 1.124 + } 1.125 + 1.126 + rv = mChannel->SetNotificationCallbacks(this); 1.127 + if (NS_FAILED(rv)) 1.128 + return SendFailedAsyncOpen(rv); 1.129 + 1.130 + nsTArray<mozilla::ipc::FileDescriptor> fds; 1.131 + nsCOMPtr<nsIInputStream> upload = DeserializeInputStream(aUploadStream, fds); 1.132 + if (upload) { 1.133 + // contentType and contentLength are ignored 1.134 + rv = mChannel->SetUploadStream(upload, EmptyCString(), 0); 1.135 + if (NS_FAILED(rv)) 1.136 + return SendFailedAsyncOpen(rv); 1.137 + } 1.138 + 1.139 + rv = mChannel->ResumeAt(aStartPos, aEntityID); 1.140 + if (NS_FAILED(rv)) 1.141 + return SendFailedAsyncOpen(rv); 1.142 + 1.143 + rv = mChannel->AsyncOpen(this, nullptr); 1.144 + if (NS_FAILED(rv)) 1.145 + return SendFailedAsyncOpen(rv); 1.146 + 1.147 + return true; 1.148 +} 1.149 + 1.150 +bool 1.151 +FTPChannelParent::ConnectChannel(const uint32_t& channelId) 1.152 +{ 1.153 + nsresult rv; 1.154 + 1.155 + LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId)); 1.156 + 1.157 + nsCOMPtr<nsIChannel> channel; 1.158 + rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel)); 1.159 + if (NS_SUCCEEDED(rv)) 1.160 + mChannel = static_cast<nsFtpChannel*>(channel.get()); 1.161 + 1.162 + LOG((" found channel %p, rv=%08x", mChannel.get(), rv)); 1.163 + 1.164 + return true; 1.165 +} 1.166 + 1.167 +bool 1.168 +FTPChannelParent::RecvCancel(const nsresult& status) 1.169 +{ 1.170 + if (mChannel) 1.171 + mChannel->Cancel(status); 1.172 + return true; 1.173 +} 1.174 + 1.175 +bool 1.176 +FTPChannelParent::RecvSuspend() 1.177 +{ 1.178 + if (mChannel) 1.179 + mChannel->Suspend(); 1.180 + return true; 1.181 +} 1.182 + 1.183 +bool 1.184 +FTPChannelParent::RecvResume() 1.185 +{ 1.186 + if (mChannel) 1.187 + mChannel->Resume(); 1.188 + return true; 1.189 +} 1.190 + 1.191 +bool 1.192 +FTPChannelParent::RecvDivertOnDataAvailable(const nsCString& data, 1.193 + const uint64_t& offset, 1.194 + const uint32_t& count) 1.195 +{ 1.196 + if (NS_WARN_IF(!mDivertingFromChild)) { 1.197 + MOZ_ASSERT(mDivertingFromChild, 1.198 + "Cannot RecvDivertOnDataAvailable if diverting is not set!"); 1.199 + FailDiversion(NS_ERROR_UNEXPECTED); 1.200 + return false; 1.201 + } 1.202 + 1.203 + // Drop OnDataAvailables if the parent was canceled already. 1.204 + if (NS_FAILED(mStatus)) { 1.205 + return true; 1.206 + } 1.207 + 1.208 + nsCOMPtr<nsIInputStream> stringStream; 1.209 + nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(), 1.210 + count, NS_ASSIGNMENT_DEPEND); 1.211 + if (NS_FAILED(rv)) { 1.212 + if (mChannel) { 1.213 + mChannel->Cancel(rv); 1.214 + } 1.215 + mStatus = rv; 1.216 + return true; 1.217 + } 1.218 + 1.219 + rv = OnDataAvailable(mChannel, nullptr, stringStream, offset, count); 1.220 + 1.221 + stringStream->Close(); 1.222 + if (NS_FAILED(rv)) { 1.223 + if (mChannel) { 1.224 + mChannel->Cancel(rv); 1.225 + } 1.226 + mStatus = rv; 1.227 + } 1.228 + return true; 1.229 +} 1.230 + 1.231 +bool 1.232 +FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode) 1.233 +{ 1.234 + if (NS_WARN_IF(!mDivertingFromChild)) { 1.235 + MOZ_ASSERT(mDivertingFromChild, 1.236 + "Cannot RecvDivertOnStopRequest if diverting is not set!"); 1.237 + FailDiversion(NS_ERROR_UNEXPECTED); 1.238 + return false; 1.239 + } 1.240 + 1.241 + // Honor the channel's status even if the underlying transaction completed. 1.242 + nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode; 1.243 + 1.244 + // Reset fake pending status in case OnStopRequest has already been called. 1.245 + if (mChannel) { 1.246 + mChannel->ForcePending(false); 1.247 + } 1.248 + 1.249 + OnStopRequest(mChannel, nullptr, status); 1.250 + return true; 1.251 +} 1.252 + 1.253 +bool 1.254 +FTPChannelParent::RecvDivertComplete() 1.255 +{ 1.256 + if (NS_WARN_IF(!mDivertingFromChild)) { 1.257 + MOZ_ASSERT(mDivertingFromChild, 1.258 + "Cannot RecvDivertComplete if diverting is not set!"); 1.259 + FailDiversion(NS_ERROR_UNEXPECTED); 1.260 + return false; 1.261 + } 1.262 + 1.263 + nsresult rv = ResumeForDiversion(); 1.264 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.265 + FailDiversion(NS_ERROR_UNEXPECTED); 1.266 + return false; 1.267 + } 1.268 + 1.269 + return true; 1.270 +} 1.271 + 1.272 +//----------------------------------------------------------------------------- 1.273 +// FTPChannelParent::nsIRequestObserver 1.274 +//----------------------------------------------------------------------------- 1.275 + 1.276 +NS_IMETHODIMP 1.277 +FTPChannelParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) 1.278 +{ 1.279 + LOG(("FTPChannelParent::OnStartRequest [this=%p]\n", this)); 1.280 + 1.281 + if (mDivertingFromChild) { 1.282 + MOZ_RELEASE_ASSERT(mDivertToListener, 1.283 + "Cannot divert if listener is unset!"); 1.284 + return mDivertToListener->OnStartRequest(aRequest, aContext); 1.285 + } 1.286 + 1.287 + nsCOMPtr<nsIChannel> chan = do_QueryInterface(aRequest); 1.288 + MOZ_ASSERT(chan); 1.289 + NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED); 1.290 + 1.291 + int64_t contentLength; 1.292 + chan->GetContentLength(&contentLength); 1.293 + nsCString contentType; 1.294 + chan->GetContentType(contentType); 1.295 + 1.296 + nsCString entityID; 1.297 + nsCOMPtr<nsIResumableChannel> resChan = do_QueryInterface(aRequest); 1.298 + MOZ_ASSERT(resChan); // both FTP and HTTP should implement nsIResumableChannel 1.299 + if (resChan) { 1.300 + resChan->GetEntityID(entityID); 1.301 + } 1.302 + 1.303 + nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(aRequest); 1.304 + PRTime lastModified = 0; 1.305 + if (ftpChan) { 1.306 + ftpChan->GetLastModifiedTime(&lastModified); 1.307 + } else { 1.308 + // Temporary hack: if we were redirected to use an HTTP channel (ie FTP is 1.309 + // using an HTTP proxy), cancel, as we don't support those redirects yet. 1.310 + aRequest->Cancel(NS_ERROR_NOT_IMPLEMENTED); 1.311 + } 1.312 + 1.313 + URIParams uriparam; 1.314 + nsCOMPtr<nsIURI> uri; 1.315 + chan->GetURI(getter_AddRefs(uri)); 1.316 + SerializeURI(uri, uriparam); 1.317 + 1.318 + if (mIPCClosed || !SendOnStartRequest(mStatus, contentLength, contentType, 1.319 + lastModified, entityID, uriparam)) { 1.320 + return NS_ERROR_UNEXPECTED; 1.321 + } 1.322 + 1.323 + return NS_OK; 1.324 +} 1.325 + 1.326 +NS_IMETHODIMP 1.327 +FTPChannelParent::OnStopRequest(nsIRequest* aRequest, 1.328 + nsISupports* aContext, 1.329 + nsresult aStatusCode) 1.330 +{ 1.331 + LOG(("FTPChannelParent::OnStopRequest: [this=%p status=%ul]\n", 1.332 + this, aStatusCode)); 1.333 + 1.334 + if (mDivertingFromChild) { 1.335 + MOZ_RELEASE_ASSERT(mDivertToListener, 1.336 + "Cannot divert if listener is unset!"); 1.337 + return mDivertToListener->OnStopRequest(aRequest, aContext, aStatusCode); 1.338 + } 1.339 + 1.340 + if (mIPCClosed || !SendOnStopRequest(aStatusCode)) { 1.341 + return NS_ERROR_UNEXPECTED; 1.342 + } 1.343 + 1.344 + return NS_OK; 1.345 +} 1.346 + 1.347 +//----------------------------------------------------------------------------- 1.348 +// FTPChannelParent::nsIStreamListener 1.349 +//----------------------------------------------------------------------------- 1.350 + 1.351 +NS_IMETHODIMP 1.352 +FTPChannelParent::OnDataAvailable(nsIRequest* aRequest, 1.353 + nsISupports* aContext, 1.354 + nsIInputStream* aInputStream, 1.355 + uint64_t aOffset, 1.356 + uint32_t aCount) 1.357 +{ 1.358 + LOG(("FTPChannelParent::OnDataAvailable [this=%p]\n", this)); 1.359 + 1.360 + if (mDivertingFromChild) { 1.361 + MOZ_RELEASE_ASSERT(mDivertToListener, 1.362 + "Cannot divert if listener is unset!"); 1.363 + return mDivertToListener->OnDataAvailable(aRequest, aContext, aInputStream, 1.364 + aOffset, aCount); 1.365 + } 1.366 + 1.367 + nsCString data; 1.368 + nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount); 1.369 + if (NS_FAILED(rv)) 1.370 + return rv; 1.371 + 1.372 + if (mIPCClosed || !SendOnDataAvailable(mStatus, data, aOffset, aCount)) 1.373 + return NS_ERROR_UNEXPECTED; 1.374 + 1.375 + return NS_OK; 1.376 +} 1.377 + 1.378 +//----------------------------------------------------------------------------- 1.379 +// FTPChannelParent::nsIParentChannel 1.380 +//----------------------------------------------------------------------------- 1.381 + 1.382 +NS_IMETHODIMP 1.383 +FTPChannelParent::SetParentListener(HttpChannelParentListener* aListener) 1.384 +{ 1.385 + // Do not need ptr to HttpChannelParentListener. 1.386 + return NS_OK; 1.387 +} 1.388 + 1.389 +NS_IMETHODIMP 1.390 +FTPChannelParent::Delete() 1.391 +{ 1.392 + if (mIPCClosed || !SendDeleteSelf()) 1.393 + return NS_ERROR_UNEXPECTED; 1.394 + 1.395 + return NS_OK; 1.396 +} 1.397 + 1.398 +//----------------------------------------------------------------------------- 1.399 +// FTPChannelParent::nsIInterfaceRequestor 1.400 +//----------------------------------------------------------------------------- 1.401 + 1.402 +NS_IMETHODIMP 1.403 +FTPChannelParent::GetInterface(const nsIID& uuid, void** result) 1.404 +{ 1.405 + // Only support nsILoadContext if child channel's callbacks did too 1.406 + if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) { 1.407 + NS_ADDREF(mLoadContext); 1.408 + *result = static_cast<nsILoadContext*>(mLoadContext); 1.409 + return NS_OK; 1.410 + } 1.411 + 1.412 + return QueryInterface(uuid, result); 1.413 +} 1.414 + 1.415 +//----------------------------------------------------------------------------- 1.416 +// FTPChannelParent::ADivertableParentChannel 1.417 +//----------------------------------------------------------------------------- 1.418 +nsresult 1.419 +FTPChannelParent::SuspendForDiversion() 1.420 +{ 1.421 + MOZ_ASSERT(mChannel); 1.422 + if (NS_WARN_IF(mDivertingFromChild)) { 1.423 + MOZ_ASSERT(!mDivertingFromChild, "Already suspended for diversion!"); 1.424 + return NS_ERROR_UNEXPECTED; 1.425 + } 1.426 + 1.427 + // Try suspending the channel. Allow it to fail, since OnStopRequest may have 1.428 + // been called and thus the channel may not be pending. 1.429 + nsresult rv = mChannel->Suspend(); 1.430 + MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE); 1.431 + mSuspendedForDiversion = NS_SUCCEEDED(rv); 1.432 + 1.433 + // Once this is set, no more OnStart/OnData/OnStop callbacks should be sent 1.434 + // to the child. 1.435 + mDivertingFromChild = true; 1.436 + 1.437 + return NS_OK; 1.438 +} 1.439 + 1.440 +/* private, supporting function for ADivertableParentChannel */ 1.441 +nsresult 1.442 +FTPChannelParent::ResumeForDiversion() 1.443 +{ 1.444 + MOZ_ASSERT(mChannel); 1.445 + MOZ_ASSERT(mDivertToListener); 1.446 + if (NS_WARN_IF(!mDivertingFromChild)) { 1.447 + MOZ_ASSERT(mDivertingFromChild, 1.448 + "Cannot ResumeForDiversion if not diverting!"); 1.449 + return NS_ERROR_UNEXPECTED; 1.450 + } 1.451 + 1.452 + if (mSuspendedForDiversion) { 1.453 + nsresult rv = mChannel->Resume(); 1.454 + if (NS_WARN_IF(NS_FAILED(rv))) { 1.455 + FailDiversion(NS_ERROR_UNEXPECTED, true); 1.456 + return rv; 1.457 + } 1.458 + mSuspendedForDiversion = false; 1.459 + } 1.460 + 1.461 + // Delete() will tear down IPDL, but ref from underlying nsFTPChannel will 1.462 + // keep us alive if there's more data to be delivered to listener. 1.463 + if (NS_WARN_IF(NS_FAILED(Delete()))) { 1.464 + FailDiversion(NS_ERROR_UNEXPECTED); 1.465 + return NS_ERROR_UNEXPECTED; 1.466 + } 1.467 + return NS_OK; 1.468 +} 1.469 + 1.470 +void 1.471 +FTPChannelParent::DivertTo(nsIStreamListener *aListener) 1.472 +{ 1.473 + MOZ_ASSERT(aListener); 1.474 + if (NS_WARN_IF(!mDivertingFromChild)) { 1.475 + MOZ_ASSERT(mDivertingFromChild, 1.476 + "Cannot DivertTo new listener if diverting is not set!"); 1.477 + return; 1.478 + } 1.479 + 1.480 + if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) { 1.481 + FailDiversion(NS_ERROR_UNEXPECTED); 1.482 + return; 1.483 + } 1.484 + 1.485 + mDivertToListener = aListener; 1.486 + 1.487 + // Call OnStartRequest and SendDivertMessages asynchronously to avoid 1.488 + // reentering client context. 1.489 + NS_DispatchToCurrentThread( 1.490 + NS_NewRunnableMethod(this, &FTPChannelParent::StartDiversion)); 1.491 + return; 1.492 +} 1.493 + 1.494 +void 1.495 +FTPChannelParent::StartDiversion() 1.496 +{ 1.497 + if (NS_WARN_IF(!mDivertingFromChild)) { 1.498 + MOZ_ASSERT(mDivertingFromChild, 1.499 + "Cannot StartDiversion if diverting is not set!"); 1.500 + return; 1.501 + } 1.502 + 1.503 + // Fake pending status in case OnStopRequest has already been called. 1.504 + if (mChannel) { 1.505 + mChannel->ForcePending(true); 1.506 + } 1.507 + 1.508 + // Call OnStartRequest for the "DivertTo" listener. 1.509 + nsresult rv = OnStartRequest(mChannel, nullptr); 1.510 + if (NS_FAILED(rv)) { 1.511 + if (mChannel) { 1.512 + mChannel->Cancel(rv); 1.513 + } 1.514 + mStatus = rv; 1.515 + return; 1.516 + } 1.517 + 1.518 + // After OnStartRequest has been called, tell FTPChannelChild to divert the 1.519 + // OnDataAvailables and OnStopRequest to this FTPChannelParent. 1.520 + if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) { 1.521 + FailDiversion(NS_ERROR_UNEXPECTED); 1.522 + return; 1.523 + } 1.524 +} 1.525 + 1.526 +class FTPFailDiversionEvent : public nsRunnable 1.527 +{ 1.528 +public: 1.529 + FTPFailDiversionEvent(FTPChannelParent *aChannelParent, 1.530 + nsresult aErrorCode, 1.531 + bool aSkipResume) 1.532 + : mChannelParent(aChannelParent) 1.533 + , mErrorCode(aErrorCode) 1.534 + , mSkipResume(aSkipResume) 1.535 + { 1.536 + MOZ_RELEASE_ASSERT(aChannelParent); 1.537 + MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode)); 1.538 + } 1.539 + NS_IMETHOD Run() 1.540 + { 1.541 + mChannelParent->NotifyDiversionFailed(mErrorCode, mSkipResume); 1.542 + return NS_OK; 1.543 + } 1.544 +private: 1.545 + nsRefPtr<FTPChannelParent> mChannelParent; 1.546 + nsresult mErrorCode; 1.547 + bool mSkipResume; 1.548 +}; 1.549 + 1.550 +void 1.551 +FTPChannelParent::FailDiversion(nsresult aErrorCode, 1.552 + bool aSkipResume) 1.553 +{ 1.554 + MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode)); 1.555 + MOZ_RELEASE_ASSERT(mDivertingFromChild); 1.556 + MOZ_RELEASE_ASSERT(mDivertToListener); 1.557 + MOZ_RELEASE_ASSERT(mChannel); 1.558 + 1.559 + NS_DispatchToCurrentThread( 1.560 + new FTPFailDiversionEvent(this, aErrorCode, aSkipResume)); 1.561 +} 1.562 + 1.563 +void 1.564 +FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode, 1.565 + bool aSkipResume) 1.566 +{ 1.567 + MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode)); 1.568 + MOZ_RELEASE_ASSERT(mDivertingFromChild); 1.569 + MOZ_RELEASE_ASSERT(mDivertToListener); 1.570 + MOZ_RELEASE_ASSERT(mChannel); 1.571 + 1.572 + mChannel->Cancel(aErrorCode); 1.573 + 1.574 + mChannel->ForcePending(false); 1.575 + 1.576 + bool isPending = false; 1.577 + nsresult rv = mChannel->IsPending(&isPending); 1.578 + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); 1.579 + 1.580 + // Resume only we suspended earlier. 1.581 + if (mSuspendedForDiversion) { 1.582 + mChannel->Resume(); 1.583 + } 1.584 + // Channel has already sent OnStartRequest to the child, so ensure that we 1.585 + // call it here if it hasn't already been called. 1.586 + if (!mDivertedOnStartRequest) { 1.587 + mChannel->ForcePending(true); 1.588 + mDivertToListener->OnStartRequest(mChannel, nullptr); 1.589 + mChannel->ForcePending(false); 1.590 + } 1.591 + // If the channel is pending, it will call OnStopRequest itself; otherwise, do 1.592 + // it here. 1.593 + if (!isPending) { 1.594 + mDivertToListener->OnStopRequest(mChannel, nullptr, aErrorCode); 1.595 + } 1.596 + mDivertToListener = nullptr; 1.597 + mChannel = nullptr; 1.598 + 1.599 + if (!mIPCClosed) { 1.600 + unused << SendDeleteSelf(); 1.601 + } 1.602 +} 1.603 + 1.604 +//--------------------- 1.605 +} // namespace net 1.606 +} // namespace mozilla 1.607 +