Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 "nsExternalHelperAppService.h"
#include "nsIContent.h"
#include "nsCExternalHandlerService.h"
#include "nsIExternalHelperAppService.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/BrowserParent.h"
#include "nsStringStream.h"
#include "mozilla/ipc/URIUtils.h"
#include "nsNetUtil.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/WindowGlobalParent.h"
#include "nsQueryObject.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(
nsIURI* uri, const int64_t& aContentLength, const bool& aWasFileChannel,
const nsACString& aContentDispositionHeader,
const uint32_t& aContentDispositionHint,
const nsAString& aContentDispositionFilename)
: mURI(uri),
mPending(false),
mIPCClosed(false),
mLoadFlags(0),
mStatus(NS_OK),
mCanceled(false),
mContentLength(aContentLength),
mWasFileChannel(aWasFileChannel) {
mContentDispositionHeader = aContentDispositionHeader;
if (!mContentDispositionHeader.IsEmpty()) {
NS_GetFilenameFromDisposition(mContentDispositionFilename,
mContentDispositionHeader);
mContentDisposition =
NS_GetContentDispositionFromHeader(mContentDispositionHeader, this);
} else {
mContentDisposition = aContentDispositionHint;
mContentDispositionFilename = aContentDispositionFilename;
}
}
bool ExternalHelperAppParent::Init(
const mozilla::net::LoadInfoArgs& aLoadInfoArgs,
const nsACString& aMimeContentType, const bool& aForceSave,
nsIURI* aReferrer, BrowsingContext* aContext,
const bool& aShouldCloseWindow) {
nsresult rv = mozilla::ipc::LoadInfoArgsToLoadInfo(
aLoadInfoArgs, ContentParent::Cast(Manager())->GetRemoteType(),
getter_AddRefs(mLoadInfo));
if (NS_FAILED(rv)) {
return false;
}
nsCOMPtr<nsIExternalHelperAppService> helperAppService =
do_GetService(NS_EXTERNALHELPERAPPSERVICE_CONTRACTID);
NS_ASSERTION(helperAppService, "No Helper App Service!");
if (aReferrer) {
SetPropertyAsInterface(u"docshell.internalReferrer"_ns, aReferrer);
}
if (aContext) {
WindowGlobalParent* parent =
aContext->Canonical()->GetCurrentWindowGlobal();
if (parent) {
RefPtr<BrowserParent> browser = parent->GetBrowserParent();
if (browser) {
bool isPrivate = false;
nsCOMPtr<nsILoadContext> loadContext = browser->GetLoadContext();
loadContext->GetUsePrivateBrowsing(&isPrivate);
SetPrivate(isPrivate);
}
}
}
helperAppService->CreateListener(aMimeContentType, this, aContext, aForceSave,
nullptr, getter_AddRefs(mListener));
if (!mListener) {
return false;
}
if (aShouldCloseWindow) {
RefPtr<nsExternalAppHandler> handler = do_QueryObject(mListener);
if (handler) {
handler->SetShouldCloseWindow();
}
}
return true;
}
void ExternalHelperAppParent::ActorDestroy(ActorDestroyReason why) {
mIPCClosed = true;
}
void ExternalHelperAppParent::Delete() {
if (!mIPCClosed) {
Unused << Send__delete__(this);
}
}
mozilla::ipc::IPCResult ExternalHelperAppParent::RecvOnStartRequest(
const nsACString& entityID) {
mEntityID = entityID;
mPending = true;
mStatus = mListener->OnStartRequest(this);
return IPC_OK();
}
mozilla::ipc::IPCResult ExternalHelperAppParent::RecvOnDataAvailable(
const nsACString& data, const uint64_t& offset, const uint32_t& count) {
if (NS_FAILED(mStatus)) {
return IPC_OK();
}
MOZ_ASSERT(mPending, "must be pending!");
nsCOMPtr<nsIInputStream> stringStream;
DebugOnly<nsresult> rv = NS_NewByteInputStream(
getter_AddRefs(stringStream), Span(data).To(count), NS_ASSIGNMENT_DEPEND);
NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create dependent string!");
mStatus = mListener->OnDataAvailable(this, stringStream, offset, count);
return IPC_OK();
}
mozilla::ipc::IPCResult ExternalHelperAppParent::RecvOnStopRequest(
const nsresult& code) {
mPending = false;
mListener->OnStopRequest(
this, (NS_SUCCEEDED(code) && NS_FAILED(mStatus)) ? mStatus : code);
Delete();
return IPC_OK();
}
//
// nsIStreamListener
//
NS_IMETHODIMP
ExternalHelperAppParent::OnDataAvailable(nsIRequest* request,
nsIInputStream* input, uint64_t offset,
uint32_t count) {
return mListener->OnDataAvailable(request, input, offset, count);
}
NS_IMETHODIMP
ExternalHelperAppParent::OnStartRequest(nsIRequest* request) {
return mListener->OnStartRequest(request);
}
NS_IMETHODIMP
ExternalHelperAppParent::OnStopRequest(nsIRequest* request, nsresult status) {
nsresult rv = mListener->OnStopRequest(request, 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::SetCanceledReason(
const nsACString& aReason) {
return SetCanceledReasonImpl(aReason);
}
NS_IMETHODIMP ExternalHelperAppParent::GetCanceledReason(nsACString& aReason) {
return GetCanceledReasonImpl(aReason);
}
NS_IMETHODIMP ExternalHelperAppParent::CancelWithReason(
nsresult aStatus, const nsACString& aReason) {
return CancelWithReasonImpl(aStatus, aReason);
}
NS_IMETHODIMP
ExternalHelperAppParent::Cancel(nsresult aStatus) {
mCanceled = true;
mStatus = aStatus;
Unused << SendCancel(aStatus);
return NS_OK;
}
NS_IMETHODIMP
ExternalHelperAppParent::GetCanceled(bool* aCanceled) {
*aCanceled = mCanceled;
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::AsyncOpen(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::GetTRRMode(nsIRequest::TRRMode* aTRRMode) {
return GetTRRModeImpl(aTRRMode);
}
NS_IMETHODIMP
ExternalHelperAppParent::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
return SetTRRModeImpl(aTRRMode);
}
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) {
NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
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(
nsITransportSecurityInfo** 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::GetIsFirstPart(bool* aIsLastPart) {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
ExternalHelperAppParent::GetIsLastPart(bool* aIsLastPart) {
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace dom
} // namespace mozilla