Blame netwerk/protocol/ftp/nsFTPChannel.cpp

Packit f0b94e
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
Packit f0b94e
/* vim:set ts=4 sts=4 sw=4 et cin: */
Packit f0b94e
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit f0b94e
Packit f0b94e
#include "nsFTPChannel.h"
Packit f0b94e
#include "nsFtpConnectionThread.h"  // defines nsFtpState
Packit f0b94e
Packit f0b94e
#include "nsThreadUtils.h"
Packit f0b94e
#include "mozilla/Attributes.h"
Packit f0b94e
Packit f0b94e
using namespace mozilla;
Packit f0b94e
using namespace mozilla::net;
Packit f0b94e
extern LazyLogModule gFTPLog;
Packit f0b94e
Packit f0b94e
// There are two transport connections established for an
Packit f0b94e
// ftp connection. One is used for the command channel , and
Packit f0b94e
// the other for the data channel. The command channel is the first
Packit f0b94e
// connection made and is used to negotiate the second, data, channel.
Packit f0b94e
// The data channel is driven by the command channel and is either
Packit f0b94e
// initiated by the server (PORT command) or by the client (PASV command).
Packit f0b94e
// Client initiation is the most common case and is attempted first.
Packit f0b94e
Packit f0b94e
//-----------------------------------------------------------------------------
Packit f0b94e
Packit f0b94e
NS_IMPL_ISUPPORTS_INHERITED(nsFtpChannel, nsBaseChannel, nsIUploadChannel,
Packit f0b94e
                            nsIResumableChannel, nsIFTPChannel,
Packit f0b94e
                            nsIProxiedChannel, nsIForcePendingChannel,
Packit f0b94e
                            nsIChannelWithDivertableParentListener)
Packit f0b94e
Packit f0b94e
//-----------------------------------------------------------------------------
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::SetUploadStream(nsIInputStream *stream,
Packit f0b94e
                              const nsACString &contentType,
Packit f0b94e
                              int64_t contentLength) {
Packit f0b94e
  NS_ENSURE_TRUE(!Pending(), NS_ERROR_IN_PROGRESS);
Packit f0b94e
Packit f0b94e
  mUploadStream = stream;
Packit f0b94e
Packit f0b94e
  // NOTE: contentLength is intentionally ignored here.
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::GetUploadStream(nsIInputStream **stream) {
Packit f0b94e
  NS_ENSURE_ARG_POINTER(stream);
Packit f0b94e
  *stream = mUploadStream;
Packit f0b94e
  NS_IF_ADDREF(*stream);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
//-----------------------------------------------------------------------------
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::ResumeAt(uint64_t aStartPos, const nsACString &aEntityID) {
Packit f0b94e
  NS_ENSURE_TRUE(!Pending(), NS_ERROR_IN_PROGRESS);
Packit f0b94e
  mEntityID = aEntityID;
Packit f0b94e
  mStartPos = aStartPos;
Packit f0b94e
  mResumeRequested = (mStartPos || !mEntityID.IsEmpty());
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::GetEntityID(nsACString &entityID) {
Packit f0b94e
  if (mEntityID.IsEmpty()) return NS_ERROR_NOT_RESUMABLE;
Packit f0b94e
Packit f0b94e
  entityID = mEntityID;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
//-----------------------------------------------------------------------------
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::GetProxyInfo(nsIProxyInfo **aProxyInfo) {
Packit f0b94e
  *aProxyInfo = ProxyInfo();
Packit f0b94e
  NS_IF_ADDREF(*aProxyInfo);
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
//-----------------------------------------------------------------------------
Packit f0b94e
Packit f0b94e
nsresult nsFtpChannel::OpenContentStream(bool async, nsIInputStream **result,
Packit f0b94e
                                         nsIChannel **channel) {
Packit f0b94e
  if (!async) return NS_ERROR_NOT_IMPLEMENTED;
Packit f0b94e
Packit f0b94e
  nsFtpState *state = new nsFtpState();
Packit f0b94e
  if (!state) return NS_ERROR_OUT_OF_MEMORY;
Packit f0b94e
  NS_ADDREF(state);
Packit f0b94e
Packit f0b94e
  nsresult rv = state->Init(this);
Packit f0b94e
  if (NS_FAILED(rv)) {
Packit f0b94e
    NS_RELEASE(state);
Packit f0b94e
    return rv;
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  *result = state;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool nsFtpChannel::GetStatusArg(nsresult status, nsString &statusArg) {
Packit f0b94e
  nsAutoCString host;
Packit f0b94e
  URI()->GetHost(host);
Packit f0b94e
  CopyUTF8toUTF16(host, statusArg);
Packit f0b94e
  return true;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
void nsFtpChannel::OnCallbacksChanged() { mFTPEventSink = nullptr; }
Packit f0b94e
Packit f0b94e
//-----------------------------------------------------------------------------
Packit f0b94e
Packit f0b94e
namespace {
Packit f0b94e
Packit f0b94e
class FTPEventSinkProxy final : public nsIFTPEventSink {
Packit f0b94e
  ~FTPEventSinkProxy() {}
Packit f0b94e
Packit f0b94e
 public:
Packit f0b94e
  explicit FTPEventSinkProxy(nsIFTPEventSink *aTarget)
Packit f0b94e
      : mTarget(aTarget), mEventTarget(GetCurrentThreadEventTarget()) {}
Packit f0b94e
Packit f0b94e
  NS_DECL_THREADSAFE_ISUPPORTS
Packit f0b94e
  NS_DECL_NSIFTPEVENTSINK
Packit f0b94e
Packit f0b94e
  class OnFTPControlLogRunnable : public Runnable {
Packit f0b94e
   public:
Packit f0b94e
    OnFTPControlLogRunnable(nsIFTPEventSink *aTarget, bool aServer,
Packit f0b94e
                            const char *aMessage)
Packit f0b94e
        : mozilla::Runnable("FTPEventSinkProxy::OnFTPControlLogRunnable"),
Packit f0b94e
          mTarget(aTarget),
Packit f0b94e
          mServer(aServer),
Packit f0b94e
          mMessage(aMessage) {}
Packit f0b94e
Packit f0b94e
    NS_DECL_NSIRUNNABLE
Packit f0b94e
Packit f0b94e
   private:
Packit f0b94e
    nsCOMPtr<nsIFTPEventSink> mTarget;
Packit f0b94e
    bool mServer;
Packit f0b94e
    nsCString mMessage;
Packit f0b94e
  };
Packit f0b94e
Packit f0b94e
 private:
Packit f0b94e
  nsCOMPtr<nsIFTPEventSink> mTarget;
Packit f0b94e
  nsCOMPtr<nsIEventTarget> mEventTarget;
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
NS_IMPL_ISUPPORTS(FTPEventSinkProxy, nsIFTPEventSink)
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
FTPEventSinkProxy::OnFTPControlLog(bool aServer, const char *aMsg) {
Packit f0b94e
  RefPtr<OnFTPControlLogRunnable> r =
Packit f0b94e
      new OnFTPControlLogRunnable(mTarget, aServer, aMsg);
Packit f0b94e
  return mEventTarget->Dispatch(r, NS_DISPATCH_NORMAL);
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
FTPEventSinkProxy::OnFTPControlLogRunnable::Run() {
Packit f0b94e
  mTarget->OnFTPControlLog(mServer, mMessage.get());
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
}  // namespace
Packit f0b94e
Packit f0b94e
void nsFtpChannel::GetFTPEventSink(nsCOMPtr<nsIFTPEventSink> &aResult) {
Packit f0b94e
  if (!mFTPEventSink) {
Packit f0b94e
    nsCOMPtr<nsIFTPEventSink> ftpSink;
Packit f0b94e
    GetCallback(ftpSink);
Packit f0b94e
    if (ftpSink) {
Packit f0b94e
      mFTPEventSink = new FTPEventSinkProxy(ftpSink);
Packit f0b94e
    }
Packit f0b94e
  }
Packit f0b94e
  aResult = mFTPEventSink;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::ForcePending(bool aForcePending) {
Packit f0b94e
  // Set true here so IsPending will return true.
Packit f0b94e
  // Required for callback diversion from child back to parent. In such cases
Packit f0b94e
  // OnStopRequest can be called in the parent before callbacks are diverted
Packit f0b94e
  // back from the child to the listener in the parent.
Packit f0b94e
  mForcePending = aForcePending;
Packit f0b94e
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::IsPending(bool *result) {
Packit f0b94e
  *result = Pending();
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
bool nsFtpChannel::Pending() const {
Packit f0b94e
  return nsBaseChannel::Pending() || mForcePending;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::Suspend() {
Packit f0b94e
  LOG(("nsFtpChannel::Suspend [this=%p]\n", this));
Packit f0b94e
Packit f0b94e
  nsresult rv = nsBaseChannel::Suspend();
Packit f0b94e
Packit f0b94e
  nsresult rvParentChannel = NS_OK;
Packit f0b94e
  if (mParentChannel) {
Packit f0b94e
    rvParentChannel = mParentChannel->SuspendMessageDiversion();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return NS_FAILED(rv) ? rv : rvParentChannel;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::Resume() {
Packit f0b94e
  LOG(("nsFtpChannel::Resume [this=%p]\n", this));
Packit f0b94e
Packit f0b94e
  nsresult rv = nsBaseChannel::Resume();
Packit f0b94e
Packit f0b94e
  nsresult rvParentChannel = NS_OK;
Packit f0b94e
  if (mParentChannel) {
Packit f0b94e
    rvParentChannel = mParentChannel->ResumeMessageDiversion();
Packit f0b94e
  }
Packit f0b94e
Packit f0b94e
  return NS_FAILED(rv) ? rv : rvParentChannel;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
//-----------------------------------------------------------------------------
Packit f0b94e
// AChannelHasDivertableParentChannelAsListener internal functions
Packit f0b94e
//-----------------------------------------------------------------------------
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::MessageDiversionStarted(
Packit f0b94e
    ADivertableParentChannel *aParentChannel) {
Packit f0b94e
  MOZ_ASSERT(!mParentChannel);
Packit f0b94e
  mParentChannel = aParentChannel;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::MessageDiversionStop() {
Packit f0b94e
  LOG(("nsFtpChannel::MessageDiversionStop [this=%p]", this));
Packit f0b94e
  MOZ_ASSERT(mParentChannel);
Packit f0b94e
  mParentChannel = nullptr;
Packit f0b94e
  return NS_OK;
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::SuspendInternal() {
Packit f0b94e
  LOG(("nsFtpChannel::SuspendInternal [this=%p]\n", this));
Packit f0b94e
Packit f0b94e
  return nsBaseChannel::Suspend();
Packit f0b94e
}
Packit f0b94e
Packit f0b94e
NS_IMETHODIMP
Packit f0b94e
nsFtpChannel::ResumeInternal() {
Packit f0b94e
  LOG(("nsFtpChannel::ResumeInternal [this=%p]\n", this));
Packit f0b94e
Packit f0b94e
  return nsBaseChannel::Resume();
Packit f0b94e
}