зеркало из https://github.com/mozilla/gecko-dev.git
480 строки
13 KiB
C++
480 строки
13 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=2 et sw=2 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/DebugOnly.h"
|
|
|
|
#include "ExternalHelperAppParent.h"
|
|
#include "nsIContent.h"
|
|
#include "nsCExternalHandlerService.h"
|
|
#include "nsIExternalHelperAppService.h"
|
|
#include "mozilla/dom/ContentParent.h"
|
|
#include "mozilla/dom/Element.h"
|
|
#include "mozilla/dom/TabParent.h"
|
|
#include "nsIBrowserDOMWindow.h"
|
|
#include "nsStringStream.h"
|
|
#include "mozilla/ipc/URIUtils.h"
|
|
#include "nsNetUtil.h"
|
|
#include "nsIDocument.h"
|
|
#include "mozilla/net/ChannelDiverterParent.h"
|
|
|
|
#include "mozilla/Unused.h"
|
|
|
|
using namespace mozilla::ipc;
|
|
|
|
namespace mozilla {
|
|
namespace dom {
|
|
|
|
NS_IMPL_ISUPPORTS_INHERITED(ExternalHelperAppParent, nsHashPropertyBag,
|
|
nsIRequest, nsIChannel, nsIMultiPartChannel,
|
|
nsIPrivateBrowsingChannel, nsIResumableChannel,
|
|
nsIStreamListener, nsIExternalHelperAppParent)
|
|
|
|
ExternalHelperAppParent::ExternalHelperAppParent(
|
|
const OptionalURIParams& uri, const int64_t& aContentLength,
|
|
const bool& aWasFileChannel, const nsCString& aContentDispositionHeader,
|
|
const uint32_t& aContentDispositionHint,
|
|
const nsString& aContentDispositionFilename)
|
|
: mURI(DeserializeURI(uri)),
|
|
mPending(false)
|
|
#ifdef DEBUG
|
|
,
|
|
mDiverted(false)
|
|
#endif
|
|
,
|
|
mIPCClosed(false),
|
|
mLoadFlags(0),
|
|
mStatus(NS_OK),
|
|
mContentLength(aContentLength),
|
|
mWasFileChannel(aWasFileChannel) {
|
|
mContentDispositionHeader = aContentDispositionHeader;
|
|
if (!mContentDispositionHeader.IsEmpty()) {
|
|
NS_GetFilenameFromDisposition(mContentDispositionFilename,
|
|
mContentDispositionHeader, mURI);
|
|
mContentDisposition =
|
|
NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
|
|
} else {
|
|
mContentDisposition = aContentDispositionHint;
|
|
mContentDispositionFilename = aContentDispositionFilename;
|
|
}
|
|
}
|
|
|
|
already_AddRefed<nsIInterfaceRequestor> GetWindowFromTabParent(
|
|
PBrowserParent* aBrowser) {
|
|
if (!aBrowser) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> window;
|
|
TabParent* tabParent = TabParent::GetFrom(aBrowser);
|
|
if (tabParent->GetOwnerElement()) {
|
|
window = do_QueryInterface(
|
|
tabParent->GetOwnerElement()->OwnerDoc()->GetWindow());
|
|
}
|
|
|
|
return window.forget();
|
|
}
|
|
|
|
void UpdateContentContext(nsIStreamListener* aListener,
|
|
PBrowserParent* aBrowser) {
|
|
MOZ_ASSERT(aListener);
|
|
nsCOMPtr<nsIInterfaceRequestor> window = GetWindowFromTabParent(aBrowser);
|
|
static_cast<nsExternalAppHandler*>(aListener)->SetContentContext(window);
|
|
}
|
|
|
|
void ExternalHelperAppParent::Init(ContentParent* parent,
|
|
const nsCString& aMimeContentType,
|
|
const bool& aForceSave,
|
|
const OptionalURIParams& aReferrer,
|
|
PBrowserParent* aBrowser) {
|
|
nsCOMPtr<nsIExternalHelperAppService> helperAppService =
|
|
do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID);
|
|
NS_ASSERTION(helperAppService, "No Helper App Service!");
|
|
|
|
nsCOMPtr<nsIURI> referrer = DeserializeURI(aReferrer);
|
|
if (referrer)
|
|
SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
|
|
referrer);
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> window;
|
|
if (aBrowser) {
|
|
TabParent* tabParent = TabParent::GetFrom(aBrowser);
|
|
if (tabParent->GetOwnerElement())
|
|
window = do_QueryInterface(
|
|
tabParent->GetOwnerElement()->OwnerDoc()->GetWindow());
|
|
|
|
bool isPrivate = false;
|
|
nsCOMPtr<nsILoadContext> loadContext = tabParent->GetLoadContext();
|
|
loadContext->GetUsePrivateBrowsing(&isPrivate);
|
|
SetPrivate(isPrivate);
|
|
}
|
|
|
|
helperAppService->DoContent(aMimeContentType, this, window, aForceSave,
|
|
nullptr, getter_AddRefs(mListener));
|
|
}
|
|
|
|
void ExternalHelperAppParent::ActorDestroy(ActorDestroyReason why) {
|
|
mIPCClosed = true;
|
|
}
|
|
|
|
void ExternalHelperAppParent::Delete() {
|
|
if (!mIPCClosed) {
|
|
Unused << Send__delete__(this);
|
|
}
|
|
}
|
|
|
|
mozilla::ipc::IPCResult ExternalHelperAppParent::RecvOnStartRequest(
|
|
const nsCString& entityID, PBrowserParent* contentContext) {
|
|
MOZ_ASSERT(!mDiverted,
|
|
"child forwarding callbacks after request was diverted");
|
|
|
|
UpdateContentContext(mListener, contentContext);
|
|
|
|
mEntityID = entityID;
|
|
mPending = true;
|
|
mStatus = mListener->OnStartRequest(this, nullptr);
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult ExternalHelperAppParent::RecvOnDataAvailable(
|
|
const nsCString& data, const uint64_t& offset, const uint32_t& count) {
|
|
if (NS_FAILED(mStatus)) return IPC_OK();
|
|
|
|
MOZ_ASSERT(!mDiverted,
|
|
"child forwarding callbacks after request was diverted");
|
|
MOZ_ASSERT(mPending, "must be pending!");
|
|
|
|
nsCOMPtr<nsIInputStream> stringStream;
|
|
DebugOnly<nsresult> rv = NS_NewByteInputStream(
|
|
getter_AddRefs(stringStream), data.get(), count, NS_ASSIGNMENT_DEPEND);
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create dependent string!");
|
|
mStatus =
|
|
mListener->OnDataAvailable(this, nullptr, stringStream, offset, count);
|
|
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult ExternalHelperAppParent::RecvOnStopRequest(
|
|
const nsresult& code) {
|
|
MOZ_ASSERT(!mDiverted,
|
|
"child forwarding callbacks after request was diverted");
|
|
|
|
mPending = false;
|
|
mListener->OnStopRequest(
|
|
this, nullptr,
|
|
(NS_SUCCEEDED(code) && NS_FAILED(mStatus)) ? mStatus : code);
|
|
Delete();
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult ExternalHelperAppParent::RecvDivertToParentUsing(
|
|
PChannelDiverterParent* diverter, PBrowserParent* contentContext) {
|
|
MOZ_ASSERT(diverter);
|
|
UpdateContentContext(mListener, contentContext);
|
|
auto p = static_cast<mozilla::net::ChannelDiverterParent*>(diverter);
|
|
p->DivertTo(this);
|
|
#ifdef DEBUG
|
|
mDiverted = true;
|
|
#endif
|
|
Unused << mozilla::net::ChannelDiverterParent::Send__delete__(p);
|
|
return IPC_OK();
|
|
}
|
|
|
|
//
|
|
// nsIStreamListener
|
|
//
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::OnDataAvailable(nsIRequest* request, nsISupports* ctx,
|
|
nsIInputStream* input, uint64_t offset,
|
|
uint32_t count) {
|
|
MOZ_ASSERT(mDiverted);
|
|
return mListener->OnDataAvailable(request, ctx, input, offset, count);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::OnStartRequest(nsIRequest* request, nsISupports* ctx) {
|
|
MOZ_ASSERT(mDiverted);
|
|
return mListener->OnStartRequest(request, ctx);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::OnStopRequest(nsIRequest* request, nsISupports* ctx,
|
|
nsresult status) {
|
|
MOZ_ASSERT(mDiverted);
|
|
nsresult rv = mListener->OnStopRequest(request, ctx, status);
|
|
Delete();
|
|
return rv;
|
|
}
|
|
|
|
ExternalHelperAppParent::~ExternalHelperAppParent() {}
|
|
|
|
//
|
|
// nsIRequest implementation...
|
|
//
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetName(nsACString& aResult) {
|
|
if (!mURI) {
|
|
aResult.Truncate();
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
mURI->GetAsciiSpec(aResult);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::IsPending(bool* aResult) {
|
|
*aResult = mPending;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetStatus(nsresult* aResult) {
|
|
*aResult = mStatus;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::Cancel(nsresult aStatus) {
|
|
mStatus = aStatus;
|
|
Unused << SendCancel(aStatus);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::Suspend() { return NS_ERROR_NOT_IMPLEMENTED; }
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::Resume() { return NS_ERROR_NOT_IMPLEMENTED; }
|
|
|
|
//
|
|
// nsIChannel implementation
|
|
//
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetOriginalURI(nsIURI** aURI) {
|
|
NS_IF_ADDREF(*aURI = mURI);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetOriginalURI(nsIURI* aURI) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetURI(nsIURI** aURI) {
|
|
NS_IF_ADDREF(*aURI = mURI);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::Open(nsIInputStream** aResult) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::Open2(nsIInputStream** aStream) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::AsyncOpen(nsIStreamListener* aListener,
|
|
nsISupports* aContext) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::AsyncOpen2(nsIStreamListener* aListener) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetLoadFlags(nsLoadFlags* aLoadFlags) {
|
|
*aLoadFlags = mLoadFlags;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetLoadFlags(nsLoadFlags aLoadFlags) {
|
|
mLoadFlags = aLoadFlags;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetIsDocument(bool* aIsDocument) {
|
|
return NS_GetIsDocumentChannel(this, aIsDocument);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetLoadGroup(nsILoadGroup** aLoadGroup) {
|
|
*aLoadGroup = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetLoadGroup(nsILoadGroup* aLoadGroup) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetOwner(nsISupports** aOwner) {
|
|
*aOwner = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetOwner(nsISupports* aOwner) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetLoadInfo(nsILoadInfo** aLoadInfo) {
|
|
*aLoadInfo = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetLoadInfo(nsILoadInfo* aLoadInfo) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetNotificationCallbacks(
|
|
nsIInterfaceRequestor** aCallbacks) {
|
|
*aCallbacks = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetNotificationCallbacks(
|
|
nsIInterfaceRequestor* aCallbacks) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetSecurityInfo(nsISupports** aSecurityInfo) {
|
|
*aSecurityInfo = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetContentType(nsACString& aContentType) {
|
|
aContentType.Truncate();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetContentType(const nsACString& aContentType) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetContentCharset(nsACString& aContentCharset) {
|
|
aContentCharset.Truncate();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetContentCharset(const nsACString& aContentCharset) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetContentDisposition(uint32_t* aContentDisposition) {
|
|
// NB: mContentDisposition may or may not be set to a non UINT32_MAX value in
|
|
// nsExternalHelperAppService::DoContentContentProcessHelper
|
|
if (mContentDispositionHeader.IsEmpty() && mContentDisposition == UINT32_MAX)
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
*aContentDisposition = mContentDisposition;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetContentDisposition(uint32_t aContentDisposition) {
|
|
mContentDisposition = aContentDisposition;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetContentDispositionFilename(
|
|
nsAString& aContentDispositionFilename) {
|
|
if (mContentDispositionFilename.IsEmpty()) return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aContentDispositionFilename = mContentDispositionFilename;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetContentDispositionFilename(
|
|
const nsAString& aContentDispositionFilename) {
|
|
mContentDispositionFilename = aContentDispositionFilename;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetContentDispositionHeader(
|
|
nsACString& aContentDispositionHeader) {
|
|
if (mContentDispositionHeader.IsEmpty()) return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
aContentDispositionHeader = mContentDispositionHeader;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetContentLength(int64_t* aContentLength) {
|
|
if (mContentLength < 0)
|
|
*aContentLength = -1;
|
|
else
|
|
*aContentLength = mContentLength;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::SetContentLength(int64_t aContentLength) {
|
|
mContentLength = aContentLength;
|
|
return NS_OK;
|
|
}
|
|
|
|
//
|
|
// nsIResumableChannel implementation
|
|
//
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::ResumeAt(uint64_t startPos,
|
|
const nsACString& entityID) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetEntityID(nsACString& aEntityID) {
|
|
aEntityID = mEntityID;
|
|
return NS_OK;
|
|
}
|
|
|
|
//
|
|
// nsIMultiPartChannel implementation
|
|
//
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetBaseChannel(nsIChannel** aChannel) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetPartID(uint32_t* aPartID) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
ExternalHelperAppParent::GetIsLastPart(bool* aIsLastPart) {
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|