netwerk/protocol/ftp/FTPChannelChild.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/NeckoChild.h"
michael@0 9 #include "mozilla/net/ChannelDiverterChild.h"
michael@0 10 #include "mozilla/net/FTPChannelChild.h"
michael@0 11 #include "mozilla/dom/TabChild.h"
michael@0 12 #include "nsFtpProtocolHandler.h"
michael@0 13 #include "nsITabChild.h"
michael@0 14 #include "nsStringStream.h"
michael@0 15 #include "nsNetUtil.h"
michael@0 16 #include "base/compiler_specific.h"
michael@0 17 #include "mozilla/ipc/InputStreamUtils.h"
michael@0 18 #include "mozilla/ipc/URIUtils.h"
michael@0 19 #include "SerializedLoadContext.h"
michael@0 20
michael@0 21 using namespace mozilla::ipc;
michael@0 22
michael@0 23 #undef LOG
michael@0 24 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
michael@0 25
michael@0 26 namespace mozilla {
michael@0 27 namespace net {
michael@0 28
michael@0 29 FTPChannelChild::FTPChannelChild(nsIURI* uri)
michael@0 30 : mIPCOpen(false)
michael@0 31 , mCanceled(false)
michael@0 32 , mSuspendCount(0)
michael@0 33 , mIsPending(false)
michael@0 34 , mWasOpened(false)
michael@0 35 , mLastModifiedTime(0)
michael@0 36 , mStartPos(0)
michael@0 37 , mDivertingToParent(false)
michael@0 38 , mFlushedForDiversion(false)
michael@0 39 , mSuspendSent(false)
michael@0 40 {
michael@0 41 LOG(("Creating FTPChannelChild @%x\n", this));
michael@0 42 // grab a reference to the handler to ensure that it doesn't go away.
michael@0 43 NS_ADDREF(gFtpHandler);
michael@0 44 SetURI(uri);
michael@0 45 mEventQ = new ChannelEventQueue(static_cast<nsIFTPChannel*>(this));
michael@0 46 }
michael@0 47
michael@0 48 FTPChannelChild::~FTPChannelChild()
michael@0 49 {
michael@0 50 LOG(("Destroying FTPChannelChild @%x\n", this));
michael@0 51 gFtpHandler->Release();
michael@0 52 }
michael@0 53
michael@0 54 void
michael@0 55 FTPChannelChild::AddIPDLReference()
michael@0 56 {
michael@0 57 NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference");
michael@0 58 mIPCOpen = true;
michael@0 59 AddRef();
michael@0 60 }
michael@0 61
michael@0 62 void
michael@0 63 FTPChannelChild::ReleaseIPDLReference()
michael@0 64 {
michael@0 65 NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
michael@0 66 mIPCOpen = false;
michael@0 67 Release();
michael@0 68 }
michael@0 69
michael@0 70 //-----------------------------------------------------------------------------
michael@0 71 // FTPChannelChild::nsISupports
michael@0 72 //-----------------------------------------------------------------------------
michael@0 73
michael@0 74 NS_IMPL_ISUPPORTS_INHERITED(FTPChannelChild,
michael@0 75 nsBaseChannel,
michael@0 76 nsIFTPChannel,
michael@0 77 nsIUploadChannel,
michael@0 78 nsIResumableChannel,
michael@0 79 nsIProxiedChannel,
michael@0 80 nsIChildChannel,
michael@0 81 nsIDivertableChannel)
michael@0 82
michael@0 83 //-----------------------------------------------------------------------------
michael@0 84
michael@0 85 NS_IMETHODIMP
michael@0 86 FTPChannelChild::GetLastModifiedTime(PRTime* lastModifiedTime)
michael@0 87 {
michael@0 88 *lastModifiedTime = mLastModifiedTime;
michael@0 89 return NS_OK;
michael@0 90 }
michael@0 91
michael@0 92 NS_IMETHODIMP
michael@0 93 FTPChannelChild::SetLastModifiedTime(PRTime lastModifiedTime)
michael@0 94 {
michael@0 95 return NS_ERROR_NOT_AVAILABLE;
michael@0 96 }
michael@0 97
michael@0 98 NS_IMETHODIMP
michael@0 99 FTPChannelChild::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID)
michael@0 100 {
michael@0 101 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
michael@0 102 mStartPos = aStartPos;
michael@0 103 mEntityID = aEntityID;
michael@0 104 return NS_OK;
michael@0 105 }
michael@0 106
michael@0 107 NS_IMETHODIMP
michael@0 108 FTPChannelChild::GetEntityID(nsACString& entityID)
michael@0 109 {
michael@0 110 entityID = mEntityID;
michael@0 111 return NS_OK;
michael@0 112 }
michael@0 113
michael@0 114 NS_IMETHODIMP
michael@0 115 FTPChannelChild::GetProxyInfo(nsIProxyInfo** aProxyInfo)
michael@0 116 {
michael@0 117 DROP_DEAD();
michael@0 118 }
michael@0 119
michael@0 120 NS_IMETHODIMP
michael@0 121 FTPChannelChild::SetUploadStream(nsIInputStream* stream,
michael@0 122 const nsACString& contentType,
michael@0 123 int64_t contentLength)
michael@0 124 {
michael@0 125 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
michael@0 126 mUploadStream = stream;
michael@0 127 // NOTE: contentLength is intentionally ignored here.
michael@0 128 return NS_OK;
michael@0 129 }
michael@0 130
michael@0 131 NS_IMETHODIMP
michael@0 132 FTPChannelChild::GetUploadStream(nsIInputStream** stream)
michael@0 133 {
michael@0 134 NS_ENSURE_ARG_POINTER(stream);
michael@0 135 *stream = mUploadStream;
michael@0 136 NS_IF_ADDREF(*stream);
michael@0 137 return NS_OK;
michael@0 138 }
michael@0 139
michael@0 140 //-----------------------------------------------------------------------------
michael@0 141
michael@0 142 NS_IMETHODIMP
michael@0 143 FTPChannelChild::AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext)
michael@0 144 {
michael@0 145 LOG(("FTPChannelChild::AsyncOpen [this=%p]\n", this));
michael@0 146
michael@0 147 NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
michael@0 148 NS_ENSURE_ARG_POINTER(listener);
michael@0 149 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
michael@0 150 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
michael@0 151
michael@0 152 // Port checked in parent, but duplicate here so we can return with error
michael@0 153 // immediately, as we've done since before e10s.
michael@0 154 nsresult rv;
michael@0 155 rv = NS_CheckPortSafety(nsBaseChannel::URI()); // Need to disambiguate,
michael@0 156 // because in the child ipdl,
michael@0 157 // a typedef URI is defined...
michael@0 158 if (NS_FAILED(rv))
michael@0 159 return rv;
michael@0 160
michael@0 161 mozilla::dom::TabChild* tabChild = nullptr;
michael@0 162 nsCOMPtr<nsITabChild> iTabChild;
michael@0 163 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
michael@0 164 NS_GET_IID(nsITabChild),
michael@0 165 getter_AddRefs(iTabChild));
michael@0 166 GetCallback(iTabChild);
michael@0 167 if (iTabChild) {
michael@0 168 tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
michael@0 169 }
michael@0 170 if (MissingRequiredTabChild(tabChild, "ftp")) {
michael@0 171 return NS_ERROR_ILLEGAL_VALUE;
michael@0 172 }
michael@0 173
michael@0 174 mListener = listener;
michael@0 175 mListenerContext = aContext;
michael@0 176
michael@0 177 // add ourselves to the load group.
michael@0 178 if (mLoadGroup)
michael@0 179 mLoadGroup->AddRequest(this, nullptr);
michael@0 180
michael@0 181 OptionalInputStreamParams uploadStream;
michael@0 182 nsTArray<mozilla::ipc::FileDescriptor> fds;
michael@0 183 SerializeInputStream(mUploadStream, uploadStream, fds);
michael@0 184
michael@0 185 MOZ_ASSERT(fds.IsEmpty());
michael@0 186
michael@0 187 FTPChannelOpenArgs openArgs;
michael@0 188 SerializeURI(nsBaseChannel::URI(), openArgs.uri());
michael@0 189 openArgs.startPos() = mStartPos;
michael@0 190 openArgs.entityID() = mEntityID;
michael@0 191 openArgs.uploadStream() = uploadStream;
michael@0 192
michael@0 193 gNeckoChild->
michael@0 194 SendPFTPChannelConstructor(this, tabChild, IPC::SerializedLoadContext(this),
michael@0 195 openArgs);
michael@0 196
michael@0 197 // The socket transport layer in the chrome process now has a logical ref to
michael@0 198 // us until OnStopRequest is called.
michael@0 199 AddIPDLReference();
michael@0 200
michael@0 201 mIsPending = true;
michael@0 202 mWasOpened = true;
michael@0 203
michael@0 204 return rv;
michael@0 205 }
michael@0 206
michael@0 207 NS_IMETHODIMP
michael@0 208 FTPChannelChild::IsPending(bool* result)
michael@0 209 {
michael@0 210 *result = mIsPending;
michael@0 211 return NS_OK;
michael@0 212 }
michael@0 213
michael@0 214 nsresult
michael@0 215 FTPChannelChild::OpenContentStream(bool async,
michael@0 216 nsIInputStream** stream,
michael@0 217 nsIChannel** channel)
michael@0 218 {
michael@0 219 NS_RUNTIMEABORT("FTPChannel*Child* should never have OpenContentStream called!");
michael@0 220 return NS_OK;
michael@0 221 }
michael@0 222
michael@0 223 //-----------------------------------------------------------------------------
michael@0 224 // FTPChannelChild::PFTPChannelChild
michael@0 225 //-----------------------------------------------------------------------------
michael@0 226
michael@0 227 class FTPStartRequestEvent : public ChannelEvent
michael@0 228 {
michael@0 229 public:
michael@0 230 FTPStartRequestEvent(FTPChannelChild* aChild,
michael@0 231 const nsresult& aChannelStatus,
michael@0 232 const int64_t& aContentLength,
michael@0 233 const nsCString& aContentType,
michael@0 234 const PRTime& aLastModified,
michael@0 235 const nsCString& aEntityID,
michael@0 236 const URIParams& aURI)
michael@0 237 : mChild(aChild)
michael@0 238 , mChannelStatus(aChannelStatus)
michael@0 239 , mContentLength(aContentLength)
michael@0 240 , mContentType(aContentType)
michael@0 241 , mLastModified(aLastModified)
michael@0 242 , mEntityID(aEntityID)
michael@0 243 , mURI(aURI)
michael@0 244 {
michael@0 245 }
michael@0 246 void Run()
michael@0 247 {
michael@0 248 mChild->DoOnStartRequest(mChannelStatus, mContentLength, mContentType,
michael@0 249 mLastModified, mEntityID, mURI);
michael@0 250 }
michael@0 251
michael@0 252 private:
michael@0 253 FTPChannelChild* mChild;
michael@0 254 nsresult mChannelStatus;
michael@0 255 int64_t mContentLength;
michael@0 256 nsCString mContentType;
michael@0 257 PRTime mLastModified;
michael@0 258 nsCString mEntityID;
michael@0 259 URIParams mURI;
michael@0 260 };
michael@0 261
michael@0 262 bool
michael@0 263 FTPChannelChild::RecvOnStartRequest(const nsresult& aChannelStatus,
michael@0 264 const int64_t& aContentLength,
michael@0 265 const nsCString& aContentType,
michael@0 266 const PRTime& aLastModified,
michael@0 267 const nsCString& aEntityID,
michael@0 268 const URIParams& aURI)
michael@0 269 {
michael@0 270 // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
michael@0 271 // stage, as they are set in the listener's OnStartRequest.
michael@0 272 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
michael@0 273 "mFlushedForDiversion should be unset before OnStartRequest!");
michael@0 274 MOZ_RELEASE_ASSERT(!mDivertingToParent,
michael@0 275 "mDivertingToParent should be unset before OnStartRequest!");
michael@0 276
michael@0 277 if (mEventQ->ShouldEnqueue()) {
michael@0 278 mEventQ->Enqueue(new FTPStartRequestEvent(this, aChannelStatus,
michael@0 279 aContentLength, aContentType,
michael@0 280 aLastModified, aEntityID, aURI));
michael@0 281 } else {
michael@0 282 DoOnStartRequest(aChannelStatus, aContentLength, aContentType,
michael@0 283 aLastModified, aEntityID, aURI);
michael@0 284 }
michael@0 285 return true;
michael@0 286 }
michael@0 287
michael@0 288 void
michael@0 289 FTPChannelChild::DoOnStartRequest(const nsresult& aChannelStatus,
michael@0 290 const int64_t& aContentLength,
michael@0 291 const nsCString& aContentType,
michael@0 292 const PRTime& aLastModified,
michael@0 293 const nsCString& aEntityID,
michael@0 294 const URIParams& aURI)
michael@0 295 {
michael@0 296 LOG(("FTPChannelChild::RecvOnStartRequest [this=%p]\n", this));
michael@0 297
michael@0 298 // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
michael@0 299 // stage, as they are set in the listener's OnStartRequest.
michael@0 300 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
michael@0 301 "mFlushedForDiversion should be unset before OnStartRequest!");
michael@0 302 MOZ_RELEASE_ASSERT(!mDivertingToParent,
michael@0 303 "mDivertingToParent should be unset before OnStartRequest!");
michael@0 304
michael@0 305 if (!mCanceled && NS_SUCCEEDED(mStatus)) {
michael@0 306 mStatus = aChannelStatus;
michael@0 307 }
michael@0 308
michael@0 309 mContentLength = aContentLength;
michael@0 310 SetContentType(aContentType);
michael@0 311 mLastModifiedTime = aLastModified;
michael@0 312 mEntityID = aEntityID;
michael@0 313
michael@0 314 nsCString spec;
michael@0 315 nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
michael@0 316 uri->GetSpec(spec);
michael@0 317 nsBaseChannel::URI()->SetSpec(spec);
michael@0 318
michael@0 319 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
michael@0 320 nsresult rv = mListener->OnStartRequest(this, mListenerContext);
michael@0 321 if (NS_FAILED(rv))
michael@0 322 Cancel(rv);
michael@0 323
michael@0 324 if (mDivertingToParent) {
michael@0 325 mListener = nullptr;
michael@0 326 mListenerContext = nullptr;
michael@0 327 if (mLoadGroup) {
michael@0 328 mLoadGroup->RemoveRequest(this, nullptr, mStatus);
michael@0 329 }
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 class FTPDataAvailableEvent : public ChannelEvent
michael@0 334 {
michael@0 335 public:
michael@0 336 FTPDataAvailableEvent(FTPChannelChild* aChild,
michael@0 337 const nsresult& aChannelStatus,
michael@0 338 const nsCString& aData,
michael@0 339 const uint64_t& aOffset,
michael@0 340 const uint32_t& aCount)
michael@0 341 : mChild(aChild)
michael@0 342 , mChannelStatus(aChannelStatus)
michael@0 343 , mData(aData)
michael@0 344 , mOffset(aOffset)
michael@0 345 , mCount(aCount)
michael@0 346 {
michael@0 347 }
michael@0 348 void Run()
michael@0 349 {
michael@0 350 mChild->DoOnDataAvailable(mChannelStatus, mData, mOffset, mCount);
michael@0 351 }
michael@0 352
michael@0 353 private:
michael@0 354 FTPChannelChild* mChild;
michael@0 355 nsresult mChannelStatus;
michael@0 356 nsCString mData;
michael@0 357 uint64_t mOffset;
michael@0 358 uint32_t mCount;
michael@0 359 };
michael@0 360
michael@0 361 bool
michael@0 362 FTPChannelChild::RecvOnDataAvailable(const nsresult& channelStatus,
michael@0 363 const nsCString& data,
michael@0 364 const uint64_t& offset,
michael@0 365 const uint32_t& count)
michael@0 366 {
michael@0 367 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
michael@0 368 "Should not be receiving any more callbacks from parent!");
michael@0 369
michael@0 370 if (mEventQ->ShouldEnqueue()) {
michael@0 371 mEventQ->Enqueue(
michael@0 372 new FTPDataAvailableEvent(this, channelStatus, data, offset, count));
michael@0 373 } else {
michael@0 374 MOZ_RELEASE_ASSERT(!mDivertingToParent,
michael@0 375 "ShouldEnqueue when diverting to parent!");
michael@0 376
michael@0 377 DoOnDataAvailable(channelStatus, data, offset, count);
michael@0 378 }
michael@0 379 return true;
michael@0 380 }
michael@0 381
michael@0 382 void
michael@0 383 FTPChannelChild::DoOnDataAvailable(const nsresult& channelStatus,
michael@0 384 const nsCString& data,
michael@0 385 const uint64_t& offset,
michael@0 386 const uint32_t& count)
michael@0 387 {
michael@0 388 LOG(("FTPChannelChild::RecvOnDataAvailable [this=%p]\n", this));
michael@0 389
michael@0 390 if (!mCanceled && NS_SUCCEEDED(mStatus)) {
michael@0 391 mStatus = channelStatus;
michael@0 392 }
michael@0 393
michael@0 394 if (mDivertingToParent) {
michael@0 395 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
michael@0 396 "Should not be processing any more callbacks from parent!");
michael@0 397
michael@0 398 SendDivertOnDataAvailable(data, offset, count);
michael@0 399 return;
michael@0 400 }
michael@0 401
michael@0 402 if (mCanceled)
michael@0 403 return;
michael@0 404
michael@0 405 // NOTE: the OnDataAvailable contract requires the client to read all the data
michael@0 406 // in the inputstream. This code relies on that ('data' will go away after
michael@0 407 // this function). Apparently the previous, non-e10s behavior was to actually
michael@0 408 // support only reading part of the data, allowing later calls to read the
michael@0 409 // rest.
michael@0 410 nsCOMPtr<nsIInputStream> stringStream;
michael@0 411 nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream),
michael@0 412 data.get(),
michael@0 413 count,
michael@0 414 NS_ASSIGNMENT_DEPEND);
michael@0 415 if (NS_FAILED(rv)) {
michael@0 416 Cancel(rv);
michael@0 417 return;
michael@0 418 }
michael@0 419
michael@0 420 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
michael@0 421 rv = mListener->OnDataAvailable(this, mListenerContext,
michael@0 422 stringStream, offset, count);
michael@0 423 if (NS_FAILED(rv))
michael@0 424 Cancel(rv);
michael@0 425 stringStream->Close();
michael@0 426 }
michael@0 427
michael@0 428 class FTPStopRequestEvent : public ChannelEvent
michael@0 429 {
michael@0 430 public:
michael@0 431 FTPStopRequestEvent(FTPChannelChild* aChild,
michael@0 432 const nsresult& aChannelStatus)
michael@0 433 : mChild(aChild)
michael@0 434 , mChannelStatus(aChannelStatus)
michael@0 435 {
michael@0 436 }
michael@0 437 void Run()
michael@0 438 {
michael@0 439 mChild->DoOnStopRequest(mChannelStatus);
michael@0 440 }
michael@0 441
michael@0 442 private:
michael@0 443 FTPChannelChild* mChild;
michael@0 444 nsresult mChannelStatus;
michael@0 445 };
michael@0 446
michael@0 447 bool
michael@0 448 FTPChannelChild::RecvOnStopRequest(const nsresult& aChannelStatus)
michael@0 449 {
michael@0 450 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
michael@0 451 "Should not be receiving any more callbacks from parent!");
michael@0 452
michael@0 453 if (mEventQ->ShouldEnqueue()) {
michael@0 454 mEventQ->Enqueue(new FTPStopRequestEvent(this, aChannelStatus));
michael@0 455 } else {
michael@0 456 DoOnStopRequest(aChannelStatus);
michael@0 457 }
michael@0 458 return true;
michael@0 459 }
michael@0 460
michael@0 461 void
michael@0 462 FTPChannelChild::DoOnStopRequest(const nsresult& aChannelStatus)
michael@0 463 {
michael@0 464 LOG(("FTPChannelChild::RecvOnStopRequest [this=%p status=%u]\n",
michael@0 465 this, aChannelStatus));
michael@0 466
michael@0 467 if (mDivertingToParent) {
michael@0 468 MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
michael@0 469 "Should not be processing any more callbacks from parent!");
michael@0 470
michael@0 471 SendDivertOnStopRequest(aChannelStatus);
michael@0 472 return;
michael@0 473 }
michael@0 474
michael@0 475 if (!mCanceled)
michael@0 476 mStatus = aChannelStatus;
michael@0 477
michael@0 478 { // Ensure that all queued ipdl events are dispatched before
michael@0 479 // we initiate protocol deletion below.
michael@0 480 mIsPending = false;
michael@0 481 AutoEventEnqueuer ensureSerialDispatch(mEventQ);
michael@0 482 (void)mListener->OnStopRequest(this, mListenerContext, aChannelStatus);
michael@0 483 mListener = nullptr;
michael@0 484 mListenerContext = nullptr;
michael@0 485
michael@0 486 if (mLoadGroup)
michael@0 487 mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus);
michael@0 488 }
michael@0 489
michael@0 490 // This calls NeckoChild::DeallocPFTPChannelChild(), which deletes |this| if IPDL
michael@0 491 // holds the last reference. Don't rely on |this| existing after here!
michael@0 492 Send__delete__(this);
michael@0 493 }
michael@0 494
michael@0 495 class FTPFailedAsyncOpenEvent : public ChannelEvent
michael@0 496 {
michael@0 497 public:
michael@0 498 FTPFailedAsyncOpenEvent(FTPChannelChild* aChild, nsresult aStatus)
michael@0 499 : mChild(aChild), mStatus(aStatus) {}
michael@0 500 void Run() { mChild->DoFailedAsyncOpen(mStatus); }
michael@0 501 private:
michael@0 502 FTPChannelChild* mChild;
michael@0 503 nsresult mStatus;
michael@0 504 };
michael@0 505
michael@0 506 bool
michael@0 507 FTPChannelChild::RecvFailedAsyncOpen(const nsresult& statusCode)
michael@0 508 {
michael@0 509 if (mEventQ->ShouldEnqueue()) {
michael@0 510 mEventQ->Enqueue(new FTPFailedAsyncOpenEvent(this, statusCode));
michael@0 511 } else {
michael@0 512 DoFailedAsyncOpen(statusCode);
michael@0 513 }
michael@0 514 return true;
michael@0 515 }
michael@0 516
michael@0 517 void
michael@0 518 FTPChannelChild::DoFailedAsyncOpen(const nsresult& statusCode)
michael@0 519 {
michael@0 520 mStatus = statusCode;
michael@0 521
michael@0 522 if (mLoadGroup)
michael@0 523 mLoadGroup->RemoveRequest(this, nullptr, statusCode);
michael@0 524
michael@0 525 if (mListener) {
michael@0 526 mListener->OnStartRequest(this, mListenerContext);
michael@0 527 mIsPending = false;
michael@0 528 mListener->OnStopRequest(this, mListenerContext, statusCode);
michael@0 529 } else {
michael@0 530 mIsPending = false;
michael@0 531 }
michael@0 532
michael@0 533 mListener = nullptr;
michael@0 534 mListenerContext = nullptr;
michael@0 535
michael@0 536 if (mIPCOpen)
michael@0 537 Send__delete__(this);
michael@0 538 }
michael@0 539
michael@0 540 class FTPFlushedForDiversionEvent : public ChannelEvent
michael@0 541 {
michael@0 542 public:
michael@0 543 FTPFlushedForDiversionEvent(FTPChannelChild* aChild)
michael@0 544 : mChild(aChild)
michael@0 545 {
michael@0 546 MOZ_RELEASE_ASSERT(aChild);
michael@0 547 }
michael@0 548
michael@0 549 void Run()
michael@0 550 {
michael@0 551 mChild->FlushedForDiversion();
michael@0 552 }
michael@0 553 private:
michael@0 554 FTPChannelChild* mChild;
michael@0 555 };
michael@0 556
michael@0 557 bool
michael@0 558 FTPChannelChild::RecvFlushedForDiversion()
michael@0 559 {
michael@0 560 MOZ_ASSERT(mDivertingToParent);
michael@0 561
michael@0 562 if (mEventQ->ShouldEnqueue()) {
michael@0 563 mEventQ->Enqueue(new FTPFlushedForDiversionEvent(this));
michael@0 564 } else {
michael@0 565 MOZ_CRASH();
michael@0 566 }
michael@0 567 return true;
michael@0 568 }
michael@0 569
michael@0 570 void
michael@0 571 FTPChannelChild::FlushedForDiversion()
michael@0 572 {
michael@0 573 MOZ_RELEASE_ASSERT(mDivertingToParent);
michael@0 574
michael@0 575 // Once this is set, it should not be unset before FTPChannelChild is taken
michael@0 576 // down. After it is set, no OnStart/OnData/OnStop callbacks should be
michael@0 577 // received from the parent channel, nor dequeued from the ChannelEventQueue.
michael@0 578 mFlushedForDiversion = true;
michael@0 579
michael@0 580 SendDivertComplete();
michael@0 581 }
michael@0 582
michael@0 583 bool
michael@0 584 FTPChannelChild::RecvDivertMessages()
michael@0 585 {
michael@0 586 MOZ_RELEASE_ASSERT(mDivertingToParent);
michael@0 587 MOZ_RELEASE_ASSERT(mSuspendCount > 0);
michael@0 588
michael@0 589 // DivertTo() has been called on parent, so we can now start sending queued
michael@0 590 // IPDL messages back to parent listener.
michael@0 591 if (NS_WARN_IF(NS_FAILED(Resume()))) {
michael@0 592 return false;
michael@0 593 }
michael@0 594 return true;
michael@0 595 }
michael@0 596
michael@0 597 class FTPDeleteSelfEvent : public ChannelEvent
michael@0 598 {
michael@0 599 public:
michael@0 600 FTPDeleteSelfEvent(FTPChannelChild* aChild)
michael@0 601 : mChild(aChild) {}
michael@0 602 void Run() { mChild->DoDeleteSelf(); }
michael@0 603 private:
michael@0 604 FTPChannelChild* mChild;
michael@0 605 };
michael@0 606
michael@0 607 bool
michael@0 608 FTPChannelChild::RecvDeleteSelf()
michael@0 609 {
michael@0 610 if (mEventQ->ShouldEnqueue()) {
michael@0 611 mEventQ->Enqueue(new FTPDeleteSelfEvent(this));
michael@0 612 } else {
michael@0 613 DoDeleteSelf();
michael@0 614 }
michael@0 615 return true;
michael@0 616 }
michael@0 617
michael@0 618 void
michael@0 619 FTPChannelChild::DoDeleteSelf()
michael@0 620 {
michael@0 621 if (mIPCOpen)
michael@0 622 Send__delete__(this);
michael@0 623 }
michael@0 624
michael@0 625 NS_IMETHODIMP
michael@0 626 FTPChannelChild::Cancel(nsresult status)
michael@0 627 {
michael@0 628 if (mCanceled)
michael@0 629 return NS_OK;
michael@0 630
michael@0 631 mCanceled = true;
michael@0 632 mStatus = status;
michael@0 633 if (mIPCOpen)
michael@0 634 SendCancel(status);
michael@0 635 return NS_OK;
michael@0 636 }
michael@0 637
michael@0 638 NS_IMETHODIMP
michael@0 639 FTPChannelChild::Suspend()
michael@0 640 {
michael@0 641 NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
michael@0 642
michael@0 643 // SendSuspend only once, when suspend goes from 0 to 1.
michael@0 644 // Don't SendSuspend at all if we're diverting callbacks to the parent;
michael@0 645 // suspend will be called at the correct time in the parent itself.
michael@0 646 if (!mSuspendCount++ && !mDivertingToParent) {
michael@0 647 SendSuspend();
michael@0 648 mSuspendSent = true;
michael@0 649 }
michael@0 650 mEventQ->Suspend();
michael@0 651
michael@0 652 return NS_OK;
michael@0 653 }
michael@0 654
michael@0 655 NS_IMETHODIMP
michael@0 656 FTPChannelChild::Resume()
michael@0 657 {
michael@0 658 NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
michael@0 659
michael@0 660 // SendResume only once, when suspend count drops to 0.
michael@0 661 // Don't SendResume at all if we're diverting callbacks to the parent (unless
michael@0 662 // suspend was sent earlier); otherwise, resume will be called at the correct
michael@0 663 // time in the parent itself.
michael@0 664 if (!--mSuspendCount && (!mDivertingToParent || mSuspendSent)) {
michael@0 665 SendResume();
michael@0 666 }
michael@0 667 mEventQ->Resume();
michael@0 668
michael@0 669 return NS_OK;
michael@0 670 }
michael@0 671
michael@0 672 //-----------------------------------------------------------------------------
michael@0 673 // FTPChannelChild::nsIChildChannel
michael@0 674 //-----------------------------------------------------------------------------
michael@0 675
michael@0 676 NS_IMETHODIMP
michael@0 677 FTPChannelChild::ConnectParent(uint32_t id)
michael@0 678 {
michael@0 679 mozilla::dom::TabChild* tabChild = nullptr;
michael@0 680 nsCOMPtr<nsITabChild> iTabChild;
michael@0 681 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
michael@0 682 NS_GET_IID(nsITabChild),
michael@0 683 getter_AddRefs(iTabChild));
michael@0 684 GetCallback(iTabChild);
michael@0 685 if (iTabChild) {
michael@0 686 tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
michael@0 687 }
michael@0 688
michael@0 689 // The socket transport in the chrome process now holds a logical ref to us
michael@0 690 // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
michael@0 691 AddIPDLReference();
michael@0 692
michael@0 693 FTPChannelConnectArgs connectArgs(id);
michael@0 694
michael@0 695 if (!gNeckoChild->SendPFTPChannelConstructor(this, tabChild,
michael@0 696 IPC::SerializedLoadContext(this),
michael@0 697 connectArgs)) {
michael@0 698 return NS_ERROR_FAILURE;
michael@0 699 }
michael@0 700
michael@0 701 return NS_OK;
michael@0 702 }
michael@0 703
michael@0 704 NS_IMETHODIMP
michael@0 705 FTPChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
michael@0 706 nsISupports *aContext)
michael@0 707 {
michael@0 708 LOG(("FTPChannelChild::CompleteRedirectSetup [this=%p]\n", this));
michael@0 709
michael@0 710 NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
michael@0 711 NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
michael@0 712
michael@0 713 mIsPending = true;
michael@0 714 mWasOpened = true;
michael@0 715 mListener = listener;
michael@0 716 mListenerContext = aContext;
michael@0 717
michael@0 718 // add ourselves to the load group.
michael@0 719 if (mLoadGroup)
michael@0 720 mLoadGroup->AddRequest(this, nullptr);
michael@0 721
michael@0 722 // We already have an open IPDL connection to the parent. If on-modify-request
michael@0 723 // listeners or load group observers canceled us, let the parent handle it
michael@0 724 // and send it back to us naturally.
michael@0 725 return NS_OK;
michael@0 726 }
michael@0 727
michael@0 728 //-----------------------------------------------------------------------------
michael@0 729 // FTPChannelChild::nsIDivertableChannel
michael@0 730 //-----------------------------------------------------------------------------
michael@0 731 NS_IMETHODIMP
michael@0 732 FTPChannelChild::DivertToParent(ChannelDiverterChild **aChild)
michael@0 733 {
michael@0 734 MOZ_RELEASE_ASSERT(aChild);
michael@0 735 MOZ_RELEASE_ASSERT(gNeckoChild);
michael@0 736 MOZ_RELEASE_ASSERT(!mDivertingToParent);
michael@0 737
michael@0 738 // We must fail DivertToParent() if there's no parent end of the channel (and
michael@0 739 // won't be!) due to early failure.
michael@0 740 if (NS_FAILED(mStatus) && !mIPCOpen) {
michael@0 741 return mStatus;
michael@0 742 }
michael@0 743
michael@0 744 nsresult rv = Suspend();
michael@0 745 if (NS_WARN_IF(NS_FAILED(rv))) {
michael@0 746 return rv;
michael@0 747 }
michael@0 748
michael@0 749 // Once this is set, it should not be unset before the child is taken down.
michael@0 750 mDivertingToParent = true;
michael@0 751
michael@0 752 PChannelDiverterChild* diverter =
michael@0 753 gNeckoChild->SendPChannelDiverterConstructor(this);
michael@0 754 MOZ_RELEASE_ASSERT(diverter);
michael@0 755
michael@0 756 *aChild = static_cast<ChannelDiverterChild*>(diverter);
michael@0 757
michael@0 758 return NS_OK;
michael@0 759 }
michael@0 760
michael@0 761 } // namespace net
michael@0 762 } // namespace mozilla
michael@0 763

mercurial