mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 09:15:35 +00:00
Bug 1622451
- minimize stream copying across IPC boundaries r=asuth,baku
Initially, IPCInternal{Request,Response} had contained IPCStreams which would result in unecessary copying when sending the objects over IPC. The patch makes these streams either: 1) ParentToParentStream (just a UUID) 2) ParentToChildStream (a PIPCBlobInputStream actor, acting as a handle) 3) ChildToParentStream (a real IPCStream) These three types are union-ed together by the BodyStreamVariant IPDL structure. This structure replaces the IPCStream members in IPCInternal{Request,Response} so that, depending on the particular IPDL protocol, we can avoid cloning streams and just pass handles/IDs instead. As a side effect, this makes file-backed Response objects cloneable. Initially, these Responses would be backed by an nsFileInputStream, which is not cloneable outside the parent process. They are now backed by IPCBlobInputStreams, which are cloneable. One thing that's not really satisfactory (IMO), is the manual management of IPCBlobInputStreamStorage so that no streams are leaked, e.g. if we store a stream in the IPCBlobInputStreamStorage but fail to send an IPC message and therefore fail to remove the stream from storage on the other side of the IPC boundary (only parent-to-parent in this case). Differential Revision: https://phabricator.services.mozilla.com/D73173
This commit is contained in:
parent
0b1ab06c29
commit
1ad4e039d4
@ -6,6 +6,8 @@ include IPCStream;
|
||||
include ChannelInfo;
|
||||
include PBackgroundSharedTypes;
|
||||
|
||||
include protocol PIPCBlobInputStream;
|
||||
|
||||
using HeadersGuardEnum from "mozilla/dom/FetchIPCTypes.h";
|
||||
using ReferrerPolicy from "mozilla/dom/FetchIPCTypes.h";
|
||||
using RequestCache from "mozilla/dom/FetchIPCTypes.h";
|
||||
@ -13,6 +15,7 @@ using RequestCredentials from "mozilla/dom/FetchIPCTypes.h";
|
||||
using RequestMode from "mozilla/dom/FetchIPCTypes.h";
|
||||
using RequestRedirect from "mozilla/dom/FetchIPCTypes.h";
|
||||
using ResponseType from "mozilla/dom/FetchIPCTypes.h";
|
||||
using struct nsID from "nsID.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -22,12 +25,31 @@ struct HeadersEntry {
|
||||
nsCString value;
|
||||
};
|
||||
|
||||
struct ParentToParentStream {
|
||||
// Used as a key for IPCBlobInputStreamStorage
|
||||
nsID uuid;
|
||||
};
|
||||
|
||||
struct ParentToChildStream {
|
||||
PIPCBlobInputStream actor;
|
||||
};
|
||||
|
||||
struct ChildToParentStream {
|
||||
IPCStream stream;
|
||||
};
|
||||
|
||||
union BodyStreamVariant {
|
||||
ParentToParentStream;
|
||||
ParentToChildStream;
|
||||
ChildToParentStream;
|
||||
};
|
||||
|
||||
struct IPCInternalRequest {
|
||||
nsCString method;
|
||||
nsCString[] urlList;
|
||||
HeadersGuardEnum headersGuard;
|
||||
HeadersEntry[] headers;
|
||||
IPCStream? body;
|
||||
BodyStreamVariant? body;
|
||||
int64_t bodySize;
|
||||
nsCString preferredAlternativeDataType;
|
||||
uint32_t contentPolicyType;
|
||||
@ -49,11 +71,11 @@ struct IPCInternalResponse {
|
||||
nsCString statusText;
|
||||
HeadersGuardEnum headersGuard;
|
||||
HeadersEntry[] headers;
|
||||
IPCStream? body;
|
||||
BodyStreamVariant? body;
|
||||
int64_t bodySize;
|
||||
nsresult errorCode;
|
||||
nsCString alternativeDataType;
|
||||
IPCStream? alternativeBody;
|
||||
BodyStreamVariant? alternativeBody;
|
||||
IPCChannelInfo channelInfo;
|
||||
PrincipalInfo? principalInfo;
|
||||
};
|
||||
|
@ -6,18 +6,17 @@
|
||||
|
||||
#include "InternalRequest.h"
|
||||
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/FetchTypes.h"
|
||||
#include "mozilla/dom/IPCBlobInputStreamChild.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
|
||||
#include "mozilla/dom/WorkerCommon.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsStreamUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -146,7 +145,6 @@ InternalRequest::InternalRequest(const IPCInternalRequest& aIPCRequest)
|
||||
mURLList(aIPCRequest.urlList()),
|
||||
mHeaders(new InternalHeaders(aIPCRequest.headers(),
|
||||
aIPCRequest.headersGuard())),
|
||||
mBodyStream(mozilla::ipc::DeserializeIPCStream(aIPCRequest.body())),
|
||||
mBodyLength(aIPCRequest.bodySize()),
|
||||
mPreferredAlternativeDataType(aIPCRequest.preferredAlternativeDataType()),
|
||||
mContentPolicyType(
|
||||
@ -163,49 +161,21 @@ InternalRequest::InternalRequest(const IPCInternalRequest& aIPCRequest)
|
||||
mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(
|
||||
aIPCRequest.principalInfo().ref());
|
||||
}
|
||||
|
||||
const Maybe<BodyStreamVariant>& body = aIPCRequest.body();
|
||||
|
||||
// This constructor is (currently) only used for parent -> child communication
|
||||
// (constructed on the child side).
|
||||
if (body) {
|
||||
MOZ_ASSERT(body->type() == BodyStreamVariant::TParentToChildStream);
|
||||
mBodyStream = static_cast<IPCBlobInputStreamChild*>(
|
||||
body->get_ParentToChildStream().actorChild())
|
||||
->CreateStream();
|
||||
}
|
||||
}
|
||||
|
||||
InternalRequest::~InternalRequest() = default;
|
||||
|
||||
template void InternalRequest::ToIPC<mozilla::ipc::PBackgroundChild>(
|
||||
IPCInternalRequest* aIPCRequest, mozilla::ipc::PBackgroundChild* aManager,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
|
||||
|
||||
template <typename M>
|
||||
void InternalRequest::ToIPC(
|
||||
IPCInternalRequest* aIPCRequest, M* aManager,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream) {
|
||||
MOZ_ASSERT(aIPCRequest);
|
||||
MOZ_ASSERT(aManager);
|
||||
MOZ_ASSERT(!mURLList.IsEmpty());
|
||||
|
||||
aIPCRequest->method() = mMethod;
|
||||
aIPCRequest->urlList() = mURLList;
|
||||
mHeaders->ToIPC(aIPCRequest->headers(), aIPCRequest->headersGuard());
|
||||
|
||||
if (mBodyStream) {
|
||||
aAutoStream.reset(new mozilla::ipc::AutoIPCStream(aIPCRequest->body()));
|
||||
DebugOnly<bool> ok = aAutoStream->Serialize(mBodyStream, aManager);
|
||||
MOZ_ASSERT(ok);
|
||||
}
|
||||
|
||||
aIPCRequest->bodySize() = mBodyLength;
|
||||
aIPCRequest->preferredAlternativeDataType() = mPreferredAlternativeDataType;
|
||||
aIPCRequest->contentPolicyType() = static_cast<uint32_t>(mContentPolicyType);
|
||||
aIPCRequest->referrer() = mReferrer;
|
||||
aIPCRequest->referrerPolicy() = mReferrerPolicy;
|
||||
aIPCRequest->requestMode() = mMode;
|
||||
aIPCRequest->requestCredentials() = mCredentialsMode;
|
||||
aIPCRequest->cacheMode() = mCacheMode;
|
||||
aIPCRequest->requestRedirect() = mRedirectMode;
|
||||
aIPCRequest->integrity() = mIntegrity;
|
||||
aIPCRequest->fragment() = mFragment;
|
||||
|
||||
if (mPrincipalInfo) {
|
||||
aIPCRequest->principalInfo().emplace(*mPrincipalInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void InternalRequest::SetContentPolicyType(
|
||||
nsContentPolicyType aContentPolicyType) {
|
||||
mContentPolicyType = aContentPolicyType;
|
||||
|
@ -25,7 +25,6 @@ namespace mozilla {
|
||||
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
class AutoIPCStream;
|
||||
} // namespace ipc
|
||||
|
||||
namespace dom {
|
||||
@ -90,10 +89,6 @@ class InternalRequest final {
|
||||
|
||||
explicit InternalRequest(const IPCInternalRequest& aIPCRequest);
|
||||
|
||||
template <typename M>
|
||||
void ToIPC(IPCInternalRequest* aIPCRequest, M* aManager,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
|
||||
|
||||
already_AddRefed<InternalRequest> Clone();
|
||||
|
||||
void GetMethod(nsCString& aMethod) const { aMethod.Assign(mMethod); }
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/FetchTypes.h"
|
||||
#include "mozilla/dom/IPCBlobInputStreamStorage.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/cache/CacheTypes.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
@ -26,6 +27,22 @@ namespace {
|
||||
// XXX This will be tweaked to something more meaningful in Bug 1383656.
|
||||
const uint32_t kMaxRandomNumber = 102400;
|
||||
|
||||
nsCOMPtr<nsIInputStream> TakeStreamFromStorage(
|
||||
const BodyStreamVariant& aVariant, int64_t aBodySize) {
|
||||
MOZ_ASSERT(aVariant.type() == BodyStreamVariant::TParentToParentStream);
|
||||
const auto& uuid = aVariant.get_ParentToParentStream().uuid();
|
||||
|
||||
IPCBlobInputStreamStorage* storage = IPCBlobInputStreamStorage::Get();
|
||||
|
||||
nsCOMPtr<nsIInputStream> body;
|
||||
storage->GetStream(uuid, 0, aBodySize, getter_AddRefs(body));
|
||||
MOZ_DIAGNOSTIC_ASSERT(body);
|
||||
|
||||
storage->ForgetStream(uuid);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
InternalResponse::InternalResponse(uint16_t aStatus,
|
||||
@ -53,15 +70,20 @@ InternalResponse::InternalResponse(uint16_t aStatus,
|
||||
response->mHeaders =
|
||||
new InternalHeaders(aIPCResponse.headers(), aIPCResponse.headersGuard());
|
||||
|
||||
nsCOMPtr<nsIInputStream> body =
|
||||
mozilla::ipc::DeserializeIPCStream(aIPCResponse.body());
|
||||
response->SetBody(body, aIPCResponse.bodySize());
|
||||
if (aIPCResponse.body()) {
|
||||
auto bodySize = aIPCResponse.bodySize();
|
||||
nsCOMPtr<nsIInputStream> body =
|
||||
TakeStreamFromStorage(*aIPCResponse.body(), bodySize);
|
||||
response->SetBody(body, bodySize);
|
||||
}
|
||||
|
||||
response->SetAlternativeDataType(aIPCResponse.alternativeDataType());
|
||||
|
||||
nsCOMPtr<nsIInputStream> alternativeBody =
|
||||
mozilla::ipc::DeserializeIPCStream(aIPCResponse.alternativeBody());
|
||||
response->SetAlternativeBody(alternativeBody);
|
||||
if (aIPCResponse.alternativeBody()) {
|
||||
nsCOMPtr<nsIInputStream> alternativeBody = TakeStreamFromStorage(
|
||||
*aIPCResponse.alternativeBody(), UNKNOWN_BODY_SIZE);
|
||||
response->SetAlternativeBody(alternativeBody);
|
||||
}
|
||||
|
||||
response->InitChannelInfo(aIPCResponse.channelInfo());
|
||||
|
||||
@ -96,54 +118,50 @@ InternalResponse::InternalResponse(uint16_t aStatus,
|
||||
|
||||
InternalResponse::~InternalResponse() = default;
|
||||
|
||||
template void InternalResponse::ToIPC<mozilla::ipc::PBackgroundChild>(
|
||||
void InternalResponse::ToIPC(
|
||||
IPCInternalResponse* aIPCResponse, mozilla::ipc::PBackgroundChild* aManager,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoBodyStream,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoAlternativeBodyStream);
|
||||
|
||||
template <typename M>
|
||||
void InternalResponse::ToIPC(
|
||||
IPCInternalResponse* aIPCResponse, M* aManager,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoBodyStream,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoAlternativeBodyStream) {
|
||||
MOZ_ASSERT(aIPCResponse);
|
||||
nsTArray<HeadersEntry> headers;
|
||||
HeadersGuardEnum headersGuard;
|
||||
UnfilteredHeaders()->ToIPC(headers, headersGuard);
|
||||
|
||||
aIPCResponse->type() = mType;
|
||||
GetUnfilteredURLList(aIPCResponse->urlList());
|
||||
aIPCResponse->status() = GetUnfilteredStatus();
|
||||
aIPCResponse->statusText() = GetUnfilteredStatusText();
|
||||
UnfilteredHeaders()->ToIPC(aIPCResponse->headers(),
|
||||
aIPCResponse->headersGuard());
|
||||
Maybe<mozilla::ipc::PrincipalInfo> principalInfo =
|
||||
mPrincipalInfo ? Some(*mPrincipalInfo) : Nothing();
|
||||
|
||||
// Note: all the arguments are copied rather than moved, which would be more
|
||||
// efficient, because there's no move-friendly constructor generated.
|
||||
*aIPCResponse =
|
||||
IPCInternalResponse(mType, GetUnfilteredURLList(), GetUnfilteredStatus(),
|
||||
GetUnfilteredStatusText(), headersGuard, headers,
|
||||
Nothing(), static_cast<uint64_t>(UNKNOWN_BODY_SIZE),
|
||||
mErrorCode, GetAlternativeDataType(), Nothing(),
|
||||
mChannelInfo.AsIPCChannelInfo(), principalInfo);
|
||||
|
||||
nsCOMPtr<nsIInputStream> body;
|
||||
int64_t bodySize;
|
||||
GetUnfilteredBody(getter_AddRefs(body), &bodySize);
|
||||
|
||||
if (body) {
|
||||
aAutoBodyStream.reset(
|
||||
new mozilla::ipc::AutoIPCStream(aIPCResponse->body()));
|
||||
aIPCResponse->body().emplace(ChildToParentStream());
|
||||
aIPCResponse->bodySize() = bodySize;
|
||||
|
||||
aAutoBodyStream.reset(new mozilla::ipc::AutoIPCStream(
|
||||
aIPCResponse->body()->get_ChildToParentStream().stream()));
|
||||
DebugOnly<bool> ok = aAutoBodyStream->Serialize(body, aManager);
|
||||
MOZ_ASSERT(ok);
|
||||
}
|
||||
|
||||
aIPCResponse->bodySize() = bodySize;
|
||||
aIPCResponse->errorCode() = mErrorCode;
|
||||
aIPCResponse->alternativeDataType() = GetAlternativeDataType();
|
||||
|
||||
nsCOMPtr<nsIInputStream> alternativeBody = TakeAlternativeBody();
|
||||
if (alternativeBody) {
|
||||
aAutoAlternativeBodyStream.reset(
|
||||
new mozilla::ipc::AutoIPCStream(aIPCResponse->alternativeBody()));
|
||||
aIPCResponse->alternativeBody().emplace(ChildToParentStream());
|
||||
|
||||
aAutoAlternativeBodyStream.reset(new mozilla::ipc::AutoIPCStream(
|
||||
aIPCResponse->alternativeBody()->get_ChildToParentStream().stream()));
|
||||
DebugOnly<bool> ok =
|
||||
aAutoAlternativeBodyStream->Serialize(alternativeBody, aManager);
|
||||
MOZ_ASSERT(ok);
|
||||
}
|
||||
|
||||
aIPCResponse->channelInfo() = mChannelInfo.AsIPCChannelInfo();
|
||||
|
||||
if (mPrincipalInfo) {
|
||||
aIPCResponse->principalInfo().emplace(*mPrincipalInfo);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<InternalResponse> InternalResponse::Clone(
|
||||
|
@ -20,8 +20,9 @@
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
class AutoIPCStream;
|
||||
class PBackgroundChild;
|
||||
class PrincipalInfo;
|
||||
} // namespace ipc
|
||||
|
||||
namespace dom {
|
||||
@ -42,9 +43,10 @@ class InternalResponse final {
|
||||
static RefPtr<InternalResponse> FromIPC(
|
||||
const IPCInternalResponse& aIPCResponse);
|
||||
|
||||
template <typename M>
|
||||
// Note: the AutoIPCStreams must outlive the IPCInternalResponse.
|
||||
void ToIPC(
|
||||
IPCInternalResponse* aIPCResponse, M* aManager,
|
||||
IPCInternalResponse* aIPCResponse,
|
||||
mozilla::ipc::PBackgroundChild* aManager,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoBodyStream,
|
||||
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoAlternativeBodyStream);
|
||||
|
||||
@ -111,6 +113,12 @@ class InternalResponse final {
|
||||
return GetURLList(aURLList);
|
||||
}
|
||||
|
||||
nsTArray<nsCString> GetUnfilteredURLList() const {
|
||||
nsTArray<nsCString> list;
|
||||
GetUnfilteredURLList(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
void SetURLList(const nsTArray<nsCString>& aURLList) {
|
||||
mURLList.Assign(aURLList);
|
||||
|
||||
|
@ -31,10 +31,6 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_ADDREF(IPCBlobInputStreamStorage)
|
||||
NS_IMPL_RELEASE(IPCBlobInputStreamStorage)
|
||||
|
||||
IPCBlobInputStreamStorage::IPCBlobInputStreamStorage() = default;
|
||||
|
||||
IPCBlobInputStreamStorage::~IPCBlobInputStreamStorage() = default;
|
||||
|
||||
/* static */
|
||||
IPCBlobInputStreamStorage* IPCBlobInputStreamStorage::Get() { return gStorage; }
|
||||
|
||||
|
@ -46,8 +46,8 @@ class IPCBlobInputStreamStorage final : public nsIObserver {
|
||||
const nsID& aID);
|
||||
|
||||
private:
|
||||
IPCBlobInputStreamStorage();
|
||||
~IPCBlobInputStreamStorage();
|
||||
IPCBlobInputStreamStorage() = default;
|
||||
~IPCBlobInputStreamStorage() = default;
|
||||
|
||||
struct StreamData {
|
||||
nsCOMPtr<nsIInputStream> mInputStream;
|
||||
|
@ -135,6 +135,14 @@ nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
|
||||
aActorParent, aManager);
|
||||
}
|
||||
|
||||
nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
|
||||
PIPCBlobInputStreamParent*& aActorParent,
|
||||
PBackgroundParent* aManager) {
|
||||
return SerializeInputStreamParent(aInputStream, aSize,
|
||||
BackgroundParent::GetChildID(aManager),
|
||||
aActorParent, aManager);
|
||||
}
|
||||
|
||||
nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
|
||||
IPCBlobStream& aIPCBlob,
|
||||
ContentParent* aManager) {
|
||||
|
@ -255,6 +255,10 @@ nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
|
||||
PIPCBlobInputStreamParent*& aActorParent,
|
||||
ContentParent* aManager);
|
||||
|
||||
nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
|
||||
PIPCBlobInputStreamParent*& aActorParent,
|
||||
mozilla::ipc::PBackgroundParent* aManager);
|
||||
|
||||
// WARNING: If you pass any actor which does not have P{Content,Background} as
|
||||
// its toplevel protocol, this method will MOZ_CRASH.
|
||||
nsresult SerializeUntyped(BlobImpl* aBlobImpl, mozilla::ipc::IProtocol* aActor,
|
||||
|
@ -16,8 +16,6 @@
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIConsoleReportCollector.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIHttpHeaderVisitor.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsILoadInfo.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
@ -25,7 +23,6 @@
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIUploadChannel2.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsTArray.h"
|
||||
@ -40,7 +37,6 @@
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/InternalRequest.h"
|
||||
#include "mozilla/dom/InternalResponse.h"
|
||||
#include "mozilla/dom/PRemoteWorkerControllerChild.h"
|
||||
#include "mozilla/dom/ServiceWorkerRegistrationInfo.h"
|
||||
@ -185,168 +181,6 @@ class SynthesizeResponseWatcher final : public nsIInterceptedBodyCallback {
|
||||
|
||||
NS_IMPL_ISUPPORTS(SynthesizeResponseWatcher, nsIInterceptedBodyCallback)
|
||||
|
||||
class HeaderFiller final : public nsIHttpHeaderVisitor {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit HeaderFiller(HeadersGuardEnum aGuard)
|
||||
: mInternalHeaders(new InternalHeaders(aGuard)) {
|
||||
MOZ_ASSERT(mInternalHeaders);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
VisitHeader(const nsACString& aHeader, const nsACString& aValue) override {
|
||||
ErrorResult result;
|
||||
mInternalHeaders->Append(aHeader, aValue, result);
|
||||
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
return result.StealNSResult();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<InternalHeaders> Extract() {
|
||||
return RefPtr<InternalHeaders>(std::move(mInternalHeaders));
|
||||
}
|
||||
|
||||
private:
|
||||
~HeaderFiller() = default;
|
||||
|
||||
RefPtr<InternalHeaders> mInternalHeaders;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(HeaderFiller, nsIHttpHeaderVisitor)
|
||||
|
||||
nsresult GetIPCInternalRequest(nsIInterceptedChannel* aChannel,
|
||||
IPCInternalRequest* aOutRequest,
|
||||
UniquePtr<AutoIPCStream>& aAutoStream) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aChannel->GetSecureUpgradedChannelURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uriNoFragment;
|
||||
rv = NS_GetURIWithoutRef(uri, getter_AddRefs(uriNoFragment));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIChannel> underlyingChannel;
|
||||
rv = aChannel->GetChannel(getter_AddRefs(underlyingChannel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(underlyingChannel);
|
||||
MOZ_ASSERT(httpChannel, "How come we don't have an HTTP channel?");
|
||||
|
||||
nsCOMPtr<nsIHttpChannelInternal> internalChannel =
|
||||
do_QueryInterface(httpChannel);
|
||||
NS_ENSURE_TRUE(internalChannel, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
nsCOMPtr<nsICacheInfoChannel> cacheInfoChannel =
|
||||
do_QueryInterface(underlyingChannel);
|
||||
|
||||
nsAutoCString spec;
|
||||
rv = uriNoFragment->GetSpec(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString fragment;
|
||||
rv = uri->GetRef(fragment);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString method;
|
||||
rv = httpChannel->GetRequestMethod(method);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This is safe due to static_asserts in ServiceWorkerManager.cpp
|
||||
uint32_t cacheModeInt;
|
||||
rv = internalChannel->GetFetchCacheMode(&cacheModeInt);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
RequestCache cacheMode = static_cast<RequestCache>(cacheModeInt);
|
||||
|
||||
RequestMode requestMode =
|
||||
InternalRequest::MapChannelToRequestMode(underlyingChannel);
|
||||
|
||||
// This is safe due to static_asserts in ServiceWorkerManager.cpp
|
||||
uint32_t redirectMode;
|
||||
rv = internalChannel->GetRedirectMode(&redirectMode);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
RequestRedirect requestRedirect = static_cast<RequestRedirect>(redirectMode);
|
||||
|
||||
RequestCredentials requestCredentials =
|
||||
InternalRequest::MapChannelToRequestCredentials(underlyingChannel);
|
||||
|
||||
nsAutoString referrer;
|
||||
ReferrerPolicy referrerPolicy = ReferrerPolicy::_empty;
|
||||
|
||||
nsCOMPtr<nsIReferrerInfo> referrerInfo = httpChannel->GetReferrerInfo();
|
||||
if (referrerInfo) {
|
||||
referrerPolicy = referrerInfo->ReferrerPolicy();
|
||||
Unused << referrerInfo->GetComputedReferrerSpec(referrer);
|
||||
}
|
||||
|
||||
uint32_t loadFlags;
|
||||
rv = underlyingChannel->GetLoadFlags(&loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
rv = underlyingChannel->GetLoadInfo(getter_AddRefs(loadInfo));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_STATE(loadInfo);
|
||||
|
||||
nsContentPolicyType contentPolicyType = loadInfo->InternalContentPolicyType();
|
||||
|
||||
nsAutoString integrity;
|
||||
rv = internalChannel->GetIntegrityMetadata(integrity);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
RefPtr<HeaderFiller> headerFiller =
|
||||
MakeRefPtr<HeaderFiller>(HeadersGuardEnum::Request);
|
||||
rv = httpChannel->VisitNonDefaultRequestHeaders(headerFiller);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
RefPtr<InternalHeaders> internalHeaders = headerFiller->Extract();
|
||||
|
||||
ErrorResult result;
|
||||
internalHeaders->SetGuard(HeadersGuardEnum::Immutable, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
return result.StealNSResult();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(httpChannel);
|
||||
nsCOMPtr<nsIInputStream> uploadStream;
|
||||
int64_t uploadStreamContentLength = -1;
|
||||
if (uploadChannel) {
|
||||
rv = uploadChannel->CloneUploadStream(&uploadStreamContentLength,
|
||||
getter_AddRefs(uploadStream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
RefPtr<InternalRequest> internalRequest = new InternalRequest(
|
||||
spec, fragment, method, internalHeaders.forget(), cacheMode, requestMode,
|
||||
requestRedirect, requestCredentials, referrer, referrerPolicy,
|
||||
contentPolicyType, integrity);
|
||||
internalRequest->SetBody(uploadStream, uploadStreamContentLength);
|
||||
|
||||
nsAutoCString alternativeDataType;
|
||||
if (cacheInfoChannel &&
|
||||
!cacheInfoChannel->PreferredAlternativeDataTypes().IsEmpty()) {
|
||||
// TODO: the internal request probably needs all the preferred types.
|
||||
alternativeDataType.Assign(
|
||||
cacheInfoChannel->PreferredAlternativeDataTypes()[0].type());
|
||||
internalRequest->SetPreferredAlternativeDataType(alternativeDataType);
|
||||
}
|
||||
|
||||
PBackgroundChild* bgChild = BackgroundChild::GetForCurrentThread();
|
||||
|
||||
if (NS_WARN_IF(!bgChild)) {
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
internalRequest->ToIPC(aOutRequest, bgChild, aAutoStream);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
/* static */ RefPtr<GenericPromise> FetchEventOpChild::SendFetchEvent(
|
||||
@ -364,28 +198,7 @@ nsresult GetIPCInternalRequest(nsIInterceptedChannel* aChannel,
|
||||
std::move(aArgs), std::move(aInterceptedChannel),
|
||||
std::move(aRegistration), std::move(aKeepAliveToken));
|
||||
|
||||
// autoStream will contain a pointer into the IPCInternalRequest passed into
|
||||
// GetIPCInternalRequest, so autoStream shouldn't outlive that
|
||||
// IPCInternalRequest or the containing FetchEventOpChild.
|
||||
auto autoStream = MakeUnique<AutoIPCStream>();
|
||||
|
||||
// const_cast-ing the IPCInternalRequest is okay because this is conceptually
|
||||
// part of initializing actor->mArgs, and `autoStream` needs its
|
||||
// IPCStream (physically part of actor->mArgs.internalRequest()) to be in its
|
||||
// final location in memory, so actor->mArgs must be created before this call.
|
||||
nsresult rv = GetIPCInternalRequest(
|
||||
actor->mInterceptedChannel,
|
||||
const_cast<IPCInternalRequest*>(&actor->mArgs.internalRequest()),
|
||||
autoStream);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// `actor` must be manually delete-d before the actor tree can manage its
|
||||
// lifetime starting with SendPFetchEventOpConstructor.
|
||||
delete actor;
|
||||
return GenericPromise::CreateAndReject(rv, __func__);
|
||||
}
|
||||
|
||||
Unused << aManager->SendPFetchEventOpConstructor(actor, actor->mArgs);
|
||||
autoStream->TakeOptionalValue();
|
||||
|
||||
return actor->mPromiseHolder.Ensure(__func__);
|
||||
}
|
||||
|
@ -120,8 +120,14 @@ void FetchEventOpProxyChild::Initialize(
|
||||
}
|
||||
|
||||
Unused << self->SendRespondWith(ipcArgs);
|
||||
autoBodyStream->TakeOptionalValue();
|
||||
autoAlternativeBodyStream->TakeOptionalValue();
|
||||
|
||||
if (ipcArgs.internalResponse().body()) {
|
||||
autoBodyStream->TakeValue();
|
||||
}
|
||||
|
||||
if (ipcArgs.internalResponse().alternativeBody()) {
|
||||
autoAlternativeBodyStream->TakeValue();
|
||||
}
|
||||
} else if (result.is<ResetInterceptionArgs>()) {
|
||||
Unused << self->SendRespondWith(
|
||||
result.extract<ResetInterceptionArgs>());
|
||||
@ -139,7 +145,7 @@ RefPtr<InternalRequest> FetchEventOpProxyChild::ExtractInternalRequest() {
|
||||
MOZ_ASSERT(IsCurrentThreadRunningWorker());
|
||||
MOZ_ASSERT(mInternalRequest);
|
||||
|
||||
return RefPtr<InternalRequest>(std::move(mInternalRequest));
|
||||
return std::move(mInternalRequest);
|
||||
}
|
||||
|
||||
void FetchEventOpProxyChild::ActorDestroy(ActorDestroyReason) {
|
||||
|
@ -9,13 +9,18 @@
|
||||
#include <utility>
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/FetchEventOpParent.h"
|
||||
#include "mozilla/dom/IPCBlobInputStreamStorage.h"
|
||||
#include "mozilla/dom/IPCBlobUtils.h"
|
||||
#include "mozilla/ipc/BackgroundParent.h"
|
||||
#include "mozilla/ipc/IPCStreamUtils.h"
|
||||
|
||||
@ -27,20 +32,25 @@ namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
void MaybeDeserializeAndReserialize(const Maybe<IPCStream>& aDeserialize,
|
||||
Maybe<IPCStream>& aReserialize,
|
||||
UniquePtr<AutoIPCStream>& aAutoStream,
|
||||
PBackgroundParent* aManager) {
|
||||
nsCOMPtr<nsIInputStream> maybeDeserialized =
|
||||
DeserializeIPCStream(aDeserialize);
|
||||
|
||||
if (!maybeDeserialized) {
|
||||
return;
|
||||
nsresult MaybeDeserializeAndWrapForMainThread(
|
||||
const Maybe<BodyStreamVariant>& aSource, int64_t aBodyStreamSize,
|
||||
Maybe<BodyStreamVariant>& aSink, PBackgroundParent* aManager) {
|
||||
if (aSource.isNothing()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aAutoStream.reset(new AutoIPCStream(aReserialize));
|
||||
DebugOnly<bool> ok = aAutoStream->Serialize(maybeDeserialized, aManager);
|
||||
MOZ_ASSERT(ok);
|
||||
nsCOMPtr<nsIInputStream> deserialized =
|
||||
DeserializeIPCStream(aSource->get_ChildToParentStream().stream());
|
||||
|
||||
aSink = Some(ParentToParentStream());
|
||||
auto& uuid = aSink->get_ParentToParentStream().uuid();
|
||||
|
||||
MOZ_TRY(nsContentUtils::GenerateUUIDInPlace(uuid));
|
||||
|
||||
IPCBlobInputStreamStorage::Get()->AddStream(deserialized, uuid,
|
||||
aBodyStreamSize, 0);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
@ -64,15 +74,30 @@ void MaybeDeserializeAndReserialize(const Maybe<IPCStream>& aDeserialize,
|
||||
ServiceWorkerFetchEventOpArgs copyArgs = aArgs;
|
||||
IPCInternalRequest& copyRequest = copyArgs.internalRequest();
|
||||
|
||||
PBackgroundParent* bgParent = aManager->Manager();
|
||||
MOZ_ASSERT(bgParent);
|
||||
if (copyRequest.body().ref().type() ==
|
||||
BodyStreamVariant::TParentToParentStream) {
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
auto streamLength = copyRequest.bodySize();
|
||||
const auto& uuid =
|
||||
copyRequest.body().ref().get_ParentToParentStream().uuid();
|
||||
IPCBlobInputStreamStorage* storage = IPCBlobInputStreamStorage::Get();
|
||||
|
||||
UniquePtr<AutoIPCStream> autoBodyStream = MakeUnique<AutoIPCStream>();
|
||||
MaybeDeserializeAndReserialize(aArgs.internalRequest().body(),
|
||||
copyRequest.body(), autoBodyStream, bgParent);
|
||||
storage->GetStream(uuid, 0, streamLength, getter_AddRefs(stream));
|
||||
storage->ForgetStream(uuid);
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(stream);
|
||||
|
||||
PBackgroundParent* bgParent = aManager->Manager();
|
||||
MOZ_ASSERT(bgParent);
|
||||
|
||||
copyRequest.body() = Some(ParentToChildStream());
|
||||
MOZ_ALWAYS_SUCCEEDS(IPCBlobUtils::SerializeInputStream(
|
||||
stream, streamLength,
|
||||
copyRequest.body().ref().get_ParentToChildStream().actorParent(),
|
||||
bgParent));
|
||||
}
|
||||
|
||||
Unused << aManager->SendPFetchEventOpProxyConstructor(actor, copyArgs);
|
||||
autoBodyStream->TakeOptionalValue();
|
||||
}
|
||||
|
||||
FetchEventOpProxyParent::~FetchEventOpProxyParent() {
|
||||
@ -125,20 +150,14 @@ mozilla::ipc::IPCResult FetchEventOpProxyParent::RecvRespondWith(
|
||||
PBackgroundParent* bgParent = manager->Manager();
|
||||
MOZ_ASSERT(bgParent);
|
||||
|
||||
UniquePtr<AutoIPCStream> autoBodyStream = MakeUnique<AutoIPCStream>();
|
||||
UniquePtr<AutoIPCStream> autoAlternativeBodyStream =
|
||||
MakeUnique<AutoIPCStream>();
|
||||
|
||||
MaybeDeserializeAndReserialize(originalResponse.body(), copyResponse.body(),
|
||||
autoBodyStream, bgParent);
|
||||
MaybeDeserializeAndReserialize(originalResponse.alternativeBody(),
|
||||
copyResponse.alternativeBody(),
|
||||
autoAlternativeBodyStream, bgParent);
|
||||
MOZ_ALWAYS_SUCCEEDS(MaybeDeserializeAndWrapForMainThread(
|
||||
originalResponse.body(), copyResponse.bodySize(), copyResponse.body(),
|
||||
bgParent));
|
||||
MOZ_ALWAYS_SUCCEEDS(MaybeDeserializeAndWrapForMainThread(
|
||||
originalResponse.alternativeBody(), InternalResponse::UNKNOWN_BODY_SIZE,
|
||||
copyResponse.alternativeBody(), bgParent));
|
||||
|
||||
Unused << mReal->SendRespondWith(copyArgs);
|
||||
|
||||
autoBodyStream->TakeOptionalValue();
|
||||
autoAlternativeBodyStream->TakeOptionalValue();
|
||||
} else {
|
||||
Unused << mReal->SendRespondWith(aResult);
|
||||
}
|
||||
|
@ -14,10 +14,13 @@
|
||||
#include "nsDebug.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIHttpHeaderVisitor.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIUploadChannel2.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "ServiceWorkerManager.h"
|
||||
@ -25,6 +28,8 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
@ -32,7 +37,9 @@
|
||||
#include "mozilla/dom/ClientIPCTypes.h"
|
||||
#include "mozilla/dom/DOMTypes.h"
|
||||
#include "mozilla/dom/FetchEventOpChild.h"
|
||||
#include "mozilla/dom/IPCBlobInputStreamStorage.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/InternalRequest.h"
|
||||
#include "mozilla/dom/ReferrerInfo.h"
|
||||
#include "mozilla/dom/RemoteWorkerControllerChild.h"
|
||||
#include "mozilla/dom/ServiceWorkerBinding.h"
|
||||
@ -574,12 +581,189 @@ ServiceWorkerPrivateImpl::PendingFetchEvent::~PendingFetchEvent() {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class HeaderFiller final : public nsIHttpHeaderVisitor {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
explicit HeaderFiller(HeadersGuardEnum aGuard)
|
||||
: mInternalHeaders(new InternalHeaders(aGuard)) {
|
||||
MOZ_ASSERT(mInternalHeaders);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
VisitHeader(const nsACString& aHeader, const nsACString& aValue) override {
|
||||
ErrorResult result;
|
||||
mInternalHeaders->Append(aHeader, aValue, result);
|
||||
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
return result.StealNSResult();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<InternalHeaders> Extract() {
|
||||
return RefPtr<InternalHeaders>(std::move(mInternalHeaders));
|
||||
}
|
||||
|
||||
private:
|
||||
~HeaderFiller() = default;
|
||||
|
||||
RefPtr<InternalHeaders> mInternalHeaders;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(HeaderFiller, nsIHttpHeaderVisitor)
|
||||
|
||||
Result<IPCInternalRequest, nsresult> GetIPCInternalRequest(
|
||||
nsIInterceptedChannel* aChannel) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
MOZ_TRY(aChannel->GetSecureUpgradedChannelURI(getter_AddRefs(uri)));
|
||||
|
||||
nsCOMPtr<nsIURI> uriNoFragment;
|
||||
MOZ_TRY(NS_GetURIWithoutRef(uri, getter_AddRefs(uriNoFragment)));
|
||||
|
||||
nsCOMPtr<nsIChannel> underlyingChannel;
|
||||
MOZ_TRY(aChannel->GetChannel(getter_AddRefs(underlyingChannel)));
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(underlyingChannel);
|
||||
MOZ_ASSERT(httpChannel, "How come we don't have an HTTP channel?");
|
||||
|
||||
nsCOMPtr<nsIHttpChannelInternal> internalChannel =
|
||||
do_QueryInterface(httpChannel);
|
||||
NS_ENSURE_TRUE(internalChannel, Err(NS_ERROR_NOT_AVAILABLE));
|
||||
|
||||
nsCOMPtr<nsICacheInfoChannel> cacheInfoChannel =
|
||||
do_QueryInterface(underlyingChannel);
|
||||
|
||||
nsAutoCString spec;
|
||||
MOZ_TRY(uriNoFragment->GetSpec(spec));
|
||||
|
||||
nsAutoCString fragment;
|
||||
MOZ_TRY(uri->GetRef(fragment));
|
||||
|
||||
nsAutoCString method;
|
||||
MOZ_TRY(httpChannel->GetRequestMethod(method));
|
||||
|
||||
// This is safe due to static_asserts in ServiceWorkerManager.cpp
|
||||
uint32_t cacheModeInt;
|
||||
MOZ_ALWAYS_SUCCEEDS(internalChannel->GetFetchCacheMode(&cacheModeInt));
|
||||
RequestCache cacheMode = static_cast<RequestCache>(cacheModeInt);
|
||||
|
||||
RequestMode requestMode =
|
||||
InternalRequest::MapChannelToRequestMode(underlyingChannel);
|
||||
|
||||
// This is safe due to static_asserts in ServiceWorkerManager.cpp
|
||||
uint32_t redirectMode;
|
||||
MOZ_ALWAYS_SUCCEEDS(internalChannel->GetRedirectMode(&redirectMode));
|
||||
RequestRedirect requestRedirect = static_cast<RequestRedirect>(redirectMode);
|
||||
|
||||
RequestCredentials requestCredentials =
|
||||
InternalRequest::MapChannelToRequestCredentials(underlyingChannel);
|
||||
|
||||
nsAutoString referrer;
|
||||
ReferrerPolicy referrerPolicy = ReferrerPolicy::_empty;
|
||||
|
||||
nsCOMPtr<nsIReferrerInfo> referrerInfo = httpChannel->GetReferrerInfo();
|
||||
if (referrerInfo) {
|
||||
referrerPolicy = referrerInfo->ReferrerPolicy();
|
||||
Unused << referrerInfo->GetComputedReferrerSpec(referrer);
|
||||
}
|
||||
|
||||
uint32_t loadFlags;
|
||||
MOZ_TRY(underlyingChannel->GetLoadFlags(&loadFlags));
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
||||
MOZ_TRY(underlyingChannel->GetLoadInfo(getter_AddRefs(loadInfo)));
|
||||
MOZ_ASSERT(loadInfo);
|
||||
|
||||
nsContentPolicyType contentPolicyType = loadInfo->InternalContentPolicyType();
|
||||
|
||||
nsAutoString integrity;
|
||||
MOZ_TRY(internalChannel->GetIntegrityMetadata(integrity));
|
||||
|
||||
RefPtr<HeaderFiller> headerFiller =
|
||||
MakeRefPtr<HeaderFiller>(HeadersGuardEnum::Request);
|
||||
MOZ_TRY(httpChannel->VisitNonDefaultRequestHeaders(headerFiller));
|
||||
|
||||
RefPtr<InternalHeaders> internalHeaders = headerFiller->Extract();
|
||||
|
||||
ErrorResult result;
|
||||
internalHeaders->SetGuard(HeadersGuardEnum::Immutable, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
return Err(result.StealNSResult());
|
||||
}
|
||||
|
||||
nsTArray<HeadersEntry> ipcHeaders;
|
||||
HeadersGuardEnum ipcHeadersGuard;
|
||||
internalHeaders->ToIPC(ipcHeaders, ipcHeadersGuard);
|
||||
|
||||
nsAutoCString alternativeDataType;
|
||||
if (cacheInfoChannel &&
|
||||
!cacheInfoChannel->PreferredAlternativeDataTypes().IsEmpty()) {
|
||||
// TODO: the internal request probably needs all the preferred types.
|
||||
alternativeDataType.Assign(
|
||||
cacheInfoChannel->PreferredAlternativeDataTypes()[0].type());
|
||||
}
|
||||
|
||||
Maybe<PrincipalInfo> principalInfo;
|
||||
|
||||
if (loadInfo->TriggeringPrincipal()) {
|
||||
principalInfo.emplace();
|
||||
MOZ_ALWAYS_SUCCEEDS(PrincipalToPrincipalInfo(
|
||||
loadInfo->TriggeringPrincipal(), principalInfo.ptr()));
|
||||
}
|
||||
|
||||
// Note: all the arguments are copied rather than moved, which would be more
|
||||
// efficient, because there's no move-friendly constructor generated.
|
||||
return IPCInternalRequest(
|
||||
method, {spec}, ipcHeadersGuard, ipcHeaders, Nothing(), -1,
|
||||
alternativeDataType, contentPolicyType, referrer, referrerPolicy,
|
||||
requestMode, requestCredentials, cacheMode, requestRedirect, integrity,
|
||||
fragment, principalInfo);
|
||||
}
|
||||
|
||||
nsresult MaybeStoreStreamForBackgroundThread(nsIInterceptedChannel* aChannel,
|
||||
IPCInternalRequest& aIPCRequest) {
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
MOZ_ALWAYS_SUCCEEDS(aChannel->GetChannel(getter_AddRefs(channel)));
|
||||
|
||||
Maybe<BodyStreamVariant> body;
|
||||
int64_t bodySize = -1;
|
||||
nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(channel);
|
||||
|
||||
if (uploadChannel) {
|
||||
nsCOMPtr<nsIInputStream> uploadStream;
|
||||
MOZ_TRY(uploadChannel->CloneUploadStream(&aIPCRequest.bodySize(),
|
||||
getter_AddRefs(uploadStream)));
|
||||
|
||||
if (uploadStream) {
|
||||
Maybe<BodyStreamVariant>& body = aIPCRequest.body();
|
||||
body.emplace(ParentToParentStream());
|
||||
|
||||
MOZ_TRY(nsContentUtils::GenerateUUIDInPlace(
|
||||
body->get_ParentToParentStream().uuid()));
|
||||
|
||||
IPCBlobInputStreamStorage::Get()->AddStream(
|
||||
uploadStream, body->get_ParentToParentStream().uuid(), bodySize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
nsresult ServiceWorkerPrivateImpl::SendFetchEvent(
|
||||
RefPtr<ServiceWorkerRegistrationInfo> aRegistration,
|
||||
nsCOMPtr<nsIInterceptedChannel> aChannel, const nsAString& aClientId,
|
||||
const nsAString& aResultingClientId) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mOuter);
|
||||
MOZ_ASSERT(mOuter->mInfo);
|
||||
MOZ_ASSERT(aRegistration);
|
||||
MOZ_ASSERT(aChannel);
|
||||
|
||||
@ -589,19 +773,15 @@ nsresult ServiceWorkerPrivateImpl::SendFetchEvent(
|
||||
});
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv = aChannel->GetChannel(getter_AddRefs(channel));
|
||||
MOZ_TRY(aChannel->GetChannel(getter_AddRefs(channel)));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
IPCInternalRequest request;
|
||||
MOZ_TRY_VAR(request, GetIPCInternalRequest(aChannel));
|
||||
|
||||
scopeExit.release();
|
||||
|
||||
MOZ_ASSERT(mOuter->mInfo);
|
||||
|
||||
// FetchEventOpChild will fill in the IPCInternalRequest.
|
||||
ServiceWorkerFetchEventOpArgs args(
|
||||
mOuter->mInfo->ScriptSpec(), IPCInternalRequest(), nsString(aClientId),
|
||||
mOuter->mInfo->ScriptSpec(), std::move(request), nsString(aClientId),
|
||||
nsString(aResultingClientId),
|
||||
nsContentUtils::IsNonSubresourceRequest(channel));
|
||||
|
||||
@ -634,11 +814,9 @@ nsresult ServiceWorkerPrivateImpl::SendFetchEventInternal(
|
||||
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
}
|
||||
|
||||
nsresult rv = SpawnWorkerIfNeeded();
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
MOZ_TRY(SpawnWorkerIfNeeded());
|
||||
MOZ_TRY(
|
||||
MaybeStoreStreamForBackgroundThread(aChannel, aArgs.internalRequest()));
|
||||
|
||||
scopeExit.release();
|
||||
|
||||
|
@ -1,7 +1,14 @@
|
||||
self.skipWaiting();
|
||||
|
||||
addEventListener("fetch", event => {
|
||||
event.respondWith(fetch(event.request));
|
||||
const url = new URL(event.request.url);
|
||||
const params = new URLSearchParams(url.search);
|
||||
|
||||
if (params.get("clone") === "1") {
|
||||
event.respondWith(fetch(event.request.clone()));
|
||||
} else {
|
||||
event.respondWith(fetch(event.request));
|
||||
}
|
||||
});
|
||||
|
||||
addEventListener("activate", function(event) {
|
||||
|
@ -14,6 +14,12 @@
|
||||
<input id="input" type="file">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function GetFormData(file) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
return formData;
|
||||
}
|
||||
|
||||
async function onOpened(message) {
|
||||
let input = document.getElementById("input");
|
||||
SpecialPowers.wrap(input).mozSetFileArray([message.file]);
|
||||
@ -24,13 +30,22 @@ async function onOpened(message) {
|
||||
let serviceWorker = reg.installing || reg.waiting || reg.active;
|
||||
await waitForState(serviceWorker, 'activated');
|
||||
|
||||
let res = await fetch('server_file_upload.sjs', {
|
||||
let res = await fetch('server_file_upload.sjs?clone=0', {
|
||||
method: 'POST',
|
||||
body: input.files[0],
|
||||
});
|
||||
|
||||
let data = await res.clone().text();
|
||||
ok(data.length > 0, "We have data!");
|
||||
ok(data.length > 0, "We have data for an uncloned request!");
|
||||
|
||||
res = await fetch('server_file_upload.sjs?clone=1', {
|
||||
method: 'POST',
|
||||
// Make sure the underlying stream is a file stream
|
||||
body: GetFormData(input.files[0]),
|
||||
});
|
||||
|
||||
data = await res.clone().text();
|
||||
ok(data.length > 0, "We have data for a file-stream-backed cloned request!");
|
||||
|
||||
await reg.unregister();
|
||||
SimpleTest.finish();
|
||||
|
Loading…
Reference in New Issue
Block a user