netwerk/protocol/ftp/FTPChannelChild.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/protocol/ftp/FTPChannelChild.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,763 @@
     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/NeckoChild.h"
    1.12 +#include "mozilla/net/ChannelDiverterChild.h"
    1.13 +#include "mozilla/net/FTPChannelChild.h"
    1.14 +#include "mozilla/dom/TabChild.h"
    1.15 +#include "nsFtpProtocolHandler.h"
    1.16 +#include "nsITabChild.h"
    1.17 +#include "nsStringStream.h"
    1.18 +#include "nsNetUtil.h"
    1.19 +#include "base/compiler_specific.h"
    1.20 +#include "mozilla/ipc/InputStreamUtils.h"
    1.21 +#include "mozilla/ipc/URIUtils.h"
    1.22 +#include "SerializedLoadContext.h"
    1.23 +
    1.24 +using namespace mozilla::ipc;
    1.25 +
    1.26 +#undef LOG
    1.27 +#define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
    1.28 +
    1.29 +namespace mozilla {
    1.30 +namespace net {
    1.31 +
    1.32 +FTPChannelChild::FTPChannelChild(nsIURI* uri)
    1.33 +: mIPCOpen(false)
    1.34 +, mCanceled(false)
    1.35 +, mSuspendCount(0)
    1.36 +, mIsPending(false)
    1.37 +, mWasOpened(false)
    1.38 +, mLastModifiedTime(0)
    1.39 +, mStartPos(0)
    1.40 +, mDivertingToParent(false)
    1.41 +, mFlushedForDiversion(false)
    1.42 +, mSuspendSent(false)
    1.43 +{
    1.44 +  LOG(("Creating FTPChannelChild @%x\n", this));
    1.45 +  // grab a reference to the handler to ensure that it doesn't go away.
    1.46 +  NS_ADDREF(gFtpHandler);
    1.47 +  SetURI(uri);
    1.48 +  mEventQ = new ChannelEventQueue(static_cast<nsIFTPChannel*>(this));
    1.49 +}
    1.50 +
    1.51 +FTPChannelChild::~FTPChannelChild()
    1.52 +{
    1.53 +  LOG(("Destroying FTPChannelChild @%x\n", this));
    1.54 +  gFtpHandler->Release();
    1.55 +}
    1.56 +
    1.57 +void
    1.58 +FTPChannelChild::AddIPDLReference()
    1.59 +{
    1.60 +  NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference");
    1.61 +  mIPCOpen = true;
    1.62 +  AddRef();
    1.63 +}
    1.64 +
    1.65 +void
    1.66 +FTPChannelChild::ReleaseIPDLReference()
    1.67 +{
    1.68 +  NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
    1.69 +  mIPCOpen = false;
    1.70 +  Release();
    1.71 +}
    1.72 +
    1.73 +//-----------------------------------------------------------------------------
    1.74 +// FTPChannelChild::nsISupports
    1.75 +//-----------------------------------------------------------------------------
    1.76 +
    1.77 +NS_IMPL_ISUPPORTS_INHERITED(FTPChannelChild,
    1.78 +                            nsBaseChannel,
    1.79 +                            nsIFTPChannel,
    1.80 +                            nsIUploadChannel,
    1.81 +                            nsIResumableChannel,
    1.82 +                            nsIProxiedChannel,
    1.83 +                            nsIChildChannel,
    1.84 +                            nsIDivertableChannel)
    1.85 +
    1.86 +//-----------------------------------------------------------------------------
    1.87 +
    1.88 +NS_IMETHODIMP
    1.89 +FTPChannelChild::GetLastModifiedTime(PRTime* lastModifiedTime)
    1.90 +{
    1.91 +  *lastModifiedTime = mLastModifiedTime;
    1.92 +  return NS_OK;
    1.93 +}
    1.94 +
    1.95 +NS_IMETHODIMP
    1.96 +FTPChannelChild::SetLastModifiedTime(PRTime lastModifiedTime)
    1.97 +{
    1.98 +  return NS_ERROR_NOT_AVAILABLE;
    1.99 +}
   1.100 +
   1.101 +NS_IMETHODIMP
   1.102 +FTPChannelChild::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID)
   1.103 +{
   1.104 +  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
   1.105 +  mStartPos = aStartPos;
   1.106 +  mEntityID = aEntityID;
   1.107 +  return NS_OK;
   1.108 +}
   1.109 +
   1.110 +NS_IMETHODIMP
   1.111 +FTPChannelChild::GetEntityID(nsACString& entityID)
   1.112 +{
   1.113 +  entityID = mEntityID;
   1.114 +  return NS_OK;
   1.115 +}
   1.116 +
   1.117 +NS_IMETHODIMP
   1.118 +FTPChannelChild::GetProxyInfo(nsIProxyInfo** aProxyInfo)
   1.119 +{
   1.120 +  DROP_DEAD();
   1.121 +}
   1.122 +
   1.123 +NS_IMETHODIMP
   1.124 +FTPChannelChild::SetUploadStream(nsIInputStream* stream,
   1.125 +                                 const nsACString& contentType,
   1.126 +                                 int64_t contentLength)
   1.127 +{
   1.128 +  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
   1.129 +  mUploadStream = stream;
   1.130 +  // NOTE: contentLength is intentionally ignored here.
   1.131 +  return NS_OK;
   1.132 +}
   1.133 +
   1.134 +NS_IMETHODIMP
   1.135 +FTPChannelChild::GetUploadStream(nsIInputStream** stream)
   1.136 +{
   1.137 +  NS_ENSURE_ARG_POINTER(stream);
   1.138 +  *stream = mUploadStream;
   1.139 +  NS_IF_ADDREF(*stream);
   1.140 +  return NS_OK;
   1.141 +}
   1.142 +
   1.143 +//-----------------------------------------------------------------------------
   1.144 +
   1.145 +NS_IMETHODIMP
   1.146 +FTPChannelChild::AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext)
   1.147 +{
   1.148 +  LOG(("FTPChannelChild::AsyncOpen [this=%p]\n", this));
   1.149 +
   1.150 +  NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
   1.151 +  NS_ENSURE_ARG_POINTER(listener);
   1.152 +  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
   1.153 +  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
   1.154 +
   1.155 +  // Port checked in parent, but duplicate here so we can return with error
   1.156 +  // immediately, as we've done since before e10s.
   1.157 +  nsresult rv;
   1.158 +  rv = NS_CheckPortSafety(nsBaseChannel::URI()); // Need to disambiguate,
   1.159 +                                                 // because in the child ipdl,
   1.160 +                                                 // a typedef URI is defined...
   1.161 +  if (NS_FAILED(rv))
   1.162 +    return rv;
   1.163 +
   1.164 +  mozilla::dom::TabChild* tabChild = nullptr;
   1.165 +  nsCOMPtr<nsITabChild> iTabChild;
   1.166 +  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
   1.167 +                                NS_GET_IID(nsITabChild),
   1.168 +                                getter_AddRefs(iTabChild));
   1.169 +  GetCallback(iTabChild);
   1.170 +  if (iTabChild) {
   1.171 +    tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
   1.172 +  }
   1.173 +  if (MissingRequiredTabChild(tabChild, "ftp")) {
   1.174 +    return NS_ERROR_ILLEGAL_VALUE;
   1.175 +  }
   1.176 +
   1.177 +  mListener = listener;
   1.178 +  mListenerContext = aContext;
   1.179 +
   1.180 +  // add ourselves to the load group. 
   1.181 +  if (mLoadGroup)
   1.182 +    mLoadGroup->AddRequest(this, nullptr);
   1.183 +
   1.184 +  OptionalInputStreamParams uploadStream;
   1.185 +  nsTArray<mozilla::ipc::FileDescriptor> fds;
   1.186 +  SerializeInputStream(mUploadStream, uploadStream, fds);
   1.187 +
   1.188 +  MOZ_ASSERT(fds.IsEmpty());
   1.189 +
   1.190 +  FTPChannelOpenArgs openArgs;
   1.191 +  SerializeURI(nsBaseChannel::URI(), openArgs.uri());
   1.192 +  openArgs.startPos() = mStartPos;
   1.193 +  openArgs.entityID() = mEntityID;
   1.194 +  openArgs.uploadStream() = uploadStream;
   1.195 +
   1.196 +  gNeckoChild->
   1.197 +    SendPFTPChannelConstructor(this, tabChild, IPC::SerializedLoadContext(this),
   1.198 +                               openArgs);
   1.199 +
   1.200 +  // The socket transport layer in the chrome process now has a logical ref to
   1.201 +  // us until OnStopRequest is called.
   1.202 +  AddIPDLReference();
   1.203 +
   1.204 +  mIsPending = true;
   1.205 +  mWasOpened = true;
   1.206 +
   1.207 +  return rv;
   1.208 +}
   1.209 +
   1.210 +NS_IMETHODIMP
   1.211 +FTPChannelChild::IsPending(bool* result)
   1.212 +{
   1.213 +  *result = mIsPending;
   1.214 +  return NS_OK;
   1.215 +}
   1.216 +
   1.217 +nsresult
   1.218 +FTPChannelChild::OpenContentStream(bool async,
   1.219 +                                   nsIInputStream** stream,
   1.220 +                                   nsIChannel** channel)
   1.221 +{
   1.222 +  NS_RUNTIMEABORT("FTPChannel*Child* should never have OpenContentStream called!");
   1.223 +  return NS_OK;
   1.224 +}
   1.225 +  
   1.226 +//-----------------------------------------------------------------------------
   1.227 +// FTPChannelChild::PFTPChannelChild
   1.228 +//-----------------------------------------------------------------------------
   1.229 +
   1.230 +class FTPStartRequestEvent : public ChannelEvent
   1.231 +{
   1.232 +public:
   1.233 +  FTPStartRequestEvent(FTPChannelChild* aChild,
   1.234 +                       const nsresult& aChannelStatus,
   1.235 +                       const int64_t& aContentLength,
   1.236 +                       const nsCString& aContentType,
   1.237 +                       const PRTime& aLastModified,
   1.238 +                       const nsCString& aEntityID,
   1.239 +                       const URIParams& aURI)
   1.240 +    : mChild(aChild)
   1.241 +    , mChannelStatus(aChannelStatus)
   1.242 +    , mContentLength(aContentLength)
   1.243 +    , mContentType(aContentType)
   1.244 +    , mLastModified(aLastModified)
   1.245 +    , mEntityID(aEntityID)
   1.246 +    , mURI(aURI)
   1.247 +  {
   1.248 +  }
   1.249 +  void Run()
   1.250 +  {
   1.251 +    mChild->DoOnStartRequest(mChannelStatus, mContentLength, mContentType,
   1.252 +                             mLastModified, mEntityID, mURI);
   1.253 +  }
   1.254 +
   1.255 +private:
   1.256 +  FTPChannelChild* mChild;
   1.257 +  nsresult mChannelStatus;
   1.258 +  int64_t mContentLength;
   1.259 +  nsCString mContentType;
   1.260 +  PRTime mLastModified;
   1.261 +  nsCString mEntityID;
   1.262 +  URIParams mURI;
   1.263 +};
   1.264 +
   1.265 +bool
   1.266 +FTPChannelChild::RecvOnStartRequest(const nsresult& aChannelStatus,
   1.267 +                                    const int64_t& aContentLength,
   1.268 +                                    const nsCString& aContentType,
   1.269 +                                    const PRTime& aLastModified,
   1.270 +                                    const nsCString& aEntityID,
   1.271 +                                    const URIParams& aURI)
   1.272 +{
   1.273 +  // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
   1.274 +  // stage, as they are set in the listener's OnStartRequest.
   1.275 +  MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.276 +    "mFlushedForDiversion should be unset before OnStartRequest!");
   1.277 +  MOZ_RELEASE_ASSERT(!mDivertingToParent,
   1.278 +    "mDivertingToParent should be unset before OnStartRequest!");
   1.279 +
   1.280 +  if (mEventQ->ShouldEnqueue()) {
   1.281 +    mEventQ->Enqueue(new FTPStartRequestEvent(this, aChannelStatus,
   1.282 +                                              aContentLength, aContentType,
   1.283 +                                              aLastModified, aEntityID, aURI));
   1.284 +  } else {
   1.285 +    DoOnStartRequest(aChannelStatus, aContentLength, aContentType,
   1.286 +                     aLastModified, aEntityID, aURI);
   1.287 +  }
   1.288 +  return true;
   1.289 +}
   1.290 +
   1.291 +void
   1.292 +FTPChannelChild::DoOnStartRequest(const nsresult& aChannelStatus,
   1.293 +                                  const int64_t& aContentLength,
   1.294 +                                  const nsCString& aContentType,
   1.295 +                                  const PRTime& aLastModified,
   1.296 +                                  const nsCString& aEntityID,
   1.297 +                                  const URIParams& aURI)
   1.298 +{
   1.299 +  LOG(("FTPChannelChild::RecvOnStartRequest [this=%p]\n", this));
   1.300 +
   1.301 +  // mFlushedForDiversion and mDivertingToParent should NEVER be set at this
   1.302 +  // stage, as they are set in the listener's OnStartRequest.
   1.303 +  MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.304 +    "mFlushedForDiversion should be unset before OnStartRequest!");
   1.305 +  MOZ_RELEASE_ASSERT(!mDivertingToParent,
   1.306 +    "mDivertingToParent should be unset before OnStartRequest!");
   1.307 +
   1.308 +  if (!mCanceled && NS_SUCCEEDED(mStatus)) {
   1.309 +    mStatus = aChannelStatus;
   1.310 +  }
   1.311 +
   1.312 +  mContentLength = aContentLength;
   1.313 +  SetContentType(aContentType);
   1.314 +  mLastModifiedTime = aLastModified;
   1.315 +  mEntityID = aEntityID;
   1.316 +
   1.317 +  nsCString spec;
   1.318 +  nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
   1.319 +  uri->GetSpec(spec);
   1.320 +  nsBaseChannel::URI()->SetSpec(spec);
   1.321 +
   1.322 +  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
   1.323 +  nsresult rv = mListener->OnStartRequest(this, mListenerContext);
   1.324 +  if (NS_FAILED(rv))
   1.325 +    Cancel(rv);
   1.326 +
   1.327 +  if (mDivertingToParent) {
   1.328 +    mListener = nullptr;
   1.329 +    mListenerContext = nullptr;
   1.330 +    if (mLoadGroup) {
   1.331 +      mLoadGroup->RemoveRequest(this, nullptr, mStatus);
   1.332 +    }
   1.333 +  }
   1.334 +}
   1.335 +
   1.336 +class FTPDataAvailableEvent : public ChannelEvent
   1.337 +{
   1.338 +public:
   1.339 +  FTPDataAvailableEvent(FTPChannelChild* aChild,
   1.340 +                        const nsresult& aChannelStatus,
   1.341 +                        const nsCString& aData,
   1.342 +                        const uint64_t& aOffset,
   1.343 +                        const uint32_t& aCount)
   1.344 +    : mChild(aChild)
   1.345 +    , mChannelStatus(aChannelStatus)
   1.346 +    , mData(aData)
   1.347 +    , mOffset(aOffset)
   1.348 +    , mCount(aCount)
   1.349 +  {
   1.350 +  }
   1.351 +  void Run()
   1.352 +  {
   1.353 +    mChild->DoOnDataAvailable(mChannelStatus, mData, mOffset, mCount);
   1.354 +  }
   1.355 +
   1.356 +private:
   1.357 +  FTPChannelChild* mChild;
   1.358 +  nsresult mChannelStatus;
   1.359 +  nsCString mData;
   1.360 +  uint64_t mOffset;
   1.361 +  uint32_t mCount;
   1.362 +};
   1.363 +
   1.364 +bool
   1.365 +FTPChannelChild::RecvOnDataAvailable(const nsresult& channelStatus,
   1.366 +                                     const nsCString& data,
   1.367 +                                     const uint64_t& offset,
   1.368 +                                     const uint32_t& count)
   1.369 +{
   1.370 +  MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.371 +                     "Should not be receiving any more callbacks from parent!");
   1.372 +
   1.373 +  if (mEventQ->ShouldEnqueue()) {
   1.374 +    mEventQ->Enqueue(
   1.375 +      new FTPDataAvailableEvent(this, channelStatus, data, offset, count));
   1.376 +  } else {
   1.377 +    MOZ_RELEASE_ASSERT(!mDivertingToParent,
   1.378 +                       "ShouldEnqueue when diverting to parent!");
   1.379 +
   1.380 +    DoOnDataAvailable(channelStatus, data, offset, count);
   1.381 +  }
   1.382 +  return true;
   1.383 +}
   1.384 +
   1.385 +void
   1.386 +FTPChannelChild::DoOnDataAvailable(const nsresult& channelStatus,
   1.387 +                                   const nsCString& data,
   1.388 +                                   const uint64_t& offset,
   1.389 +                                   const uint32_t& count)
   1.390 +{
   1.391 +  LOG(("FTPChannelChild::RecvOnDataAvailable [this=%p]\n", this));
   1.392 +
   1.393 +  if (!mCanceled && NS_SUCCEEDED(mStatus)) {
   1.394 +    mStatus = channelStatus;
   1.395 +  }
   1.396 +
   1.397 +  if (mDivertingToParent) {
   1.398 +    MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.399 +      "Should not be processing any more callbacks from parent!");
   1.400 +
   1.401 +    SendDivertOnDataAvailable(data, offset, count);
   1.402 +    return;
   1.403 +  }
   1.404 +
   1.405 +  if (mCanceled)
   1.406 +    return;
   1.407 +
   1.408 +  // NOTE: the OnDataAvailable contract requires the client to read all the data
   1.409 +  // in the inputstream.  This code relies on that ('data' will go away after
   1.410 +  // this function).  Apparently the previous, non-e10s behavior was to actually
   1.411 +  // support only reading part of the data, allowing later calls to read the
   1.412 +  // rest.
   1.413 +  nsCOMPtr<nsIInputStream> stringStream;
   1.414 +  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream),
   1.415 +                                      data.get(),
   1.416 +                                      count,
   1.417 +                                      NS_ASSIGNMENT_DEPEND);
   1.418 +  if (NS_FAILED(rv)) {
   1.419 +    Cancel(rv);
   1.420 +    return;
   1.421 +  }
   1.422 +
   1.423 +  AutoEventEnqueuer ensureSerialDispatch(mEventQ);
   1.424 +  rv = mListener->OnDataAvailable(this, mListenerContext,
   1.425 +                                  stringStream, offset, count);
   1.426 +  if (NS_FAILED(rv))
   1.427 +    Cancel(rv);
   1.428 +  stringStream->Close();
   1.429 +}
   1.430 +
   1.431 +class FTPStopRequestEvent : public ChannelEvent
   1.432 +{
   1.433 +public:
   1.434 +  FTPStopRequestEvent(FTPChannelChild* aChild,
   1.435 +                      const nsresult& aChannelStatus)
   1.436 +    : mChild(aChild)
   1.437 +    , mChannelStatus(aChannelStatus)
   1.438 +  {
   1.439 +  }
   1.440 +  void Run()
   1.441 +  {
   1.442 +    mChild->DoOnStopRequest(mChannelStatus);
   1.443 +  }
   1.444 +
   1.445 +private:
   1.446 +  FTPChannelChild* mChild;
   1.447 +  nsresult mChannelStatus;
   1.448 +};
   1.449 +
   1.450 +bool
   1.451 +FTPChannelChild::RecvOnStopRequest(const nsresult& aChannelStatus)
   1.452 +{
   1.453 +  MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.454 +    "Should not be receiving any more callbacks from parent!");
   1.455 +
   1.456 +  if (mEventQ->ShouldEnqueue()) {
   1.457 +    mEventQ->Enqueue(new FTPStopRequestEvent(this, aChannelStatus));
   1.458 +  } else {
   1.459 +    DoOnStopRequest(aChannelStatus);
   1.460 +  }
   1.461 +  return true;
   1.462 +}
   1.463 +
   1.464 +void
   1.465 +FTPChannelChild::DoOnStopRequest(const nsresult& aChannelStatus)
   1.466 +{
   1.467 +  LOG(("FTPChannelChild::RecvOnStopRequest [this=%p status=%u]\n",
   1.468 +       this, aChannelStatus));
   1.469 +
   1.470 +  if (mDivertingToParent) {
   1.471 +    MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
   1.472 +      "Should not be processing any more callbacks from parent!");
   1.473 +
   1.474 +    SendDivertOnStopRequest(aChannelStatus);
   1.475 +    return;
   1.476 +  }
   1.477 +
   1.478 +  if (!mCanceled)
   1.479 +    mStatus = aChannelStatus;
   1.480 +
   1.481 +  { // Ensure that all queued ipdl events are dispatched before
   1.482 +    // we initiate protocol deletion below.
   1.483 +    mIsPending = false;
   1.484 +    AutoEventEnqueuer ensureSerialDispatch(mEventQ);
   1.485 +    (void)mListener->OnStopRequest(this, mListenerContext, aChannelStatus);
   1.486 +    mListener = nullptr;
   1.487 +    mListenerContext = nullptr;
   1.488 +
   1.489 +    if (mLoadGroup)
   1.490 +      mLoadGroup->RemoveRequest(this, nullptr, aChannelStatus);
   1.491 +  }
   1.492 +
   1.493 +  // This calls NeckoChild::DeallocPFTPChannelChild(), which deletes |this| if IPDL
   1.494 +  // holds the last reference.  Don't rely on |this| existing after here!
   1.495 +  Send__delete__(this);
   1.496 +}
   1.497 +
   1.498 +class FTPFailedAsyncOpenEvent : public ChannelEvent
   1.499 +{
   1.500 + public:
   1.501 +  FTPFailedAsyncOpenEvent(FTPChannelChild* aChild, nsresult aStatus)
   1.502 +  : mChild(aChild), mStatus(aStatus) {}
   1.503 +  void Run() { mChild->DoFailedAsyncOpen(mStatus); }
   1.504 + private:
   1.505 +  FTPChannelChild* mChild;
   1.506 +  nsresult mStatus;
   1.507 +};
   1.508 +
   1.509 +bool
   1.510 +FTPChannelChild::RecvFailedAsyncOpen(const nsresult& statusCode)
   1.511 +{
   1.512 +  if (mEventQ->ShouldEnqueue()) {
   1.513 +    mEventQ->Enqueue(new FTPFailedAsyncOpenEvent(this, statusCode));
   1.514 +  } else {
   1.515 +    DoFailedAsyncOpen(statusCode);
   1.516 +  }
   1.517 +  return true;
   1.518 +}
   1.519 +
   1.520 +void
   1.521 +FTPChannelChild::DoFailedAsyncOpen(const nsresult& statusCode)
   1.522 +{
   1.523 +  mStatus = statusCode;
   1.524 +
   1.525 +  if (mLoadGroup)
   1.526 +    mLoadGroup->RemoveRequest(this, nullptr, statusCode);
   1.527 +
   1.528 +  if (mListener) {
   1.529 +    mListener->OnStartRequest(this, mListenerContext);
   1.530 +    mIsPending = false;
   1.531 +    mListener->OnStopRequest(this, mListenerContext, statusCode);
   1.532 +  } else {
   1.533 +    mIsPending = false;
   1.534 +  }
   1.535 +
   1.536 +  mListener = nullptr;
   1.537 +  mListenerContext = nullptr;
   1.538 +
   1.539 +  if (mIPCOpen)
   1.540 +    Send__delete__(this);
   1.541 +}
   1.542 +
   1.543 +class FTPFlushedForDiversionEvent : public ChannelEvent
   1.544 +{
   1.545 + public:
   1.546 +  FTPFlushedForDiversionEvent(FTPChannelChild* aChild)
   1.547 +  : mChild(aChild)
   1.548 +  {
   1.549 +    MOZ_RELEASE_ASSERT(aChild);
   1.550 +  }
   1.551 +
   1.552 +  void Run()
   1.553 +  {
   1.554 +    mChild->FlushedForDiversion();
   1.555 +  }
   1.556 + private:
   1.557 +  FTPChannelChild* mChild;
   1.558 +};
   1.559 +
   1.560 +bool
   1.561 +FTPChannelChild::RecvFlushedForDiversion()
   1.562 +{
   1.563 +  MOZ_ASSERT(mDivertingToParent);
   1.564 +
   1.565 +  if (mEventQ->ShouldEnqueue()) {
   1.566 +    mEventQ->Enqueue(new FTPFlushedForDiversionEvent(this));
   1.567 +  } else {
   1.568 +    MOZ_CRASH();
   1.569 +  }
   1.570 +  return true;
   1.571 +}
   1.572 +
   1.573 +void
   1.574 +FTPChannelChild::FlushedForDiversion()
   1.575 +{
   1.576 +  MOZ_RELEASE_ASSERT(mDivertingToParent);
   1.577 +
   1.578 +  // Once this is set, it should not be unset before FTPChannelChild is taken
   1.579 +  // down. After it is set, no OnStart/OnData/OnStop callbacks should be
   1.580 +  // received from the parent channel, nor dequeued from the ChannelEventQueue.
   1.581 +  mFlushedForDiversion = true;
   1.582 +
   1.583 +  SendDivertComplete();
   1.584 +}
   1.585 +
   1.586 +bool
   1.587 +FTPChannelChild::RecvDivertMessages()
   1.588 +{
   1.589 +  MOZ_RELEASE_ASSERT(mDivertingToParent);
   1.590 +  MOZ_RELEASE_ASSERT(mSuspendCount > 0);
   1.591 +
   1.592 +  // DivertTo() has been called on parent, so we can now start sending queued
   1.593 +  // IPDL messages back to parent listener.
   1.594 +  if (NS_WARN_IF(NS_FAILED(Resume()))) {
   1.595 +    return false;
   1.596 +  }
   1.597 +  return true;
   1.598 +}
   1.599 +
   1.600 +class FTPDeleteSelfEvent : public ChannelEvent
   1.601 +{
   1.602 + public:
   1.603 +  FTPDeleteSelfEvent(FTPChannelChild* aChild)
   1.604 +  : mChild(aChild) {}
   1.605 +  void Run() { mChild->DoDeleteSelf(); }
   1.606 + private:
   1.607 +  FTPChannelChild* mChild;
   1.608 +};
   1.609 +
   1.610 +bool
   1.611 +FTPChannelChild::RecvDeleteSelf()
   1.612 +{
   1.613 +  if (mEventQ->ShouldEnqueue()) {
   1.614 +    mEventQ->Enqueue(new FTPDeleteSelfEvent(this));
   1.615 +  } else {
   1.616 +    DoDeleteSelf();
   1.617 +  }
   1.618 +  return true;
   1.619 +}
   1.620 +
   1.621 +void
   1.622 +FTPChannelChild::DoDeleteSelf()
   1.623 +{
   1.624 +  if (mIPCOpen)
   1.625 +    Send__delete__(this);
   1.626 +}
   1.627 +
   1.628 +NS_IMETHODIMP
   1.629 +FTPChannelChild::Cancel(nsresult status)
   1.630 +{
   1.631 +  if (mCanceled)
   1.632 +    return NS_OK;
   1.633 +
   1.634 +  mCanceled = true;
   1.635 +  mStatus = status;
   1.636 +  if (mIPCOpen)
   1.637 +    SendCancel(status);
   1.638 +  return NS_OK;
   1.639 +}
   1.640 +
   1.641 +NS_IMETHODIMP
   1.642 +FTPChannelChild::Suspend()
   1.643 +{
   1.644 +  NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
   1.645 +
   1.646 +  // SendSuspend only once, when suspend goes from 0 to 1.
   1.647 +  // Don't SendSuspend at all if we're diverting callbacks to the parent;
   1.648 +  // suspend will be called at the correct time in the parent itself.
   1.649 +  if (!mSuspendCount++ && !mDivertingToParent) {
   1.650 +    SendSuspend();
   1.651 +    mSuspendSent = true;
   1.652 +  }
   1.653 +  mEventQ->Suspend();
   1.654 +
   1.655 +  return NS_OK;
   1.656 +}
   1.657 +
   1.658 +NS_IMETHODIMP
   1.659 +FTPChannelChild::Resume()
   1.660 +{
   1.661 +  NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
   1.662 +
   1.663 +  // SendResume only once, when suspend count drops to 0.
   1.664 +  // Don't SendResume at all if we're diverting callbacks to the parent (unless
   1.665 +  // suspend was sent earlier); otherwise, resume will be called at the correct
   1.666 +  // time in the parent itself.
   1.667 +  if (!--mSuspendCount && (!mDivertingToParent || mSuspendSent)) {
   1.668 +    SendResume();
   1.669 +  }
   1.670 +  mEventQ->Resume();
   1.671 +
   1.672 +  return NS_OK;
   1.673 +}
   1.674 +
   1.675 +//-----------------------------------------------------------------------------
   1.676 +// FTPChannelChild::nsIChildChannel
   1.677 +//-----------------------------------------------------------------------------
   1.678 +
   1.679 +NS_IMETHODIMP
   1.680 +FTPChannelChild::ConnectParent(uint32_t id)
   1.681 +{
   1.682 +  mozilla::dom::TabChild* tabChild = nullptr;
   1.683 +  nsCOMPtr<nsITabChild> iTabChild;
   1.684 +  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
   1.685 +                                NS_GET_IID(nsITabChild),
   1.686 +                                getter_AddRefs(iTabChild));
   1.687 +  GetCallback(iTabChild);
   1.688 +  if (iTabChild) {
   1.689 +    tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
   1.690 +  }
   1.691 +
   1.692 +  // The socket transport in the chrome process now holds a logical ref to us
   1.693 +  // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
   1.694 +  AddIPDLReference();
   1.695 +
   1.696 +  FTPChannelConnectArgs connectArgs(id);
   1.697 +
   1.698 +  if (!gNeckoChild->SendPFTPChannelConstructor(this, tabChild,
   1.699 +                                               IPC::SerializedLoadContext(this),
   1.700 +                                               connectArgs)) {
   1.701 +    return NS_ERROR_FAILURE;
   1.702 +  }
   1.703 +
   1.704 +  return NS_OK;
   1.705 +}
   1.706 +
   1.707 +NS_IMETHODIMP
   1.708 +FTPChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
   1.709 +                                       nsISupports *aContext)
   1.710 +{
   1.711 +  LOG(("FTPChannelChild::CompleteRedirectSetup [this=%p]\n", this));
   1.712 +
   1.713 +  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
   1.714 +  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
   1.715 +
   1.716 +  mIsPending = true;
   1.717 +  mWasOpened = true;
   1.718 +  mListener = listener;
   1.719 +  mListenerContext = aContext;
   1.720 +
   1.721 +  // add ourselves to the load group.
   1.722 +  if (mLoadGroup)
   1.723 +    mLoadGroup->AddRequest(this, nullptr);
   1.724 +
   1.725 +  // We already have an open IPDL connection to the parent. If on-modify-request
   1.726 +  // listeners or load group observers canceled us, let the parent handle it
   1.727 +  // and send it back to us naturally.
   1.728 +  return NS_OK;
   1.729 +}
   1.730 +
   1.731 +//-----------------------------------------------------------------------------
   1.732 +// FTPChannelChild::nsIDivertableChannel
   1.733 +//-----------------------------------------------------------------------------
   1.734 +NS_IMETHODIMP
   1.735 +FTPChannelChild::DivertToParent(ChannelDiverterChild **aChild)
   1.736 +{
   1.737 +  MOZ_RELEASE_ASSERT(aChild);
   1.738 +  MOZ_RELEASE_ASSERT(gNeckoChild);
   1.739 +  MOZ_RELEASE_ASSERT(!mDivertingToParent);
   1.740 +
   1.741 +  // We must fail DivertToParent() if there's no parent end of the channel (and
   1.742 +  // won't be!) due to early failure.
   1.743 +  if (NS_FAILED(mStatus) && !mIPCOpen) {
   1.744 +    return mStatus;
   1.745 +  }
   1.746 +
   1.747 +  nsresult rv = Suspend();
   1.748 +  if (NS_WARN_IF(NS_FAILED(rv))) {
   1.749 +    return rv;
   1.750 +  }
   1.751 +
   1.752 +  // Once this is set, it should not be unset before the child is taken down.
   1.753 +  mDivertingToParent = true;
   1.754 +
   1.755 +  PChannelDiverterChild* diverter =
   1.756 +    gNeckoChild->SendPChannelDiverterConstructor(this);
   1.757 +  MOZ_RELEASE_ASSERT(diverter);
   1.758 +
   1.759 +  *aChild = static_cast<ChannelDiverterChild*>(diverter);
   1.760 +
   1.761 +  return NS_OK;
   1.762 +}
   1.763 +
   1.764 +} // namespace net
   1.765 +} // namespace mozilla
   1.766 +

mercurial