--- a/netwerk/base/nsICacheInfoChannel.idl
+++ b/netwerk/base/nsICacheInfoChannel.idl
@@ -1,14 +1,16 @@
/* 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 "nsISupports.idl"
+interface nsIOutputStream;
+
[scriptable, uuid(72c34415-c6eb-48af-851f-772fa9ee5972)]
interface nsICacheInfoChannel : nsISupports
{
/**
* Get expiration time from cache token. This attribute is equivalent to
* nsICachingChannel.cacheToken.expirationTime.
*/
readonly attribute uint32_t cacheTokenExpirationTime;
@@ -47,9 +49,37 @@ interface nsICacheInfoChannel : nsISuppo
attribute nsISupports cacheKey;
/**
* Tells the channel to behave as if the LOAD_FROM_CACHE flag has been set,
* but without affecting the loads for the entire loadGroup in case of this
* channel being the default load group's channel.
*/
attribute boolean allowStaleCacheContent;
+
+ /**
+ * Calling this method instructs the channel to serve the alternative data
+ * if that was previously saved in the cache, otherwise it will serve the
+ * real data.
+ * Must be called before AsyncOpen.
+ */
+ void preferAlternativeDataType(in ACString type);
+
+ /**
+ * Holds the type of the alternative data representation that the channel
+ * is returning.
+ * Is empty string if no alternative data representation was requested, or
+ * if the requested representation wasn't found in the cache.
+ * Can only be called during or after OnStartRequest.
+ */
+ readonly attribute ACString alternativeDataType;
+
+ /**
+ * Opens and returns an output stream that a consumer may use to save an
+ * alternate representation of the data.
+ * Must be called after the OnStopRequest that delivered the real data.
+ * The consumer may choose to replace the saved alt representation.
+ * Opening the output stream will fail if there are any open input streams
+ * reading the already saved alt representation.
+ * TODO: clarify when consumers are allowed to save alt-data.
+ */
+ nsIOutputStream openAlternativeOutputStream(in ACString type);
};
--- a/netwerk/cache2/CacheEntry.cpp
+++ b/netwerk/cache2/CacheEntry.cpp
@@ -21,31 +21,37 @@
#include "nsComponentManagerUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsProxyRelease.h"
#include "nsSerializationHelper.h"
#include "nsThreadUtils.h"
#include "mozilla/Telemetry.h"
+#include "mozilla/Tokenizer.h"
+#include "mozilla/unused.h"
#include <math.h>
#include <algorithm>
namespace mozilla {
namespace net {
static uint32_t const ENTRY_WANTED =
nsICacheEntryOpenCallback::ENTRY_WANTED;
static uint32_t const RECHECK_AFTER_WRITE_FINISHED =
nsICacheEntryOpenCallback::RECHECK_AFTER_WRITE_FINISHED;
static uint32_t const ENTRY_NEEDS_REVALIDATION =
nsICacheEntryOpenCallback::ENTRY_NEEDS_REVALIDATION;
static uint32_t const ENTRY_NOT_WANTED =
nsICacheEntryOpenCallback::ENTRY_NOT_WANTED;
+// This designates the format for the "alt-data" metadata.
+// When the format changes we need to update the version.
+static uint32_t const ALT_DATA_META_VERSION = 1;
+
NS_IMPL_ISUPPORTS(CacheEntryHandle, nsICacheEntry)
// CacheEntryHandle
CacheEntryHandle::CacheEntryHandle(CacheEntry* aEntry)
: mEntry(aEntry)
{
MOZ_COUNT_CTOR(CacheEntryHandle);
@@ -1215,16 +1221,72 @@ nsresult CacheEntry::OpenOutputStreamInt
// Prevent opening output stream again.
mHasData = true;
stream.swap(*_retval);
return NS_OK;
}
+NS_IMETHODIMP CacheEntry::OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval)
+{
+ // Check metadata
+ // Open output stream
+ // When closing output stream set the metadata offset+type using CacheOutputCloseListener
+ // TODO: fail if there is an alternative input stream open
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP CacheEntry::OpenAlternativeInputStream(const nsACString & type, nsIInputStream * *_retval)
+{
+ nsresult rv;
+ nsXPIDLCString altDataMetadata;
+ rv = GetMetaDataElement("alt-data", getter_Copies(altDataMetadata));
+
+ if (NS_FAILED(rv)) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ // The format is: "1;12345,javascript/binary"
+ // <version>;<offset>,<type>
+ mozilla::Tokenizer p(altDataMetadata, nullptr, "/");
+ uint32_t metadataVersion = 0;
+ int64_t altDataOffset = -1;
+
+ // The metadata format has a wrong version number.
+ if (!p.ReadInteger(&metadataVersion) ||
+ metadataVersion != ALT_DATA_META_VERSION) {
+ LOG(("CacheEntry::SetPredictedDataSize [this=%p] metadataVersion=%u", metadataVersion));
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ if (!p.CheckChar(';') ||
+ !p.ReadInteger(&altDataOffset) ||
+ !p.CheckChar(',')) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ // The requested alt-data representation is not available
+ if (altDataOffset < 0) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsDependentCSubstring availableAltData;
+ mozilla::Unused << p.ReadUntil(Tokenizer::Token::Char(';'), availableAltData);
+
+ // If the alt-data type we find in the metadata matches the type
+ // preferred by consumers, we will serve that one.
+ if (availableAltData != type) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ // TODO: Open the actual input stream
+ return NS_OK;
+}
+
NS_IMETHODIMP CacheEntry::GetPredictedDataSize(int64_t *aPredictedDataSize)
{
*aPredictedDataSize = mPredictedDataSize;
return NS_OK;
}
NS_IMETHODIMP CacheEntry::SetPredictedDataSize(int64_t aPredictedDataSize)
{
mPredictedDataSize = aPredictedDataSize;
--- a/netwerk/cache2/OldWrappers.h
+++ b/netwerk/cache2/OldWrappers.h
@@ -40,16 +40,25 @@ public:
return !mOldDesc ? NS_ERROR_NULL_POINTER :
mOldDesc->OpenInputStream(offset, _retval);
}
nsresult OpenOutputStream(uint32_t offset, nsIOutputStream * *_retval)
{
return !mOldDesc ? NS_ERROR_NULL_POINTER :
mOldDesc->OpenOutputStream(offset, _retval);
}
+ NS_IMETHOD OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval) override
+ {
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+ NS_IMETHOD OpenAlternativeInputStream(const nsACString & type, nsIInputStream * *_retval) override
+ {
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
NS_IMETHOD GetPredictedDataSize(int64_t *aPredictedDataSize) override
{
return !mOldDesc ? NS_ERROR_NULL_POINTER :
mOldDesc->GetPredictedDataSize(aPredictedDataSize);
}
NS_IMETHOD SetPredictedDataSize(int64_t aPredictedDataSize) override
{
return !mOldDesc ? NS_ERROR_NULL_POINTER :
--- a/netwerk/cache2/nsICacheEntry.idl
+++ b/netwerk/cache2/nsICacheEntry.idl
@@ -194,16 +194,36 @@ interface nsICacheEntry : nsISupports
/**
* Returns the length of data this entry holds.
* @throws
* NS_ERROR_IN_PROGRESS when the write is still in progress.
*/
readonly attribute long long dataSize;
+ /**
+ * Opens and returns an output stream that a consumer may use to save an
+ * alternate representation of the data.
+ * @throws
+ * - NS_ERROR_NOT_AVAILABLE if the real data hasn't been written.
+ * - NS_ERROR_IN_PROGRESS when the write is still in progress.
+ *
+ * If there is alt-data already saved, it will be overwritten.
+ */
+ nsIOutputStream openAlternativeOutputStream(in ACString type);
+
+ /**
+ * Opens and returns an input stream that can be used to read the alternative
+ * representation previously saved in the cache.
+ * @throws
+ * - NS_ERROR_NOT_AVAILABLE if the alt-data representation doesn't exist at
+ * all or if alt-data of the given type doesn't exist.
+ */
+ nsIInputStream openAlternativeInputStream(in ACString type);
+
/****************************************************************************
* The following methods might be added to some nsICacheEntryInternal
* interface since we want to remove them as soon as the old cache backend is
* completely removed.
*/
/**
* @deprecated
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -116,16 +116,17 @@ struct HttpChannelOpenArgs
uint32_t cacheKey;
nsCString requestContextID;
OptionalCorsPreflightArgs preflightArgs;
uint32_t initialRwin;
bool blockAuthPrompt;
bool suspendAfterSynthesizeResponse;
bool allowStaleCacheContent;
nsCString contentTypeHint;
+ nsCString preferredAlternativeType;
};
struct HttpChannelConnectArgs
{
uint32_t channelId;
bool shouldIntercept;
};
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -17,16 +17,18 @@
#include "mozilla/net/WebSocketChannelChild.h"
#include "mozilla/net/WebSocketEventListenerChild.h"
#include "mozilla/net/DNSRequestChild.h"
#include "mozilla/net/RemoteOpenFileChild.h"
#include "mozilla/net/ChannelDiverterChild.h"
#include "mozilla/dom/network/TCPSocketChild.h"
#include "mozilla/dom/network/TCPServerSocketChild.h"
#include "mozilla/dom/network/UDPSocketChild.h"
+#include "mozilla/net/AltDataOutputStreamChild.h"
+
#ifdef NECKO_PROTOCOL_rtsp
#include "mozilla/net/RtspControllerChild.h"
#include "mozilla/net/RtspChannelChild.h"
#endif
#include "SerializedLoadContext.h"
#include "nsIOService.h"
#include "nsINetworkPredictor.h"
#include "nsINetworkPredictorVerifier.h"
@@ -82,16 +84,34 @@ NeckoChild::DeallocPHttpChannelChild(PHt
{
MOZ_ASSERT(IsNeckoChild(), "DeallocPHttpChannelChild called by non-child!");
HttpChannelChild* child = static_cast<HttpChannelChild*>(channel);
child->ReleaseIPDLReference();
return true;
}
+PAltDataOutputStreamChild*
+NeckoChild::AllocPAltDataOutputStreamChild(
+ const nsCString& type,
+ PHttpChannelChild* channel)
+{
+ AltDataOutputStreamChild* stream = new AltDataOutputStreamChild();
+ stream->AddIPDLReference();
+ return stream;
+}
+
+bool
+NeckoChild::DeallocPAltDataOutputStreamChild(PAltDataOutputStreamChild* aActor)
+{
+ AltDataOutputStreamChild* child = static_cast<AltDataOutputStreamChild*>(aActor);
+ child->ReleaseIPDLReference();
+ return true;
+}
+
PFTPChannelChild*
NeckoChild::AllocPFTPChannelChild(const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const FTPChannelCreationArgs& aOpenArgs)
{
// We don't allocate here: see FTPChannelChild::AsyncOpen()
NS_RUNTIMEABORT("AllocPFTPChannelChild should not be called");
return nullptr;
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -24,16 +24,20 @@ public:
static void InitNeckoChild();
protected:
virtual PHttpChannelChild*
AllocPHttpChannelChild(const PBrowserOrId&, const SerializedLoadContext&,
const HttpChannelCreationArgs& aOpenArgs) override;
virtual bool DeallocPHttpChannelChild(PHttpChannelChild*) override;
+
+ virtual PAltDataOutputStreamChild* AllocPAltDataOutputStreamChild(const nsCString& type, PHttpChannelChild* channel) override;
+ virtual bool DeallocPAltDataOutputStreamChild(PAltDataOutputStreamChild* aActor) override;
+
virtual PCookieServiceChild* AllocPCookieServiceChild() override;
virtual bool DeallocPCookieServiceChild(PCookieServiceChild*) override;
virtual PWyciwygChannelChild* AllocPWyciwygChannelChild() override;
virtual bool DeallocPWyciwygChannelChild(PWyciwygChannelChild*) override;
virtual PFTPChannelChild*
AllocPFTPChannelChild(const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const FTPChannelCreationArgs& aOpenArgs) override;
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -10,16 +10,18 @@
#include "mozilla/net/NeckoParent.h"
#include "mozilla/net/HttpChannelParent.h"
#include "mozilla/net/CookieServiceParent.h"
#include "mozilla/net/WyciwygChannelParent.h"
#include "mozilla/net/FTPChannelParent.h"
#include "mozilla/net/WebSocketChannelParent.h"
#include "mozilla/net/WebSocketEventListenerParent.h"
#include "mozilla/net/DataChannelParent.h"
+#include "mozilla/net/AltDataOutputStreamParent.h"
+#include "mozilla/unused.h"
#ifdef NECKO_PROTOCOL_rtsp
#include "mozilla/net/RtspControllerParent.h"
#include "mozilla/net/RtspChannelParent.h"
#endif
#include "mozilla/net/DNSRequestParent.h"
#include "mozilla/net/RemoteOpenFileParent.h"
#include "mozilla/net/ChannelDiverterParent.h"
#include "mozilla/dom/ContentParent.h"
@@ -253,16 +255,41 @@ NeckoParent::RecvPHttpChannelConstructor
const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const HttpChannelCreationArgs& aOpenArgs)
{
HttpChannelParent* p = static_cast<HttpChannelParent*>(aActor);
return p->Init(aOpenArgs);
}
+PAltDataOutputStreamParent*
+NeckoParent::AllocPAltDataOutputStreamParent(
+ const nsCString& type,
+ PHttpChannelParent* channel)
+{
+ HttpChannelParent* chan = static_cast<HttpChannelParent*>(channel);
+ nsCOMPtr<nsIOutputStream> stream;
+ nsresult rv = chan->OpenAlternativeOutputStream(type, getter_AddRefs(stream));
+ AltDataOutputStreamParent* parent = new AltDataOutputStreamParent(stream);
+ parent->AddRef();
+ if (NS_FAILED(rv)) {
+ Unused << parent->SendError(rv);
+ }
+ return parent;
+ return 0;
+}
+
+bool
+NeckoParent::DeallocPAltDataOutputStreamParent(PAltDataOutputStreamParent* aActor)
+{
+ AltDataOutputStreamParent* parent = static_cast<AltDataOutputStreamParent*>(aActor);
+ parent->Release();
+ return true;
+}
+
PFTPChannelParent*
NeckoParent::AllocPFTPChannelParent(const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const FTPChannelCreationArgs& aOpenArgs)
{
nsCOMPtr<nsILoadContext> loadContext;
const char *error = CreateChannelLoadContext(aBrowser, Manager(),
aSerialized, loadContext);
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -103,16 +103,22 @@ protected:
const HttpChannelCreationArgs& aOpenArgs) override;
virtual bool
RecvPHttpChannelConstructor(
PHttpChannelParent* aActor,
const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const HttpChannelCreationArgs& aOpenArgs) override;
virtual bool DeallocPHttpChannelParent(PHttpChannelParent*) override;
+
+ virtual PAltDataOutputStreamParent* AllocPAltDataOutputStreamParent(
+ const nsCString& type, PHttpChannelParent* channel) override;
+ virtual bool DeallocPAltDataOutputStreamParent(
+ PAltDataOutputStreamParent* aActor) override;
+
virtual bool DeallocPCookieServiceParent(PCookieServiceParent*) override;
virtual PWyciwygChannelParent* AllocPWyciwygChannelParent() override;
virtual bool DeallocPWyciwygChannelParent(PWyciwygChannelParent*) override;
virtual PFTPChannelParent*
AllocPFTPChannelParent(const PBrowserOrId& aBrowser,
const SerializedLoadContext& aSerialized,
const FTPChannelCreationArgs& aOpenArgs) override;
virtual bool
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -24,16 +24,17 @@ include protocol PFileDescriptorSet;
include protocol PDataChannel;
include protocol PRtspController;
include protocol PRtspChannel;
include URIParams;
include InputStreamParams;
include NeckoChannelParams;
include PBrowserOrId;
+include protocol PAltDataOutputStream;
using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
namespace mozilla {
namespace net {
@@ -51,16 +52,17 @@ prio(normal upto urgent) sync protocol P
manages PTCPServerSocket;
manages PUDPSocket;
manages PDNSRequest;
manages PRemoteOpenFile;
manages PDataChannel;
manages PRtspController;
manages PRtspChannel;
manages PChannelDiverter;
+ manages PAltDataOutputStream;
parent:
async __delete__();
prio(urgent) async PCookieService();
async PHttpChannel(PBrowserOrId browser,
SerializedLoadContext loadContext,
HttpChannelCreationArgs args);
@@ -109,16 +111,18 @@ parent:
* corresponding to an nsIAuthPromptCallback
*/
async OnAuthAvailable(uint64_t callbackId, nsString user,
nsString password, nsString domain);
async OnAuthCancelled(uint64_t callbackId, bool userCancel);
async RemoveRequestContext(nsCString rcid);
+ async PAltDataOutputStream(nsCString type, PHttpChannel channel);
+
child:
/*
* Bring up the http auth prompt for a nested remote mozbrowser.
* NestedFrameId is the id corresponding to the PBrowser. It is the same id
* that was passed to the PBrowserOrId param in to the PHttpChannel constructor
*/
async AsyncAuthPromptForNestedFrame(TabId nestedFrameId, nsCString uri,
nsString realm, uint64_t callbackId);
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/AltDataOutputStreamChild.cpp
@@ -0,0 +1,172 @@
+#include "mozilla/net/AltDataOutputStreamChild.h"
+#include "mozilla/unused.h"
+#include "nsIInputStream.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ADDREF(AltDataOutputStreamChild)
+
+NS_IMETHODIMP_(MozExternalRefCountType) AltDataOutputStreamChild::Release()
+{
+ NS_PRECONDITION(0 != mRefCnt, "dup release");
+ NS_ASSERT_OWNINGTHREAD(AltDataOutputStreamChild);
+ --mRefCnt;
+ NS_LOG_RELEASE(this, mRefCnt, "AltDataOutputStreamChild");
+
+ if (mRefCnt == 1 && mIPCOpen) {
+ // Send_delete calls NeckoChild::PAltDataOutputStreamChild, which will release
+ // again to refcount == 0
+ PAltDataOutputStreamChild::Send__delete__(this);
+ return 0;
+ }
+
+ if (mRefCnt == 0) {
+ mRefCnt = 1; /* stabilize */
+ delete this;
+ return 0;
+ }
+ return mRefCnt;
+}
+
+NS_INTERFACE_MAP_BEGIN(AltDataOutputStreamChild)
+ NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
+NS_INTERFACE_MAP_END
+
+AltDataOutputStreamChild::AltDataOutputStreamChild()
+ : mIPCOpen(false)
+ , mError(NS_OK)
+{
+ MOZ_COUNT_CTOR(AltDataOutputStreamChild);
+}
+
+AltDataOutputStreamChild::~AltDataOutputStreamChild()
+{
+ MOZ_COUNT_DTOR(AltDataOutputStreamChild);
+}
+
+void
+AltDataOutputStreamChild::AddIPDLReference()
+{
+ MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
+ mIPCOpen = true;
+ AddRef();
+}
+
+void
+AltDataOutputStreamChild::ReleaseIPDLReference()
+{
+ MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
+ mIPCOpen = false;
+ Release();
+}
+
+NS_IMETHODIMP
+AltDataOutputStreamChild::Close()
+{
+ if (!mIPCOpen) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ if (NS_FAILED(mError)) {
+ return mError;
+ }
+ Unused << SendClose();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+AltDataOutputStreamChild::Flush()
+{
+ if (!mIPCOpen) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ if (NS_FAILED(mError)) {
+ return mError;
+ }
+
+ // In CacheFileOutputStream this is a no-op
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+AltDataOutputStreamChild::Write(const char * aBuf, uint32_t aCount, uint32_t *_retval)
+{
+ if (!mIPCOpen) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ if (NS_FAILED(mError)) {
+ return mError;
+ }
+ Unused << SendWriteData(nsCString(aBuf, aCount));
+ *_retval = aCount;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+AltDataOutputStreamChild::WriteFrom(nsIInputStream *aFromStream, uint32_t aCount, uint32_t *_retval)
+{
+ if (!mIPCOpen) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ if (NS_FAILED(mError)) {
+ return mError;
+ }
+ nsAutoCString buffer;
+ buffer.SetCapacity(aCount);
+ aFromStream->Read(buffer.BeginWriting(), aCount, _retval);
+ buffer.SetCapacity(*_retval);
+ Unused << SendWriteData(buffer);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+AltDataOutputStreamChild::WriteSegments(nsReadSegmentFun aReader, void *aClosure, uint32_t aCount, uint32_t *_retval)
+{
+ if (!mIPCOpen) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ if (NS_FAILED(mError)) {
+ return mError;
+ }
+ nsAutoCString buffer;
+ buffer.SetCapacity(aCount);
+
+ *_retval = 0;
+ nsresult rv;
+ uint32_t cursor = 0;
+ uint32_t left = aCount;
+ while (left > 0) {
+ uint32_t read = 0;
+ rv = aReader(this, aClosure, buffer.BeginWriting() + cursor, *_retval, left, &read);
+
+ if (NS_FAILED(rv)) {
+ buffer.SetCapacity(cursor);
+ Unused << SendWriteData(buffer);
+ return (*_retval > 0) ? NS_OK : rv;
+ }
+ cursor += read;
+ *_retval += read;
+ left -= read;
+ }
+
+ Unused << SendWriteData(buffer);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+AltDataOutputStreamChild::IsNonBlocking(bool *_retval)
+{
+ *_retval = false;
+ return NS_OK;
+}
+
+bool
+AltDataOutputStreamChild::RecvError(const nsresult& err)
+{
+ mError = err;
+ return true;
+}
+
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/AltDataOutputStreamChild.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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/. */
+
+#ifndef mozilla_net_AltDataOutputStreamChild_h
+#define mozilla_net_AltDataOutputStreamChild_h
+
+#include "mozilla/net/PAltDataOutputStreamChild.h"
+#include "nsIOutputStream.h"
+
+namespace mozilla {
+namespace net {
+
+class AltDataOutputStreamChild
+ : public PAltDataOutputStreamChild
+ , public nsIOutputStream
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIOUTPUTSTREAM
+ explicit AltDataOutputStreamChild();
+
+ void AddIPDLReference();
+ void ReleaseIPDLReference();
+ virtual bool RecvError(const nsresult& err) override;
+
+private:
+ virtual ~AltDataOutputStreamChild();
+ bool mIPCOpen;
+ nsresult mError;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_AltDataOutputStreamChild_h
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/AltDataOutputStreamParent.cpp
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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/net/AltDataOutputStreamParent.h"
+#include "mozilla/unused.h"
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ISUPPORTS0(AltDataOutputStreamParent)
+
+AltDataOutputStreamParent::AltDataOutputStreamParent(nsIOutputStream* aStream)
+ : mOutputStream(aStream)
+{
+ MOZ_COUNT_CTOR(AltDataOutputStreamParent);
+}
+
+AltDataOutputStreamParent::~AltDataOutputStreamParent()
+{
+ MOZ_COUNT_DTOR(AltDataOutputStreamParent);
+}
+
+bool
+AltDataOutputStreamParent::RecvWriteData(const nsCString& data)
+{
+ nsresult rv;
+ uint32_t n;
+ if (mOutputStream) {
+ rv = mOutputStream->Write(data.BeginReading(), data.Length(), &n);
+ if (NS_FAILED(rv)) {
+ Unused << SendError(rv);
+ }
+ }
+ return true;
+}
+
+bool
+AltDataOutputStreamParent::RecvClose()
+{
+ nsresult rv;
+ if (mOutputStream) {
+ rv = mOutputStream->Close();
+ if (NS_FAILED(rv)) {
+ Unused << SendError(rv);
+ }
+ }
+ return true;
+}
+
+void
+AltDataOutputStreamParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+}
+
+} // namespace net
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/AltDataOutputStreamParent.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et 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/. */
+
+#ifndef mozilla_net_AltDataOutputStreamParent_h
+#define mozilla_net_AltDataOutputStreamParent_h
+
+#include "mozilla/net/PAltDataOutputStreamParent.h"
+#include "nsIOutputStream.h"
+
+namespace mozilla {
+namespace net {
+
+class AltDataOutputStreamParent
+ : public PAltDataOutputStreamParent
+ , public nsISupports
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ explicit AltDataOutputStreamParent(nsIOutputStream* aStream);
+
+ virtual bool RecvWriteData(const nsCString& data) override;
+ virtual bool RecvClose() override;
+ virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+private:
+ virtual ~AltDataOutputStreamParent();
+ nsCOMPtr<nsIOutputStream> mOutputStream;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_AltDataOutputStreamParent_h
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -48,16 +48,17 @@
#include "mozilla/ConsoleReportCollector.h"
#include "LoadInfo.h"
#include "nsISSLSocketControl.h"
#include "mozilla/Telemetry.h"
#include "nsIURL.h"
#include "nsIConsoleService.h"
#include "mozilla/BinarySearch.h"
#include "nsIHttpHeaderVisitor.h"
+#include "nsICacheInfoChannel.h"
#include <algorithm>
namespace mozilla {
namespace net {
HttpBaseChannel::HttpBaseChannel()
: mStartPos(UINT64_MAX)
@@ -101,16 +102,17 @@ HttpBaseChannel::HttpBaseChannel()
, mRedirectCount(0)
, mForcePending(false)
, mCorsIncludeCredentials(false)
, mCorsMode(nsIHttpChannelInternal::CORS_MODE_NO_CORS)
, mRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW)
, mFetchCacheMode(nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT)
, mOnStartRequestCalled(false)
, mOnStopRequestCalled(false)
+ , mAfterOnStartRequestBegun(false)
, mTransferSize(0)
, mDecodedBodySize(0)
, mEncodedBodySize(0)
, mRequireCORSPreflight(false)
, mReportCollector(new ConsoleReportCollector())
, mForceMainDocumentChannel(false)
{
LOG(("Creating HttpBaseChannel @%x\n", this));
@@ -3029,16 +3031,23 @@ HttpBaseChannel::SetupReplacementChannel
if (loadInfo && loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) {
nsCOMPtr<nsIPrincipal> principal = loadInfo->LoadingPrincipal();
newTimedChannel->SetAllRedirectsPassTimingAllowCheck(
mAllRedirectsPassTimingAllowCheck &&
oldTimedChannel->TimingAllowCheck(principal));
}
}
+ // Pass the preferred alt-data type on to the new channel.
+ nsCOMPtr<nsICacheInfoChannel> cacheInfoChan(do_QueryInterface(newChannel));
+ if (cacheInfoChan) {
+ cacheInfoChan->PreferAlternativeDataType(mPreferredCachedAltDataType);
+ }
+
+
if (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
nsIChannelEventSink::REDIRECT_STS_UPGRADE)) {
// Copy non-origin related headers to the new channel.
nsCOMPtr<nsIHttpHeaderVisitor> visitor =
new SetupReplacementChannelHeaderVisitor(httpChannel);
mRequestHead.VisitHeaders(visitor);
}
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -494,31 +494,40 @@ protected:
uint32_t mRedirectMode;
uint32_t mFetchCacheMode;
// These parameters are used to ensure that we do not call OnStartRequest and
// OnStopRequest more than once.
bool mOnStartRequestCalled;
bool mOnStopRequestCalled;
+ // Defaults to false. Is set to true at the begining of OnStartRequest.
+ // Used to ensure methods can't be called before OnStartRequest.
+ bool mAfterOnStartRequestBegun;
+
uint64_t mTransferSize;
uint64_t mDecodedBodySize;
uint64_t mEncodedBodySize;
// The network interface id that's associated with this channel.
nsCString mNetworkInterfaceId;
nsID mRequestContextID;
bool EnsureRequestContextID();
bool mRequireCORSPreflight;
nsTArray<nsCString> mUnsafeHeaders;
nsCOMPtr<nsIConsoleReportCollector> mReportCollector;
+ // Holds the name of the preferred alt-data type.
+ nsCString mPreferredCachedAltDataType;
+ // Holds the name of the alternative data type the channel returned.
+ nsCString mAvailableCachedAltDataType;
+
bool mForceMainDocumentChannel;
};
// Share some code while working around C++'s absurd inability to handle casting
// of member functions between base/derived types.
// - We want to store member function pointer to call at resume time, but one
// such function--HandleAsyncAbort--we want to share between the
// nsHttpChannel/HttpChannelChild. Can't define it in base class, because
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -309,71 +309,75 @@ class StartRequestEvent : public Channel
const nsHttpHeaderArray& requestHeaders,
const bool& isFromCache,
const bool& cacheEntryAvailable,
const uint32_t& cacheExpirationTime,
const nsCString& cachedCharset,
const nsCString& securityInfoSerialization,
const NetAddr& selfAddr,
const NetAddr& peerAddr,
- const uint32_t& cacheKey)
+ const uint32_t& cacheKey,
+ const nsCString& altDataType)
: mChild(child)
, mChannelStatus(channelStatus)
, mResponseHead(responseHead)
, mRequestHeaders(requestHeaders)
, mUseResponseHead(useResponseHead)
, mIsFromCache(isFromCache)
, mCacheEntryAvailable(cacheEntryAvailable)
, mCacheExpirationTime(cacheExpirationTime)
, mCachedCharset(cachedCharset)
, mSecurityInfoSerialization(securityInfoSerialization)
, mSelfAddr(selfAddr)
, mPeerAddr(peerAddr)
, mCacheKey(cacheKey)
+ , mAltDataType(altDataType)
{}
void Run()
{
LOG(("StartRequestEvent [this=%p]\n", mChild));
mChild->OnStartRequest(mChannelStatus, mResponseHead, mUseResponseHead,
mRequestHeaders, mIsFromCache, mCacheEntryAvailable,
mCacheExpirationTime, mCachedCharset,
mSecurityInfoSerialization, mSelfAddr, mPeerAddr,
- mCacheKey);
+ mCacheKey, mAltDataType);
}
private:
HttpChannelChild* mChild;
nsresult mChannelStatus;
nsHttpResponseHead mResponseHead;
nsHttpHeaderArray mRequestHeaders;
bool mUseResponseHead;
bool mIsFromCache;
bool mCacheEntryAvailable;
uint32_t mCacheExpirationTime;
nsCString mCachedCharset;
nsCString mSecurityInfoSerialization;
NetAddr mSelfAddr;
NetAddr mPeerAddr;
uint32_t mCacheKey;
+ nsCString mAltDataType;
};
bool
HttpChannelChild::RecvOnStartRequest(const nsresult& channelStatus,
const nsHttpResponseHead& responseHead,
const bool& useResponseHead,
const nsHttpHeaderArray& requestHeaders,
const bool& isFromCache,
const bool& cacheEntryAvailable,
const uint32_t& cacheExpirationTime,
const nsCString& cachedCharset,
const nsCString& securityInfoSerialization,
const NetAddr& selfAddr,
const NetAddr& peerAddr,
const int16_t& redirectCount,
- const uint32_t& cacheKey)
+ const uint32_t& cacheKey,
+ const nsCString& altDataType)
{
LOG(("HttpChannelChild::RecvOnStartRequest [this=%p]\n", this));
// mFlushedForDiversion and mDivertingToParent should NEVER be set at this
// stage, as they are set in the listener's OnStartRequest.
MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
"mFlushedForDiversion should be unset before OnStartRequest!");
MOZ_RELEASE_ASSERT(!mDivertingToParent,
"mDivertingToParent should be unset before OnStartRequest!");
@@ -382,33 +386,35 @@ HttpChannelChild::RecvOnStartRequest(con
mRedirectCount = redirectCount;
mEventQ->RunOrEnqueue(new StartRequestEvent(this, channelStatus, responseHead,
useResponseHead, requestHeaders,
isFromCache, cacheEntryAvailable,
cacheExpirationTime,
cachedCharset,
securityInfoSerialization,
- selfAddr, peerAddr, cacheKey));
+ selfAddr, peerAddr, cacheKey,
+ altDataType));
return true;
}
void
HttpChannelChild::OnStartRequest(const nsresult& channelStatus,
const nsHttpResponseHead& responseHead,
const bool& useResponseHead,
const nsHttpHeaderArray& requestHeaders,
const bool& isFromCache,
const bool& cacheEntryAvailable,
const uint32_t& cacheExpirationTime,
const nsCString& cachedCharset,
const nsCString& securityInfoSerialization,
const NetAddr& selfAddr,
const NetAddr& peerAddr,
- const uint32_t& cacheKey)
+ const uint32_t& cacheKey,
+ const nsCString& altDataType)
{
LOG(("HttpChannelChild::OnStartRequest [this=%p]\n", this));
// mFlushedForDiversion and mDivertingToParent should NEVER be set at this
// stage, as they are set in the listener's OnStartRequest.
MOZ_RELEASE_ASSERT(!mFlushedForDiversion,
"mFlushedForDiversion should be unset before OnStartRequest!");
MOZ_RELEASE_ASSERT(!mDivertingToParent,
@@ -428,16 +434,21 @@ HttpChannelChild::OnStartRequest(const n
mIsFromCache = isFromCache;
mCacheEntryAvailable = cacheEntryAvailable;
mCacheExpirationTime = cacheExpirationTime;
mCachedCharset = cachedCharset;
mSelfAddr = selfAddr;
mPeerAddr = peerAddr;
+ mAvailableCachedAltDataType = altDataType;
+
+ MOZ_ASSERT(!mAfterOnStartRequestBegun, "OnStartRequest should be called only once");
+ mAfterOnStartRequestBegun = true;
+
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
nsresult rv;
nsCOMPtr<nsISupportsPRUint32> container =
do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
Cancel(rv);
return;
@@ -901,16 +912,25 @@ HttpChannelChild::OnStopRequest(const ns
// so make sure this goes out of scope before then.
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
DoOnStopRequest(this, channelStatus, mListenerContext);
}
ReleaseListeners();
+
+ // TODO: we can't simply close the channel because we might need it to write
+ // alt-data
+ // Possible strategies:
+ // 1. Don't close the channel only if mPreferredCachedAltDataType is set.
+ // 2. Alloc AltDatOutputStream right now and close the channel
+ // - this would only keep a ref to the cache entry, not the channel bits
+ // 3. If possible use FD to write alt-data instead.
+
if (mLoadFlags & LOAD_DOCUMENT_URI) {
// Keep IPDL channel open, but only for updating security info.
mKeptAlive = true;
SendDocumentChannelCleanup();
} else {
// This calls NeckoChild::DeallocPHttpChannelChild(), which deletes |this| if IPDL
// holds the last reference. Don't rely on |this| existing after here.
PHttpChannelChild::Send__delete__(this);
@@ -1850,16 +1870,17 @@ HttpChannelChild::ContinueAsyncOpen()
SerializeURI(mOriginalURI, openArgs.original());
SerializeURI(mDocumentURI, openArgs.doc());
SerializeURI(mReferrer, openArgs.referrer());
openArgs.referrerPolicy() = mReferrerPolicy;
SerializeURI(mAPIRedirectToURI, openArgs.apiRedirectTo());
openArgs.loadFlags() = mLoadFlags;
openArgs.requestHeaders() = mClientSetRequestHeaders;
mRequestHead.Method(openArgs.requestMethod());
+ openArgs.preferredAlternativeType() = mPreferredCachedAltDataType;
nsTArray<mozilla::ipc::FileDescriptor> fds;
SerializeInputStream(mUploadStream, openArgs.uploadStream(), fds);
if (mResponseHead) {
openArgs.synthesizedResponseHead() = *mResponseHead;
openArgs.suspendAfterSynthesizeResponse() =
mSuspendParentAfterSynthesizeResponse;
@@ -2109,16 +2130,45 @@ HttpChannelChild::SetAllowStaleCacheCont
NS_IMETHODIMP
HttpChannelChild::GetAllowStaleCacheContent(bool *aAllowStaleCacheContent)
{
NS_ENSURE_ARG(aAllowStaleCacheContent);
*aAllowStaleCacheContent = mAllowStaleCacheContent;
return NS_OK;
}
+NS_IMETHODIMP
+HttpChannelChild::PreferAlternativeDataType(const nsACString & aType)
+{
+ ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+ mPreferredCachedAltDataType = aType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpChannelChild::GetAlternativeDataType(nsACString & aType)
+{
+ // Must be called during or after OnStartRequest
+ if (!mAfterOnStartRequestBegun) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ aType = mAvailableCachedAltDataType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpChannelChild::OpenAlternativeOutputStream(const nsACString & aType, nsIOutputStream * *_retval)
+{
+ RefPtr<AltDataOutputStreamChild> stream =
+ static_cast<AltDataOutputStreamChild*>(gNeckoChild->SendPAltDataOutputStreamConstructor(nsCString(aType), this));
+ stream.forget(_retval);
+ return NS_OK;
+}
+
//-----------------------------------------------------------------------------
// HttpChannelChild::nsIResumableChannel
//-----------------------------------------------------------------------------
NS_IMETHODIMP
HttpChannelChild::ResumeAt(uint64_t startPos, const nsACString& entityID)
{
LOG(("HttpChannelChild::ResumeAt [this=%p]\n", this));
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -116,17 +116,18 @@ protected:
const bool& isFromCache,
const bool& cacheEntryAvailable,
const uint32_t& cacheExpirationTime,
const nsCString& cachedCharset,
const nsCString& securityInfoSerialization,
const NetAddr& selfAddr,
const NetAddr& peerAddr,
const int16_t& redirectCount,
- const uint32_t& cacheKey) override;
+ const uint32_t& cacheKey,
+ const nsCString& altDataType) override;
bool RecvOnTransportAndData(const nsresult& channelStatus,
const nsresult& status,
const uint64_t& progress,
const uint64_t& progressMax,
const uint64_t& offset,
const uint32_t& count,
const nsCString& data) override;
bool RecvOnStopRequest(const nsresult& statusCode, const ResourceTimingStruct& timing) override;
@@ -255,17 +256,18 @@ private:
const nsHttpHeaderArray& requestHeaders,
const bool& isFromCache,
const bool& cacheEntryAvailable,
const uint32_t& cacheExpirationTime,
const nsCString& cachedCharset,
const nsCString& securityInfoSerialization,
const NetAddr& selfAddr,
const NetAddr& peerAddr,
- const uint32_t& cacheKey);
+ const uint32_t& cacheKey,
+ const nsCString& altDataType);
void MaybeDivertOnData(const nsCString& data,
const uint64_t& offset,
const uint32_t& count);
void OnTransportAndData(const nsresult& channelStatus,
const nsresult& status,
const uint64_t progress,
const uint64_t& progressMax,
const uint64_t& offset,
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -128,17 +128,18 @@ HttpChannelParent::Init(const HttpChanne
a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
a.entityID(), a.chooseApplicationCache(),
a.appCacheClientID(), a.allowSpdy(), a.allowAltSvc(), a.fds(),
a.loadInfo(), a.synthesizedResponseHead(),
a.synthesizedSecurityInfoSerialization(),
a.cacheKey(), a.requestContextID(), a.preflightArgs(),
a.initialRwin(), a.blockAuthPrompt(),
a.suspendAfterSynthesizeResponse(),
- a.allowStaleCacheContent(), a.contentTypeHint());
+ a.allowStaleCacheContent(), a.contentTypeHint(),
+ a.preferredAlternativeType());
}
case HttpChannelCreationArgs::THttpChannelConnectArgs:
{
const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
return ConnectChannel(cArgs.channelId(), cArgs.shouldIntercept());
}
default:
NS_NOTREACHED("unknown open type");
@@ -259,17 +260,18 @@ HttpChannelParent::DoAsyncOpen( const U
const nsCString& aSecurityInfoSerialization,
const uint32_t& aCacheKey,
const nsCString& aRequestContextID,
const OptionalCorsPreflightArgs& aCorsPreflightArgs,
const uint32_t& aInitialRwin,
const bool& aBlockAuthPrompt,
const bool& aSuspendAfterSynthesizeResponse,
const bool& aAllowStaleCacheContent,
- const nsCString& aContentTypeHint)
+ const nsCString& aContentTypeHint,
+ const nsCString& aPreferredAlternativeType)
{
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
if (!uri) {
// URIParams does MOZ_ASSERT if null, but we need to protect opt builds from
// null deref here.
return false;
}
nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
@@ -407,16 +409,17 @@ HttpChannelParent::DoAsyncOpen( const U
}
rv = cacheKey->SetData(aCacheKey);
if (NS_FAILED(rv)) {
return SendFailedAsyncOpen(rv);
}
mChannel->SetCacheKey(cacheKey);
+ mChannel->PreferAlternativeDataType(aPreferredAlternativeType);
mChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent);
mChannel->SetContentType(aContentTypeHint);
if (priority != nsISupportsPriority::PRIORITY_NORMAL) {
mChannel->SetPriority(priority);
}
@@ -1052,30 +1055,34 @@ HttpChannelParent::OnStartRequest(nsIReq
}
nsresult rv = container->GetData(&cacheKeyValue);
if (NS_FAILED(rv)) {
return rv;
}
}
+ nsAutoCString altDataType;
+ mChannel->GetAlternativeDataType(altDataType);
+
// !!! We need to lock headers and please don't forget to unlock them !!!
requestHead->Lock();
nsresult rv = NS_OK;
if (mIPCClosed ||
!SendOnStartRequest(channelStatus,
responseHead ? *responseHead : nsHttpResponseHead(),
!!responseHead,
requestHead->Headers(),
isFromCache,
mCacheEntry ? true : false,
expirationTime, cachedCharset, secInfoSerialization,
mChannel->GetSelfAddr(), mChannel->GetPeerAddr(),
redirectCount,
- cacheKeyValue))
+ cacheKeyValue,
+ altDataType))
{
rv = NS_ERROR_UNEXPECTED;
}
requestHead->Unlock();
return rv;
}
NS_IMETHODIMP
@@ -1574,16 +1581,27 @@ HttpChannelParent::NotifyDiversionFailed
mParentListener = nullptr;
mChannel = nullptr;
if (!mIPCClosed) {
Unused << SendDeleteSelf();
}
}
+nsresult
+HttpChannelParent::OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval)
+{
+ // TODO: use mChannel or mCacheEntry
+ // XXX: problem - these area cleared in RecvDocumentChannelCleanup()
+ if (!mChannel) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ return mChannel->OpenAlternativeOutputStream(type, _retval);
+}
+
void
HttpChannelParent::OfflineDisconnect()
{
if (mChannel) {
mChannel->Cancel(NS_ERROR_OFFLINE);
}
mStatus = NS_ERROR_OFFLINE;
}
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -93,16 +93,18 @@ public:
// Forwarded to nsHttpChannel::SetApplyConversion.
void SetApplyConversion(bool aApplyConversion) {
if (mChannel) {
mChannel->SetApplyConversion(aApplyConversion);
}
}
+ nsresult OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval);
+
protected:
// used to connect redirected-to channel in parent with just created
// ChildChannel. Used during redirects.
bool ConnectChannel(const uint32_t& channelId, const bool& shouldIntercept);
bool DoAsyncOpen(const URIParams& uri,
const OptionalURIParams& originalUri,
const OptionalURIParams& docUri,
@@ -134,17 +136,18 @@ protected:
const nsCString& aSecurityInfoSerialization,
const uint32_t& aCacheKey,
const nsCString& aRequestContextID,
const OptionalCorsPreflightArgs& aCorsPreflightArgs,
const uint32_t& aInitialRwin,
const bool& aBlockAuthPrompt,
const bool& aSuspendAfterSynthesizeResponse,
const bool& aAllowStaleCacheContent,
- const nsCString& aContentTypeHint);
+ const nsCString& aContentTypeHint,
+ const nsCString& aPreferredAlternativeType);
virtual bool RecvSetPriority(const uint16_t& priority) override;
virtual bool RecvSetClassOfService(const uint32_t& cos) override;
virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset) override;
virtual bool RecvSuspend() override;
virtual bool RecvResume() override;
virtual bool RecvCancel(const nsresult& status) override;
virtual bool RecvRedirect2Verify(const nsresult& result,
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/PAltDataOutputStream.ipdl
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+
+/* 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 protocol PNecko;
+
+namespace mozilla {
+namespace net {
+
+protocol PAltDataOutputStream
+{
+ manager PNecko;
+
+parent:
+ async WriteData(nsCString data);
+ async Close();
+ async __delete__();
+
+child:
+ async Error(nsresult err);
+};
+
+} // namespace net
+} // namespace mozilla
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -94,17 +94,18 @@ child:
bool isFromCache,
bool cacheEntryAvailable,
uint32_t cacheExpirationTime,
nsCString cachedCharset,
nsCString securityInfoSerialization,
NetAddr selfAddr,
NetAddr peerAddr,
int16_t redirectCount,
- uint32_t cacheKey);
+ uint32_t cacheKey,
+ nsCString altDataType);
// Combines a single OnDataAvailable and its associated OnProgress &
// OnStatus calls into one IPDL message
async OnTransportAndData(nsresult channelStatus,
nsresult transportStatus,
uint64_t progress,
uint64_t progressMax,
uint64_t offset,
--- a/netwerk/protocol/http/moz.build
+++ b/netwerk/protocol/http/moz.build
@@ -25,16 +25,18 @@ EXPORTS += [
'nsHttp.h',
'nsHttpAtomList.h',
'nsHttpHeaderArray.h',
'nsHttpRequestHead.h',
'nsHttpResponseHead.h',
]
EXPORTS.mozilla.net += [
+ 'AltDataOutputStreamChild.h',
+ 'AltDataOutputStreamParent.h',
'HttpBaseChannel.h',
'HttpChannelChild.h',
'HttpChannelParent.h',
'HttpInfo.h',
'NullHttpChannel.h',
'PackagedAppService.h',
'PackagedAppVerifier.h',
'PHttpChannelParams.h',
@@ -47,16 +49,18 @@ EXPORTS.mozilla.net += [
SOURCES += [
'AlternateServices.cpp',
'ASpdySession.cpp',
'nsHttpAuthCache.cpp',
'nsHttpChannelAuthProvider.cpp', # redefines GetAuthType
]
UNIFIED_SOURCES += [
+ 'AltDataOutputStreamChild.cpp',
+ 'AltDataOutputStreamParent.cpp',
'ConnectionDiagnostics.cpp',
'Http2Compression.cpp',
'Http2Push.cpp',
'Http2Session.cpp',
'Http2Stream.cpp',
'HttpBaseChannel.cpp',
'HttpChannelChild.cpp',
'HttpChannelParent.cpp',
@@ -92,16 +96,17 @@ UNIFIED_SOURCES += [
]
# These files cannot be built in unified mode because of OS X headers.
SOURCES += [
'nsHttpHandler.cpp',
]
IPDL_SOURCES += [
+ 'PAltDataOutputStream.ipdl',
'PHttpChannel.ipdl',
]
EXTRA_JS_MODULES += [
'UserAgentOverrides.jsm',
'UserAgentUpdates.jsm',
]
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -4124,17 +4124,30 @@ nsHttpChannel::OpenCacheInputStream(nsIC
// just in case.
LOG(("May skip read from cache based on LOAD_ONLY_IF_MODIFIED "
"load flag\n"));
}
// Open an input stream for the entity, so that the call to OpenInputStream
// happens off the main thread.
nsCOMPtr<nsIInputStream> stream;
- rv = cacheEntry->OpenInputStream(0, getter_AddRefs(stream));
+
+ // If an alternate representation was requested, try to open the alt
+ // input stream.
+ if (!mPreferredCachedAltDataType.IsEmpty()) {
+ rv = cacheEntry->OpenAlternativeInputStream(mPreferredCachedAltDataType, getter_AddRefs(stream));
+ if (NS_SUCCEEDED(rv)) {
+ // We have succeeded.
+ mAvailableCachedAltDataType = mPreferredCachedAltDataType;
+ }
+ }
+
+ if (!stream) {
+ rv = cacheEntry->OpenInputStream(0, getter_AddRefs(stream));
+ }
if (NS_FAILED(rv)) {
LOG(("Failed to open cache input stream [channel=%p, "
"mCacheEntry=%p]", this, cacheEntry));
return rv;
}
if (startBuffering) {
@@ -4323,17 +4336,16 @@ nsHttpChannel::CloseCacheEntry(bool doom
} else {
// Store updated security info, makes cached EV status race less likely
// (see bug 1040086)
if (mSecurityInfo)
mCacheEntry->SetSecurityInfo(mSecurityInfo);
}
mCachedResponseHead = nullptr;
-
mCachePump = nullptr;
mCacheEntry = nullptr;
mCacheEntryIsWriteOnly = false;
mInitedCacheEntry = false;
}
void
@@ -5941,16 +5953,19 @@ nsHttpChannel::OnStartRequest(nsIRequest
this, request, mStatus));
// Make sure things are what we expect them to be...
MOZ_ASSERT(request == mCachePump || request == mTransactionPump,
"Unexpected request");
MOZ_ASSERT(!(mTransactionPump && mCachePump) || mCachedContentIsPartial,
"If we have both pumps, the cache content must be partial");
+ MOZ_ASSERT(!mAfterOnStartRequestBegun, "OnStartRequest should be called only once");
+ mAfterOnStartRequestBegun = true;
+
if (!mSecurityInfo && !mCachePump && mTransaction) {
// grab the security info from the connection object; the transaction
// is guaranteed to own a reference to the connection.
mSecurityInfo = mTransaction->SecurityInfo();
}
// don't enter this block if we're reading from the cache...
if (NS_SUCCEEDED(mStatus) && !mCachePump && mTransaction) {
@@ -6637,16 +6652,49 @@ nsHttpChannel::SetAllowStaleCacheContent
NS_IMETHODIMP
nsHttpChannel::GetAllowStaleCacheContent(bool *aAllowStaleCacheContent)
{
NS_ENSURE_ARG(aAllowStaleCacheContent);
*aAllowStaleCacheContent = mAllowStaleCacheContent;
return NS_OK;
}
+NS_IMETHODIMP
+nsHttpChannel::PreferAlternativeDataType(const nsACString & aType)
+{
+ ENSURE_CALLED_BEFORE_ASYNC_OPEN();
+ mPreferredCachedAltDataType = aType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHttpChannel::GetAlternativeDataType(nsACString & aType)
+{
+ // must be called during or after OnStartRequest
+ if (!mAfterOnStartRequestBegun) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ aType = mAvailableCachedAltDataType;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHttpChannel::OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval)
+{
+ if (!mCacheEntry) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ nsresult rv;
+ rv = mCacheEntry->OpenAlternativeOutputStream(type, _retval);
+ if (NS_FAILED(rv)) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ return NS_OK;
+}
+
//-----------------------------------------------------------------------------
// nsHttpChannel::nsICachingChannel
//-----------------------------------------------------------------------------
NS_IMETHODIMP
nsHttpChannel::GetCacheToken(nsISupports **token)
{
NS_ENSURE_ARG_POINTER(token);
--- a/netwerk/protocol/http/nsHttpHeaderArray.cpp
+++ b/netwerk/protocol/http/nsHttpHeaderArray.cpp
@@ -5,16 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// HttpLog.h should generally be included first
#include "HttpLog.h"
#include "nsHttpHeaderArray.h"
#include "nsURLHelper.h"
#include "nsIHttpHeaderVisitor.h"
+#include "nsHttpHandler.h"
namespace mozilla {
namespace net {
//-----------------------------------------------------------------------------
// nsHttpHeaderArray <public>
//-----------------------------------------------------------------------------
nsresult