mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
c4c18521be
This is probably the worst patch that I have ever written! We add a setPrivate method to nsIPrivateBrowsingChannel which will be implemented by channels who care about private browsing. This allows the client to explicitly override the private bit on the channel. NS_UsePrivateBrowsing is also taught about this override bit using the internal nsIPrivateBrowsingChannel::IsPrivateModeOverriden API. This patch implements the new API for HTTP, FTP and wyciwyg channels. This also modifies the IPC implementations of these channels to correctly transfer that bit to the parent process if it has been set in the child process channel.
573 lines
15 KiB
C++
573 lines
15 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set sw=2 ts=8 et tw=80 : */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "mozilla/net/NeckoChild.h"
|
|
#include "mozilla/net/FTPChannelChild.h"
|
|
#include "nsFtpProtocolHandler.h"
|
|
|
|
#include "nsStringStream.h"
|
|
#include "nsMimeTypes.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsIURIFixup.h"
|
|
#include "nsILoadContext.h"
|
|
#include "nsCDefaultURIFixup.h"
|
|
#include "base/compiler_specific.h"
|
|
#include "mozilla/ipc/InputStreamUtils.h"
|
|
#include "mozilla/ipc/URIUtils.h"
|
|
|
|
using namespace mozilla::ipc;
|
|
|
|
#undef LOG
|
|
#define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
|
|
|
|
namespace mozilla {
|
|
namespace net {
|
|
|
|
FTPChannelChild::FTPChannelChild(nsIURI* uri)
|
|
: mIPCOpen(false)
|
|
, ALLOW_THIS_IN_INITIALIZER_LIST(mEventQ(static_cast<nsIFTPChannel*>(this)))
|
|
, mCanceled(false)
|
|
, mSuspendCount(0)
|
|
, mIsPending(false)
|
|
, mWasOpened(false)
|
|
, mLastModifiedTime(0)
|
|
, mStartPos(0)
|
|
{
|
|
LOG(("Creating FTPChannelChild @%x\n", this));
|
|
// grab a reference to the handler to ensure that it doesn't go away.
|
|
NS_ADDREF(gFtpHandler);
|
|
SetURI(uri);
|
|
}
|
|
|
|
FTPChannelChild::~FTPChannelChild()
|
|
{
|
|
LOG(("Destroying FTPChannelChild @%x\n", this));
|
|
gFtpHandler->Release();
|
|
}
|
|
|
|
void
|
|
FTPChannelChild::AddIPDLReference()
|
|
{
|
|
NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference");
|
|
mIPCOpen = true;
|
|
AddRef();
|
|
}
|
|
|
|
void
|
|
FTPChannelChild::ReleaseIPDLReference()
|
|
{
|
|
NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
|
|
mIPCOpen = false;
|
|
Release();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// FTPChannelChild::nsISupports
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED6(FTPChannelChild,
|
|
nsBaseChannel,
|
|
nsIFTPChannel,
|
|
nsIUploadChannel,
|
|
nsIResumableChannel,
|
|
nsIProxiedChannel,
|
|
nsIChildChannel,
|
|
nsIPrivateBrowsingChannel)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::GetLastModifiedTime(PRTime* lastModifiedTime)
|
|
{
|
|
*lastModifiedTime = mLastModifiedTime;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::SetLastModifiedTime(PRTime lastModifiedTime)
|
|
{
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::ResumeAt(uint64_t aStartPos, const nsACString& aEntityID)
|
|
{
|
|
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
|
mStartPos = aStartPos;
|
|
mEntityID = aEntityID;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::GetEntityID(nsACString& entityID)
|
|
{
|
|
entityID = mEntityID;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::GetProxyInfo(nsIProxyInfo** aProxyInfo)
|
|
{
|
|
DROP_DEAD();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::SetUploadStream(nsIInputStream* stream,
|
|
const nsACString& contentType,
|
|
int32_t contentLength)
|
|
{
|
|
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
|
mUploadStream = stream;
|
|
// NOTE: contentLength is intentionally ignored here.
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::GetUploadStream(nsIInputStream** stream)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(stream);
|
|
*stream = mUploadStream;
|
|
NS_IF_ADDREF(*stream);
|
|
return NS_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext)
|
|
{
|
|
LOG(("FTPChannelChild::AsyncOpen [this=%x]\n", this));
|
|
|
|
NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
|
|
NS_ENSURE_ARG_POINTER(listener);
|
|
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
|
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
|
|
|
|
// Port checked in parent, but duplicate here so we can return with error
|
|
// immediately, as we've done since before e10s.
|
|
nsresult rv;
|
|
rv = NS_CheckPortSafety(nsBaseChannel::URI()); // Need to disambiguate,
|
|
// because in the child ipdl,
|
|
// a typedef URI is defined...
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
// FIXME: like bug 558623, merge constructor+SendAsyncOpen into 1 IPC msg
|
|
gNeckoChild->SendPFTPChannelConstructor(this);
|
|
mListener = listener;
|
|
mListenerContext = aContext;
|
|
|
|
// add ourselves to the load group.
|
|
if (mLoadGroup)
|
|
mLoadGroup->AddRequest(this, nullptr);
|
|
|
|
URIParams uri;
|
|
SerializeURI(nsBaseChannel::URI(), uri);
|
|
|
|
OptionalInputStreamParams uploadStream;
|
|
SerializeInputStream(mUploadStream, uploadStream);
|
|
|
|
SendAsyncOpen(uri, mStartPos, mEntityID, uploadStream,
|
|
IPC::SerializedLoadContext(this));
|
|
|
|
// The socket transport layer in the chrome process now has a logical ref to
|
|
// us until OnStopRequest is called.
|
|
AddIPDLReference();
|
|
|
|
mIsPending = true;
|
|
mWasOpened = true;
|
|
|
|
return rv;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::IsPending(bool* result)
|
|
{
|
|
*result = mIsPending;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
FTPChannelChild::OpenContentStream(bool async,
|
|
nsIInputStream** stream,
|
|
nsIChannel** channel)
|
|
{
|
|
NS_RUNTIMEABORT("FTPChannel*Child* should never have OpenContentStream called!");
|
|
return NS_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// FTPChannelChild::PFTPChannelChild
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class FTPStartRequestEvent : public ChannelEvent
|
|
{
|
|
public:
|
|
FTPStartRequestEvent(FTPChannelChild* aChild, const int32_t& aContentLength,
|
|
const nsCString& aContentType, const PRTime& aLastModified,
|
|
const nsCString& aEntityID, const URIParams& aURI)
|
|
: mChild(aChild), mContentLength(aContentLength), mContentType(aContentType),
|
|
mLastModified(aLastModified), mEntityID(aEntityID), mURI(aURI) {}
|
|
void Run() { mChild->DoOnStartRequest(mContentLength, mContentType,
|
|
mLastModified, mEntityID, mURI); }
|
|
private:
|
|
FTPChannelChild* mChild;
|
|
int32_t mContentLength;
|
|
nsCString mContentType;
|
|
PRTime mLastModified;
|
|
nsCString mEntityID;
|
|
URIParams mURI;
|
|
};
|
|
|
|
bool
|
|
FTPChannelChild::RecvOnStartRequest(const int32_t& aContentLength,
|
|
const nsCString& aContentType,
|
|
const PRTime& aLastModified,
|
|
const nsCString& aEntityID,
|
|
const URIParams& aURI)
|
|
{
|
|
if (mEventQ.ShouldEnqueue()) {
|
|
mEventQ.Enqueue(new FTPStartRequestEvent(this, aContentLength, aContentType,
|
|
aLastModified, aEntityID, aURI));
|
|
} else {
|
|
DoOnStartRequest(aContentLength, aContentType, aLastModified,
|
|
aEntityID, aURI);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
FTPChannelChild::DoOnStartRequest(const int32_t& aContentLength,
|
|
const nsCString& aContentType,
|
|
const PRTime& aLastModified,
|
|
const nsCString& aEntityID,
|
|
const URIParams& aURI)
|
|
{
|
|
LOG(("FTPChannelChild::RecvOnStartRequest [this=%x]\n", this));
|
|
|
|
SetContentLength(aContentLength);
|
|
SetContentType(aContentType);
|
|
mLastModifiedTime = aLastModified;
|
|
mEntityID = aEntityID;
|
|
|
|
nsCString spec;
|
|
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
|
|
uri->GetSpec(spec);
|
|
nsBaseChannel::URI()->SetSpec(spec);
|
|
|
|
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
|
|
nsresult rv = mListener->OnStartRequest(this, mListenerContext);
|
|
if (NS_FAILED(rv))
|
|
Cancel(rv);
|
|
}
|
|
|
|
class FTPDataAvailableEvent : public ChannelEvent
|
|
{
|
|
public:
|
|
FTPDataAvailableEvent(FTPChannelChild* aChild, const nsCString& aData,
|
|
const uint64_t& aOffset, const uint32_t& aCount)
|
|
: mChild(aChild), mData(aData), mOffset(aOffset), mCount(aCount) {}
|
|
void Run() { mChild->DoOnDataAvailable(mData, mOffset, mCount); }
|
|
private:
|
|
FTPChannelChild* mChild;
|
|
nsCString mData;
|
|
uint64_t mOffset;
|
|
uint32_t mCount;
|
|
};
|
|
|
|
bool
|
|
FTPChannelChild::RecvOnDataAvailable(const nsCString& data,
|
|
const uint64_t& offset,
|
|
const uint32_t& count)
|
|
{
|
|
if (mEventQ.ShouldEnqueue()) {
|
|
mEventQ.Enqueue(new FTPDataAvailableEvent(this, data, offset, count));
|
|
} else {
|
|
DoOnDataAvailable(data, offset, count);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
FTPChannelChild::DoOnDataAvailable(const nsCString& data,
|
|
const uint64_t& offset,
|
|
const uint32_t& count)
|
|
{
|
|
LOG(("FTPChannelChild::RecvOnDataAvailable [this=%x]\n", this));
|
|
|
|
if (mCanceled)
|
|
return;
|
|
|
|
// NOTE: the OnDataAvailable contract requires the client to read all the data
|
|
// in the inputstream. This code relies on that ('data' will go away after
|
|
// this function). Apparently the previous, non-e10s behavior was to actually
|
|
// support only reading part of the data, allowing later calls to read the
|
|
// rest.
|
|
nsCOMPtr<nsIInputStream> stringStream;
|
|
nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream),
|
|
data.get(),
|
|
count,
|
|
NS_ASSIGNMENT_DEPEND);
|
|
if (NS_FAILED(rv)) {
|
|
Cancel(rv);
|
|
return;
|
|
}
|
|
|
|
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
|
|
rv = mListener->OnDataAvailable(this, mListenerContext,
|
|
stringStream, offset, count);
|
|
if (NS_FAILED(rv))
|
|
Cancel(rv);
|
|
stringStream->Close();
|
|
}
|
|
|
|
class FTPStopRequestEvent : public ChannelEvent
|
|
{
|
|
public:
|
|
FTPStopRequestEvent(FTPChannelChild* aChild, const nsresult& aStatusCode)
|
|
: mChild(aChild), mStatusCode(aStatusCode) {}
|
|
void Run() { mChild->DoOnStopRequest(mStatusCode); }
|
|
private:
|
|
FTPChannelChild* mChild;
|
|
nsresult mStatusCode;
|
|
};
|
|
|
|
bool
|
|
FTPChannelChild::RecvOnStopRequest(const nsresult& statusCode)
|
|
{
|
|
if (mEventQ.ShouldEnqueue()) {
|
|
mEventQ.Enqueue(new FTPStopRequestEvent(this, statusCode));
|
|
} else {
|
|
DoOnStopRequest(statusCode);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
FTPChannelChild::DoOnStopRequest(const nsresult& statusCode)
|
|
{
|
|
LOG(("FTPChannelChild::RecvOnStopRequest [this=%x status=%u]\n",
|
|
this, statusCode));
|
|
|
|
if (!mCanceled)
|
|
mStatus = statusCode;
|
|
|
|
{ // Ensure that all queued ipdl events are dispatched before
|
|
// we initiate protocol deletion below.
|
|
mIsPending = false;
|
|
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
|
|
(void)mListener->OnStopRequest(this, mListenerContext, statusCode);
|
|
mListener = nullptr;
|
|
mListenerContext = nullptr;
|
|
|
|
if (mLoadGroup)
|
|
mLoadGroup->RemoveRequest(this, nullptr, statusCode);
|
|
}
|
|
|
|
// This calls NeckoChild::DeallocPFTPChannel(), which deletes |this| if IPDL
|
|
// holds the last reference. Don't rely on |this| existing after here!
|
|
Send__delete__(this);
|
|
}
|
|
|
|
class FTPFailedAsyncOpenEvent : public ChannelEvent
|
|
{
|
|
public:
|
|
FTPFailedAsyncOpenEvent(FTPChannelChild* aChild, nsresult aStatus)
|
|
: mChild(aChild), mStatus(aStatus) {}
|
|
void Run() { mChild->DoFailedAsyncOpen(mStatus); }
|
|
private:
|
|
FTPChannelChild* mChild;
|
|
nsresult mStatus;
|
|
};
|
|
|
|
bool
|
|
FTPChannelChild::RecvFailedAsyncOpen(const nsresult& statusCode)
|
|
{
|
|
if (mEventQ.ShouldEnqueue()) {
|
|
mEventQ.Enqueue(new FTPFailedAsyncOpenEvent(this, statusCode));
|
|
} else {
|
|
DoFailedAsyncOpen(statusCode);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
FTPChannelChild::DoFailedAsyncOpen(const nsresult& statusCode)
|
|
{
|
|
mStatus = statusCode;
|
|
|
|
if (mLoadGroup)
|
|
mLoadGroup->RemoveRequest(this, nullptr, statusCode);
|
|
|
|
if (mListener) {
|
|
mListener->OnStartRequest(this, mListenerContext);
|
|
mIsPending = false;
|
|
mListener->OnStopRequest(this, mListenerContext, statusCode);
|
|
} else {
|
|
mIsPending = false;
|
|
}
|
|
|
|
mListener = nullptr;
|
|
mListenerContext = nullptr;
|
|
|
|
if (mIPCOpen)
|
|
Send__delete__(this);
|
|
}
|
|
|
|
class FTPDeleteSelfEvent : public ChannelEvent
|
|
{
|
|
public:
|
|
FTPDeleteSelfEvent(FTPChannelChild* aChild)
|
|
: mChild(aChild) {}
|
|
void Run() { mChild->DoDeleteSelf(); }
|
|
private:
|
|
FTPChannelChild* mChild;
|
|
};
|
|
|
|
bool
|
|
FTPChannelChild::RecvDeleteSelf()
|
|
{
|
|
if (mEventQ.ShouldEnqueue()) {
|
|
mEventQ.Enqueue(new FTPDeleteSelfEvent(this));
|
|
} else {
|
|
DoDeleteSelf();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
FTPChannelChild::DoDeleteSelf()
|
|
{
|
|
if (mIPCOpen)
|
|
Send__delete__(this);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::Cancel(nsresult status)
|
|
{
|
|
if (mCanceled)
|
|
return NS_OK;
|
|
|
|
mCanceled = true;
|
|
mStatus = status;
|
|
if (mIPCOpen)
|
|
SendCancel(status);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::Suspend()
|
|
{
|
|
NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
|
|
if (!mSuspendCount++) {
|
|
SendSuspend();
|
|
mEventQ.Suspend();
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
FTPChannelChild::AsyncCall(void (FTPChannelChild::*funcPtr)(),
|
|
nsRunnableMethod<FTPChannelChild> **retval)
|
|
{
|
|
nsresult rv;
|
|
|
|
nsRefPtr<nsRunnableMethod<FTPChannelChild> > event = NS_NewRunnableMethod(this, funcPtr);
|
|
rv = NS_DispatchToCurrentThread(event);
|
|
if (NS_SUCCEEDED(rv) && retval) {
|
|
*retval = event;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
FTPChannelChild::CompleteResume()
|
|
{
|
|
mEventQ.Resume();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::Resume()
|
|
{
|
|
NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
if (!--mSuspendCount) {
|
|
SendResume();
|
|
AsyncCall(&FTPChannelChild::CompleteResume);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// FTPChannelChild::nsIChildChannel
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::ConnectParent(uint32_t id)
|
|
{
|
|
// The socket transport in the chrome process now holds a logical ref to us
|
|
// until OnStopRequest, or we do a redirect, or we hit an IPDL error.
|
|
AddIPDLReference();
|
|
|
|
if (!gNeckoChild->SendPFTPChannelConstructor(this))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (!SendConnectChannel(id))
|
|
return NS_ERROR_FAILURE;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
|
|
nsISupports *aContext)
|
|
{
|
|
LOG(("FTPChannelChild::CompleteRedirectSetup [this=%x]\n", this));
|
|
|
|
NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
|
|
NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
|
|
|
|
mIsPending = true;
|
|
mWasOpened = true;
|
|
mListener = listener;
|
|
mListenerContext = aContext;
|
|
|
|
// add ourselves to the load group.
|
|
if (mLoadGroup)
|
|
mLoadGroup->AddRequest(this, nullptr);
|
|
|
|
// We already have an open IPDL connection to the parent. If on-modify-request
|
|
// listeners or load group observers canceled us, let the parent handle it
|
|
// and send it back to us naturally.
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
|
|
{
|
|
if (!CanSetCallbacks()) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return nsBaseChannel::SetNotificationCallbacks(aCallbacks);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
FTPChannelChild::SetLoadGroup(nsILoadGroup * aLoadGroup)
|
|
{
|
|
if (!CanSetLoadGroup()) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return nsBaseChannel::SetLoadGroup(aLoadGroup);
|
|
}
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|
|
|