netwerk/protocol/ftp/FTPChannelParent.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

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
michael@0 4 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 5 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 7
michael@0 8 #include "mozilla/net/FTPChannelParent.h"
michael@0 9 #include "nsFTPChannel.h"
michael@0 10 #include "nsNetUtil.h"
michael@0 11 #include "nsFtpProtocolHandler.h"
michael@0 12 #include "mozilla/ipc/InputStreamUtils.h"
michael@0 13 #include "mozilla/ipc/URIUtils.h"
michael@0 14 #include "mozilla/unused.h"
michael@0 15 #include "SerializedLoadContext.h"
michael@0 16
michael@0 17 using namespace mozilla::ipc;
michael@0 18
michael@0 19 #undef LOG
michael@0 20 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
michael@0 21
michael@0 22 namespace mozilla {
michael@0 23 namespace net {
michael@0 24
michael@0 25 FTPChannelParent::FTPChannelParent(nsILoadContext* aLoadContext, PBOverrideStatus aOverrideStatus)
michael@0 26 : mIPCClosed(false)
michael@0 27 , mLoadContext(aLoadContext)
michael@0 28 , mPBOverride(aOverrideStatus)
michael@0 29 , mStatus(NS_OK)
michael@0 30 , mDivertingFromChild(false)
michael@0 31 , mDivertedOnStartRequest(false)
michael@0 32 , mSuspendedForDiversion(false)
michael@0 33 {
michael@0 34 nsIProtocolHandler* handler;
michael@0 35 CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &handler);
michael@0 36 NS_ASSERTION(handler, "no ftp handler");
michael@0 37 }
michael@0 38
michael@0 39 FTPChannelParent::~FTPChannelParent()
michael@0 40 {
michael@0 41 gFtpHandler->Release();
michael@0 42 }
michael@0 43
michael@0 44 void
michael@0 45 FTPChannelParent::ActorDestroy(ActorDestroyReason why)
michael@0 46 {
michael@0 47 // We may still have refcount>0 if the channel hasn't called OnStopRequest
michael@0 48 // yet, but we must not send any more msgs to child.
michael@0 49 mIPCClosed = true;
michael@0 50 }
michael@0 51
michael@0 52 //-----------------------------------------------------------------------------
michael@0 53 // FTPChannelParent::nsISupports
michael@0 54 //-----------------------------------------------------------------------------
michael@0 55
michael@0 56 NS_IMPL_ISUPPORTS(FTPChannelParent,
michael@0 57 nsIStreamListener,
michael@0 58 nsIParentChannel,
michael@0 59 nsIInterfaceRequestor,
michael@0 60 nsIRequestObserver)
michael@0 61
michael@0 62 //-----------------------------------------------------------------------------
michael@0 63 // FTPChannelParent::PFTPChannelParent
michael@0 64 //-----------------------------------------------------------------------------
michael@0 65
michael@0 66 //-----------------------------------------------------------------------------
michael@0 67 // FTPChannelParent methods
michael@0 68 //-----------------------------------------------------------------------------
michael@0 69
michael@0 70 bool
michael@0 71 FTPChannelParent::Init(const FTPChannelCreationArgs& aArgs)
michael@0 72 {
michael@0 73 switch (aArgs.type()) {
michael@0 74 case FTPChannelCreationArgs::TFTPChannelOpenArgs:
michael@0 75 {
michael@0 76 const FTPChannelOpenArgs& a = aArgs.get_FTPChannelOpenArgs();
michael@0 77 return DoAsyncOpen(a.uri(), a.startPos(), a.entityID(), a.uploadStream());
michael@0 78 }
michael@0 79 case FTPChannelCreationArgs::TFTPChannelConnectArgs:
michael@0 80 {
michael@0 81 const FTPChannelConnectArgs& cArgs = aArgs.get_FTPChannelConnectArgs();
michael@0 82 return ConnectChannel(cArgs.channelId());
michael@0 83 }
michael@0 84 default:
michael@0 85 NS_NOTREACHED("unknown open type");
michael@0 86 return false;
michael@0 87 }
michael@0 88 }
michael@0 89
michael@0 90 bool
michael@0 91 FTPChannelParent::DoAsyncOpen(const URIParams& aURI,
michael@0 92 const uint64_t& aStartPos,
michael@0 93 const nsCString& aEntityID,
michael@0 94 const OptionalInputStreamParams& aUploadStream)
michael@0 95 {
michael@0 96 nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
michael@0 97 if (!uri)
michael@0 98 return false;
michael@0 99
michael@0 100 #ifdef DEBUG
michael@0 101 nsCString uriSpec;
michael@0 102 uri->GetSpec(uriSpec);
michael@0 103 LOG(("FTPChannelParent DoAsyncOpen [this=%p uri=%s]\n",
michael@0 104 this, uriSpec.get()));
michael@0 105 #endif
michael@0 106
michael@0 107 nsresult rv;
michael@0 108 nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
michael@0 109 if (NS_FAILED(rv))
michael@0 110 return SendFailedAsyncOpen(rv);
michael@0 111
michael@0 112 nsCOMPtr<nsIChannel> chan;
michael@0 113 rv = NS_NewChannel(getter_AddRefs(chan), uri, ios);
michael@0 114 if (NS_FAILED(rv))
michael@0 115 return SendFailedAsyncOpen(rv);
michael@0 116
michael@0 117 mChannel = static_cast<nsFtpChannel*>(chan.get());
michael@0 118
michael@0 119 if (mPBOverride != kPBOverride_Unset) {
michael@0 120 mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
michael@0 121 }
michael@0 122
michael@0 123 rv = mChannel->SetNotificationCallbacks(this);
michael@0 124 if (NS_FAILED(rv))
michael@0 125 return SendFailedAsyncOpen(rv);
michael@0 126
michael@0 127 nsTArray<mozilla::ipc::FileDescriptor> fds;
michael@0 128 nsCOMPtr<nsIInputStream> upload = DeserializeInputStream(aUploadStream, fds);
michael@0 129 if (upload) {
michael@0 130 // contentType and contentLength are ignored
michael@0 131 rv = mChannel->SetUploadStream(upload, EmptyCString(), 0);
michael@0 132 if (NS_FAILED(rv))
michael@0 133 return SendFailedAsyncOpen(rv);
michael@0 134 }
michael@0 135
michael@0 136 rv = mChannel->ResumeAt(aStartPos, aEntityID);
michael@0 137 if (NS_FAILED(rv))
michael@0 138 return SendFailedAsyncOpen(rv);
michael@0 139
michael@0 140 rv = mChannel->AsyncOpen(this, nullptr);
michael@0 141 if (NS_FAILED(rv))
michael@0 142 return SendFailedAsyncOpen(rv);
michael@0 143
michael@0 144 return true;
michael@0 145 }
michael@0 146
michael@0 147 bool
michael@0 148 FTPChannelParent::ConnectChannel(const uint32_t& channelId)
michael@0 149 {
michael@0 150 nsresult rv;
michael@0 151
michael@0 152 LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId));
michael@0 153
michael@0 154 nsCOMPtr<nsIChannel> channel;
michael@0 155 rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
michael@0 156 if (NS_SUCCEEDED(rv))
michael@0 157 mChannel = static_cast<nsFtpChannel*>(channel.get());
michael@0 158
michael@0 159 LOG((" found channel %p, rv=%08x", mChannel.get(), rv));
michael@0 160
michael@0 161 return true;
michael@0 162 }
michael@0 163
michael@0 164 bool
michael@0 165 FTPChannelParent::RecvCancel(const nsresult& status)
michael@0 166 {
michael@0 167 if (mChannel)
michael@0 168 mChannel->Cancel(status);
michael@0 169 return true;
michael@0 170 }
michael@0 171
michael@0 172 bool
michael@0 173 FTPChannelParent::RecvSuspend()
michael@0 174 {
michael@0 175 if (mChannel)
michael@0 176 mChannel->Suspend();
michael@0 177 return true;
michael@0 178 }
michael@0 179
michael@0 180 bool
michael@0 181 FTPChannelParent::RecvResume()
michael@0 182 {
michael@0 183 if (mChannel)
michael@0 184 mChannel->Resume();
michael@0 185 return true;
michael@0 186 }
michael@0 187
michael@0 188 bool
michael@0 189 FTPChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
michael@0 190 const uint64_t& offset,
michael@0 191 const uint32_t& count)
michael@0 192 {
michael@0 193 if (NS_WARN_IF(!mDivertingFromChild)) {
michael@0 194 MOZ_ASSERT(mDivertingFromChild,
michael@0 195 "Cannot RecvDivertOnDataAvailable if diverting is not set!");
michael@0 196 FailDiversion(NS_ERROR_UNEXPECTED);
michael@0 197 return false;
michael@0 198 }
michael@0 199
michael@0 200 // Drop OnDataAvailables if the parent was canceled already.
michael@0 201 if (NS_FAILED(mStatus)) {
michael@0 202 return true;
michael@0 203 }
michael@0 204
michael@0 205 nsCOMPtr<nsIInputStream> stringStream;
michael@0 206 nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
michael@0 207 count, NS_ASSIGNMENT_DEPEND);
michael@0 208 if (NS_FAILED(rv)) {
michael@0 209 if (mChannel) {
michael@0 210 mChannel->Cancel(rv);
michael@0 211 }
michael@0 212 mStatus = rv;
michael@0 213 return true;
michael@0 214 }
michael@0 215
michael@0 216 rv = OnDataAvailable(mChannel, nullptr, stringStream, offset, count);
michael@0 217
michael@0 218 stringStream->Close();
michael@0 219 if (NS_FAILED(rv)) {
michael@0 220 if (mChannel) {
michael@0 221 mChannel->Cancel(rv);
michael@0 222 }
michael@0 223 mStatus = rv;
michael@0 224 }
michael@0 225 return true;
michael@0 226 }
michael@0 227
michael@0 228 bool
michael@0 229 FTPChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
michael@0 230 {
michael@0 231 if (NS_WARN_IF(!mDivertingFromChild)) {
michael@0 232 MOZ_ASSERT(mDivertingFromChild,
michael@0 233 "Cannot RecvDivertOnStopRequest if diverting is not set!");
michael@0 234 FailDiversion(NS_ERROR_UNEXPECTED);
michael@0 235 return false;
michael@0 236 }
michael@0 237
michael@0 238 // Honor the channel's status even if the underlying transaction completed.
michael@0 239 nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode;
michael@0 240
michael@0 241 // Reset fake pending status in case OnStopRequest has already been called.
michael@0 242 if (mChannel) {
michael@0 243 mChannel->ForcePending(false);
michael@0 244 }
michael@0 245
michael@0 246 OnStopRequest(mChannel, nullptr, status);
michael@0 247 return true;
michael@0 248 }
michael@0 249
michael@0 250 bool
michael@0 251 FTPChannelParent::RecvDivertComplete()
michael@0 252 {
michael@0 253 if (NS_WARN_IF(!mDivertingFromChild)) {
michael@0 254 MOZ_ASSERT(mDivertingFromChild,
michael@0 255 "Cannot RecvDivertComplete if diverting is not set!");
michael@0 256 FailDiversion(NS_ERROR_UNEXPECTED);
michael@0 257 return false;
michael@0 258 }
michael@0 259
michael@0 260 nsresult rv = ResumeForDiversion();
michael@0 261 if (NS_WARN_IF(NS_FAILED(rv))) {
michael@0 262 FailDiversion(NS_ERROR_UNEXPECTED);
michael@0 263 return false;
michael@0 264 }
michael@0 265
michael@0 266 return true;
michael@0 267 }
michael@0 268
michael@0 269 //-----------------------------------------------------------------------------
michael@0 270 // FTPChannelParent::nsIRequestObserver
michael@0 271 //-----------------------------------------------------------------------------
michael@0 272
michael@0 273 NS_IMETHODIMP
michael@0 274 FTPChannelParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
michael@0 275 {
michael@0 276 LOG(("FTPChannelParent::OnStartRequest [this=%p]\n", this));
michael@0 277
michael@0 278 if (mDivertingFromChild) {
michael@0 279 MOZ_RELEASE_ASSERT(mDivertToListener,
michael@0 280 "Cannot divert if listener is unset!");
michael@0 281 return mDivertToListener->OnStartRequest(aRequest, aContext);
michael@0 282 }
michael@0 283
michael@0 284 nsCOMPtr<nsIChannel> chan = do_QueryInterface(aRequest);
michael@0 285 MOZ_ASSERT(chan);
michael@0 286 NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
michael@0 287
michael@0 288 int64_t contentLength;
michael@0 289 chan->GetContentLength(&contentLength);
michael@0 290 nsCString contentType;
michael@0 291 chan->GetContentType(contentType);
michael@0 292
michael@0 293 nsCString entityID;
michael@0 294 nsCOMPtr<nsIResumableChannel> resChan = do_QueryInterface(aRequest);
michael@0 295 MOZ_ASSERT(resChan); // both FTP and HTTP should implement nsIResumableChannel
michael@0 296 if (resChan) {
michael@0 297 resChan->GetEntityID(entityID);
michael@0 298 }
michael@0 299
michael@0 300 nsCOMPtr<nsIFTPChannel> ftpChan = do_QueryInterface(aRequest);
michael@0 301 PRTime lastModified = 0;
michael@0 302 if (ftpChan) {
michael@0 303 ftpChan->GetLastModifiedTime(&lastModified);
michael@0 304 } else {
michael@0 305 // Temporary hack: if we were redirected to use an HTTP channel (ie FTP is
michael@0 306 // using an HTTP proxy), cancel, as we don't support those redirects yet.
michael@0 307 aRequest->Cancel(NS_ERROR_NOT_IMPLEMENTED);
michael@0 308 }
michael@0 309
michael@0 310 URIParams uriparam;
michael@0 311 nsCOMPtr<nsIURI> uri;
michael@0 312 chan->GetURI(getter_AddRefs(uri));
michael@0 313 SerializeURI(uri, uriparam);
michael@0 314
michael@0 315 if (mIPCClosed || !SendOnStartRequest(mStatus, contentLength, contentType,
michael@0 316 lastModified, entityID, uriparam)) {
michael@0 317 return NS_ERROR_UNEXPECTED;
michael@0 318 }
michael@0 319
michael@0 320 return NS_OK;
michael@0 321 }
michael@0 322
michael@0 323 NS_IMETHODIMP
michael@0 324 FTPChannelParent::OnStopRequest(nsIRequest* aRequest,
michael@0 325 nsISupports* aContext,
michael@0 326 nsresult aStatusCode)
michael@0 327 {
michael@0 328 LOG(("FTPChannelParent::OnStopRequest: [this=%p status=%ul]\n",
michael@0 329 this, aStatusCode));
michael@0 330
michael@0 331 if (mDivertingFromChild) {
michael@0 332 MOZ_RELEASE_ASSERT(mDivertToListener,
michael@0 333 "Cannot divert if listener is unset!");
michael@0 334 return mDivertToListener->OnStopRequest(aRequest, aContext, aStatusCode);
michael@0 335 }
michael@0 336
michael@0 337 if (mIPCClosed || !SendOnStopRequest(aStatusCode)) {
michael@0 338 return NS_ERROR_UNEXPECTED;
michael@0 339 }
michael@0 340
michael@0 341 return NS_OK;
michael@0 342 }
michael@0 343
michael@0 344 //-----------------------------------------------------------------------------
michael@0 345 // FTPChannelParent::nsIStreamListener
michael@0 346 //-----------------------------------------------------------------------------
michael@0 347
michael@0 348 NS_IMETHODIMP
michael@0 349 FTPChannelParent::OnDataAvailable(nsIRequest* aRequest,
michael@0 350 nsISupports* aContext,
michael@0 351 nsIInputStream* aInputStream,
michael@0 352 uint64_t aOffset,
michael@0 353 uint32_t aCount)
michael@0 354 {
michael@0 355 LOG(("FTPChannelParent::OnDataAvailable [this=%p]\n", this));
michael@0 356
michael@0 357 if (mDivertingFromChild) {
michael@0 358 MOZ_RELEASE_ASSERT(mDivertToListener,
michael@0 359 "Cannot divert if listener is unset!");
michael@0 360 return mDivertToListener->OnDataAvailable(aRequest, aContext, aInputStream,
michael@0 361 aOffset, aCount);
michael@0 362 }
michael@0 363
michael@0 364 nsCString data;
michael@0 365 nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
michael@0 366 if (NS_FAILED(rv))
michael@0 367 return rv;
michael@0 368
michael@0 369 if (mIPCClosed || !SendOnDataAvailable(mStatus, data, aOffset, aCount))
michael@0 370 return NS_ERROR_UNEXPECTED;
michael@0 371
michael@0 372 return NS_OK;
michael@0 373 }
michael@0 374
michael@0 375 //-----------------------------------------------------------------------------
michael@0 376 // FTPChannelParent::nsIParentChannel
michael@0 377 //-----------------------------------------------------------------------------
michael@0 378
michael@0 379 NS_IMETHODIMP
michael@0 380 FTPChannelParent::SetParentListener(HttpChannelParentListener* aListener)
michael@0 381 {
michael@0 382 // Do not need ptr to HttpChannelParentListener.
michael@0 383 return NS_OK;
michael@0 384 }
michael@0 385
michael@0 386 NS_IMETHODIMP
michael@0 387 FTPChannelParent::Delete()
michael@0 388 {
michael@0 389 if (mIPCClosed || !SendDeleteSelf())
michael@0 390 return NS_ERROR_UNEXPECTED;
michael@0 391
michael@0 392 return NS_OK;
michael@0 393 }
michael@0 394
michael@0 395 //-----------------------------------------------------------------------------
michael@0 396 // FTPChannelParent::nsIInterfaceRequestor
michael@0 397 //-----------------------------------------------------------------------------
michael@0 398
michael@0 399 NS_IMETHODIMP
michael@0 400 FTPChannelParent::GetInterface(const nsIID& uuid, void** result)
michael@0 401 {
michael@0 402 // Only support nsILoadContext if child channel's callbacks did too
michael@0 403 if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
michael@0 404 NS_ADDREF(mLoadContext);
michael@0 405 *result = static_cast<nsILoadContext*>(mLoadContext);
michael@0 406 return NS_OK;
michael@0 407 }
michael@0 408
michael@0 409 return QueryInterface(uuid, result);
michael@0 410 }
michael@0 411
michael@0 412 //-----------------------------------------------------------------------------
michael@0 413 // FTPChannelParent::ADivertableParentChannel
michael@0 414 //-----------------------------------------------------------------------------
michael@0 415 nsresult
michael@0 416 FTPChannelParent::SuspendForDiversion()
michael@0 417 {
michael@0 418 MOZ_ASSERT(mChannel);
michael@0 419 if (NS_WARN_IF(mDivertingFromChild)) {
michael@0 420 MOZ_ASSERT(!mDivertingFromChild, "Already suspended for diversion!");
michael@0 421 return NS_ERROR_UNEXPECTED;
michael@0 422 }
michael@0 423
michael@0 424 // Try suspending the channel. Allow it to fail, since OnStopRequest may have
michael@0 425 // been called and thus the channel may not be pending.
michael@0 426 nsresult rv = mChannel->Suspend();
michael@0 427 MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE);
michael@0 428 mSuspendedForDiversion = NS_SUCCEEDED(rv);
michael@0 429
michael@0 430 // Once this is set, no more OnStart/OnData/OnStop callbacks should be sent
michael@0 431 // to the child.
michael@0 432 mDivertingFromChild = true;
michael@0 433
michael@0 434 return NS_OK;
michael@0 435 }
michael@0 436
michael@0 437 /* private, supporting function for ADivertableParentChannel */
michael@0 438 nsresult
michael@0 439 FTPChannelParent::ResumeForDiversion()
michael@0 440 {
michael@0 441 MOZ_ASSERT(mChannel);
michael@0 442 MOZ_ASSERT(mDivertToListener);
michael@0 443 if (NS_WARN_IF(!mDivertingFromChild)) {
michael@0 444 MOZ_ASSERT(mDivertingFromChild,
michael@0 445 "Cannot ResumeForDiversion if not diverting!");
michael@0 446 return NS_ERROR_UNEXPECTED;
michael@0 447 }
michael@0 448
michael@0 449 if (mSuspendedForDiversion) {
michael@0 450 nsresult rv = mChannel->Resume();
michael@0 451 if (NS_WARN_IF(NS_FAILED(rv))) {
michael@0 452 FailDiversion(NS_ERROR_UNEXPECTED, true);
michael@0 453 return rv;
michael@0 454 }
michael@0 455 mSuspendedForDiversion = false;
michael@0 456 }
michael@0 457
michael@0 458 // Delete() will tear down IPDL, but ref from underlying nsFTPChannel will
michael@0 459 // keep us alive if there's more data to be delivered to listener.
michael@0 460 if (NS_WARN_IF(NS_FAILED(Delete()))) {
michael@0 461 FailDiversion(NS_ERROR_UNEXPECTED);
michael@0 462 return NS_ERROR_UNEXPECTED;
michael@0 463 }
michael@0 464 return NS_OK;
michael@0 465 }
michael@0 466
michael@0 467 void
michael@0 468 FTPChannelParent::DivertTo(nsIStreamListener *aListener)
michael@0 469 {
michael@0 470 MOZ_ASSERT(aListener);
michael@0 471 if (NS_WARN_IF(!mDivertingFromChild)) {
michael@0 472 MOZ_ASSERT(mDivertingFromChild,
michael@0 473 "Cannot DivertTo new listener if diverting is not set!");
michael@0 474 return;
michael@0 475 }
michael@0 476
michael@0 477 if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) {
michael@0 478 FailDiversion(NS_ERROR_UNEXPECTED);
michael@0 479 return;
michael@0 480 }
michael@0 481
michael@0 482 mDivertToListener = aListener;
michael@0 483
michael@0 484 // Call OnStartRequest and SendDivertMessages asynchronously to avoid
michael@0 485 // reentering client context.
michael@0 486 NS_DispatchToCurrentThread(
michael@0 487 NS_NewRunnableMethod(this, &FTPChannelParent::StartDiversion));
michael@0 488 return;
michael@0 489 }
michael@0 490
michael@0 491 void
michael@0 492 FTPChannelParent::StartDiversion()
michael@0 493 {
michael@0 494 if (NS_WARN_IF(!mDivertingFromChild)) {
michael@0 495 MOZ_ASSERT(mDivertingFromChild,
michael@0 496 "Cannot StartDiversion if diverting is not set!");
michael@0 497 return;
michael@0 498 }
michael@0 499
michael@0 500 // Fake pending status in case OnStopRequest has already been called.
michael@0 501 if (mChannel) {
michael@0 502 mChannel->ForcePending(true);
michael@0 503 }
michael@0 504
michael@0 505 // Call OnStartRequest for the "DivertTo" listener.
michael@0 506 nsresult rv = OnStartRequest(mChannel, nullptr);
michael@0 507 if (NS_FAILED(rv)) {
michael@0 508 if (mChannel) {
michael@0 509 mChannel->Cancel(rv);
michael@0 510 }
michael@0 511 mStatus = rv;
michael@0 512 return;
michael@0 513 }
michael@0 514
michael@0 515 // After OnStartRequest has been called, tell FTPChannelChild to divert the
michael@0 516 // OnDataAvailables and OnStopRequest to this FTPChannelParent.
michael@0 517 if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) {
michael@0 518 FailDiversion(NS_ERROR_UNEXPECTED);
michael@0 519 return;
michael@0 520 }
michael@0 521 }
michael@0 522
michael@0 523 class FTPFailDiversionEvent : public nsRunnable
michael@0 524 {
michael@0 525 public:
michael@0 526 FTPFailDiversionEvent(FTPChannelParent *aChannelParent,
michael@0 527 nsresult aErrorCode,
michael@0 528 bool aSkipResume)
michael@0 529 : mChannelParent(aChannelParent)
michael@0 530 , mErrorCode(aErrorCode)
michael@0 531 , mSkipResume(aSkipResume)
michael@0 532 {
michael@0 533 MOZ_RELEASE_ASSERT(aChannelParent);
michael@0 534 MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
michael@0 535 }
michael@0 536 NS_IMETHOD Run()
michael@0 537 {
michael@0 538 mChannelParent->NotifyDiversionFailed(mErrorCode, mSkipResume);
michael@0 539 return NS_OK;
michael@0 540 }
michael@0 541 private:
michael@0 542 nsRefPtr<FTPChannelParent> mChannelParent;
michael@0 543 nsresult mErrorCode;
michael@0 544 bool mSkipResume;
michael@0 545 };
michael@0 546
michael@0 547 void
michael@0 548 FTPChannelParent::FailDiversion(nsresult aErrorCode,
michael@0 549 bool aSkipResume)
michael@0 550 {
michael@0 551 MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
michael@0 552 MOZ_RELEASE_ASSERT(mDivertingFromChild);
michael@0 553 MOZ_RELEASE_ASSERT(mDivertToListener);
michael@0 554 MOZ_RELEASE_ASSERT(mChannel);
michael@0 555
michael@0 556 NS_DispatchToCurrentThread(
michael@0 557 new FTPFailDiversionEvent(this, aErrorCode, aSkipResume));
michael@0 558 }
michael@0 559
michael@0 560 void
michael@0 561 FTPChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
michael@0 562 bool aSkipResume)
michael@0 563 {
michael@0 564 MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
michael@0 565 MOZ_RELEASE_ASSERT(mDivertingFromChild);
michael@0 566 MOZ_RELEASE_ASSERT(mDivertToListener);
michael@0 567 MOZ_RELEASE_ASSERT(mChannel);
michael@0 568
michael@0 569 mChannel->Cancel(aErrorCode);
michael@0 570
michael@0 571 mChannel->ForcePending(false);
michael@0 572
michael@0 573 bool isPending = false;
michael@0 574 nsresult rv = mChannel->IsPending(&isPending);
michael@0 575 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
michael@0 576
michael@0 577 // Resume only we suspended earlier.
michael@0 578 if (mSuspendedForDiversion) {
michael@0 579 mChannel->Resume();
michael@0 580 }
michael@0 581 // Channel has already sent OnStartRequest to the child, so ensure that we
michael@0 582 // call it here if it hasn't already been called.
michael@0 583 if (!mDivertedOnStartRequest) {
michael@0 584 mChannel->ForcePending(true);
michael@0 585 mDivertToListener->OnStartRequest(mChannel, nullptr);
michael@0 586 mChannel->ForcePending(false);
michael@0 587 }
michael@0 588 // If the channel is pending, it will call OnStopRequest itself; otherwise, do
michael@0 589 // it here.
michael@0 590 if (!isPending) {
michael@0 591 mDivertToListener->OnStopRequest(mChannel, nullptr, aErrorCode);
michael@0 592 }
michael@0 593 mDivertToListener = nullptr;
michael@0 594 mChannel = nullptr;
michael@0 595
michael@0 596 if (!mIPCClosed) {
michael@0 597 unused << SendDeleteSelf();
michael@0 598 }
michael@0 599 }
michael@0 600
michael@0 601 //---------------------
michael@0 602 } // namespace net
michael@0 603 } // namespace mozilla
michael@0 604

mercurial