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': {
|
||||
'implicitJSContext': [ 'add', 'addAll' ],
|
||||
'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/unused.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/InternalRequest.h"
|
||||
#include "mozilla/dom/cache/CacheParent.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/CacheStreamControlParent.h"
|
||||
@@ -17,6 +19,8 @@
|
||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetParent.h"
|
||||
#include "mozilla/ipc/PBackgroundParent.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsHttp.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -168,15 +172,6 @@ AutoChildOpArgs::~AutoChildOpArgs()
|
||||
CleanupChild(args.requestOrVoid().get_CacheRequest().body(), action);
|
||||
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:
|
||||
{
|
||||
CachePutAllArgs& args = mOpArgs.get_CachePutAllArgs();
|
||||
@@ -216,8 +211,7 @@ AutoChildOpArgs::~AutoChildOpArgs()
|
||||
|
||||
void
|
||||
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv)
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
|
||||
@@ -226,7 +220,7 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
{
|
||||
CacheMatchArgs& args = mOpArgs.get_CacheMatchArgs();
|
||||
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheMatchAllArgs:
|
||||
@@ -235,35 +229,14 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
|
||||
args.requestOrVoid() = CacheRequest();
|
||||
mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
|
||||
aRequest, aBodyAction, aReferrerAction,
|
||||
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);
|
||||
}
|
||||
aRequest, aBodyAction, aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheDeleteArgs:
|
||||
{
|
||||
CacheDeleteArgs& args = mOpArgs.get_CacheDeleteArgs();
|
||||
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TCacheKeysArgs:
|
||||
@@ -272,15 +245,14 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
MOZ_ASSERT(args.requestOrVoid().type() == CacheRequestOrVoid::Tvoid_t);
|
||||
args.requestOrVoid() = CacheRequest();
|
||||
mTypeUtils->ToCacheRequest(args.requestOrVoid().get_CacheRequest(),
|
||||
aRequest, aBodyAction, aReferrerAction,
|
||||
aSchemeAction, aRv);
|
||||
aRequest, aBodyAction, aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
case CacheOpArgs::TStorageMatchArgs:
|
||||
{
|
||||
StorageMatchArgs& args = mOpArgs.get_StorageMatchArgs();
|
||||
mTypeUtils->ToCacheRequest(args.request(), aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
aSchemeAction, aRv);
|
||||
break;
|
||||
}
|
||||
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
|
||||
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
Response& aResponse, ErrorResult& aRv)
|
||||
SchemeAction aSchemeAction, Response& aResponse,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!mSent);
|
||||
|
||||
@@ -300,6 +374,14 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
{
|
||||
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
|
||||
// been removed. The copy constructor, however, simply duplicates the
|
||||
// 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();
|
||||
|
||||
mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction,
|
||||
aReferrerAction, aSchemeAction, aRv);
|
||||
aSchemeAction, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
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:
|
||||
typedef TypeUtils::BodyAction BodyAction;
|
||||
typedef TypeUtils::ReferrerAction ReferrerAction;
|
||||
typedef TypeUtils::SchemeAction SchemeAction;
|
||||
|
||||
AutoChildOpArgs(TypeUtils* aTypeUtils, const CacheOpArgs& aOpArgs);
|
||||
~AutoChildOpArgs();
|
||||
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv);
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv);
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction, SchemeAction aSchemeAction,
|
||||
Response& aResponse, ErrorResult& aRv);
|
||||
SchemeAction aSchemeAction, Response& aResponse, ErrorResult& aRv);
|
||||
|
||||
const CacheOpArgs& SendAsOpArgs();
|
||||
|
||||
|
||||
335
dom/cache/Cache.cpp
vendored
335
dom/cache/Cache.cpp
vendored
@@ -9,12 +9,14 @@
|
||||
#include "mozilla/dom/Headers.h"
|
||||
#include "mozilla/dom/InternalResponse.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/CacheBinding.h"
|
||||
#include "mozilla/dom/cache/AutoUtils.h"
|
||||
#include "mozilla/dom/cache/CacheChild.h"
|
||||
#include "mozilla/dom/cache/CachePushStreamChild.h"
|
||||
#include "mozilla/dom/cache/Feature.h"
|
||||
#include "mozilla/dom/cache/ReadStream.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@@ -22,30 +24,53 @@
|
||||
#include "nsIGlobalObject.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
|
||||
using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
|
||||
using mozilla::dom::workers::WorkerPrivate;
|
||||
|
||||
namespace {
|
||||
|
||||
using mozilla::ErrorResult;
|
||||
using mozilla::dom::MSG_INVALID_REQUEST_METHOD;
|
||||
using mozilla::dom::OwningRequestOrUSVString;
|
||||
using mozilla::dom::Request;
|
||||
using mozilla::dom::RequestOrUSVString;
|
||||
bool
|
||||
IsValidPutRequestURL(const nsAString& aUrl, ErrorResult& aRv)
|
||||
{
|
||||
bool validScheme = false;
|
||||
|
||||
// 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
|
||||
IsValidPutRequestMethod(const Request& aRequest, ErrorResult& aRv)
|
||||
{
|
||||
nsAutoCString method;
|
||||
aRequest.GetMethod(method);
|
||||
bool valid = method.LowerCaseEqualsLiteral("get");
|
||||
if (!valid) {
|
||||
if (!method.LowerCaseEqualsLiteral("get")) {
|
||||
NS_ConvertASCIItoUTF16 label(method);
|
||||
aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
|
||||
return false;
|
||||
}
|
||||
return valid;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsValidPutRequestMethod(const RequestOrUSVString& aRequest,
|
||||
ErrorResult& aRv)
|
||||
IsValidPutRequestMethod(const RequestOrUSVString& aRequest, ErrorResult& aRv)
|
||||
{
|
||||
// If the provided request is a string URL, then it will default to
|
||||
// a valid http method automatically.
|
||||
@@ -55,26 +80,132 @@ IsValidPutRequestMethod(const RequestOrUSVString& aRequest,
|
||||
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
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace cache {
|
||||
// Helper class to wait for Add()/AddAll() fetch requests to complete and
|
||||
// then perform a PutAll() with the responses. This class holds a Feature
|
||||
// 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;
|
||||
using mozilla::unused;
|
||||
using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
|
||||
using mozilla::dom::workers::WorkerPrivate;
|
||||
virtual void
|
||||
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
|
||||
{
|
||||
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_RELEASE(mozilla::dom::cache::Cache);
|
||||
@@ -110,7 +241,7 @@ Cache::Match(const RequestOrUSVString& aRequest,
|
||||
|
||||
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())) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -136,7 +267,7 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -146,66 +277,72 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
}
|
||||
|
||||
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)) {
|
||||
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()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoChildOpArgs args(this, CacheAddAllArgs());
|
||||
|
||||
args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
nsAutoString url;
|
||||
request->GetUrl(url);
|
||||
if (!IsValidPutRequestURL(url, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ExecuteOp(args, aRv);
|
||||
requestList.AppendElement(Move(request));
|
||||
return AddAll(global, Move(requestList), aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::AddAll(const Sequence<OwningRequestOrUSVString>& aRequests,
|
||||
Cache::AddAll(JSContext* aContext,
|
||||
const Sequence<OwningRequestOrUSVString>& aRequestList,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
|
||||
MOZ_ASSERT(!global.Failed());
|
||||
|
||||
// If there is no work to do, then resolve immediately
|
||||
if (aRequests.IsEmpty()) {
|
||||
nsRefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
|
||||
if (!promise) {
|
||||
nsTArray<nsRefPtr<Request>> requestList(aRequestList.Length());
|
||||
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
|
||||
RequestOrUSVString requestOrString;
|
||||
|
||||
if (aRequestList[i].IsRequest()) {
|
||||
requestOrString.SetAsRequest() = aRequestList[i].GetAsRequest();
|
||||
if (!IsValidPutRequestMethod(requestOrString.GetAsRequest(), aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
} else {
|
||||
requestOrString.SetAsUSVString().Rebind(
|
||||
aRequestList[i].GetAsUSVString().Data(),
|
||||
aRequestList[i].GetAsUSVString().Length());
|
||||
}
|
||||
|
||||
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);
|
||||
nsRefPtr<Request> request = Request::Constructor(global, requestOrString,
|
||||
RequestInit(), aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
args.Add(ir, ReadBody, ExpandReferrer, NetworkErrorOnInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
nsAutoString url;
|
||||
request->GetUrl(url);
|
||||
if (!IsValidPutRequestURL(url, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
requestList.AppendElement(Move(request));
|
||||
}
|
||||
|
||||
return ExecuteOp(args, aRv);
|
||||
return AddAll(global, Move(requestList), aRv);
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
@@ -225,7 +362,7 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
|
||||
AutoChildOpArgs args(this, CachePutAllArgs());
|
||||
|
||||
args.Add(ir, ReadBody, PassThroughReferrer, TypeErrorOnInvalidScheme,
|
||||
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme,
|
||||
aResponse, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
@@ -250,7 +387,7 @@ Cache::Delete(const RequestOrUSVString& aRequest,
|
||||
|
||||
AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params));
|
||||
|
||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -276,7 +413,7 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
args.Add(ir, IgnoreBody, PassThroughReferrer, IgnoreInvalidScheme, aRv);
|
||||
args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -375,6 +512,80 @@ Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
|
||||
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 dom
|
||||
} // namespace mozilla
|
||||
|
||||
18
dom/cache/Cache.h
vendored
18
dom/cache/Cache.h
vendored
@@ -50,11 +50,12 @@ public:
|
||||
MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Add(const RequestOrUSVString& aRequest, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
AddAll(const Sequence<OwningRequestOrUSVString>& aRequests,
|
||||
Add(JSContext* aContext, const RequestOrUSVString& aRequest,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
AddAll(JSContext* aContext,
|
||||
const Sequence<OwningRequestOrUSVString>& aRequests, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
@@ -85,6 +86,8 @@ public:
|
||||
CreatePushStream(nsIAsyncInputStream* aStream) override;
|
||||
|
||||
private:
|
||||
class FetchHandler;
|
||||
|
||||
~Cache();
|
||||
|
||||
// Called when we're destroyed or CCed.
|
||||
@@ -93,6 +96,15 @@ private:
|
||||
already_AddRefed<Promise>
|
||||
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;
|
||||
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());
|
||||
break;
|
||||
}
|
||||
case CacheOpResult::TCacheAddAllResult:
|
||||
case CacheOpResult::TCachePutAllResult:
|
||||
{
|
||||
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;
|
||||
|
||||
// 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
|
||||
if (mOpArgs.type() == CacheOpArgs::TCachePutAllArgs) {
|
||||
MOZ_ASSERT(mCacheId != INVALID_CACHE_ID);
|
||||
@@ -151,11 +127,6 @@ CacheOpParent::ActorDestroy(ActorDestroyReason aReason)
|
||||
mVerifier = nullptr;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mFetchPutList.Length(); ++i) {
|
||||
mFetchPutList[i]->ClearListener();
|
||||
}
|
||||
mFetchPutList.Clear();
|
||||
|
||||
if (mManager) {
|
||||
mManager->RemoveListener(this);
|
||||
mManager = nullptr;
|
||||
@@ -222,18 +193,6 @@ CacheOpParent::OnOpComplete(ErrorResult&& aRv, const CacheOpResult& aResult,
|
||||
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>
|
||||
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
|
||||
#define mozilla_dom_cache_CacheOpParent_h
|
||||
|
||||
#include "mozilla/dom/cache/FetchPut.h"
|
||||
#include "mozilla/dom/cache/Manager.h"
|
||||
#include "mozilla/dom/cache/PCacheOpParent.h"
|
||||
#include "mozilla/dom/cache/PrincipalVerifier.h"
|
||||
@@ -23,7 +22,6 @@ namespace cache {
|
||||
class CacheOpParent final : public PCacheOpParent
|
||||
, public PrincipalVerifier::Listener
|
||||
, public Manager::Listener
|
||||
, public FetchPut::Listener
|
||||
{
|
||||
// to allow use of convenience overrides
|
||||
using Manager::Listener::OnOpComplete;
|
||||
@@ -61,10 +59,6 @@ private:
|
||||
const nsTArray<SavedRequest>& aSavedRequestList,
|
||||
StreamList* aStreamList) override;
|
||||
|
||||
// FetchPut::Listener methods
|
||||
virtual void
|
||||
OnFetchPut(FetchPut* aFetchPut, ErrorResult&& aRv) override;
|
||||
|
||||
// utility methods
|
||||
already_AddRefed<nsIInputStream>
|
||||
DeserializeCacheStream(const CacheReadStreamOrVoid& aStreamOrVoid);
|
||||
@@ -75,7 +69,6 @@ private:
|
||||
const CacheOpArgs mOpArgs;
|
||||
nsRefPtr<Manager> mManager;
|
||||
nsRefPtr<PrincipalVerifier> mVerifier;
|
||||
nsTArray<nsRefPtr<FetchPut>> mFetchPutList;
|
||||
|
||||
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 &&
|
||||
aOpArgs.type() != CacheOpArgs::TCacheMatchAllArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TCachePutAllArgs &&
|
||||
aOpArgs.type() != CacheOpArgs::TCacheDeleteArgs &&
|
||||
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());
|
||||
AutoChildOpArgs args(this, entry->mArgs);
|
||||
if (entry->mRequest) {
|
||||
args.Add(entry->mRequest, IgnoreBody, PassThroughReferrer,
|
||||
IgnoreInvalidScheme, rv);
|
||||
args.Add(entry->mRequest, IgnoreBody, IgnoreInvalidScheme, rv);
|
||||
}
|
||||
if (rv.Failed()) {
|
||||
entry->mPromise->MaybeReject(rv);
|
||||
|
||||
11
dom/cache/CacheTypes.ipdlh
vendored
11
dom/cache/CacheTypes.ipdlh
vendored
@@ -108,11 +108,6 @@ struct CacheMatchAllArgs
|
||||
CacheQueryParams params;
|
||||
};
|
||||
|
||||
struct CacheAddAllArgs
|
||||
{
|
||||
CacheRequest[] requestList;
|
||||
};
|
||||
|
||||
struct CachePutAllArgs
|
||||
{
|
||||
CacheRequestResponse[] requestResponseList;
|
||||
@@ -159,7 +154,6 @@ union CacheOpArgs
|
||||
{
|
||||
CacheMatchArgs;
|
||||
CacheMatchAllArgs;
|
||||
CacheAddAllArgs;
|
||||
CachePutAllArgs;
|
||||
CacheDeleteArgs;
|
||||
CacheKeysArgs;
|
||||
@@ -180,10 +174,6 @@ struct CacheMatchAllResult
|
||||
CacheResponse[] responseList;
|
||||
};
|
||||
|
||||
struct CacheAddAllResult
|
||||
{
|
||||
};
|
||||
|
||||
struct CachePutAllResult
|
||||
{
|
||||
};
|
||||
@@ -228,7 +218,6 @@ union CacheOpResult
|
||||
void_t;
|
||||
CacheMatchResult;
|
||||
CacheMatchAllResult;
|
||||
CacheAddAllResult;
|
||||
CachePutAllResult;
|
||||
CacheDeleteResult;
|
||||
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);
|
||||
MOZ_ASSERT(aListener);
|
||||
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs);
|
||||
MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs);
|
||||
|
||||
if (mState == Closing) {
|
||||
|
||||
3
dom/cache/Manager.h
vendored
3
dom/cache/Manager.h
vendored
@@ -18,6 +18,9 @@ class nsIInputStream;
|
||||
class nsIThread;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
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/ReadStream.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/FileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PFileDescriptorSetChild.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
@@ -30,85 +29,16 @@
|
||||
#include "nsCRT.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::FileDescriptor;
|
||||
using mozilla::ipc::PBackgroundChild;
|
||||
using mozilla::ipc::PFileDescriptorSetChild;
|
||||
|
||||
// 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
|
||||
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);
|
||||
}
|
||||
namespace {
|
||||
|
||||
static bool
|
||||
HasVaryStar(mozilla::dom::InternalHeaders* aHeaders)
|
||||
@@ -174,18 +104,6 @@ ToHeadersEntryList(nsTArray<HeadersEntry>& aOut, InternalHeaders* aHeaders)
|
||||
|
||||
} // 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>
|
||||
TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
|
||||
BodyAction aBodyAction, ErrorResult& aRv)
|
||||
@@ -225,9 +143,8 @@ TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn,
|
||||
|
||||
void
|
||||
TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||
BodyAction aBodyAction,
|
||||
ReferrerAction aReferrerAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv)
|
||||
BodyAction aBodyAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aIn);
|
||||
|
||||
@@ -249,16 +166,8 @@ TypeUtils::ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||
aRv.ThrowTypeError(MSG_INVALID_URL_SCHEME, &label, &aOut.url());
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSchemeAction == NetworkErrorOnInvalidScheme) {
|
||||
aRv.Throw(NS_ERROR_DOM_NETWORK_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (aReferrerAction == ExpandReferrer) {
|
||||
UpdateRequestReferrer(GetGlobalObject(), aIn);
|
||||
}
|
||||
aIn->GetReferrer(aOut.referrer());
|
||||
|
||||
nsRefPtr<InternalHeaders> headers = aIn->Headers();
|
||||
@@ -465,6 +374,73 @@ TypeUtils::ToInternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
|
||||
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
|
||||
TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
||||
ErrorResult& aRv)
|
||||
|
||||
17
dom/cache/TypeUtils.h
vendored
17
dom/cache/TypeUtils.h
vendored
@@ -46,17 +46,10 @@ public:
|
||||
ReadBody
|
||||
};
|
||||
|
||||
enum ReferrerAction
|
||||
{
|
||||
PassThroughReferrer,
|
||||
ExpandReferrer
|
||||
};
|
||||
|
||||
enum SchemeAction
|
||||
{
|
||||
IgnoreInvalidScheme,
|
||||
TypeErrorOnInvalidScheme,
|
||||
NetworkErrorOnInvalidScheme
|
||||
TypeErrorOnInvalidScheme
|
||||
};
|
||||
|
||||
~TypeUtils() { }
|
||||
@@ -80,8 +73,8 @@ public:
|
||||
|
||||
void
|
||||
ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||
BodyAction aBodyAction, ReferrerAction aReferrerAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv);
|
||||
BodyAction aBodyAction, SchemeAction aSchemeAction,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToCacheResponseWithoutBody(CacheResponse& aOut, InternalResponse& aIn,
|
||||
@@ -107,6 +100,10 @@ public:
|
||||
ToInternalHeaders(const nsTArray<HeadersEntry>& aHeadersEntryList,
|
||||
HeadersGuardEnum aGuard = HeadersGuardEnum::None);
|
||||
|
||||
static void
|
||||
ProcessURL(nsAString& aUrl, bool* aSchemeValidOut,
|
||||
nsAString* aUrlWithoutQueryOut, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
void
|
||||
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',
|
||||
'DBSchema.h',
|
||||
'Feature.h',
|
||||
'FetchPut.h',
|
||||
'FileUtils.h',
|
||||
'IPCUtils.h',
|
||||
'Manager.h',
|
||||
@@ -61,7 +60,6 @@ UNIFIED_SOURCES += [
|
||||
'DBAction.cpp',
|
||||
'DBSchema.cpp',
|
||||
'Feature.cpp',
|
||||
'FetchPut.cpp',
|
||||
'FileUtils.cpp',
|
||||
'Manager.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;
|
||||
return cache.add('ftp://example.com/invalid' + context);
|
||||
}).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]);
|
||||
}).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) {
|
||||
return cache.match(url);
|
||||
});
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
#include "mozilla/dom/Fetch.h"
|
||||
#include "mozilla/dom/ResponseBinding.h"
|
||||
|
||||
#include "InternalHeaders.h"
|
||||
#include "InternalResponse.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class Headers;
|
||||
class InternalHeaders;
|
||||
|
||||
class Response final : public nsISupports
|
||||
, public FetchBody<Response>
|
||||
|
||||
Reference in New Issue
Block a user