mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
34e62a0d9c
This is done using slightly different mechanisms for each of LoadInfo and nsDocShellLoadState, and will be used in the next part to validate document loads based on the RemoteType responsible for the load. For subresource loads, the TriggeringRemoteType is fairly straightforward - it is the process which created the channel. We can handle this by getting the current remote type when creating the channel, and then using the remote type of the sending process when receiving the LoadInfo over IPC to either replace the triggering remote type, or validate it. For document loads, the situation is a bit more complex, as there are at least 3 (potentially-)different processes responsible for different parts of the navigation: 1. The "Triggering Process" is the process which provided the URI to load. This is also the process which provides the Triggering Principal. This is the process being tracked in this patch. 2. The "Loading Process" is the process which actually creates the channel and starts the load. This may be the same as the triggering process, or may be a different process starting the navigation on behalf of the triggering process. In general this is the process hosting the current docshell, though it may be the parent process in the case of parent-initiated loads. 3. The "Final Process" is the process which receives the response and renders the final document. This isn't known at channel creation time, and is determined by the result principal and process isolation policy. This change uses a serializer and special field on nsDocShellLoadState to track the "Triggering Process" for the load, even as the load state is serialized between processes by tracking which loads were sent into which content processes, and matching them up when the parent process sees them again. The information is then copied into the LoadInfo before configuring the real channel, so it can be used for security checks. The "Triggering Process" is overridden to be the parent process for history loads, as history loads are often started in processes which wouldn't normally be able to navigate to those pages. This is OK thanks to the changes in part 1 which validate history loads against the real session history when SHIP is enabled. Differential Revision: https://phabricator.services.mozilla.com/D161198
478 lines
12 KiB
C++
478 lines
12 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 "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 Maybe<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
|