Bug 1624318 - Serialize replacement config input stream as a blob. r=baku,necko-reviewers,valentin

Differential Revision: https://phabricator.services.mozilla.com/D71872
This commit is contained in:
Matt Woodrow 2020-04-27 04:49:00 +00:00
Родитель 753c84b4a5
Коммит 20f213591b
8 изменённых файлов: 82 добавлений и 51 удалений

Просмотреть файл

@ -78,7 +78,8 @@ already_AddRefed<BlobImpl> Deserialize(const IPCBlob& aIPCBlob) {
template <typename M>
nsresult SerializeInputStreamParent(nsIInputStream* aInputStream,
uint64_t aSize, uint64_t aChildID,
IPCBlob& aIPCBlob, M* aManager) {
PIPCBlobInputStreamParent*& aActorParent,
M* aManager) {
// Parent to Child we always send a IPCBlobInputStream.
MOZ_ASSERT(XRE_IsParentProcess());
@ -111,60 +112,58 @@ nsresult SerializeInputStreamParent(nsIInputStream* aInputStream,
return NS_ERROR_FAILURE;
}
aIPCBlob.inputStream() = parentActor;
aActorParent = parentActor;
return NS_OK;
}
template <typename M>
nsresult SerializeInputStreamChild(nsIInputStream* aInputStream,
IPCBlob& aIPCBlob, M* aManager) {
IPCBlobStream& aIPCBlob, M* aManager) {
AutoIPCStream ipcStream(true /* delayed start */);
if (!ipcStream.Serialize(aInputStream, aManager)) {
return NS_ERROR_FAILURE;
}
aIPCBlob.inputStream() = ipcStream.TakeValue();
aIPCBlob = ipcStream.TakeValue();
return NS_OK;
}
nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
uint64_t aChildID, IPCBlob& aIPCBlob,
PIPCBlobInputStreamParent*& aActorParent,
ContentParent* aManager) {
return SerializeInputStreamParent(aInputStream, aSize, aChildID, aIPCBlob,
return SerializeInputStreamParent(aInputStream, aSize, aManager->ChildID(),
aActorParent, aManager);
}
nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
IPCBlobStream& aIPCBlob,
ContentParent* aManager) {
aIPCBlob = (PIPCBlobInputStreamParent*)nullptr;
return SerializeInputStreamParent(aInputStream, aSize, aManager->ChildID(),
aIPCBlob.get_PIPCBlobInputStreamParent(),
aManager);
}
nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
uint64_t aChildID, IPCBlob& aIPCBlob,
IPCBlobStream& aIPCBlob,
PBackgroundParent* aManager) {
return SerializeInputStreamParent(aInputStream, aSize, aChildID, aIPCBlob,
aManager);
aIPCBlob = (PIPCBlobInputStreamParent*)nullptr;
return SerializeInputStreamParent(
aInputStream, aSize, BackgroundParent::GetChildID(aManager),
aIPCBlob.get_PIPCBlobInputStreamParent(), aManager);
}
nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
uint64_t aChildID, IPCBlob& aIPCBlob,
ContentChild* aManager) {
IPCBlobStream& aIPCBlob, ContentChild* aManager) {
return SerializeInputStreamChild(aInputStream, aIPCBlob, aManager);
}
nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
uint64_t aChildID, IPCBlob& aIPCBlob,
IPCBlobStream& aIPCBlob,
PBackgroundChild* aManager) {
return SerializeInputStreamChild(aInputStream, aIPCBlob, aManager);
}
uint64_t ChildIDFromManager(ContentParent* aManager) {
return aManager->ChildID();
}
uint64_t ChildIDFromManager(PBackgroundParent* aManager) {
return BackgroundParent::GetChildID(aManager);
}
uint64_t ChildIDFromManager(ContentChild* aManager) { return 0; }
uint64_t ChildIDFromManager(PBackgroundChild* aManager) { return 0; }
template <typename M>
nsresult SerializeInternal(BlobImpl* aBlobImpl, M* aManager,
IPCBlob& aIPCBlob) {
@ -219,7 +218,7 @@ nsresult SerializeInternal(BlobImpl* aBlobImpl, M* aManager,
}
rv = SerializeInputStream(inputStream, aIPCBlob.size(),
ChildIDFromManager(aManager), aIPCBlob, aManager);
aIPCBlob.inputStream(), aManager);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}

Просмотреть файл

@ -47,6 +47,12 @@
* parent process and sent to content (a FilePicker creates Blobs and it runs on
* the parent process).
*
* DocumentLoadListener uses blobs to serialize the POST data back to the
* content process (for insertion into session history). This lets it correclty
* handle OS files by reference, and avoid copying the underlying buffer data
* unless it is read. This can hopefully be removed once SessionHistory is
* handled in the parent process.
*
* Child to Parent Blob Serialization
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@ -224,6 +230,7 @@ namespace dom {
class IPCBlob;
class ContentChild;
class ContentParent;
class PIPCBlobInputStreamParent;
namespace IPCBlobUtils {
@ -244,6 +251,10 @@ nsresult Serialize(BlobImpl* aBlobImpl,
mozilla::ipc::PBackgroundParent* aManager,
IPCBlob& aIPCBlob);
nsresult SerializeInputStream(nsIInputStream* aInputStream, uint64_t aSize,
PIPCBlobInputStreamParent*& aActorParent,
ContentParent* 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,

Просмотреть файл

@ -11,6 +11,7 @@ include "mozilla/layers/LayersMessageUtils.h";
include IPCBlob;
include IPCStream;
include protocol PIPCBlobInputStream;
include ProtocolTypes;
include protocol PSHEntry;
@ -320,7 +321,7 @@ struct ReplacementChannelConfigInit
nsCString? method;
nsIReferrerInfo referrerInfo;
TimedChannelInfo? timedChannel;
nsIInputStream uploadStream;
nullable PIPCBlobInputStream uploadStream;
bool uploadStreamHasHeaders;
nsCString? contentType;
nsCString? contentLength;

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/ClientInfo.h"
#include "mozilla/dom/ContentParent.h"
extern mozilla::LazyLogModule gDocumentChannelLog;
#define LOG(fmt) MOZ_LOG(gDocumentChannelLog, mozilla::LogLevel::Verbose, fmt)
@ -68,7 +69,9 @@ DocumentChannelParent::RedirectToRealChannel(
CreateAndReject(ResponseRejectReason::ChannelClosed, __func__);
}
RedirectToRealChannelArgs args;
mParent->SerializeRedirectData(args, false, aRedirectFlags, aLoadFlags);
mParent->SerializeRedirectData(
args, false, aRedirectFlags, aLoadFlags,
static_cast<ContentParent*>(Manager()->Manager()));
return SendRedirectToRealChannel(args, std::move(aStreamFilterEndpoints));
}

Просмотреть файл

@ -1046,7 +1046,8 @@ bool DocumentLoadListener::ResumeSuspendedChannel(
void DocumentLoadListener::SerializeRedirectData(
RedirectToRealChannelArgs& aArgs, bool aIsCrossProcess,
uint32_t aRedirectFlags, uint32_t aLoadFlags) const {
uint32_t aRedirectFlags, uint32_t aLoadFlags,
ContentParent* aParent) const {
// Use the original URI of the current channel, as this is what
// we'll use to construct the channel in the content process.
aArgs.uri() = mChannelCreationURI;
@ -1132,7 +1133,7 @@ void DocumentLoadListener::SerializeRedirectData(
->CloneReplacementChannelConfig(
true, aRedirectFlags,
HttpBaseChannel::ReplacementReason::DocumentChannel)
.Serialize());
.Serialize(aParent));
}
uint32_t contentDispositionTemp;
@ -1389,7 +1390,7 @@ DocumentLoadListener::RedirectToRealChannel(
RedirectToRealChannelArgs args;
SerializeRedirectData(args, !!aDestinationProcess, aRedirectFlags,
aLoadFlags);
aLoadFlags, cp);
if (mTiming) {
mTiming->Anonymize(args.uri());
args.timing() = Some(std::move(mTiming));

Просмотреть файл

@ -200,7 +200,8 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
// in the content process into the RedirectToRealChannelArgs struct.
void SerializeRedirectData(RedirectToRealChannelArgs& aArgs,
bool aIsCrossProcess, uint32_t aRedirectFlags,
uint32_t aLoadFlags) const;
uint32_t aLoadFlags,
dom::ContentParent* aParent) const;
const nsTArray<DocumentChannelRedirect>& Redirects() const {
return mRedirects;

Просмотреть файл

@ -77,6 +77,8 @@
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include "nsURLHelper.h"
#include "mozilla/dom/IPCBlobUtils.h"
#include "mozilla/dom/IPCBlobInputStreamChild.h"
namespace mozilla {
namespace net {
@ -3181,7 +3183,15 @@ HttpBaseChannel::CloneReplacementChannelConfig(bool aPreserveMethod,
mRequestHead.Method(method);
config.method = Some(method);
config.uploadStream = mUploadStream;
if (mUploadStream) {
// rewind upload stream
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
if (seekable) {
seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
}
config.uploadStream = mUploadStream;
}
config.uploadStreamLength = mReqContentLength;
config.uploadStreamHasHeaders = mUploadStreamHasHeaders;
nsAutoCString contentType;
@ -3312,13 +3322,6 @@ HttpBaseChannel::CloneReplacementChannelConfig(bool aPreserveMethod,
nsCOMPtr<nsIUploadChannel> uploadChannel = do_QueryInterface(httpChannel);
nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(httpChannel);
if (uploadChannel2 || uploadChannel) {
// rewind upload stream
nsCOMPtr<nsISeekableStream> seekable =
do_QueryInterface(config.uploadStream);
if (seekable) {
seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
}
// replicate original call to SetUploadStream...
if (uploadChannel2) {
const nsACString& ctype =
@ -3331,16 +3334,13 @@ HttpBaseChannel::CloneReplacementChannelConfig(bool aPreserveMethod,
const nsACString& method =
config.method ? *config.method : VoidCString();
int64_t len = (!config.contentLength || config.contentLength->IsEmpty())
? -1
: nsCRT::atoll(config.contentLength->get());
uploadChannel2->ExplicitSetUploadStream(config.uploadStream, ctype, len,
method,
config.uploadStreamHasHeaders);
uploadChannel2->ExplicitSetUploadStream(
config.uploadStream, ctype, config.uploadStreamLength, method,
config.uploadStreamHasHeaders);
} else {
if (config.uploadStreamHasHeaders) {
uploadChannel->SetUploadStream(config.uploadStream, EmptyCString(),
-1);
config.uploadStreamLength);
} else {
nsAutoCString ctype;
if (config.contentType) {
@ -3378,14 +3378,24 @@ HttpBaseChannel::ReplacementChannelConfig::ReplacementChannelConfig(
method = aInit.method();
referrerInfo = aInit.referrerInfo();
timedChannel = aInit.timedChannel();
uploadStream = aInit.uploadStream();
if (dom::IPCBlobInputStreamChild* actor =
static_cast<dom::IPCBlobInputStreamChild*>(
aInit.uploadStreamChild())) {
uploadStreamLength = actor->Size();
uploadStream = actor->CreateStream();
// actor can be deleted by CreateStream, so don't touch it
// after this.
} else {
uploadStreamLength = 0;
}
uploadStreamHasHeaders = aInit.uploadStreamHasHeaders();
contentType = aInit.contentType();
contentLength = aInit.contentLength();
}
dom::ReplacementChannelConfigInit
HttpBaseChannel::ReplacementChannelConfig::Serialize() {
HttpBaseChannel::ReplacementChannelConfig::Serialize(
dom::ContentParent* aParent) {
dom::ReplacementChannelConfigInit config;
config.redirectFlags() = redirectFlags;
config.classOfService() = classOfService;
@ -3393,7 +3403,10 @@ HttpBaseChannel::ReplacementChannelConfig::Serialize() {
config.method() = method;
config.referrerInfo() = referrerInfo;
config.timedChannel() = timedChannel;
config.uploadStream() = uploadStream;
if (uploadStream) {
dom::IPCBlobUtils::SerializeInputStream(
uploadStream, uploadStreamLength, config.uploadStreamParent(), aParent);
}
config.uploadStreamHasHeaders() = uploadStreamHasHeaders;
config.contentType() = contentType;
config.contentLength() = contentLength;

Просмотреть файл

@ -66,7 +66,8 @@ namespace mozilla {
namespace dom {
class PerformanceStorage;
}
class ContentParent;
} // namespace dom
class LogCollector;
@ -491,11 +492,12 @@ class HttpBaseChannel : public nsHashPropertyBag,
nsCOMPtr<nsIReferrerInfo> referrerInfo;
Maybe<dom::TimedChannelInfo> timedChannel;
nsCOMPtr<nsIInputStream> uploadStream;
uint64_t uploadStreamLength;
bool uploadStreamHasHeaders;
Maybe<nsCString> contentType;
Maybe<nsCString> contentLength;
dom::ReplacementChannelConfigInit Serialize();
dom::ReplacementChannelConfigInit Serialize(dom::ContentParent* aParent);
};
enum class ReplacementReason {