Bug 1120501 P2 Move Cache Add/AddAll logic to child process. r=ehsan,smaug
This commit is contained in:
@@ -197,6 +197,7 @@ DOMInterfaces = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'Cache': {
|
'Cache': {
|
||||||
|
'implicitJSContext': [ 'add', 'addAll' ],
|
||||||
'nativeType': 'mozilla::dom::cache::Cache',
|
'nativeType': 'mozilla::dom::cache::Cache',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
164
dom/cache/AutoUtils.cpp
vendored
164
dom/cache/AutoUtils.cpp
vendored
@@ -7,6 +7,8 @@
|
|||||||
#include "mozilla/dom/cache/AutoUtils.h"
|
#include "mozilla/dom/cache/AutoUtils.h"
|
||||||
|
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
|
#include "mozilla/dom/InternalHeaders.h"
|
||||||
|
#include "mozilla/dom/InternalRequest.h"
|
||||||
#include "mozilla/dom/cache/CacheParent.h"
|
#include "mozilla/dom/cache/CacheParent.h"
|
||||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||||
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
||||||
@@ -17,6 +19,8 @@
|
|||||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||||
#include "mozilla/ipc/PBackgroundParent.h"
|
#include "mozilla/ipc/PBackgroundParent.h"
|
||||||
|
#include "nsCRT.h"
|
||||||
|
#include "nsHttp.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -168,15 +172,6 @@ AutoChildOpArgs::~AutoChildOpArgs()
|
|||||||
CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action);
|
CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CacheOpArgs::TCacheAddAllArgs:
|
|
||||||
{
|
|
||||||
CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
|
|
||||||
auto& list = args.requestList();
|
|
||||||
for (uint32_t i = 0; i < list.Length(); ++i) {
|
|
||||||
CleanupChild(list[i].body(), action);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CacheOpArgs::TCachePutAllArgs:
|
case CacheOpArgs::TCachePutAllArgs:
|
||||||
{
|
{
|
||||||
CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
|
CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
|
||||||
@@ -216,8 +211,7 @@ AutoChildOpArgs::~AutoChildOpArgs()
|
|||||||
|
|
||||||
void
|
void
|
||||||
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
SchemeAction aSchemeAction, ErrorResult& aRv)
|
||||||
ErrorResult& aRv)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!mSent);
|
MOZ_ASSERT(!mSent);
|
||||||
|
|
||||||
@@ -226,7 +220,7 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
|||||||
{
|
{
|
||||||
CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
|
CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
|
||||||
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
||||||
aReferrerAction, aSchemeAction, aRv);
|
aSchemeAction, aRv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CacheOpArgs::TCacheMatchAllArgs:
|
case CacheOpArgs::TCacheMatchAllArgs:
|
||||||
@@ -235,35 +229,14 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
|||||||
MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
|
MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
|
||||||
args.requestOrVoid() = CacheRequest();
|
args.requestOrVoid() = CacheRequest();
|
||||||
mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
|
mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
|
||||||
aRequest, aBodyAction, aReferrerAction,
|
aRequest, aBodyAction, aSchemeAction, aRv);
|
||||||
aSchemeAction, aRv);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CacheOpArgs::TCacheAddAllArgs:
|
|
||||||
{
|
|
||||||
CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
|
|
||||||
|
|
||||||
// The FileDescriptorSetChild asserts in its destructor that all fds have
|
|
||||||
// been removed. The copy constructor, however, simply duplicates the
|
|
||||||
// fds without removing any. This means each temporary and copy must be
|
|
||||||
// explicitly cleaned up.
|
|
||||||
//
|
|
||||||
// Avoid a lot of this hassle by making sure we only create one here. On
|
|
||||||
// error we remove it.
|
|
||||||
CacheRequest& request = *args.requestList().AppendElement();
|
|
||||||
|
|
||||||
mTypeUtils->ToCacheRequest(request, aRequest, aBodyAction,
|
|
||||||
aReferrerAction, aSchemeAction, aRv);
|
|
||||||
if (aRv.Failed()) {
|
|
||||||
args.requestList().RemoveElementAt(args.requestList().Length() - 1);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CacheOpArgs::TCacheDeleteArgs:
|
case CacheOpArgs::TCacheDeleteArgs:
|
||||||
{
|
{
|
||||||
CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
|
CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
|
||||||
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
||||||
aReferrerAction, aSchemeAction, aRv);
|
aSchemeAction, aRv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CacheOpArgs::TCacheKeysArgs:
|
case CacheOpArgs::TCacheKeysArgs:
|
||||||
@@ -272,15 +245,14 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
|||||||
MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
|
MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
|
||||||
args.requestOrVoid() = CacheRequest();
|
args.requestOrVoid() = CacheRequest();
|
||||||
mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
|
mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
|
||||||
aRequest, aBodyAction, aReferrerAction,
|
aRequest, aBodyAction, aSchemeAction, aRv);
|
||||||
aSchemeAction, aRv);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CacheOpArgs::TStorageMatchArgs:
|
case CacheOpArgs::TStorageMatchArgs:
|
||||||
{
|
{
|
||||||
StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
|
StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
|
||||||
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
||||||
aReferrerAction, aSchemeAction, aRv);
|
aSchemeAction, aRv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -288,10 +260,112 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool
|
||||||
|
MatchInPutList(InternalRequest* aRequest,
|
||||||
|
const nsTArray<CacheRequestResponse>& aPutList)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aRequest);
|
||||||
|
|
||||||
|
// This method implements the SW spec QueryCache algorithm against an
|
||||||
|
// in memory array of Request/Response objects. This essentially the
|
||||||
|
// same algorithm that is implemented in DBSchema.cpp. Unfortunately
|
||||||
|
// we cannot unify them because when operating against the real database
|
||||||
|
// we don't want to load all request/response objects into memory.
|
||||||
|
|
||||||
|
// Note, we can skip the check for a invalid request method because
|
||||||
|
// Cache should only call into here with a GET or HEAD.
|
||||||
|
#ifdef DEBUG
|
||||||
|
nsAutoCString method;
|
||||||
|
aRequest->GetMethod(method);
|
||||||
|
MOZ_ASSERT(method.LowerCaseEqualsLiteral("get") ||
|
||||||
|
method.LowerCaseEqualsLiteral("head"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nsRefPtr<InternalHeaders> requestHeaders = aRequest->Headers();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < aPutList.Length(); ++i) {
|
||||||
|
const CacheRequest& cachedRequest = aPutList[i].request();
|
||||||
|
const CacheResponse& cachedResponse = aPutList[i].response();
|
||||||
|
|
||||||
|
nsAutoCString url;
|
||||||
|
aRequest->GetURL(url);
|
||||||
|
|
||||||
|
// If the URLs don't match, then just skip to the next entry.
|
||||||
|
if (NS_ConvertUTF8toUTF16(url) != cachedRequest.url()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<InternalHeaders> cachedRequestHeaders =
|
||||||
|
TypeUtils::ToInternalHeaders(cachedRequest.headers());
|
||||||
|
|
||||||
|
nsRefPtr<InternalHeaders> cachedResponseHeaders =
|
||||||
|
TypeUtils::ToInternalHeaders(cachedResponse.headers());
|
||||||
|
|
||||||
|
nsAutoTArray<nsCString, 16> varyHeaders;
|
||||||
|
ErrorResult rv;
|
||||||
|
cachedResponseHeaders->GetAll(NS_LITERAL_CSTRING("vary"), varyHeaders, rv);
|
||||||
|
MOZ_ALWAYS_TRUE(!rv.Failed());
|
||||||
|
|
||||||
|
// Assume the vary headers match until we find a conflict
|
||||||
|
bool varyHeadersMatch = true;
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < varyHeaders.Length(); ++j) {
|
||||||
|
// Extract the header names inside the Vary header value.
|
||||||
|
nsAutoCString varyValue(varyHeaders[j]);
|
||||||
|
char* rawBuffer = varyValue.BeginWriting();
|
||||||
|
char* token = nsCRT::strtok(rawBuffer, NS_HTTP_HEADER_SEPS, &rawBuffer);
|
||||||
|
bool bailOut = false;
|
||||||
|
for (; token;
|
||||||
|
token = nsCRT::strtok(rawBuffer, NS_HTTP_HEADER_SEPS, &rawBuffer)) {
|
||||||
|
nsDependentCString header(token);
|
||||||
|
MOZ_ASSERT(!header.EqualsLiteral("*"),
|
||||||
|
"We should have already caught this in "
|
||||||
|
"TypeUtils::ToPCacheResponseWithoutBody()");
|
||||||
|
|
||||||
|
ErrorResult headerRv;
|
||||||
|
nsAutoCString value;
|
||||||
|
requestHeaders->Get(header, value, headerRv);
|
||||||
|
if (NS_WARN_IF(headerRv.Failed())) {
|
||||||
|
headerRv.SuppressException();
|
||||||
|
MOZ_ASSERT(value.IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoCString cachedValue;
|
||||||
|
cachedRequestHeaders->Get(header, value, headerRv);
|
||||||
|
if (NS_WARN_IF(headerRv.Failed())) {
|
||||||
|
headerRv.SuppressException();
|
||||||
|
MOZ_ASSERT(cachedValue.IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != cachedValue) {
|
||||||
|
varyHeadersMatch = false;
|
||||||
|
bailOut = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bailOut) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL was equal and all vary headers match!
|
||||||
|
if (varyHeadersMatch) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
void
|
void
|
||||||
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
SchemeAction aSchemeAction, Response& aResponse,
|
||||||
Response& aResponse, ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!mSent);
|
MOZ_ASSERT(!mSent);
|
||||||
|
|
||||||
@@ -300,6 +374,14 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
|||||||
{
|
{
|
||||||
CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
|
CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
|
||||||
|
|
||||||
|
// Throw an error if a request/response pair would mask another
|
||||||
|
// request/response pair in the same PutAll operation. This is
|
||||||
|
// step 2.3.2.3 from the "Batch Cache Operations" spec algorithm.
|
||||||
|
if (MatchInPutList(aRequest, args.requestResponseList())) {
|
||||||
|
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The FileDescriptorSetChild asserts in its destructor that all fds have
|
// The FileDescriptorSetChild asserts in its destructor that all fds have
|
||||||
// been removed. The copy constructor, however, simply duplicates the
|
// been removed. The copy constructor, however, simply duplicates the
|
||||||
// fds without removing any. This means each temporary and copy must be
|
// fds without removing any. This means each temporary and copy must be
|
||||||
@@ -312,7 +394,7 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
|||||||
pair.response().body() = void_t();
|
pair.response().body() = void_t();
|
||||||
|
|
||||||
mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction,
|
mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction,
|
||||||
aReferrerAction, aSchemeAction, aRv);
|
aSchemeAction, aRv);
|
||||||
if (!aRv.Failed()) {
|
if (!aRv.Failed()) {
|
||||||
mTypeUtils->ToCacheResponse(pair.response(), aResponse, aRv);
|
mTypeUtils->ToCacheResponse(pair.response(), aResponse, aRv);
|
||||||
}
|
}
|
||||||
|
|||||||
7
dom/cache/AutoUtils.h
vendored
7
dom/cache/AutoUtils.h
vendored
@@ -47,18 +47,15 @@ class MOZ_STACK_CLASS AutoChildOpArgs final
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef TypeUtils::BodyAction BodyAction;
|
typedef TypeUtils::BodyAction BodyAction;
|
||||||
typedef TypeUtils::ReferrerAction ReferrerAction;
|
|
||||||
typedef TypeUtils::SchemeAction SchemeAction;
|
typedef TypeUtils::SchemeAction SchemeAction;
|
||||||
|
|
||||||
AutoChildOpArgs(TypeUtils* aTypeUtils, const CacheOpArgs& aOpArgs);
|
AutoChildOpArgs(TypeUtils* aTypeUtils, const CacheOpArgs& aOpArgs);
|
||||||
~AutoChildOpArgs();
|
~AutoChildOpArgs();
|
||||||
|
|
||||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
SchemeAction aSchemeAction, ErrorResult& aRv);
|
||||||
ErrorResult& aRv);
|
|
||||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
SchemeAction aSchemeAction, Response& aResponse, ErrorResult& aRv);
|
||||||
Response& aResponse, ErrorResult& aRv);
|
|
||||||
|
|
||||||
const CacheOpArgs& SendAsOpArgs();
|
const CacheOpArgs& SendAsOpArgs();
|
||||||
|
|
||||||
|
|||||||
339
dom/cache/Cache.cpp
vendored
339
dom/cache/Cache.cpp
vendored
@@ -9,12 +9,14 @@
|
|||||||
#include "mozilla/dom/Headers.h"
|
#include "mozilla/dom/Headers.h"
|
||||||
#include "mozilla/dom/InternalResponse.h"
|
#include "mozilla/dom/InternalResponse.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
|
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||||
#include "mozilla/dom/Response.h"
|
#include "mozilla/dom/Response.h"
|
||||||
#include "mozilla/dom/WorkerPrivate.h"
|
#include "mozilla/dom/WorkerPrivate.h"
|
||||||
#include "mozilla/dom/CacheBinding.h"
|
#include "mozilla/dom/CacheBinding.h"
|
||||||
#include "mozilla/dom/cache/AutoUtils.h"
|
#include "mozilla/dom/cache/AutoUtils.h"
|
||||||
#include "mozilla/dom/cache/CacheChild.h"
|
#include "mozilla/dom/cache/CacheChild.h"
|
||||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||||
|
#include "mozilla/dom/cache/Feature.h"
|
||||||
#include "mozilla/dom/cache/ReadStream.h"
|
#include "mozilla/dom/cache/ReadStream.h"
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
@@ -22,30 +24,53 @@
|
|||||||
#include "nsIGlobalObject.h"
|
#include "nsIGlobalObject.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
namespace cache {
|
||||||
|
|
||||||
|
using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
|
||||||
|
using mozilla::dom::workers::WorkerPrivate;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using mozilla::ErrorResult;
|
bool
|
||||||
using mozilla::dom::MSG_INVALID_REQUEST_METHOD;
|
IsValidPutRequestURL(const nsAString& aUrl, ErrorResult& aRv)
|
||||||
using mozilla::dom::OwningRequestOrUSVString;
|
{
|
||||||
using mozilla::dom::Request;
|
bool validScheme = false;
|
||||||
using mozilla::dom::RequestOrUSVString;
|
|
||||||
|
// make a copy because ProcessURL strips the fragmet
|
||||||
|
nsAutoString url(aUrl);
|
||||||
|
|
||||||
|
TypeUtils::ProcessURL(url, &validScheme, nullptr, aRv);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validScheme) {
|
||||||
|
NS_NAMED_LITERAL_STRING(label, "Request");
|
||||||
|
aRv.ThrowTypeError(MSG_INVALID_URL_SCHEME, &label, &url);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
IsValidPutRequestMethod(const Request& aRequest, ErrorResult& aRv)
|
IsValidPutRequestMethod(const Request& aRequest, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
nsAutoCString method;
|
nsAutoCString method;
|
||||||
aRequest.GetMethod(method);
|
aRequest.GetMethod(method);
|
||||||
bool valid = method.LowerCaseEqualsLiteral("get");
|
if (!method.LowerCaseEqualsLiteral("get")) {
|
||||||
if (!valid) {
|
|
||||||
NS_ConvertASCIItoUTF16 label(method);
|
NS_ConvertASCIItoUTF16 label(method);
|
||||||
aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
|
aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return valid;
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
IsValidPutRequestMethod(const RequestOrUSVString& aRequest,
|
IsValidPutRequestMethod(const RequestOrUSVString& aRequest, ErrorResult& aRv)
|
||||||
ErrorResult& aRv)
|
|
||||||
{
|
{
|
||||||
// If the provided request is a string URL, then it will default to
|
// If the provided request is a string URL, then it will default to
|
||||||
// a valid http method automatically.
|
// a valid http method automatically.
|
||||||
@@ -55,26 +80,132 @@ IsValidPutRequestMethod(const RequestOrUSVString& aRequest,
|
|||||||
return IsValidPutRequestMethod(aRequest.GetAsRequest(), aRv);
|
return IsValidPutRequestMethod(aRequest.GetAsRequest(), aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
IsValidPutRequestMethod(const OwningRequestOrUSVString& aRequest,
|
|
||||||
ErrorResult& aRv)
|
|
||||||
{
|
|
||||||
if (!aRequest.IsRequest()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return IsValidPutRequestMethod(*aRequest.GetAsRequest().get(), aRv);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace mozilla {
|
// Helper class to wait for Add()/AddAll() fetch requests to complete and
|
||||||
namespace dom {
|
// then perform a PutAll() with the responses. This class holds a Feature
|
||||||
namespace cache {
|
// to keep the Worker thread alive. This is mainly to ensure that Add/AddAll
|
||||||
|
// act the same as other Cache operations that directly create a CacheOpChild
|
||||||
|
// actor.
|
||||||
|
class Cache::FetchHandler final : public PromiseNativeHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FetchHandler(Feature* aFeature, Cache* aCache,
|
||||||
|
nsTArray<nsRefPtr<Request>>&& aRequestList, Promise* aPromise)
|
||||||
|
: mFeature(aFeature)
|
||||||
|
, mCache(aCache)
|
||||||
|
, mRequestList(Move(aRequestList))
|
||||||
|
, mPromise(aPromise)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT_IF(!NS_IsMainThread(), mFeature);
|
||||||
|
MOZ_ASSERT(mCache);
|
||||||
|
MOZ_ASSERT(mPromise);
|
||||||
|
}
|
||||||
|
|
||||||
using mozilla::ErrorResult;
|
virtual void
|
||||||
using mozilla::unused;
|
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
|
{
|
||||||
using mozilla::dom::workers::WorkerPrivate;
|
NS_ASSERT_OWNINGTHREAD(FetchHandler);
|
||||||
|
|
||||||
|
// Stop holding the worker alive when we leave this method.
|
||||||
|
nsRefPtr<Feature> feature;
|
||||||
|
feature.swap(mFeature);
|
||||||
|
|
||||||
|
// Promise::All() passed an array of fetch() Promises should give us
|
||||||
|
// an Array of Response objects. The following code unwraps these
|
||||||
|
// JS values back to an nsTArray<nsRefPtr<Response>>.
|
||||||
|
|
||||||
|
nsAutoTArray<nsRefPtr<Response>, 256> responseList;
|
||||||
|
responseList.SetCapacity(mRequestList.Length());
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!JS_IsArrayObject(aCx, aValue))) {
|
||||||
|
Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
|
||||||
|
|
||||||
|
uint32_t length;
|
||||||
|
if (NS_WARN_IF(!JS_GetArrayLength(aCx, obj, &length))) {
|
||||||
|
Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < length; ++i) {
|
||||||
|
JS::Rooted<JS::Value> value(aCx);
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!JS_GetElement(aCx, obj, i, &value))) {
|
||||||
|
Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!value.isObject())) {
|
||||||
|
Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> responseObj(aCx, &value.toObject());
|
||||||
|
|
||||||
|
nsRefPtr<Response> response;
|
||||||
|
nsresult rv = UNWRAP_OBJECT(Response, responseObj, response);
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
|
Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NS_WARN_IF(response->Type() == ResponseType::Error)) {
|
||||||
|
Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
responseList.AppendElement(Move(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(mRequestList.Length() == responseList.Length());
|
||||||
|
|
||||||
|
// Now store the unwrapped Response list in the Cache.
|
||||||
|
ErrorResult result;
|
||||||
|
nsRefPtr<Promise> put = mCache->PutAll(mRequestList, responseList, result);
|
||||||
|
if (NS_WARN_IF(result.Failed())) {
|
||||||
|
// TODO: abort the fetch requests we have running (bug 1157434)
|
||||||
|
mPromise->MaybeReject(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chain the Cache::Put() promise to the original promise returned to
|
||||||
|
// the content script.
|
||||||
|
mPromise->MaybeResolve(put);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void
|
||||||
|
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||||
|
{
|
||||||
|
NS_ASSERT_OWNINGTHREAD(FetchHandler);
|
||||||
|
Fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
~FetchHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Fail()
|
||||||
|
{
|
||||||
|
ErrorResult rv;
|
||||||
|
rv.ThrowTypeError(MSG_FETCH_FAILED);
|
||||||
|
mPromise->MaybeReject(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<Feature> mFeature;
|
||||||
|
nsRefPtr<Cache> mCache;
|
||||||
|
nsTArray<nsRefPtr<Request>> mRequestList;
|
||||||
|
nsRefPtr<Promise> mPromise;
|
||||||
|
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_IMPL_ISUPPORTS0(Cache::FetchHandler)
|
||||||
|
|
||||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::Cache);
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::Cache);
|
||||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::Cache);
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::Cache);
|
||||||
@@ -110,7 +241,7 @@ Cache::Match(const RequestOrUSVString& aRequest,
|
|||||||
|
|
||||||
AutoChildOpArgs args(this, CacheMatchArgs(CacheRequest(), params));
|
AutoChildOpArgs args(this, CacheMatchArgs(CacheRequest(), params));
|
||||||
|
|
||||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
||||||
if (NS_WARN_IF(aRv.Failed())) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -136,7 +267,7 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -146,66 +277,72 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
Cache::Add(const RequestOrUSVString& aRequest, ErrorResult& aRv)
|
Cache::Add(JSContext* aContext, const RequestOrUSVString& aRequest,
|
||||||
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
|
||||||
|
|
||||||
if (!IsValidPutRequestMethod(aRequest, aRv)) {
|
if (!IsValidPutRequestMethod(aRequest, aRv)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
|
GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
|
||||||
|
MOZ_ASSERT(!global.Failed());
|
||||||
|
|
||||||
|
nsTArray<nsRefPtr<Request>> requestList(1);
|
||||||
|
nsRefPtr<Request> request = Request::Constructor(global, aRequest,
|
||||||
|
RequestInit(), aRv);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoChildOpArgs args(this, CacheAddAllArgs());
|
nsAutoString url;
|
||||||
|
request->GetUrl(url);
|
||||||
args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
|
if (!IsValidPutRequestURL(url, aRv)) {
|
||||||
if (aRv.Failed()) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExecuteOp(args, aRv);
|
requestList.AppendElement(Move(request));
|
||||||
|
return AddAll(global, Move(requestList), aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
Cache::AddAll(const Sequence<OwningRequestOrUSVString>& aRequests,
|
Cache::AddAll(JSContext* aContext,
|
||||||
|
const Sequence<OwningRequestOrUSVString>& aRequestList,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mActor);
|
GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
|
||||||
|
MOZ_ASSERT(!global.Failed());
|
||||||
|
|
||||||
// If there is no work to do, then resolve immediately
|
nsTArray<nsRefPtr<Request>> requestList(aRequestList.Length());
|
||||||
if (aRequests.IsEmpty()) {
|
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
|
||||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
RequestOrUSVString requestOrString;
|
||||||
if (!promise) {
|
|
||||||
return nullptr;
|
if (aRequestList[i].IsRequest()) {
|
||||||
|
requestOrString.SetAsRequest() = aRequestList[i].GetAsRequest();
|
||||||
|
if (!IsValidPutRequestMethod(requestOrString.GetAsRequest(), aRv)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
requestOrString.SetAsUSVString().Rebind(
|
||||||
|
aRequestList[i].GetAsUSVString().Data(),
|
||||||
|
aRequestList[i].GetAsUSVString().Length());
|
||||||
}
|
}
|
||||||
|
|
||||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
nsRefPtr<Request> request = Request::Constructor(global, requestOrString,
|
||||||
return promise.forget();
|
RequestInit(), aRv);
|
||||||
}
|
|
||||||
|
|
||||||
AutoChildOpArgs args(this, CacheAddAllArgs());
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
|
|
||||||
if (!IsValidPutRequestMethod(aRequests[i], aRv)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<InternalRequest> ir = ToInternalRequest(aRequests[i], ReadBody,
|
|
||||||
aRv);
|
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
|
nsAutoString url;
|
||||||
if (aRv.Failed()) {
|
request->GetUrl(url);
|
||||||
|
if (!IsValidPutRequestURL(url, aRv)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestList.AppendElement(Move(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ExecuteOp(args, aRv);
|
return AddAll(global, Move(requestList), aRv);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
@@ -225,7 +362,7 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
|||||||
|
|
||||||
AutoChildOpArgs args(this, CachePutAllArgs());
|
AutoChildOpArgs args(this, CachePutAllArgs());
|
||||||
|
|
||||||
args.Add(ir, ReadBody, PassThroughReferrer, TypeErrorOnInvalidScheme,
|
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme,
|
||||||
aResponse, aRv);
|
aResponse, aRv);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -250,7 +387,7 @@ Cache::Delete(const RequestOrUSVString& aRequest,
|
|||||||
|
|
||||||
AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params));
|
AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params));
|
||||||
|
|
||||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -276,7 +413,7 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
||||||
if (aRv.Failed()) {
|
if (aRv.Failed()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -375,6 +512,80 @@ Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
|
|||||||
return promise.forget();
|
return promise.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<Promise>
|
||||||
|
Cache::AddAll(const GlobalObject& aGlobal,
|
||||||
|
nsTArray<nsRefPtr<Request>>&& aRequestList, ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
|
||||||
|
// If there is no work to do, then resolve immediately
|
||||||
|
if (aRequestList.IsEmpty()) {
|
||||||
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
|
if (!promise) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||||
|
return promise.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoTArray<nsRefPtr<Promise>, 256> fetchList;
|
||||||
|
fetchList.SetCapacity(aRequestList.Length());
|
||||||
|
|
||||||
|
// Begin fetching each request in parallel. For now, if an error occurs just
|
||||||
|
// abandon our previous fetch calls. In theory we could cancel them in the
|
||||||
|
// future once fetch supports it.
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
|
||||||
|
RequestOrUSVString requestOrString;
|
||||||
|
requestOrString.SetAsRequest() = aRequestList[i];
|
||||||
|
nsRefPtr<Promise> fetch = FetchRequest(mGlobal, requestOrString,
|
||||||
|
RequestInit(), aRv);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchList.AppendElement(Move(fetch));
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsRefPtr<FetchHandler> handler = new FetchHandler(mActor->GetFeature(), this,
|
||||||
|
Move(aRequestList), promise);
|
||||||
|
|
||||||
|
nsRefPtr<Promise> fetchPromise = Promise::All(aGlobal, fetchList, aRv);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
fetchPromise->AppendNativeHandler(handler);
|
||||||
|
|
||||||
|
return promise.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<Promise>
|
||||||
|
Cache::PutAll(const nsTArray<nsRefPtr<Request>>& aRequestList,
|
||||||
|
const nsTArray<nsRefPtr<Response>>& aResponseList,
|
||||||
|
ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mActor);
|
||||||
|
MOZ_ASSERT(aRequestList.Length() == aResponseList.Length());
|
||||||
|
|
||||||
|
AutoChildOpArgs args(this, CachePutAllArgs());
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
|
||||||
|
nsRefPtr<InternalRequest> ir = aRequestList[i]->GetInternalRequest();
|
||||||
|
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i], aRv);
|
||||||
|
if (aRv.Failed()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExecuteOp(args, aRv);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace cache
|
} // namespace cache
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|||||||
18
dom/cache/Cache.h
vendored
18
dom/cache/Cache.h
vendored
@@ -50,10 +50,11 @@ public:
|
|||||||
MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
Add(const RequestOrUSVString& aRequest, ErrorResult& aRv);
|
Add(JSContext* aContext, const RequestOrUSVString& aRequest,
|
||||||
|
ErrorResult& aRv);
|
||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
AddAll(const Sequence<OwningRequestOrUSVString>& aRequests,
|
AddAll(JSContext* aContext,
|
||||||
ErrorResult& aRv);
|
const Sequence<OwningRequestOrUSVString>& aRequests, ErrorResult& aRv);
|
||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
@@ -85,6 +86,8 @@ public:
|
|||||||
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class FetchHandler;
|
||||||
|
|
||||||
~Cache();
|
~Cache();
|
||||||
|
|
||||||
// Called when we're destroyed or CCed.
|
// Called when we're destroyed or CCed.
|
||||||
@@ -93,6 +96,15 @@ private:
|
|||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv);
|
ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv);
|
||||||
|
|
||||||
|
already_AddRefed<Promise>
|
||||||
|
AddAll(const GlobalObject& aGlobal, nsTArray<nsRefPtr<Request>>&& aRequestList,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
already_AddRefed<Promise>
|
||||||
|
PutAll(const nsTArray<nsRefPtr<Request>>& aRequestList,
|
||||||
|
const nsTArray<nsRefPtr<Response>>& aResponseList,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||||
CacheChild* mActor;
|
CacheChild* mActor;
|
||||||
|
|
||||||
|
|||||||
1
dom/cache/CacheOpChild.cpp
vendored
1
dom/cache/CacheOpChild.cpp
vendored
@@ -116,7 +116,6 @@ CacheOpChild::Recv__delete__(const ErrorResult& aRv,
|
|||||||
HandleResponseList(aResult.get_CacheMatchAllResult().responseList());
|
HandleResponseList(aResult.get_CacheMatchAllResult().responseList());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CacheOpResult::TCacheAddAllResult:
|
|
||||||
case CacheOpResult::TCachePutAllResult:
|
case CacheOpResult::TCachePutAllResult:
|
||||||
{
|
{
|
||||||
mPromise->MaybeResolve(JS::UndefinedHandleValue);
|
mPromise->MaybeResolve(JS::UndefinedHandleValue);
|
||||||
|
|||||||
41
dom/cache/CacheOpParent.cpp
vendored
41
dom/cache/CacheOpParent.cpp
vendored
@@ -72,30 +72,6 @@ CacheOpParent::Execute(Manager* aManager)
|
|||||||
|
|
||||||
mManager = aManager;
|
mManager = aManager;
|
||||||
|
|
||||||
// Handle add/addAll op with a FetchPut object
|
|
||||||
if (mOpArgs.type() == CacheOpArgs::TCacheAddAllArgs) {
|
|
||||||
MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
|
|
||||||
|
|
||||||
const CacheAddAllArgs& args = mOpArgs.get_CacheAddAllArgs();
|
|
||||||
const nsTArray<CacheRequest>& list = args.requestList();
|
|
||||||
|
|
||||||
nsAutoTArray<nsCOMPtr<nsIInputStream>, 256> requestStreamList;
|
|
||||||
for (uint32_t i = 0; i < list.Length(); ++i) {
|
|
||||||
requestStreamList.AppendElement(DeserializeCacheStream(list[i].body()));
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<FetchPut> fetchPut;
|
|
||||||
nsresult rv = FetchPut::Create(this, mManager, mCacheId, list,
|
|
||||||
requestStreamList, getter_AddRefs(fetchPut));
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
OnOpComplete(ErrorResult(rv), CacheAddAllResult());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mFetchPutList.AppendElement(fetchPut.forget());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle put op
|
// Handle put op
|
||||||
if (mOpArgs.type() == CacheOpArgs::TCachePutAllArgs) {
|
if (mOpArgs.type() == CacheOpArgs::TCachePutAllArgs) {
|
||||||
MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
|
MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
|
||||||
@@ -151,11 +127,6 @@ CacheOpParent::ActorDestroy(ActorDestroyReason aReason)
|
|||||||
mVerifier = nullptr;
|
mVerifier = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mFetchPutList.Length(); ++i) {
|
|
||||||
mFetchPutList[i]->ClearListener();
|
|
||||||
}
|
|
||||||
mFetchPutList.Clear();
|
|
||||||
|
|
||||||
if (mManager) {
|
if (mManager) {
|
||||||
mManager->RemoveListener(this);
|
mManager->RemoveListener(this);
|
||||||
mManager = nullptr;
|
mManager = nullptr;
|
||||||
@@ -222,18 +193,6 @@ CacheOpParent::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
|||||||
unused << Send__delete__(this, aRv, result.SendAsOpResult());
|
unused << Send__delete__(this, aRv, result.SendAsOpResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
CacheOpParent::OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv)
|
|
||||||
{
|
|
||||||
NS_ASSERT_OWNINGTHREAD(CacheOpParent);
|
|
||||||
MOZ_ASSERT(aFetchPut);
|
|
||||||
|
|
||||||
aFetchPut->ClearListener();
|
|
||||||
MOZ_ALWAYS_TRUE(mFetchPutList.RemoveElement(aFetchPut));
|
|
||||||
|
|
||||||
OnOpComplete(Move(aRv), CacheAddAllResult());
|
|
||||||
}
|
|
||||||
|
|
||||||
already_AddRefed<nsIInputStream>
|
already_AddRefed<nsIInputStream>
|
||||||
CacheOpParent::DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid)
|
CacheOpParent::DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid)
|
||||||
{
|
{
|
||||||
|
|||||||
7
dom/cache/CacheOpParent.h
vendored
7
dom/cache/CacheOpParent.h
vendored
@@ -7,7 +7,6 @@
|
|||||||
#ifndef mozilla_dom_cache_CacheOpParent_h
|
#ifndef mozilla_dom_cache_CacheOpParent_h
|
||||||
#define mozilla_dom_cache_CacheOpParent_h
|
#define mozilla_dom_cache_CacheOpParent_h
|
||||||
|
|
||||||
#include "mozilla/dom/cache/FetchPut.h"
|
|
||||||
#include "mozilla/dom/cache/Manager.h"
|
#include "mozilla/dom/cache/Manager.h"
|
||||||
#include "mozilla/dom/cache/PCacheOpParent.h"
|
#include "mozilla/dom/cache/PCacheOpParent.h"
|
||||||
#include "mozilla/dom/cache/PrincipalVerifier.h"
|
#include "mozilla/dom/cache/PrincipalVerifier.h"
|
||||||
@@ -23,7 +22,6 @@ namespace cache {
|
|||||||
class CacheOpParent final : public PCacheOpParent
|
class CacheOpParent final : public PCacheOpParent
|
||||||
, public PrincipalVerifier::Listener
|
, public PrincipalVerifier::Listener
|
||||||
, public Manager::Listener
|
, public Manager::Listener
|
||||||
, public FetchPut::Listener
|
|
||||||
{
|
{
|
||||||
// to allow use of convenience overrides
|
// to allow use of convenience overrides
|
||||||
using Manager::Listener::OnOpComplete;
|
using Manager::Listener::OnOpComplete;
|
||||||
@@ -61,10 +59,6 @@ private:
|
|||||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
const nsTArray<SavedRequest>& aSavedRequestList,
|
||||||
StreamList* aStreamList) override;
|
StreamList* aStreamList) override;
|
||||||
|
|
||||||
// FetchPut::Listener methods
|
|
||||||
virtual void
|
|
||||||
OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv) override;
|
|
||||||
|
|
||||||
// utility methods
|
// utility methods
|
||||||
already_AddRefed<nsIInputStream>
|
already_AddRefed<nsIInputStream>
|
||||||
DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid);
|
DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid);
|
||||||
@@ -75,7 +69,6 @@ private:
|
|||||||
const CacheOpArgs mOpArgs;
|
const CacheOpArgs mOpArgs;
|
||||||
nsRefPtr<Manager> mManager;
|
nsRefPtr<Manager> mManager;
|
||||||
nsRefPtr<PrincipalVerifier> mVerifier;
|
nsRefPtr<PrincipalVerifier> mVerifier;
|
||||||
nsTArray<nsRefPtr<FetchPut>> mFetchPutList;
|
|
||||||
|
|
||||||
NS_DECL_OWNINGTHREAD
|
NS_DECL_OWNINGTHREAD
|
||||||
};
|
};
|
||||||
|
|||||||
1
dom/cache/CacheParent.cpp
vendored
1
dom/cache/CacheParent.cpp
vendored
@@ -49,7 +49,6 @@ CacheParent::AllocPCacheOpParent(const CacheOpArgs& aOpArgs)
|
|||||||
{
|
{
|
||||||
if (aOpArgs.type() != CacheOpArgs::TCacheMatchArgs &&
|
if (aOpArgs.type() != CacheOpArgs::TCacheMatchArgs &&
|
||||||
aOpArgs.type() != CacheOpArgs::TCacheMatchAllArgs &&
|
aOpArgs.type() != CacheOpArgs::TCacheMatchAllArgs &&
|
||||||
aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs &&
|
|
||||||
aOpArgs.type() != CacheOpArgs::TCachePutAllArgs &&
|
aOpArgs.type() != CacheOpArgs::TCachePutAllArgs &&
|
||||||
aOpArgs.type() != CacheOpArgs::TCacheDeleteArgs &&
|
aOpArgs.type() != CacheOpArgs::TCacheDeleteArgs &&
|
||||||
aOpArgs.type() != CacheOpArgs::TCacheKeysArgs)
|
aOpArgs.type() != CacheOpArgs::TCacheKeysArgs)
|
||||||
|
|||||||
3
dom/cache/CacheStorage.cpp
vendored
3
dom/cache/CacheStorage.cpp
vendored
@@ -432,8 +432,7 @@ CacheStorage::MaybeRunPendingRequests()
|
|||||||
nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
|
nsAutoPtr<Entry> entry(mPendingRequests[i].forget());
|
||||||
AutoChildOpArgs args(this, entry->mArgs);
|
AutoChildOpArgs args(this, entry->mArgs);
|
||||||
if (entry->mRequest) {
|
if (entry->mRequest) {
|
||||||
args.Add(entry->mRequest, IgnoreBody, PassThroughReferrer,
|
args.Add(entry->mRequest, IgnoreBody, IgnoreInvalidScheme, rv);
|
||||||
IgnoreInvalidScheme, rv);
|
|
||||||
}
|
}
|
||||||
if (rv.Failed()) {
|
if (rv.Failed()) {
|
||||||
entry->mPromise->MaybeReject(rv);
|
entry->mPromise->MaybeReject(rv);
|
||||||
|
|||||||
11
dom/cache/CacheTypes.ipdlh
vendored
11
dom/cache/CacheTypes.ipdlh
vendored
@@ -108,11 +108,6 @@ struct CacheMatchAllArgs
|
|||||||
CacheQueryParams params;
|
CacheQueryParams params;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CacheAddAllArgs
|
|
||||||
{
|
|
||||||
CacheRequest[] requestList;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CachePutAllArgs
|
struct CachePutAllArgs
|
||||||
{
|
{
|
||||||
CacheRequestResponse[] requestResponseList;
|
CacheRequestResponse[] requestResponseList;
|
||||||
@@ -159,7 +154,6 @@ union CacheOpArgs
|
|||||||
{
|
{
|
||||||
CacheMatchArgs;
|
CacheMatchArgs;
|
||||||
CacheMatchAllArgs;
|
CacheMatchAllArgs;
|
||||||
CacheAddAllArgs;
|
|
||||||
CachePutAllArgs;
|
CachePutAllArgs;
|
||||||
CacheDeleteArgs;
|
CacheDeleteArgs;
|
||||||
CacheKeysArgs;
|
CacheKeysArgs;
|
||||||
@@ -180,10 +174,6 @@ struct CacheMatchAllResult
|
|||||||
CacheResponse[] responseList;
|
CacheResponse[] responseList;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CacheAddAllResult
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CachePutAllResult
|
struct CachePutAllResult
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
@@ -228,7 +218,6 @@ union CacheOpResult
|
|||||||
void_t;
|
void_t;
|
||||||
CacheMatchResult;
|
CacheMatchResult;
|
||||||
CacheMatchAllResult;
|
CacheMatchAllResult;
|
||||||
CacheAddAllResult;
|
|
||||||
CachePutAllResult;
|
CachePutAllResult;
|
||||||
CacheDeleteResult;
|
CacheDeleteResult;
|
||||||
CacheKeysResult;
|
CacheKeysResult;
|
||||||
|
|||||||
483
dom/cache/FetchPut.cpp
vendored
483
dom/cache/FetchPut.cpp
vendored
@@ -1,483 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 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/dom/cache/FetchPut.h"
|
|
||||||
|
|
||||||
#include "mozilla/dom/Fetch.h"
|
|
||||||
#include "mozilla/dom/FetchDriver.h"
|
|
||||||
#include "mozilla/dom/Headers.h"
|
|
||||||
#include "mozilla/dom/Promise.h"
|
|
||||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
|
||||||
#include "mozilla/dom/Request.h"
|
|
||||||
#include "mozilla/dom/Response.h"
|
|
||||||
#include "mozilla/dom/ResponseBinding.h"
|
|
||||||
#include "mozilla/dom/UnionTypes.h"
|
|
||||||
#include "mozilla/dom/cache/ManagerId.h"
|
|
||||||
#include "nsContentUtils.h"
|
|
||||||
#include "nsNetUtil.h"
|
|
||||||
#include "nsThreadUtils.h"
|
|
||||||
#include "nsCRT.h"
|
|
||||||
#include "nsHttp.h"
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
namespace cache {
|
|
||||||
|
|
||||||
class FetchPut::Runnable final : public nsRunnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Runnable(FetchPut* aFetchPut)
|
|
||||||
: mFetchPut(aFetchPut)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mFetchPut);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHOD Run() override
|
|
||||||
{
|
|
||||||
if (NS_IsMainThread())
|
|
||||||
{
|
|
||||||
mFetchPut->DoFetchOnMainThread();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(mFetchPut->mInitiatingThread == NS_GetCurrentThread());
|
|
||||||
|
|
||||||
mFetchPut->DoPutOnWorkerThread();
|
|
||||||
|
|
||||||
// The FetchPut object must ultimately be freed on the worker thread,
|
|
||||||
// so make sure we release our reference here. The runnable may end
|
|
||||||
// up getting deleted on the main thread.
|
|
||||||
mFetchPut = nullptr;
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsRefPtr<FetchPut> mFetchPut;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FetchPut::FetchObserver final : public FetchDriverObserver
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit FetchObserver(FetchPut* aFetchPut)
|
|
||||||
: mFetchPut(aFetchPut)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnResponseAvailable(InternalResponse* aResponse) override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!mInternalResponse);
|
|
||||||
mInternalResponse = aResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void OnResponseEnd() override
|
|
||||||
{
|
|
||||||
mFetchPut->FetchComplete(this, mInternalResponse);
|
|
||||||
if (mFetchPut->mInitiatingThread == NS_GetCurrentThread()) {
|
|
||||||
mFetchPut = nullptr;
|
|
||||||
} else {
|
|
||||||
nsCOMPtr<nsIThread> initiatingThread(mFetchPut->mInitiatingThread);
|
|
||||||
nsCOMPtr<nsIRunnable> runnable =
|
|
||||||
NS_NewNonOwningRunnableMethod(mFetchPut.forget().take(), &FetchPut::Release);
|
|
||||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
|
||||||
initiatingThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~FetchObserver() { }
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsRefPtr<FetchPut> mFetchPut;
|
|
||||||
nsRefPtr<InternalResponse> mInternalResponse;
|
|
||||||
};
|
|
||||||
|
|
||||||
// static
|
|
||||||
nsresult
|
|
||||||
FetchPut::Create(Listener* aListener, Manager* aManager, CacheId aCacheId,
|
|
||||||
const nsTArray<CacheRequest>& aRequests,
|
|
||||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams,
|
|
||||||
FetchPut** aFetchPutOut)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(aRequests.Length() == aRequestStreams.Length());
|
|
||||||
|
|
||||||
// The FetchDriver requires that all requests have a referrer already set.
|
|
||||||
#ifdef DEBUG
|
|
||||||
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
|
|
||||||
if (aRequests[i].referrer() == EmptyString()) {
|
|
||||||
return NS_ERROR_UNEXPECTED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
nsRefPtr<FetchPut> ref = new FetchPut(aListener, aManager, aCacheId,
|
|
||||||
aRequests, aRequestStreams);
|
|
||||||
|
|
||||||
nsresult rv = ref->DispatchToMainThread();
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
|
|
||||||
|
|
||||||
ref.forget(aFetchPutOut);
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FetchPut::ClearListener()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mListener);
|
|
||||||
mListener = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
FetchPut::FetchPut(Listener* aListener, Manager* aManager, CacheId aCacheId,
|
|
||||||
const nsTArray<CacheRequest>& aRequests,
|
|
||||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams)
|
|
||||||
: mListener(aListener)
|
|
||||||
, mManager(aManager)
|
|
||||||
, mCacheId(aCacheId)
|
|
||||||
, mInitiatingThread(NS_GetCurrentThread())
|
|
||||||
, mStateList(aRequests.Length())
|
|
||||||
, mPendingCount(0)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mListener);
|
|
||||||
MOZ_ASSERT(mManager);
|
|
||||||
MOZ_ASSERT(aRequests.Length() == aRequestStreams.Length());
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aRequests.Length(); ++i) {
|
|
||||||
State* s = mStateList.AppendElement();
|
|
||||||
s->mCacheRequest = aRequests[i];
|
|
||||||
s->mRequestStream = aRequestStreams[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
mManager->AddRefCacheId(mCacheId);
|
|
||||||
}
|
|
||||||
|
|
||||||
FetchPut::~FetchPut()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mInitiatingThread == NS_GetCurrentThread());
|
|
||||||
MOZ_ASSERT(!mListener);
|
|
||||||
mManager->RemoveListener(this);
|
|
||||||
mManager->ReleaseCacheId(mCacheId);
|
|
||||||
mResult.SuppressException(); // XXXbz should we really be ending up here with
|
|
||||||
// a failed mResult we never reported to anyone?
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
FetchPut::DispatchToMainThread()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!mRunnable);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> runnable = new Runnable(this);
|
|
||||||
|
|
||||||
nsresult rv = NS_DispatchToMainThread(runnable, nsIThread::DISPATCH_NORMAL);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT(!mRunnable);
|
|
||||||
mRunnable = runnable.forget();
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FetchPut::DispatchToInitiatingThread()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mRunnable);
|
|
||||||
|
|
||||||
nsresult rv = mInitiatingThread->Dispatch(mRunnable,
|
|
||||||
nsIThread::DISPATCH_NORMAL);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
MOZ_CRASH("Failed to dispatch to worker thread after fetch completion.");
|
|
||||||
}
|
|
||||||
|
|
||||||
mRunnable = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FetchPut::DoFetchOnMainThread()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
nsRefPtr<ManagerId> managerId = mManager->GetManagerId();
|
|
||||||
nsCOMPtr<nsIPrincipal> principal = managerId->Principal();
|
|
||||||
mPendingCount = mStateList.Length();
|
|
||||||
|
|
||||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
|
||||||
nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
MaybeSetError(ErrorResult(rv));
|
|
||||||
MaybeCompleteOnMainThread();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mStateList.Length(); ++i) {
|
|
||||||
nsRefPtr<InternalRequest> internalRequest =
|
|
||||||
ToInternalRequest(mStateList[i].mCacheRequest);
|
|
||||||
|
|
||||||
// If there is a stream we must clone it so that its still available
|
|
||||||
// to store in the cache later;
|
|
||||||
if (mStateList[i].mRequestStream) {
|
|
||||||
internalRequest->SetBody(mStateList[i].mRequestStream);
|
|
||||||
nsRefPtr<InternalRequest> clone = internalRequest->Clone();
|
|
||||||
|
|
||||||
// The copy construction clone above can change the source stream,
|
|
||||||
// so get it back out to use when we put this in the cache.
|
|
||||||
internalRequest->GetBody(getter_AddRefs(mStateList[i].mRequestStream));
|
|
||||||
|
|
||||||
internalRequest = clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<FetchDriver> fetchDriver = new FetchDriver(internalRequest,
|
|
||||||
principal,
|
|
||||||
loadGroup);
|
|
||||||
|
|
||||||
mStateList[i].mFetchObserver = new FetchObserver(this);
|
|
||||||
rv = fetchDriver->Fetch(mStateList[i].mFetchObserver);
|
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
||||||
MaybeSetError(ErrorResult(rv));
|
|
||||||
mStateList[i].mFetchObserver = nullptr;
|
|
||||||
mPendingCount -= 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If they all failed, then we might need to complete main thread immediately
|
|
||||||
MaybeCompleteOnMainThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FetchPut::FetchComplete(FetchObserver* aObserver,
|
|
||||||
InternalResponse* aInternalResponse)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (aInternalResponse->IsError() && !mResult.Failed()) {
|
|
||||||
MaybeSetError(ErrorResult(NS_ERROR_FAILURE));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mStateList.Length(); ++i) {
|
|
||||||
if (mStateList[i].mFetchObserver == aObserver) {
|
|
||||||
ErrorResult rv;
|
|
||||||
ToCacheResponseWithoutBody(mStateList[i].mCacheResponse,
|
|
||||||
*aInternalResponse, rv);
|
|
||||||
if (rv.Failed()) {
|
|
||||||
MaybeSetError(Move(rv));
|
|
||||||
} else {
|
|
||||||
aInternalResponse->GetBody(getter_AddRefs(mStateList[i].mResponseStream));
|
|
||||||
}
|
|
||||||
mStateList[i].mFetchObserver = nullptr;
|
|
||||||
MOZ_ASSERT(mPendingCount > 0);
|
|
||||||
mPendingCount -= 1;
|
|
||||||
MaybeCompleteOnMainThread();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MOZ_ASSERT_UNREACHABLE("Should never get called by unknown fetch observer.");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FetchPut::MaybeCompleteOnMainThread()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (mPendingCount > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DispatchToInitiatingThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FetchPut::DoPutOnWorkerThread()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mInitiatingThread == NS_GetCurrentThread());
|
|
||||||
|
|
||||||
if (mResult.Failed()) {
|
|
||||||
MaybeNotifyListener();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These allocate ~4.5k combined on the stack
|
|
||||||
nsAutoTArray<CacheRequestResponse, 16> putList;
|
|
||||||
nsAutoTArray<nsCOMPtr<nsIInputStream>, 16> requestStreamList;
|
|
||||||
nsAutoTArray<nsCOMPtr<nsIInputStream>, 16> responseStreamList;
|
|
||||||
|
|
||||||
putList.SetCapacity(mStateList.Length());
|
|
||||||
requestStreamList.SetCapacity(mStateList.Length());
|
|
||||||
responseStreamList.SetCapacity(mStateList.Length());
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < mStateList.Length(); ++i) {
|
|
||||||
// The spec requires us to catch if content tries to insert a set of
|
|
||||||
// requests that would overwrite each other.
|
|
||||||
if (MatchInPutList(mStateList[i].mCacheRequest, putList)) {
|
|
||||||
MaybeSetError(ErrorResult(NS_ERROR_DOM_INVALID_STATE_ERR));
|
|
||||||
MaybeNotifyListener();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CacheRequestResponse* entry = putList.AppendElement();
|
|
||||||
entry->request() = mStateList[i].mCacheRequest;
|
|
||||||
entry->response() = mStateList[i].mCacheResponse;
|
|
||||||
requestStreamList.AppendElement(mStateList[i].mRequestStream.forget());
|
|
||||||
responseStreamList.AppendElement(mStateList[i].mResponseStream.forget());
|
|
||||||
}
|
|
||||||
mStateList.Clear();
|
|
||||||
|
|
||||||
mManager->ExecutePutAll(this, mCacheId, putList, requestStreamList,
|
|
||||||
responseStreamList);
|
|
||||||
}
|
|
||||||
|
|
||||||
// static
|
|
||||||
bool
|
|
||||||
FetchPut::MatchInPutList(const CacheRequest& aRequest,
|
|
||||||
const nsTArray<CacheRequestResponse>& aPutList)
|
|
||||||
{
|
|
||||||
// This method implements the SW spec QueryCache algorithm against an
|
|
||||||
// in memory array of Request/Response objects. This essentially the
|
|
||||||
// same algorithm that is implemented in DBSchema.cpp. Unfortunately
|
|
||||||
// we cannot unify them because when operating against the real database
|
|
||||||
// we don't want to load all request/response objects into memory.
|
|
||||||
|
|
||||||
if (!aRequest.method().LowerCaseEqualsLiteral("get") &&
|
|
||||||
!aRequest.method().LowerCaseEqualsLiteral("head")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<InternalHeaders> requestHeaders =
|
|
||||||
ToInternalHeaders(aRequest.headers());
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < aPutList.Length(); ++i) {
|
|
||||||
const CacheRequest& cachedRequest = aPutList[i].request();
|
|
||||||
const CacheResponse& cachedResponse = aPutList[i].response();
|
|
||||||
|
|
||||||
// If the URLs don't match, then just skip to the next entry.
|
|
||||||
if (aRequest.url() != cachedRequest.url()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsRefPtr<InternalHeaders> cachedRequestHeaders =
|
|
||||||
ToInternalHeaders(cachedRequest.headers());
|
|
||||||
|
|
||||||
nsRefPtr<InternalHeaders> cachedResponseHeaders =
|
|
||||||
ToInternalHeaders(cachedResponse.headers());
|
|
||||||
|
|
||||||
nsAutoTArray<nsCString, 16> varyHeaders;
|
|
||||||
ErrorResult rv;
|
|
||||||
cachedResponseHeaders->GetAll(NS_LITERAL_CSTRING("vary"), varyHeaders, rv);
|
|
||||||
MOZ_ALWAYS_TRUE(!rv.Failed());
|
|
||||||
|
|
||||||
// Assume the vary headers match until we find a conflict
|
|
||||||
bool varyHeadersMatch = true;
|
|
||||||
|
|
||||||
for (uint32_t j = 0; j < varyHeaders.Length(); ++j) {
|
|
||||||
// Extract the header names inside the Vary header value.
|
|
||||||
nsAutoCString varyValue(varyHeaders[j]);
|
|
||||||
char* rawBuffer = varyValue.BeginWriting();
|
|
||||||
char* token = nsCRT::strtok(rawBuffer, NS_HTTP_HEADER_SEPS, &rawBuffer);
|
|
||||||
bool bailOut = false;
|
|
||||||
for (; token;
|
|
||||||
token = nsCRT::strtok(rawBuffer, NS_HTTP_HEADER_SEPS, &rawBuffer)) {
|
|
||||||
nsDependentCString header(token);
|
|
||||||
MOZ_ASSERT(!header.EqualsLiteral("*"),
|
|
||||||
"We should have already caught this in "
|
|
||||||
"TypeUtils::ToPCacheResponseWithoutBody()");
|
|
||||||
|
|
||||||
ErrorResult headerRv;
|
|
||||||
nsAutoCString value;
|
|
||||||
requestHeaders->Get(header, value, headerRv);
|
|
||||||
if (NS_WARN_IF(headerRv.Failed())) {
|
|
||||||
headerRv.SuppressException();
|
|
||||||
MOZ_ASSERT(value.IsEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
nsAutoCString cachedValue;
|
|
||||||
cachedRequestHeaders->Get(header, value, headerRv);
|
|
||||||
if (NS_WARN_IF(headerRv.Failed())) {
|
|
||||||
headerRv.SuppressException();
|
|
||||||
MOZ_ASSERT(cachedValue.IsEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value != cachedValue) {
|
|
||||||
varyHeadersMatch = false;
|
|
||||||
bailOut = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bailOut) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// URL was equal and all vary headers match!
|
|
||||||
if (varyHeadersMatch) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FetchPut::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
|
||||||
CacheId aOpenedCacheId,
|
|
||||||
const nsTArray<SavedResponse>& aSavedResponseList,
|
|
||||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
|
||||||
StreamList* aStreamList)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mInitiatingThread == NS_GetCurrentThread());
|
|
||||||
MOZ_ASSERT(aResult.type() == CacheOpResult::TCachePutAllResult);
|
|
||||||
MaybeSetError(Move(aRv));
|
|
||||||
MaybeNotifyListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FetchPut::MaybeSetError(ErrorResult&& aRv)
|
|
||||||
{
|
|
||||||
if (mResult.Failed() || !aRv.Failed()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mResult = Move(aRv);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FetchPut::MaybeNotifyListener()
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mInitiatingThread == NS_GetCurrentThread());
|
|
||||||
if (!mListener) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// CacheParent::OnFetchPut can lead to the destruction of |this| when the
|
|
||||||
// object is removed from CacheParent::mFetchPutList, so make sure that
|
|
||||||
// doesn't happen until this method returns.
|
|
||||||
nsRefPtr<FetchPut> kungFuDeathGrip(this);
|
|
||||||
mListener->OnFetchPut(this, Move(mResult));
|
|
||||||
}
|
|
||||||
|
|
||||||
nsIGlobalObject*
|
|
||||||
FetchPut::GetGlobalObject() const
|
|
||||||
{
|
|
||||||
MOZ_CRASH("No global object in parent-size FetchPut operation!");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
void
|
|
||||||
FetchPut::AssertOwningThread() const
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mInitiatingThread == NS_GetCurrentThread());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CachePushStreamChild*
|
|
||||||
FetchPut::CreatePushStream(nsIAsyncInputStream* aStream)
|
|
||||||
{
|
|
||||||
MOZ_CRASH("FetchPut should never create a push stream!");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cache
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
123
dom/cache/FetchPut.h
vendored
123
dom/cache/FetchPut.h
vendored
@@ -1,123 +0,0 @@
|
|||||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
||||||
/* vim: set ts=8 sts=2 et sw=2 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_dom_cache_FetchPut_h
|
|
||||||
#define mozilla_dom_cache_FetchPut_h
|
|
||||||
|
|
||||||
#include "mozilla/AlreadyAddRefed.h"
|
|
||||||
#include "mozilla/Attributes.h"
|
|
||||||
#include "mozilla/ErrorResult.h"
|
|
||||||
#include "mozilla/dom/cache/Manager.h"
|
|
||||||
#include "mozilla/dom/cache/CacheTypes.h"
|
|
||||||
#include "mozilla/dom/cache/Types.h"
|
|
||||||
#include "mozilla/dom/cache/TypeUtils.h"
|
|
||||||
#include "nsRefPtr.h"
|
|
||||||
#include "nsTArray.h"
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
class nsIInputStream;
|
|
||||||
class nsIRunnable;
|
|
||||||
class nsIThread;
|
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
|
|
||||||
class Request;
|
|
||||||
class Response;
|
|
||||||
|
|
||||||
namespace cache {
|
|
||||||
|
|
||||||
class FetchPut final : public Manager::Listener
|
|
||||||
, public TypeUtils
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::pair<nsRefPtr<Request>, nsRefPtr<Response>> PutPair;
|
|
||||||
|
|
||||||
class Listener
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void
|
|
||||||
OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
static nsresult
|
|
||||||
Create(Listener* aListener, Manager* aManager, CacheId aCacheId,
|
|
||||||
const nsTArray<CacheRequest>& aRequests,
|
|
||||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams,
|
|
||||||
FetchPut** aFetchPutOut);
|
|
||||||
|
|
||||||
void ClearListener();
|
|
||||||
|
|
||||||
private:
|
|
||||||
class Runnable;
|
|
||||||
class FetchObserver;
|
|
||||||
friend class FetchObserver;
|
|
||||||
struct State
|
|
||||||
{
|
|
||||||
CacheRequest mCacheRequest;
|
|
||||||
nsCOMPtr<nsIInputStream> mRequestStream;
|
|
||||||
nsRefPtr<FetchObserver> mFetchObserver;
|
|
||||||
CacheResponse mCacheResponse;
|
|
||||||
nsCOMPtr<nsIInputStream> mResponseStream;
|
|
||||||
|
|
||||||
nsRefPtr<Request> mRequest;
|
|
||||||
nsRefPtr<Response> mResponse;
|
|
||||||
};
|
|
||||||
|
|
||||||
FetchPut(Listener* aListener, Manager* aManager, CacheId aCacheId,
|
|
||||||
const nsTArray<CacheRequest>& aRequests,
|
|
||||||
const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreams);
|
|
||||||
~FetchPut();
|
|
||||||
|
|
||||||
nsresult DispatchToMainThread();
|
|
||||||
void DispatchToInitiatingThread();
|
|
||||||
|
|
||||||
void DoFetchOnMainThread();
|
|
||||||
void FetchComplete(FetchObserver* aObserver,
|
|
||||||
InternalResponse* aInternalResponse);
|
|
||||||
void MaybeCompleteOnMainThread();
|
|
||||||
|
|
||||||
void DoPutOnWorkerThread();
|
|
||||||
static bool MatchInPutList(const CacheRequest& aRequest,
|
|
||||||
const nsTArray<CacheRequestResponse>& aPutList);
|
|
||||||
|
|
||||||
virtual void
|
|
||||||
OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
|
||||||
CacheId aOpenedCacheId,
|
|
||||||
const nsTArray<SavedResponse>& aSavedResponseList,
|
|
||||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
|
||||||
StreamList* aStreamList) override;
|
|
||||||
|
|
||||||
void MaybeSetError(ErrorResult&& aRv);
|
|
||||||
void MaybeNotifyListener();
|
|
||||||
|
|
||||||
// TypeUtils methods
|
|
||||||
virtual nsIGlobalObject* GetGlobalObject() const override;
|
|
||||||
#ifdef DEBUG
|
|
||||||
virtual void AssertOwningThread() const override;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
virtual CachePushStreamChild*
|
|
||||||
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
|
||||||
|
|
||||||
Listener* mListener;
|
|
||||||
nsRefPtr<Manager> mManager;
|
|
||||||
const CacheId mCacheId;
|
|
||||||
nsCOMPtr<nsIThread> mInitiatingThread;
|
|
||||||
nsTArray<State> mStateList;
|
|
||||||
uint32_t mPendingCount;
|
|
||||||
ErrorResult mResult;
|
|
||||||
nsCOMPtr<nsIRunnable> mRunnable;
|
|
||||||
|
|
||||||
public:
|
|
||||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::cache::FetchPut)
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cache
|
|
||||||
} // namespace dom
|
|
||||||
} // namespace mozilla
|
|
||||||
|
|
||||||
#endif // mozilla_dom_cache_FetchPut_h
|
|
||||||
1
dom/cache/Manager.cpp
vendored
1
dom/cache/Manager.cpp
vendored
@@ -1621,7 +1621,6 @@ Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId,
|
|||||||
{
|
{
|
||||||
NS_ASSERT_OWNINGTHREAD(Manager);
|
NS_ASSERT_OWNINGTHREAD(Manager);
|
||||||
MOZ_ASSERT(aListener);
|
MOZ_ASSERT(aListener);
|
||||||
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs);
|
|
||||||
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs);
|
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs);
|
||||||
|
|
||||||
if (mState == Closing) {
|
if (mState == Closing) {
|
||||||
|
|||||||
3
dom/cache/Manager.h
vendored
3
dom/cache/Manager.h
vendored
@@ -18,6 +18,9 @@ class nsIInputStream;
|
|||||||
class nsIThread;
|
class nsIThread;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
class ErrorResult;
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
namespace cache {
|
namespace cache {
|
||||||
|
|
||||||
|
|||||||
170
dom/cache/TypeUtils.cpp
vendored
170
dom/cache/TypeUtils.cpp
vendored
@@ -15,7 +15,6 @@
|
|||||||
#include "mozilla/dom/cache/CacheTypes.h"
|
#include "mozilla/dom/cache/CacheTypes.h"
|
||||||
#include "mozilla/dom/cache/ReadStream.h"
|
#include "mozilla/dom/cache/ReadStream.h"
|
||||||
#include "mozilla/ipc/BackgroundChild.h"
|
#include "mozilla/ipc/BackgroundChild.h"
|
||||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
|
||||||
#include "mozilla/ipc/PBackgroundChild.h"
|
#include "mozilla/ipc/PBackgroundChild.h"
|
||||||
#include "mozilla/ipc/PFileDescriptorSetChild.h"
|
#include "mozilla/ipc/PFileDescriptorSetChild.h"
|
||||||
#include "mozilla/ipc/InputStreamUtils.h"
|
#include "mozilla/ipc/InputStreamUtils.h"
|
||||||
@@ -30,85 +29,16 @@
|
|||||||
#include "nsCRT.h"
|
#include "nsCRT.h"
|
||||||
#include "nsHttp.h"
|
#include "nsHttp.h"
|
||||||
|
|
||||||
namespace {
|
namespace mozilla {
|
||||||
|
namespace dom {
|
||||||
|
namespace cache {
|
||||||
|
|
||||||
using mozilla::ErrorResult;
|
|
||||||
using mozilla::unused;
|
|
||||||
using mozilla::void_t;
|
|
||||||
using mozilla::dom::InternalHeaders;
|
|
||||||
using mozilla::dom::cache::CacheReadStream;
|
|
||||||
using mozilla::dom::cache::HeadersEntry;
|
|
||||||
using mozilla::ipc::BackgroundChild;
|
using mozilla::ipc::BackgroundChild;
|
||||||
using mozilla::ipc::FileDescriptor;
|
using mozilla::ipc::FileDescriptor;
|
||||||
using mozilla::ipc::PBackgroundChild;
|
using mozilla::ipc::PBackgroundChild;
|
||||||
using mozilla::ipc::PFileDescriptorSetChild;
|
using mozilla::ipc::PFileDescriptorSetChild;
|
||||||
|
|
||||||
// Utility function to remove the fragment from a URL, check its scheme, and optionally
|
namespace {
|
||||||
// provide a URL without the query. We're not using nsIURL or URL to do this because
|
|
||||||
// they require going to the main thread.
|
|
||||||
static void
|
|
||||||
ProcessURL(nsAString& aUrl, bool* aSchemeValidOut,
|
|
||||||
nsAString* aUrlWithoutQueryOut, ErrorResult& aRv)
|
|
||||||
{
|
|
||||||
NS_ConvertUTF16toUTF8 flatURL(aUrl);
|
|
||||||
const char* url = flatURL.get();
|
|
||||||
|
|
||||||
// off the main thread URL parsing using nsStdURLParser.
|
|
||||||
nsCOMPtr<nsIURLParser> urlParser = new nsStdURLParser();
|
|
||||||
|
|
||||||
uint32_t pathPos;
|
|
||||||
int32_t pathLen;
|
|
||||||
uint32_t schemePos;
|
|
||||||
int32_t schemeLen;
|
|
||||||
aRv = urlParser->ParseURL(url, flatURL.Length(), &schemePos, &schemeLen,
|
|
||||||
nullptr, nullptr, // ignore authority
|
|
||||||
&pathPos, &pathLen);
|
|
||||||
if (NS_WARN_IF(aRv.Failed())) { return; }
|
|
||||||
|
|
||||||
if (aSchemeValidOut) {
|
|
||||||
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
|
|
||||||
*aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") ||
|
|
||||||
scheme.LowerCaseEqualsLiteral("https") ||
|
|
||||||
scheme.LowerCaseEqualsLiteral("app");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t queryPos;
|
|
||||||
int32_t queryLen;
|
|
||||||
uint32_t refPos;
|
|
||||||
int32_t refLen;
|
|
||||||
|
|
||||||
aRv = urlParser->ParsePath(url + pathPos, flatURL.Length() - pathPos,
|
|
||||||
nullptr, nullptr, // ignore filepath
|
|
||||||
&queryPos, &queryLen,
|
|
||||||
&refPos, &refLen);
|
|
||||||
if (NS_WARN_IF(aRv.Failed())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove this once Request/Response properly strip the fragment (bug 1110476)
|
|
||||||
if (refLen >= 0) {
|
|
||||||
// ParsePath gives us ref position relative to the start of the path
|
|
||||||
refPos += pathPos;
|
|
||||||
|
|
||||||
aUrl = Substring(aUrl, 0, refPos - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!aUrlWithoutQueryOut) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (queryLen < 0) {
|
|
||||||
*aUrlWithoutQueryOut = aUrl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParsePath gives us query position relative to the start of the path
|
|
||||||
queryPos += pathPos;
|
|
||||||
|
|
||||||
// We want everything before the query sine we already removed the trailing
|
|
||||||
// fragment
|
|
||||||
*aUrlWithoutQueryOut = Substring(aUrl, 0, queryPos - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
HasVaryStar(mozilla::dom::InternalHeaders* aHeaders)
|
HasVaryStar(mozilla::dom::InternalHeaders* aHeaders)
|
||||||
@@ -174,18 +104,6 @@ ToHeadersEntryList(nsTArray<HeadersEntry>& aOut, InternalHeaders* aHeaders)
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
namespace mozilla {
|
|
||||||
namespace dom {
|
|
||||||
namespace cache {
|
|
||||||
|
|
||||||
using mozilla::ipc::BackgroundChild;
|
|
||||||
using mozilla::ipc::FileDescriptor;
|
|
||||||
using mozilla::ipc::FileDescriptorSetChild;
|
|
||||||
using mozilla::ipc::PFileDescriptorSetChild;
|
|
||||||
using mozilla::ipc::PBackgroundChild;
|
|
||||||
using mozilla::ipc::OptionalFileDescriptorSet;
|
|
||||||
|
|
||||||
|
|
||||||
already_AddRefed<InternalRequest>
|
already_AddRefed<InternalRequest>
|
||||||
TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
|
TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
|
||||||
BodyAction aBodyAction, ErrorResult& aRv)
|
BodyAction aBodyAction, ErrorResult& aRv)
|
||||||
@@ -225,9 +143,8 @@ TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn,
|
|||||||
|
|
||||||
void
|
void
|
||||||
TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||||
BodyAction aBodyAction,
|
BodyAction aBodyAction, SchemeAction aSchemeAction,
|
||||||
ReferrerAction aReferrerAction,
|
ErrorResult& aRv)
|
||||||
SchemeAction aSchemeAction, ErrorResult& aRv)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aIn);
|
MOZ_ASSERT(aIn);
|
||||||
|
|
||||||
@@ -249,16 +166,8 @@ TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
|||||||
aRv.ThrowTypeError(MSG_INVALID_URL_SCHEME, &label, &aOut.url());
|
aRv.ThrowTypeError(MSG_INVALID_URL_SCHEME, &label, &aOut.url());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aSchemeAction == NetworkErrorOnInvalidScheme) {
|
|
||||||
aRv.Throw(NS_ERROR_DOM_NETWORK_ERR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aReferrerAction == ExpandReferrer) {
|
|
||||||
UpdateRequestReferrer(GetGlobalObject(), aIn);
|
|
||||||
}
|
|
||||||
aIn->GetReferrer(aOut.referrer());
|
aIn->GetReferrer(aOut.referrer());
|
||||||
|
|
||||||
nsRefPtr<InternalHeaders> headers = aIn->Headers();
|
nsRefPtr<InternalHeaders> headers = aIn->Headers();
|
||||||
@@ -465,6 +374,73 @@ TypeUtils::ToInternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
|
|||||||
return ref.forget();
|
return ref.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Utility function to remove the fragment from a URL, check its scheme, and optionally
|
||||||
|
// provide a URL without the query. We're not using nsIURL or URL to do this because
|
||||||
|
// they require going to the main thread.
|
||||||
|
// static
|
||||||
|
void
|
||||||
|
TypeUtils::ProcessURL(nsAString& aUrl, bool* aSchemeValidOut,
|
||||||
|
nsAString* aUrlWithoutQueryOut, ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
NS_ConvertUTF16toUTF8 flatURL(aUrl);
|
||||||
|
const char* url = flatURL.get();
|
||||||
|
|
||||||
|
// off the main thread URL parsing using nsStdURLParser.
|
||||||
|
nsCOMPtr<nsIURLParser> urlParser = new nsStdURLParser();
|
||||||
|
|
||||||
|
uint32_t pathPos;
|
||||||
|
int32_t pathLen;
|
||||||
|
uint32_t schemePos;
|
||||||
|
int32_t schemeLen;
|
||||||
|
aRv = urlParser->ParseURL(url, flatURL.Length(), &schemePos, &schemeLen,
|
||||||
|
nullptr, nullptr, // ignore authority
|
||||||
|
&pathPos, &pathLen);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) { return; }
|
||||||
|
|
||||||
|
if (aSchemeValidOut) {
|
||||||
|
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
|
||||||
|
*aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") ||
|
||||||
|
scheme.LowerCaseEqualsLiteral("https");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t queryPos;
|
||||||
|
int32_t queryLen;
|
||||||
|
uint32_t refPos;
|
||||||
|
int32_t refLen;
|
||||||
|
|
||||||
|
aRv = urlParser->ParsePath(url + pathPos, flatURL.Length() - pathPos,
|
||||||
|
nullptr, nullptr, // ignore filepath
|
||||||
|
&queryPos, &queryLen,
|
||||||
|
&refPos, &refLen);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this once Request/Response properly strip the fragment (bug 1110476)
|
||||||
|
if (refLen >= 0) {
|
||||||
|
// ParsePath gives us ref position relative to the start of the path
|
||||||
|
refPos += pathPos;
|
||||||
|
|
||||||
|
aUrl = Substring(aUrl, 0, refPos - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aUrlWithoutQueryOut) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryLen < 0) {
|
||||||
|
*aUrlWithoutQueryOut = aUrl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsePath gives us query position relative to the start of the path
|
||||||
|
queryPos += pathPos;
|
||||||
|
|
||||||
|
// We want everything before the query sine we already removed the trailing
|
||||||
|
// fragment
|
||||||
|
*aUrlWithoutQueryOut = Substring(aUrl, 0, queryPos - 1);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
|
|||||||
17
dom/cache/TypeUtils.h
vendored
17
dom/cache/TypeUtils.h
vendored
@@ -46,17 +46,10 @@ public:
|
|||||||
ReadBody
|
ReadBody
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ReferrerAction
|
|
||||||
{
|
|
||||||
PassThroughReferrer,
|
|
||||||
ExpandReferrer
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SchemeAction
|
enum SchemeAction
|
||||||
{
|
{
|
||||||
IgnoreInvalidScheme,
|
IgnoreInvalidScheme,
|
||||||
TypeErrorOnInvalidScheme,
|
TypeErrorOnInvalidScheme
|
||||||
NetworkErrorOnInvalidScheme
|
|
||||||
};
|
};
|
||||||
|
|
||||||
~TypeUtils() { }
|
~TypeUtils() { }
|
||||||
@@ -80,8 +73,8 @@ public:
|
|||||||
|
|
||||||
void
|
void
|
||||||
ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||||
BodyAction aBodyAction, ReferrerAction aReferrerAction,
|
BodyAction aBodyAction, SchemeAction aSchemeAction,
|
||||||
SchemeAction aSchemeAction, ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
void
|
void
|
||||||
ToCacheResponseWithoutBody(CacheResponse& aOut, InternalResponse& aIn,
|
ToCacheResponseWithoutBody(CacheResponse& aOut, InternalResponse& aIn,
|
||||||
@@ -107,6 +100,10 @@ public:
|
|||||||
ToInternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
|
ToInternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
|
||||||
HeadersGuardEnum aGuard = HeadersGuardEnum::None);
|
HeadersGuardEnum aGuard = HeadersGuardEnum::None);
|
||||||
|
|
||||||
|
static void
|
||||||
|
ProcessURL(nsAString& aUrl, bool* aSchemeValidOut,
|
||||||
|
nsAString* aUrlWithoutQueryOut, ErrorResult& aRv);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void
|
void
|
||||||
CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
||||||
|
|||||||
2
dom/cache/moz.build
vendored
2
dom/cache/moz.build
vendored
@@ -25,7 +25,6 @@ EXPORTS.mozilla.dom.cache += [
|
|||||||
'DBAction.h',
|
'DBAction.h',
|
||||||
'DBSchema.h',
|
'DBSchema.h',
|
||||||
'Feature.h',
|
'Feature.h',
|
||||||
'FetchPut.h',
|
|
||||||
'FileUtils.h',
|
'FileUtils.h',
|
||||||
'IPCUtils.h',
|
'IPCUtils.h',
|
||||||
'Manager.h',
|
'Manager.h',
|
||||||
@@ -61,7 +60,6 @@ UNIFIED_SOURCES += [
|
|||||||
'DBAction.cpp',
|
'DBAction.cpp',
|
||||||
'DBSchema.cpp',
|
'DBSchema.cpp',
|
||||||
'Feature.cpp',
|
'Feature.cpp',
|
||||||
'FetchPut.cpp',
|
|
||||||
'FileUtils.cpp',
|
'FileUtils.cpp',
|
||||||
'Manager.cpp',
|
'Manager.cpp',
|
||||||
'ManagerId.cpp',
|
'ManagerId.cpp',
|
||||||
|
|||||||
4
dom/cache/test/mochitest/test_cache_add.js
vendored
4
dom/cache/test/mochitest/test_cache_add.js
vendored
@@ -10,10 +10,10 @@ caches.open(name).then(function(openCache) {
|
|||||||
cache = openCache;
|
cache = openCache;
|
||||||
return cache.add('ftp://example.com/invalid' + context);
|
return cache.add('ftp://example.com/invalid' + context);
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
is(err.name, 'NetworkError', 'add() should throw NetworkError for invalid scheme');
|
is(err.name, 'TypeError', 'add() should throw TypeError for invalid scheme');
|
||||||
return cache.addAll(['http://example.com/valid' + context, 'ftp://example.com/invalid' + context]);
|
return cache.addAll(['http://example.com/valid' + context, 'ftp://example.com/invalid' + context]);
|
||||||
}).catch(function (err) {
|
}).catch(function (err) {
|
||||||
is(err.name, 'NetworkError', 'addAll() should throw NetworkError for invalid scheme');
|
is(err.name, 'TypeError', 'addAll() should throw TypeError for invalid scheme');
|
||||||
var promiseList = urlList.map(function(url) {
|
var promiseList = urlList.map(function(url) {
|
||||||
return cache.match(url);
|
return cache.match(url);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,13 +12,13 @@
|
|||||||
#include "mozilla/dom/Fetch.h"
|
#include "mozilla/dom/Fetch.h"
|
||||||
#include "mozilla/dom/ResponseBinding.h"
|
#include "mozilla/dom/ResponseBinding.h"
|
||||||
|
|
||||||
|
#include "InternalHeaders.h"
|
||||||
#include "InternalResponse.h"
|
#include "InternalResponse.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class Headers;
|
class Headers;
|
||||||
class InternalHeaders;
|
|
||||||
|
|
||||||
class Response final : public nsISupports
|
class Response final : public nsISupports
|
||||||
, public FetchBody<Response>
|
, public FetchBody<Response>
|
||||||
|
|||||||
Reference in New Issue
Block a user