Backed out changeset e1be97ce43d1 (bug 1622451) for failures on browser_download_canceled.js. CLOSED TREE

This commit is contained in:
Csoregi Natalia 2020-05-01 03:58:25 +03:00
parent 42b619b62e
commit 83cd8858fc
15 changed files with 332 additions and 391 deletions

View File

@ -6,8 +6,6 @@ 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";
@ -15,7 +13,6 @@ 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 {
@ -25,31 +22,12 @@ 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;
BodyStreamVariant? body;
IPCStream? body;
int64_t bodySize;
nsCString preferredAlternativeDataType;
uint32_t contentPolicyType;
@ -71,11 +49,11 @@ struct IPCInternalResponse {
nsCString statusText;
HeadersGuardEnum headersGuard;
HeadersEntry[] headers;
BodyStreamVariant? body;
IPCStream? body;
int64_t bodySize;
nsresult errorCode;
nsCString alternativeDataType;
BodyStreamVariant? alternativeBody;
IPCStream? alternativeBody;
IPCChannelInfo channelInfo;
PrincipalInfo? principalInfo;
};

View File

@ -6,17 +6,18 @@
#include "InternalRequest.h"
#include "mozilla/ErrorResult.h"
#include "nsIContentPolicy.h"
#include "mozilla/dom/Document.h"
#include "nsStreamUtils.h"
#include "mozilla/ErrorResult.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 {
@ -145,6 +146,7 @@ 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(
@ -161,21 +163,49 @@ 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;

View File

@ -25,6 +25,7 @@ namespace mozilla {
namespace ipc {
class PrincipalInfo;
class AutoIPCStream;
} // namespace ipc
namespace dom {
@ -89,6 +90,10 @@ 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); }

View File

@ -9,7 +9,6 @@
#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"
@ -27,22 +26,6 @@ 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,
@ -70,20 +53,15 @@ InternalResponse::InternalResponse(uint16_t aStatus,
response->mHeaders =
new InternalHeaders(aIPCResponse.headers(), aIPCResponse.headersGuard());
if (aIPCResponse.body()) {
auto bodySize = aIPCResponse.bodySize();
nsCOMPtr<nsIInputStream> body =
TakeStreamFromStorage(*aIPCResponse.body(), bodySize);
response->SetBody(body, bodySize);
}
nsCOMPtr<nsIInputStream> body =
mozilla::ipc::DeserializeIPCStream(aIPCResponse.body());
response->SetBody(body, aIPCResponse.bodySize());
response->SetAlternativeDataType(aIPCResponse.alternativeDataType());
if (aIPCResponse.alternativeBody()) {
nsCOMPtr<nsIInputStream> alternativeBody = TakeStreamFromStorage(
*aIPCResponse.alternativeBody(), UNKNOWN_BODY_SIZE);
response->SetAlternativeBody(alternativeBody);
}
nsCOMPtr<nsIInputStream> alternativeBody =
mozilla::ipc::DeserializeIPCStream(aIPCResponse.alternativeBody());
response->SetAlternativeBody(alternativeBody);
response->InitChannelInfo(aIPCResponse.channelInfo());
@ -118,50 +96,54 @@ InternalResponse::InternalResponse(uint16_t aStatus,
InternalResponse::~InternalResponse() = default;
void InternalResponse::ToIPC(
template void InternalResponse::ToIPC<mozilla::ipc::PBackgroundChild>(
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) {
nsTArray<HeadersEntry> headers;
HeadersGuardEnum headersGuard;
UnfilteredHeaders()->ToIPC(headers, headersGuard);
MOZ_ASSERT(aIPCResponse);
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);
aIPCResponse->type() = mType;
GetUnfilteredURLList(aIPCResponse->urlList());
aIPCResponse->status() = GetUnfilteredStatus();
aIPCResponse->statusText() = GetUnfilteredStatusText();
UnfilteredHeaders()->ToIPC(aIPCResponse->headers(),
aIPCResponse->headersGuard());
nsCOMPtr<nsIInputStream> body;
int64_t bodySize;
GetUnfilteredBody(getter_AddRefs(body), &bodySize);
if (body) {
aIPCResponse->body().emplace(ChildToParentStream());
aIPCResponse->bodySize() = bodySize;
aAutoBodyStream.reset(new mozilla::ipc::AutoIPCStream(
aIPCResponse->body()->get_ChildToParentStream().stream()));
aAutoBodyStream.reset(
new mozilla::ipc::AutoIPCStream(aIPCResponse->body()));
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) {
aIPCResponse->alternativeBody().emplace(ChildToParentStream());
aAutoAlternativeBodyStream.reset(new mozilla::ipc::AutoIPCStream(
aIPCResponse->alternativeBody()->get_ChildToParentStream().stream()));
aAutoAlternativeBodyStream.reset(
new mozilla::ipc::AutoIPCStream(aIPCResponse->alternativeBody()));
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(

View File

@ -20,9 +20,8 @@
namespace mozilla {
namespace ipc {
class AutoIPCStream;
class PBackgroundChild;
class PrincipalInfo;
class AutoIPCStream;
} // namespace ipc
namespace dom {
@ -43,10 +42,9 @@ class InternalResponse final {
static RefPtr<InternalResponse> FromIPC(
const IPCInternalResponse& aIPCResponse);
// Note: the AutoIPCStreams must outlive the IPCInternalResponse.
template <typename M>
void ToIPC(
IPCInternalResponse* aIPCResponse,
mozilla::ipc::PBackgroundChild* aManager,
IPCInternalResponse* aIPCResponse, M* aManager,
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoBodyStream,
UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoAlternativeBodyStream);
@ -113,12 +111,6 @@ 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);

View File

@ -31,6 +31,10 @@ NS_INTERFACE_MAP_END
NS_IMPL_ADDREF(IPCBlobInputStreamStorage)
NS_IMPL_RELEASE(IPCBlobInputStreamStorage)
IPCBlobInputStreamStorage::IPCBlobInputStreamStorage() = default;
IPCBlobInputStreamStorage::~IPCBlobInputStreamStorage() = default;
/* static */
IPCBlobInputStreamStorage* IPCBlobInputStreamStorage::Get() { return gStorage; }

View File

@ -46,8 +46,8 @@ class IPCBlobInputStreamStorage final : public nsIObserver {
const nsID& aID);
private:
IPCBlobInputStreamStorage() = default;
~IPCBlobInputStreamStorage() = default;
IPCBlobInputStreamStorage();
~IPCBlobInputStreamStorage();
struct StreamData {
nsCOMPtr<nsIInputStream> mInputStream;

View File

@ -135,14 +135,6 @@ 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) {

View File

@ -255,10 +255,6 @@ 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,

View File

@ -16,6 +16,8 @@
#include "nsIChannel.h"
#include "nsIConsoleReportCollector.h"
#include "nsIContentPolicy.h"
#include "nsIHttpChannelInternal.h"
#include "nsIHttpHeaderVisitor.h"
#include "nsIInputStream.h"
#include "nsILoadInfo.h"
#include "nsINetworkInterceptController.h"
@ -23,6 +25,7 @@
#include "nsIScriptError.h"
#include "nsISupportsImpl.h"
#include "nsIURI.h"
#include "nsIUploadChannel2.h"
#include "nsNetUtil.h"
#include "nsProxyRelease.h"
#include "nsTArray.h"
@ -37,6 +40,7 @@
#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"
@ -181,6 +185,168 @@ 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(
@ -198,7 +364,28 @@ NS_IMPL_ISUPPORTS(SynthesizeResponseWatcher, nsIInterceptedBodyCallback)
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__);
}

View File

@ -120,14 +120,8 @@ void FetchEventOpProxyChild::Initialize(
}
Unused << self->SendRespondWith(ipcArgs);
if (ipcArgs.internalResponse().body()) {
autoBodyStream->TakeValue();
}
if (ipcArgs.internalResponse().alternativeBody()) {
autoAlternativeBodyStream->TakeValue();
}
autoBodyStream->TakeOptionalValue();
autoAlternativeBodyStream->TakeOptionalValue();
} else if (result.is<ResetInterceptionArgs>()) {
Unused << self->SendRespondWith(
result.extract<ResetInterceptionArgs>());
@ -145,7 +139,7 @@ RefPtr<InternalRequest> FetchEventOpProxyChild::ExtractInternalRequest() {
MOZ_ASSERT(IsCurrentThreadRunningWorker());
MOZ_ASSERT(mInternalRequest);
return std::move(mInternalRequest);
return RefPtr<InternalRequest>(std::move(mInternalRequest));
}
void FetchEventOpProxyChild::ActorDestroy(ActorDestroyReason) {

View File

@ -9,18 +9,13 @@
#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"
@ -32,25 +27,20 @@ namespace dom {
namespace {
nsresult MaybeDeserializeAndWrapForMainThread(
const Maybe<BodyStreamVariant>& aSource, int64_t aBodyStreamSize,
Maybe<BodyStreamVariant>& aSink, PBackgroundParent* aManager) {
if (aSource.isNothing()) {
return NS_OK;
void MaybeDeserializeAndReserialize(const Maybe<IPCStream>& aDeserialize,
Maybe<IPCStream>& aReserialize,
UniquePtr<AutoIPCStream>& aAutoStream,
PBackgroundParent* aManager) {
nsCOMPtr<nsIInputStream> maybeDeserialized =
DeserializeIPCStream(aDeserialize);
if (!maybeDeserialized) {
return;
}
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;
aAutoStream.reset(new AutoIPCStream(aReserialize));
DebugOnly<bool> ok = aAutoStream->Serialize(maybeDeserialized, aManager);
MOZ_ASSERT(ok);
}
} // anonymous namespace
@ -74,30 +64,15 @@ nsresult MaybeDeserializeAndWrapForMainThread(
ServiceWorkerFetchEventOpArgs copyArgs = aArgs;
IPCInternalRequest& copyRequest = copyArgs.internalRequest();
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();
PBackgroundParent* bgParent = aManager->Manager();
MOZ_ASSERT(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));
}
UniquePtr<AutoIPCStream> autoBodyStream = MakeUnique<AutoIPCStream>();
MaybeDeserializeAndReserialize(aArgs.internalRequest().body(),
copyRequest.body(), autoBodyStream, bgParent);
Unused << aManager->SendPFetchEventOpProxyConstructor(actor, copyArgs);
autoBodyStream->TakeOptionalValue();
}
FetchEventOpProxyParent::~FetchEventOpProxyParent() {
@ -150,14 +125,20 @@ mozilla::ipc::IPCResult FetchEventOpProxyParent::RecvRespondWith(
PBackgroundParent* bgParent = manager->Manager();
MOZ_ASSERT(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));
UniquePtr<AutoIPCStream> autoBodyStream = MakeUnique<AutoIPCStream>();
UniquePtr<AutoIPCStream> autoAlternativeBodyStream =
MakeUnique<AutoIPCStream>();
MaybeDeserializeAndReserialize(originalResponse.body(), copyResponse.body(),
autoBodyStream, bgParent);
MaybeDeserializeAndReserialize(originalResponse.alternativeBody(),
copyResponse.alternativeBody(),
autoAlternativeBodyStream, bgParent);
Unused << mReal->SendRespondWith(copyArgs);
autoBodyStream->TakeOptionalValue();
autoAlternativeBodyStream->TakeOptionalValue();
} else {
Unused << mReal->SendRespondWith(aResult);
}

View File

@ -14,13 +14,10 @@
#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"
@ -28,8 +25,6 @@
#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"
@ -37,9 +32,7 @@
#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"
@ -581,189 +574,12 @@ 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);
@ -773,15 +589,19 @@ nsresult ServiceWorkerPrivateImpl::SendFetchEvent(
});
nsCOMPtr<nsIChannel> channel;
MOZ_TRY(aChannel->GetChannel(getter_AddRefs(channel)));
nsresult rv = aChannel->GetChannel(getter_AddRefs(channel));
IPCInternalRequest request;
MOZ_TRY_VAR(request, GetIPCInternalRequest(aChannel));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
scopeExit.release();
MOZ_ASSERT(mOuter->mInfo);
// FetchEventOpChild will fill in the IPCInternalRequest.
ServiceWorkerFetchEventOpArgs args(
mOuter->mInfo->ScriptSpec(), std::move(request), nsString(aClientId),
mOuter->mInfo->ScriptSpec(), IPCInternalRequest(), nsString(aClientId),
nsString(aResultingClientId),
nsContentUtils::IsNonSubresourceRequest(channel));
@ -814,9 +634,11 @@ nsresult ServiceWorkerPrivateImpl::SendFetchEventInternal(
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
MOZ_TRY(SpawnWorkerIfNeeded());
MOZ_TRY(
MaybeStoreStreamForBackgroundThread(aChannel, aArgs.internalRequest()));
nsresult rv = SpawnWorkerIfNeeded();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
scopeExit.release();

View File

@ -1,14 +1,7 @@
self.skipWaiting();
addEventListener("fetch", event => {
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));
}
event.respondWith(fetch(event.request));
});
addEventListener("activate", function(event) {

View File

@ -14,12 +14,6 @@
<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]);
@ -30,22 +24,13 @@ async function onOpened(message) {
let serviceWorker = reg.installing || reg.waiting || reg.active;
await waitForState(serviceWorker, 'activated');
let res = await fetch('server_file_upload.sjs?clone=0', {
let res = await fetch('server_file_upload.sjs', {
method: 'POST',
body: input.files[0],
});
let data = await res.clone().text();
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!");
ok(data.length > 0, "We have data!");
await reg.unregister();
SimpleTest.finish();