Bug 1487100 - Allow calling nsICacheInfoChannel.preferAlternativeDataType(altDataType, contentType) multiple times r=michal,luke

This patch changes the way we set and handle the preferred alternate data type.
It is no longer just one choice, but a set of preferences, each conditional
on the contentType of the resource.

For example:
  var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
  cc.preferAlternativeDataType("js-bytecode", "text/javascript");
  cc.preferAlternativeDataType("ammended-text", "text/plain");
  cc.preferAlternativeDataType("something-else", "");

When loaded from the cache, the available alt-data type will be checked against
"js-bytecode" if the contentType is "text/javascript", "ammended-text" if the contentType is "text/plain" or "something-else" for all contentTypes.
Note that the alt-data type could be "something-else" even if the contentType is "text/javascript".

The preferences are saved as an nsTArray<mozilla::Tuple<nsCString, nsCString>>.

Differential Revision: https://phabricator.services.mozilla.com/D8071

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Valentin Gosu 2018-10-17 13:58:30 +00:00
parent 8103abc63b
commit e392dbc5dd
29 changed files with 193 additions and 85 deletions

View File

@ -734,7 +734,7 @@ FetchDriver::HttpFetch(const nsACString& aPreferredAlternativeDataType)
if (!aPreferredAlternativeDataType.IsEmpty()) {
nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(chan);
if (cic) {
cic->PreferAlternativeDataType(aPreferredAlternativeDataType);
cic->PreferAlternativeDataType(aPreferredAlternativeDataType, EmptyCString());
MOZ_ASSERT(!mAltDataListener);
mAltDataListener =
new AlternativeDataStreamListener(this, chan, aPreferredAlternativeDataType);

View File

@ -1109,7 +1109,7 @@ ScriptLoader::StartLoad(ScriptLoadRequest* aRequest)
// Inform the HTTP cache that we prefer to have information coming from the
// bytecode cache instead of the sources, if such entry is already registered.
LOG(("ScriptLoadRequest (%p): Maybe request bytecode", aRequest));
cic->PreferAlternativeDataType(nsContentUtils::JSBytecodeMimeType());
cic->PreferAlternativeDataType(nsContentUtils::JSBytecodeMimeType(), EmptyCString());
} else {
// If we are explicitly loading from the sources, such as after a
// restarted request, we might still want to save the bytecode after.
@ -1118,7 +1118,7 @@ ScriptLoader::StartLoad(ScriptLoadRequest* aRequest)
// does not exist, such that we can later save the bytecode with a
// different alternative data type.
LOG(("ScriptLoadRequest (%p): Request saving bytecode later", aRequest));
cic->PreferAlternativeDataType(kNullMimeType);
cic->PreferAlternativeDataType(kNullMimeType, EmptyCString());
}
}

View File

@ -343,8 +343,9 @@ public:
// Get the preferred alternative data type of outter channel
nsAutoCString preferredAltDataType(EmptyCString());
nsCOMPtr<nsICacheInfoChannel> outerChannel = do_QueryInterface(underlyingChannel);
if (outerChannel) {
outerChannel->GetPreferredAlternativeDataType(preferredAltDataType);
if (outerChannel && !outerChannel->PreferredAlternativeDataTypes().IsEmpty()) {
// TODO: handle multiple types properly.
preferredAltDataType.Assign(mozilla::Get<0>(outerChannel->PreferredAlternativeDataTypes()[0]));
}
// Get the alternative data type saved in the InternalResponse

View File

@ -1587,11 +1587,11 @@ private:
nsresult rv = mInterceptedChannel->GetChannel(getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, false);
nsAutoCString alternativeDataType;
nsCOMPtr<nsICacheInfoChannel> cic = do_QueryInterface(channel);
if (cic &&
NS_SUCCEEDED(cic->GetPreferredAlternativeDataType(alternativeDataType)) &&
!alternativeDataType.IsEmpty()) {
if (cic && !cic->PreferredAlternativeDataTypes().IsEmpty()) {
// TODO: the internal request probably needs all the preferred types.
nsAutoCString alternativeDataType;
alternativeDataType.Assign(mozilla::Get<0>(cic->PreferredAlternativeDataTypes()[0]));
internalReq->SetPreferredAlternativeDataType(alternativeDataType);
}

View File

@ -6,6 +6,14 @@
interface nsIOutputStream;
%{C++
namespace mozilla {
template<typename... Elements> class Tuple;
} // namespace mozilla
%}
[ref] native ConstPreferenceArray(const nsTArray<mozilla::Tuple<nsCString, nsCString>>);
[scriptable, uuid(72c34415-c6eb-48af-851f-772fa9ee5972)]
interface nsICacheInfoChannel : nsISupports
{
@ -79,16 +87,25 @@ interface nsICacheInfoChannel : nsISupports
* 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.
* @param type
* a string identifying the alt-data format
* @param contentType
* the contentType for which the preference applies.
* an empty contentType means the preference applies for ANY contentType
*
* The method may be called several times, with different type and contentType.
*
* Must be called before AsyncOpen.
*/
void preferAlternativeDataType(in ACString type);
void preferAlternativeDataType(in ACString type, in ACString contentType);
/**
* Get the preferred alternative data type set by preferAlternativeDataType().
* This attribute stands for the desired data type instead of the type of the
* The returned types stand for the desired data type instead of the type of the
* information retrieved from the network stack.
*/
readonly attribute ACString preferredAlternativeDataType;
[noscript, notxpcom, nostdcall]
ConstPreferenceArray preferredAlternativeDataTypes();
/**
* Holds the type of the alternative data representation that the channel

View File

@ -1275,6 +1275,11 @@ nsresult CacheEntry::OpenAlternativeOutputStream(const nsACString & type, int64_
nsresult rv;
if (type.IsEmpty()) {
// The empty string is reserved to mean no alt-data available.
return NS_ERROR_INVALID_ARG;
}
mozilla::MutexAutoLock lock(mLock);
if (!mHasData || mState < READY || mOutputStream || mIsDoomed) {
@ -1554,7 +1559,6 @@ nsresult CacheEntry::GetDataSize(int64_t *aDataSize)
return NS_OK;
}
nsresult CacheEntry::GetAltDataSize(int64_t *aDataSize)
{
LOG(("CacheEntry::GetAltDataSize [this=%p]", this));
@ -1564,6 +1568,14 @@ nsresult CacheEntry::GetAltDataSize(int64_t *aDataSize)
return mFile->GetAltDataSize(aDataSize);
}
nsresult CacheEntry::GetAltDataType(nsACString &aType)
{
LOG(("CacheEntry::GetAltDataType [this=%p]", this));
if (NS_FAILED(mFileStatus)) {
return mFileStatus;
}
return mFile->GetAltDataType(aType);
}
nsresult CacheEntry::MarkValid()
{

View File

@ -93,6 +93,7 @@ public:
nsresult Recreate(bool aMemoryOnly, nsICacheEntry * *_retval);
nsresult GetDataSize(int64_t *aDataSize);
nsresult GetAltDataSize(int64_t *aAltDataSize);
nsresult GetAltDataType(nsACString &aAltDataType);
nsresult OpenAlternativeOutputStream(const nsACString & type, int64_t predictedSize, nsIOutputStream * *_retval);
nsresult OpenAlternativeInputStream(const nsACString & type, nsIInputStream * *_retval);
nsresult GetLoadContextInfo(nsILoadContextInfo * *aLoadContextInfo);
@ -461,6 +462,7 @@ public:
NS_IMETHOD Recreate(bool aMemoryOnly, nsICacheEntry * *_retval) override { return mEntry->Recreate(aMemoryOnly, _retval); }
NS_IMETHOD GetDataSize(int64_t *aDataSize) override { return mEntry->GetDataSize(aDataSize); }
NS_IMETHOD GetAltDataSize(int64_t *aAltDataSize) override { return mEntry->GetAltDataSize(aAltDataSize); }
NS_IMETHOD GetAltDataType(nsACString &aType) override { return mEntry->GetAltDataType(aType); }
NS_IMETHOD OpenAlternativeOutputStream(const nsACString & type, int64_t predictedSize, nsIOutputStream * *_retval) override { return mEntry->OpenAlternativeOutputStream(type, predictedSize, _retval); }
NS_IMETHOD OpenAlternativeInputStream(const nsACString & type, nsIInputStream * *_retval) override { return mEntry->OpenAlternativeInputStream(type, _retval); }
NS_IMETHOD GetLoadContextInfo(nsILoadContextInfo * *aLoadContextInfo) override { return mEntry->GetLoadContextInfo(aLoadContextInfo); }

View File

@ -647,12 +647,13 @@ CacheFile::OnMetadataRead(nsresult aResult)
const char *altData = mMetadata->GetElement(CacheFileUtils::kAltDataKey);
if (altData &&
(NS_FAILED(CacheFileUtils::ParseAlternativeDataInfo(
altData, &mAltDataOffset, nullptr)) ||
altData, &mAltDataOffset, &mAltDataType)) ||
(mAltDataOffset > mDataSize))) {
// alt-metadata cannot be parsed or alt-data offset is invalid
mMetadata->InitEmptyMetadata();
isNew = true;
mAltDataOffset = -1;
mAltDataType.Truncate();
mDataSize = 0;
} else {
CacheFileAutoLock lock(this);
@ -801,8 +802,6 @@ CacheFile::OpenAlternativeInputStream(nsICacheEntry *aEntryHandle,
MOZ_ASSERT(mHandle || mMemoryOnly || mOpeningFile);
nsresult rv;
if (NS_WARN_IF(!mReady)) {
LOG(("CacheFile::OpenAlternativeInputStream() - CacheFile is not ready "
"[this=%p]", this));
@ -828,35 +827,13 @@ CacheFile::OpenAlternativeInputStream(nsICacheEntry *aEntryHandle,
return mStatus;
}
const char *altData = mMetadata->GetElement(CacheFileUtils::kAltDataKey);
MOZ_ASSERT(altData, "alt-metadata should exist but was not found!");
if (NS_WARN_IF(!altData)) {
LOG(("CacheFile::OpenAlternativeInputStream() - alt-metadata not found but "
"alt-data exists according to mAltDataOffset! [this=%p, ]", this));
return NS_ERROR_NOT_AVAILABLE;
}
int64_t offset;
nsCString availableAltData;
rv = CacheFileUtils::ParseAlternativeDataInfo(altData, &offset,
&availableAltData);
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_ASSERT(false, "alt-metadata unexpectedly failed to parse");
LOG(("CacheFile::OpenAlternativeInputStream() - Cannot parse alternative "
"metadata! [this=%p]", this));
return rv;
}
if (availableAltData != aAltDataType) {
if (mAltDataType != aAltDataType) {
LOG(("CacheFile::OpenAlternativeInputStream() - Alternative data is of a "
"different type than requested [this=%p, availableType=%s, "
"requestedType=%s]", this, availableAltData.get(), aAltDataType));
"requestedType=%s]", this, mAltDataType.get(), aAltDataType));
return NS_ERROR_NOT_AVAILABLE;
}
// mAltDataOffset must be in sync with what is stored in metadata
MOZ_ASSERT(mAltDataOffset == offset);
// Once we open input stream we no longer allow preloading of chunks without
// input stream, i.e. we will no longer keep first few chunks preloaded when
// the last input stream is closed.
@ -925,6 +902,7 @@ CacheFile::OpenOutputStream(CacheOutputCloseListener *aCloseListener, nsIOutputS
}
SetAltMetadata(nullptr);
mAltDataOffset = -1;
mAltDataType.Truncate();
}
// Once we open output stream we no longer allow preloading of chunks without
@ -1019,6 +997,7 @@ CacheFile::OpenAlternativeOutputStream(CacheOutputCloseListener *aCloseListener,
"%p [this=%p]", mOutput, this));
mDataAccessed = true;
mAltDataType = aAltDataType;
NS_ADDREF(*_retval = mOutput);
return NS_OK;
}
@ -1328,6 +1307,7 @@ CacheFile::SetAltMetadata(const char* aAltMetadata)
mMetadata->SetElement(CacheFileUtils::kAltDataKey, nullptr);
mAltDataOffset = -1;
mAltDataType.Truncate();
hasAltData = false;
}
@ -2196,6 +2176,7 @@ CacheFile::RemoveOutput(CacheFileOutputStream *aOutput, nsresult aStatus)
} else {
SetAltMetadata(nullptr);
mAltDataOffset = -1;
mAltDataType.Truncate();
}
}
} else {
@ -2381,6 +2362,19 @@ CacheFile::GetAltDataSize(int64_t *aSize)
return NS_OK;
}
nsresult
CacheFile::GetAltDataType(nsACString& aType)
{
CacheFileAutoLock lock(this);
if (mAltDataOffset == -1) {
return NS_ERROR_NOT_AVAILABLE;
}
aType = mAltDataType;
return NS_OK;
}
bool
CacheFile::IsDoomed()
{

View File

@ -92,6 +92,7 @@ public:
nsresult ThrowMemoryCachedData();
nsresult GetAltDataSize(int64_t *aSize);
nsresult GetAltDataType(nsACString& aType);
// metadata forwarders
nsresult GetElement(const char *aKey, char **_retval);
@ -215,6 +216,7 @@ private:
// offset where alternative data starts.
// Otherwise it is -1.
nsCString mKey;
nsCString mAltDataType; // The type of the saved alt-data. May be empty.
RefPtr<CacheFileHandle> mHandle;
RefPtr<CacheFileMetadata> mMetadata;

View File

@ -396,6 +396,11 @@ NS_IMETHODIMP _OldCacheEntryWrapper::GetAltDataSize(int64_t *aSize)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP _OldCacheEntryWrapper::GetAltDataType(nsACString &aType)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP _OldCacheEntryWrapper::GetPersistent(bool *aPersistToDisk)
{
if (!mOldDesc) {

View File

@ -160,6 +160,7 @@ public:
NS_IMETHOD Recreate(bool, nsICacheEntry**) override;
NS_IMETHOD GetDataSize(int64_t *size) override;
NS_IMETHOD GetAltDataSize(int64_t *size) override;
NS_IMETHOD GetAltDataType(nsACString &aType) override;
NS_IMETHOD OpenInputStream(int64_t offset, nsIInputStream * *_retval) override;
NS_IMETHOD OpenOutputStream(int64_t offset, int64_t predictedSize, nsIOutputStream * *_retval) override;
NS_IMETHOD MaybeMarkValid() override;

View File

@ -239,6 +239,13 @@ interface nsICacheEntry : nsISupports
*/
readonly attribute long long altDataSize;
/**
* Returns the type of the saved alt data.
* @throws
* - NS_ERROR_NOT_AVAILABLE if alt data does not exist.
*/
readonly attribute ACString altDataType;
/**
* Opens and returns an output stream that a consumer may use to save an
* alternate representation of the data.

View File

@ -18,6 +18,7 @@ include PBackgroundSharedTypes;
using mozilla::OriginAttributes from "mozilla/ipc/BackgroundUtils.h";
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
using RequestHeaderTuples from "mozilla/net/PHttpChannelParams.h";
using ArrayOfStringPairs from "mozilla/net/PHttpChannelParams.h";
using struct nsHttpAtom from "nsHttp.h";
using class mozilla::net::nsHttpResponseHead from "nsHttpResponseHead.h";
using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
@ -245,7 +246,7 @@ struct HttpChannelOpenArgs
uint64_t channelId;
nsString integrityMetadata;
uint64_t contentWindowId;
nsCString preferredAlternativeType;
ArrayOfStringPairs preferredAlternativeTypes;
uint64_t topLevelOuterContentWindowId;
TimeStamp launchServiceWorkerStart;
TimeStamp launchServiceWorkerEnd;

View File

@ -3909,7 +3909,9 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
// Pass the preferred alt-data type on to the new channel.
nsCOMPtr<nsICacheInfoChannel> cacheInfoChan(do_QueryInterface(newChannel));
if (cacheInfoChan) {
cacheInfoChan->PreferAlternativeDataType(mPreferredCachedAltDataType);
for (auto& pair : mPreferredCachedAltDataTypes) {
cacheInfoChan->PreferAlternativeDataType(mozilla::Get<0>(pair), mozilla::Get<1>(pair));
}
}
if (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |

View File

@ -46,6 +46,7 @@
#include "nsCOMArray.h"
#include "mozilla/net/ChannelEventQueue.h"
#include "mozilla/Move.h"
#include "mozilla/Tuple.h"
#include "nsIThrottledInputChannel.h"
#include "nsTArray.h"
#include "nsCOMPtr.h"
@ -71,6 +72,8 @@ class LogCollector;
namespace net {
extern mozilla::LazyLogModule gHttpLog;
typedef nsTArray<Tuple<nsCString, nsCString>> ArrayOfStringPairs;
/*
* This class is a partial implementation of nsIHttpChannel. It contains code
* shared by nsHttpChannel and HttpChannelChild.
@ -553,8 +556,8 @@ protected:
// The initiator type (for this resource) - how was the resource referenced in
// the HTML file.
nsString mInitiatorType;
// Holds the name of the preferred alt-data type.
nsCString mPreferredCachedAltDataType;
// Holds the name of the preferred alt-data type for each contentType.
ArrayOfStringPairs mPreferredCachedAltDataTypes;
// Holds the name of the alternative data type the channel returned.
nsCString mAvailableCachedAltDataType;
nsString mIntegrityMetadata;

View File

@ -1267,7 +1267,7 @@ HttpChannelChild::OnStopRequest(const nsresult& channelStatus,
// message but request the cache entry to be kept by the parent.
// If the channel has failed, the cache entry is in a non-writtable state and
// we want to release it to not block following consumers.
if (NS_SUCCEEDED(channelStatus) && !mPreferredCachedAltDataType.IsEmpty()) {
if (NS_SUCCEEDED(channelStatus) && !mPreferredCachedAltDataTypes.IsEmpty()) {
mKeptAlive = true;
SendDocumentChannelCleanup(false); // don't clear cache entry
return;
@ -1374,7 +1374,7 @@ HttpChannelChild::DoOnStopRequest(nsIRequest* aRequest, nsresult aChannelStatus,
// If a preferred alt-data type was set, the parent would hold a reference to
// the cache entry in case the child calls openAlternativeOutputStream().
// (see nsHttpChannel::OnStopRequest)
if (!mPreferredCachedAltDataType.IsEmpty()) {
if (!mPreferredCachedAltDataTypes.IsEmpty()) {
mAltDataCacheEntryAvailable = mCacheEntryAvailable;
}
mCacheEntryAvailable = false;
@ -2874,7 +2874,7 @@ HttpChannelChild::ContinueAsyncOpen()
openArgs.loadFlags() = mLoadFlags;
openArgs.requestHeaders() = mClientSetRequestHeaders;
mRequestHead.Method(openArgs.requestMethod());
openArgs.preferredAlternativeType() = mPreferredCachedAltDataType;
openArgs.preferredAlternativeTypes() = mPreferredCachedAltDataTypes;
AutoIPCStream autoStream(openArgs.uploadStream());
if (mUploadStream) {
@ -3271,23 +3271,23 @@ HttpChannelChild::GetAllowStaleCacheContent(bool *aAllowStaleCacheContent)
}
NS_IMETHODIMP
HttpChannelChild::PreferAlternativeDataType(const nsACString & aType)
HttpChannelChild::PreferAlternativeDataType(const nsACString& aType,
const nsACString& aContentType)
{
ENSURE_CALLED_BEFORE_ASYNC_OPEN();
if (mSynthesizedCacheInfo) {
return mSynthesizedCacheInfo->PreferAlternativeDataType(aType);
return mSynthesizedCacheInfo->PreferAlternativeDataType(aType, aContentType);
}
mPreferredCachedAltDataType = aType;
mPreferredCachedAltDataTypes.AppendElement(MakePair(nsCString(aType), nsCString(aContentType)));
return NS_OK;
}
NS_IMETHODIMP
HttpChannelChild::GetPreferredAlternativeDataType(nsACString & aType)
const nsTArray<mozilla::Tuple<nsCString, nsCString>>&
HttpChannelChild::PreferredAlternativeDataTypes()
{
aType = mPreferredCachedAltDataType;
return NS_OK;
return mPreferredCachedAltDataTypes;
}
NS_IMETHODIMP

View File

@ -153,7 +153,7 @@ HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
a.allowStaleCacheContent(), a.contentTypeHint(),
a.corsMode(), a.redirectMode(),
a.channelId(), a.integrityMetadata(),
a.contentWindowId(), a.preferredAlternativeType(),
a.contentWindowId(), a.preferredAlternativeTypes(),
a.topLevelOuterContentWindowId(),
a.launchServiceWorkerStart(),
a.launchServiceWorkerEnd(),
@ -455,7 +455,7 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
const uint64_t& aChannelId,
const nsString& aIntegrityMetadata,
const uint64_t& aContentWindowId,
const nsCString& aPreferredAlternativeType,
const ArrayOfStringPairs& aPreferredAlternativeTypes,
const uint64_t& aTopLevelOuterContentWindowId,
const TimeStamp& aLaunchServiceWorkerStart,
const TimeStamp& aLaunchServiceWorkerEnd,
@ -614,7 +614,9 @@ HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
do_QueryInterface(static_cast<nsIChannel*>(httpChannel.get()));
if (cacheChannel) {
cacheChannel->SetCacheKey(aCacheKey);
cacheChannel->PreferAlternativeDataType(aPreferredAlternativeType);
for (auto& pair : aPreferredAlternativeTypes) {
cacheChannel->PreferAlternativeDataType(mozilla::Get<0>(pair), mozilla::Get<1>(pair));
}
cacheChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent);

View File

@ -173,7 +173,7 @@ protected:
const uint64_t& aChannelId,
const nsString& aIntegrityMetadata,
const uint64_t& aContentWindowId,
const nsCString& aPreferredAlternativeType,
const ArrayOfStringPairs& aPreferredAlternativeTypes,
const uint64_t& aTopLevelOuterContentWindowId,
const TimeStamp& aLaunchServiceWorkerStart,
const TimeStamp& aLaunchServiceWorkerEnd,

View File

@ -1315,18 +1315,18 @@ InterceptedHttpChannel::GetAllowStaleCacheContent(bool *aAllowStaleCacheContent)
}
NS_IMETHODIMP
InterceptedHttpChannel::PreferAlternativeDataType(const nsACString & aType)
InterceptedHttpChannel::PreferAlternativeDataType(const nsACString & aType,
const nsACString& aContentType)
{
ENSURE_CALLED_BEFORE_ASYNC_OPEN();
mPreferredCachedAltDataType = aType;
mPreferredCachedAltDataTypes.AppendElement(MakePair(nsCString(aType), nsCString(aContentType)));
return NS_OK;
}
NS_IMETHODIMP
InterceptedHttpChannel::GetPreferredAlternativeDataType(nsACString & aType)
const nsTArray<mozilla::Tuple<nsCString, nsCString>>&
InterceptedHttpChannel::PreferredAlternativeDataTypes()
{
aType = mPreferredCachedAltDataType;
return NS_OK;
return mPreferredCachedAltDataTypes;
}
NS_IMETHODIMP

View File

@ -14,6 +14,7 @@
#include "nsHttp.h"
#include "nsHttpHeaderArray.h"
#include "nsHttpResponseHead.h"
#include "mozilla/Tuple.h"
#include "nsIClassInfo.h"
@ -36,11 +37,37 @@ struct RequestHeaderTuple {
typedef nsTArray<RequestHeaderTuple> RequestHeaderTuples;
typedef nsTArray<Tuple<nsCString, nsCString>> ArrayOfStringPairs;
} // namespace net
} // namespace mozilla
namespace IPC {
template<>
struct ParamTraits<mozilla::Tuple<nsCString, nsCString>>
{
typedef mozilla::Tuple<nsCString, nsCString> paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, mozilla::Get<0>(aParam));
WriteParam(aMsg, mozilla::Get<1>(aParam));
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
nsCString first;
nsCString second;
if (!ReadParam(aMsg, aIter, &first) ||
!ReadParam(aMsg, aIter, &second))
return false;
*aResult = mozilla::MakeTuple(first, second);
return true;
}
};
template<>
struct ParamTraits<mozilla::net::RequestHeaderTuple>
{

View File

@ -5003,12 +5003,31 @@ nsHttpChannel::OpenCacheInputStream(nsICacheEntry* cacheEntry, bool startBufferi
altDataFromChild = !value.IsEmpty();
}
if (!mPreferredCachedAltDataType.IsEmpty() && (altDataFromChild == mAltDataForChild)) {
rv = cacheEntry->OpenAlternativeInputStream(mPreferredCachedAltDataType,
nsAutoCString altDataType;
Unused << cacheEntry->GetAltDataType(altDataType);
nsAutoCString contentType;
mCachedResponseHead->ContentType(contentType);
bool foundAltData = false;
if (!altDataType.IsEmpty() &&
!mPreferredCachedAltDataTypes.IsEmpty() &&
altDataFromChild == mAltDataForChild) {
for (auto& pref : mPreferredCachedAltDataTypes) {
if (mozilla::Get<0>(pref) == altDataType &&
(mozilla::Get<1>(pref).IsEmpty() || mozilla::Get<1>(pref) == contentType)) {
foundAltData = true;
break;
}
}
}
if (foundAltData) {
rv = cacheEntry->OpenAlternativeInputStream(altDataType,
getter_AddRefs(stream));
if (NS_SUCCEEDED(rv)) {
LOG(("Opened alt-data input stream type=%s", altDataType.get()));
// We have succeeded.
mAvailableCachedAltDataType = mPreferredCachedAltDataType;
mAvailableCachedAltDataType = altDataType;
// Set the correct data size on the channel.
int64_t altDataSize;
if (NS_SUCCEEDED(cacheEntry->GetAltDataSize(&altDataSize))) {
@ -5017,6 +5036,7 @@ nsHttpChannel::OpenCacheInputStream(nsICacheEntry* cacheEntry, bool startBufferi
}
}
if (!stream) {
rv = cacheEntry->OpenInputStream(0, getter_AddRefs(stream));
}
@ -7864,7 +7884,7 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
// interested in reading and/or writing the alt-data representation.
// We need to hold a reference to the cache entry in case the listener calls
// openAlternativeOutputStream() after CloseCacheEntry() clears mCacheEntry.
if (!mPreferredCachedAltDataType.IsEmpty()) {
if (!mPreferredCachedAltDataTypes.IsEmpty()) {
mAltDataCacheEntry = mCacheEntry;
}
@ -8286,18 +8306,18 @@ nsHttpChannel::GetAllowStaleCacheContent(bool *aAllowStaleCacheContent)
}
NS_IMETHODIMP
nsHttpChannel::PreferAlternativeDataType(const nsACString & aType)
nsHttpChannel::PreferAlternativeDataType(const nsACString& aType,
const nsACString& aContentType)
{
ENSURE_CALLED_BEFORE_ASYNC_OPEN();
mPreferredCachedAltDataType = aType;
mPreferredCachedAltDataTypes.AppendElement(MakePair(nsCString(aType), nsCString(aContentType)));
return NS_OK;
}
NS_IMETHODIMP
nsHttpChannel::GetPreferredAlternativeDataType(nsACString & aType)
const nsTArray<mozilla::Tuple<nsCString, nsCString>>&
nsHttpChannel::PreferredAlternativeDataTypes()
{
aType = mPreferredCachedAltDataType;
return NS_OK;
return mPreferredCachedAltDataTypes;
}
NS_IMETHODIMP

View File

@ -1146,3 +1146,12 @@ nsViewSourceChannel::LogBlockedCORSRequest(const nsAString& aMessage,
}
return mHttpChannel->LogBlockedCORSRequest(aMessage, aCategory);
}
const nsTArray<mozilla::Tuple<nsCString, nsCString>>&
nsViewSourceChannel::PreferredAlternativeDataTypes()
{
if (mCacheInfoChannel) {
return mCacheInfoChannel->PreferredAlternativeDataTypes();
}
return mEmptyArray;
}

View File

@ -65,6 +65,7 @@ public:
protected:
~nsViewSourceChannel() = default;
nsTArray<mozilla::Tuple<nsCString, nsCString>> mEmptyArray;
// Clones aURI and prefixes it with "view-source:" schema,
nsresult BuildViewSourceURI(nsIURI* aURI, nsIURI** aResult);

View File

@ -85,7 +85,7 @@ function asyncOpen()
var chan = make_channel(URL);
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(altContentType);
cc.preferAlternativeDataType(altContentType, "");
chan.asyncOpen2(new ChannelListener(readServerContent, null));
}
@ -120,7 +120,7 @@ function flushAndOpenAltChannel()
function openAltChannel() {
var chan = make_channel(URL);
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(altContentType);
cc.preferAlternativeDataType(altContentType, "");
chan.asyncOpen2(new ChannelListener(readAltContent, null));
}

View File

@ -26,7 +26,7 @@ function make_and_open_channel(url, altContentType, callback) {
let chan = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
if (altContentType) {
let cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(altContentType);
cc.preferAlternativeDataType(altContentType, "");
}
chan.asyncOpen2(new ChannelListener(callback, null));
}

View File

@ -91,7 +91,7 @@ function asyncOpen()
var chan = make_channel(URL);
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(altContentType);
cc.preferAlternativeDataType(altContentType, "");
chan.asyncOpen2(new ChannelListener(readServerContent, null));
}
@ -136,7 +136,9 @@ function flushAndOpenAltChannel()
function openAltChannel() {
var chan = make_channel(URL);
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(altContentType);
cc.preferAlternativeDataType("dummy1", "text/javascript");
cc.preferAlternativeDataType(altContentType, "text/plain");
cc.preferAlternativeDataType("dummy2", "");
chan.asyncOpen2(new ChannelListener(readAltContent, null));
}
@ -158,7 +160,7 @@ function requestAgain()
shouldPassRevalidation = false;
var chan = make_channel(URL);
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(altContentType);
cc.preferAlternativeDataType(altContentType, "");
chan.asyncOpen2(new ChannelListener(readEmptyAltContent, null));
}

View File

@ -60,7 +60,7 @@ function run_test()
var chan = make_channel(URL);
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(altContentType);
cc.preferAlternativeDataType(altContentType, "");
chan.asyncOpen2(new ChannelListener(readServerContent, null));
do_test_pending();
@ -89,7 +89,7 @@ function openAltChannel()
{
var chan = make_channel(URL);
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(altContentType);
cc.preferAlternativeDataType(altContentType, "");
chan.asyncOpen2(listener);
}

View File

@ -53,7 +53,7 @@ function fetch(preferredDataType = null)
if (preferredDataType) {
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType(altContentType);
cc.preferAlternativeDataType(altContentType, "");
}
chan.asyncOpen2(new ChannelListener((request,

View File

@ -32,7 +32,7 @@ function load_channel(url) {
URL = url; // save this to open the alt data channel later
var chan = make_channel(url);
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType("text/binary");
cc.preferAlternativeDataType("text/binary", "");
chan.asyncOpen2(new ChannelListener(readTextData, null));
}
@ -64,7 +64,7 @@ function readTextData(request, buffer)
function openAltChannel() {
var chan = make_channel(URL);
var cc = chan.QueryInterface(Ci.nsICacheInfoChannel);
cc.preferAlternativeDataType("text/parent-binary");
cc.preferAlternativeDataType("text/parent-binary", "");
chan.asyncOpen2(new ChannelListener(readAltData, null));
}