Issue #1442 - Part 14 - Starting body consuming and passing the JSContext down from the binding entrypoints to where the ReadableStream could be read. https://bugzilla.mozilla.org/show_bug.cgi?id=1128959

This commit is contained in:
Brian Smith 2023-09-28 19:35:59 -05:00 • committed by roytam1
commit 842b9d47b3
15 changed files with 192 additions and 77 deletions

View file

@ -116,11 +116,13 @@ DOMInterfaces = {
}, },
'Cache': { 'Cache': {
'implicitJSContext': [ 'add', 'addAll' ], 'implicitJSContext': [ 'add', 'addAll', 'match', 'matchAll', 'put',
'delete', 'keys' ],
'nativeType': 'mozilla::dom::cache::Cache', 'nativeType': 'mozilla::dom::cache::Cache',
}, },
'CacheStorage': { 'CacheStorage': {
'implicitJSContext': [ 'match' ],
'nativeType': 'mozilla::dom::cache::CacheStorage', 'nativeType': 'mozilla::dom::cache::CacheStorage',
}, },

View file

@ -289,9 +289,9 @@ MatchInPutList(InternalRequest* aRequest,
} // namespace } // namespace
void void
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction, AutoChildOpArgs::Add(JSContext* aCx, InternalRequest* aRequest,
SchemeAction aSchemeAction, Response& aResponse, BodyAction aBodyAction, SchemeAction aSchemeAction,
ErrorResult& aRv) Response& aResponse, ErrorResult& aRv)
{ {
MOZ_DIAGNOSTIC_ASSERT(!mSent); MOZ_DIAGNOSTIC_ASSERT(!mSent);
@ -329,7 +329,7 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction, mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction,
aSchemeAction, mStreamCleanupList, aRv); aSchemeAction, mStreamCleanupList, aRv);
if (!aRv.Failed()) { if (!aRv.Failed()) {
mTypeUtils->ToCacheResponse(pair.response(), aResponse, mTypeUtils->ToCacheResponse(aCx, pair.response(), aResponse,
mStreamCleanupList, aRv); mStreamCleanupList, aRv);
} }

View file

@ -55,7 +55,7 @@ public:
void Add(InternalRequest* aRequest, BodyAction aBodyAction, void Add(InternalRequest* aRequest, BodyAction aBodyAction,
SchemeAction aSchemeAction, ErrorResult& aRv); SchemeAction aSchemeAction, ErrorResult& aRv);
void Add(InternalRequest* aRequest, BodyAction aBodyAction, void Add(JSContext* aCx, InternalRequest* aRequest, BodyAction aBodyAction,
SchemeAction aSchemeAction, Response& aResponse, ErrorResult& aRv); SchemeAction aSchemeAction, Response& aResponse, ErrorResult& aRv);
const CacheOpArgs& SendAsOpArgs(); const CacheOpArgs& SendAsOpArgs();

38
dom/cache/Cache.cpp vendored
View file

@ -184,7 +184,10 @@ public:
// Now store the unwrapped Response list in the Cache. // Now store the unwrapped Response list in the Cache.
ErrorResult result; ErrorResult result;
RefPtr<Promise> put = mCache->PutAll(mRequestList, responseList, result); // TODO: Here we use the JSContext as received by the ResolvedCallback, and
// its state could be the wrong one. The spec doesn't say anything
// about it, yet (bug 1384006)
RefPtr<Promise> put = mCache->PutAll(aCx, mRequestList, responseList, result);
if (NS_WARN_IF(result.Failed())) { if (NS_WARN_IF(result.Failed())) {
// TODO: abort the fetch requests we have running (bug 1157434) // TODO: abort the fetch requests we have running (bug 1157434)
mPromise->MaybeReject(result); mPromise->MaybeReject(result);
@ -245,7 +248,7 @@ Cache::Cache(nsIGlobalObject* aGlobal, CacheChild* aActor)
} }
already_AddRefed<Promise> already_AddRefed<Promise>
Cache::Match(const RequestOrUSVString& aRequest, Cache::Match(JSContext* aCx, const RequestOrUSVString& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv) const CacheQueryOptions& aOptions, ErrorResult& aRv)
{ {
if (NS_WARN_IF(!mActor)) { if (NS_WARN_IF(!mActor)) {
@ -255,7 +258,8 @@ Cache::Match(const RequestOrUSVString& aRequest,
CacheChild::AutoLock actorLock(mActor); CacheChild::AutoLock actorLock(mActor);
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv); RefPtr<InternalRequest> ir =
ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@ -274,7 +278,7 @@ Cache::Match(const RequestOrUSVString& aRequest,
} }
already_AddRefed<Promise> already_AddRefed<Promise>
Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest, Cache::MatchAll(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv) const CacheQueryOptions& aOptions, ErrorResult& aRv)
{ {
if (NS_WARN_IF(!mActor)) { if (NS_WARN_IF(!mActor)) {
@ -290,7 +294,7 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
AutoChildOpArgs args(this, CacheMatchAllArgs(void_t(), params), 1); AutoChildOpArgs args(this, CacheMatchAllArgs(void_t(), params), 1);
if (aRequest.WasPassed()) { if (aRequest.WasPassed()) {
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(), RefPtr<InternalRequest> ir = ToInternalRequest(aCx, aRequest.Value(),
IgnoreBody, aRv); IgnoreBody, aRv);
if (aRv.Failed()) { if (aRv.Failed()) {
return nullptr; return nullptr;
@ -390,8 +394,8 @@ Cache::AddAll(JSContext* aContext,
} }
already_AddRefed<Promise> already_AddRefed<Promise>
Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse, Cache::Put(JSContext* aCx, const RequestOrUSVString& aRequest,
ErrorResult& aRv) Response& aResponse, ErrorResult& aRv)
{ {
if (NS_WARN_IF(!mActor)) { if (NS_WARN_IF(!mActor)) {
aRv.Throw(NS_ERROR_UNEXPECTED); aRv.Throw(NS_ERROR_UNEXPECTED);
@ -404,14 +408,14 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
return nullptr; return nullptr;
} }
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv); RefPtr<InternalRequest> ir = ToInternalRequest(aCx, aRequest, ReadBody, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
AutoChildOpArgs args(this, CachePutAllArgs(), 1); AutoChildOpArgs args(this, CachePutAllArgs(), 1);
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme, args.Add(aCx, ir, ReadBody, TypeErrorOnInvalidScheme,
aResponse, aRv); aResponse, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
@ -421,7 +425,7 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
} }
already_AddRefed<Promise> already_AddRefed<Promise>
Cache::Delete(const RequestOrUSVString& aRequest, Cache::Delete(JSContext* aCx, const RequestOrUSVString& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv) const CacheQueryOptions& aOptions, ErrorResult& aRv)
{ {
if (NS_WARN_IF(!mActor)) { if (NS_WARN_IF(!mActor)) {
@ -431,7 +435,8 @@ Cache::Delete(const RequestOrUSVString& aRequest,
CacheChild::AutoLock actorLock(mActor); CacheChild::AutoLock actorLock(mActor);
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv); RefPtr<InternalRequest> ir =
ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@ -450,7 +455,7 @@ Cache::Delete(const RequestOrUSVString& aRequest,
} }
already_AddRefed<Promise> already_AddRefed<Promise>
Cache::Keys(const Optional<RequestOrUSVString>& aRequest, Cache::Keys(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv) const CacheQueryOptions& aOptions, ErrorResult& aRv)
{ {
if (NS_WARN_IF(!mActor)) { if (NS_WARN_IF(!mActor)) {
@ -466,8 +471,8 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
AutoChildOpArgs args(this, CacheKeysArgs(void_t(), params), 1); AutoChildOpArgs args(this, CacheKeysArgs(void_t(), params), 1);
if (aRequest.WasPassed()) { if (aRequest.WasPassed()) {
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(), RefPtr<InternalRequest> ir =
IgnoreBody, aRv); ToInternalRequest(aCx, aRequest.Value(), IgnoreBody, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
@ -627,7 +632,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
} }
already_AddRefed<Promise> already_AddRefed<Promise>
Cache::PutAll(const nsTArray<RefPtr<Request>>& aRequestList, Cache::PutAll(JSContext* aCx, const nsTArray<RefPtr<Request>>& aRequestList,
const nsTArray<RefPtr<Response>>& aResponseList, const nsTArray<RefPtr<Response>>& aResponseList,
ErrorResult& aRv) ErrorResult& aRv)
{ {
@ -644,7 +649,8 @@ Cache::PutAll(const nsTArray<RefPtr<Request>>& aRequestList,
for (uint32_t i = 0; i < aRequestList.Length(); ++i) { for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
RefPtr<InternalRequest> ir = aRequestList[i]->GetInternalRequest(); RefPtr<InternalRequest> ir = aRequestList[i]->GetInternalRequest();
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i], aRv); args.Add(aCx, ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i],
aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }

16
dom/cache/Cache.h vendored
View file

@ -43,10 +43,10 @@ public:
// webidl interface methods // webidl interface methods
already_AddRefed<Promise> already_AddRefed<Promise>
Match(const RequestOrUSVString& aRequest, const CacheQueryOptions& aOptions, Match(JSContext* aCx, const RequestOrUSVString& aRequest,
ErrorResult& aRv); const CacheQueryOptions& aOptions, ErrorResult& aRv);
already_AddRefed<Promise> already_AddRefed<Promise>
MatchAll(const Optional<RequestOrUSVString>& aRequest, MatchAll(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv); const CacheQueryOptions& aOptions, ErrorResult& aRv);
already_AddRefed<Promise> already_AddRefed<Promise>
Add(JSContext* aContext, const RequestOrUSVString& aRequest, Add(JSContext* aContext, const RequestOrUSVString& aRequest,
@ -55,13 +55,13 @@ public:
AddAll(JSContext* aContext, AddAll(JSContext* aContext,
const Sequence<OwningRequestOrUSVString>& aRequests, ErrorResult& aRv); const Sequence<OwningRequestOrUSVString>& aRequests, ErrorResult& aRv);
already_AddRefed<Promise> already_AddRefed<Promise>
Put(const RequestOrUSVString& aRequest, Response& aResponse, Put(JSContext* aCx, const RequestOrUSVString& aRequest, Response& aResponse,
ErrorResult& aRv); ErrorResult& aRv);
already_AddRefed<Promise> already_AddRefed<Promise>
Delete(const RequestOrUSVString& aRequest, const CacheQueryOptions& aOptions, Delete(JSContext* aCx, const RequestOrUSVString& aRequest,
ErrorResult& aRv); const CacheQueryOptions& aOptions, ErrorResult& aRv);
already_AddRefed<Promise> already_AddRefed<Promise>
Keys(const Optional<RequestOrUSVString>& aRequest, Keys(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
const CacheQueryOptions& aParams, ErrorResult& aRv); const CacheQueryOptions& aParams, ErrorResult& aRv);
// binding methods // binding methods
@ -100,7 +100,7 @@ private:
ErrorResult& aRv); ErrorResult& aRv);
already_AddRefed<Promise> already_AddRefed<Promise>
PutAll(const nsTArray<RefPtr<Request>>& aRequestList, PutAll(JSContext* aCx, const nsTArray<RefPtr<Request>>& aRequestList,
const nsTArray<RefPtr<Response>>& aResponseList, const nsTArray<RefPtr<Response>>& aResponseList,
ErrorResult& aRv); ErrorResult& aRv);

View file

@ -316,7 +316,7 @@ CacheStorage::CacheStorage(nsresult aFailureResult)
} }
already_AddRefed<Promise> already_AddRefed<Promise>
CacheStorage::Match(const RequestOrUSVString& aRequest, CacheStorage::Match(JSContext* aCx, const RequestOrUSVString& aRequest,
const CacheQueryOptions& aOptions, ErrorResult& aRv) const CacheQueryOptions& aOptions, ErrorResult& aRv)
{ {
NS_ASSERT_OWNINGTHREAD(CacheStorage); NS_ASSERT_OWNINGTHREAD(CacheStorage);
@ -326,8 +326,8 @@ CacheStorage::Match(const RequestOrUSVString& aRequest,
return nullptr; return nullptr;
} }
RefPtr<InternalRequest> request = ToInternalRequest(aRequest, IgnoreBody, RefPtr<InternalRequest> request =
aRv); ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }

View file

@ -59,9 +59,9 @@ public:
DefineCaches(JSContext* aCx, JS::Handle<JSObject*> aGlobal); DefineCaches(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
// webidl interface methods // webidl interface methods
already_AddRefed<Promise> Match(const RequestOrUSVString& aRequest, already_AddRefed<Promise>
const CacheQueryOptions& aOptions, Match(JSContext* aCx, const RequestOrUSVString& aRequest,
ErrorResult& aRv); const CacheQueryOptions& aOptions, ErrorResult& aRv);
already_AddRefed<Promise> Has(const nsAString& aKey, ErrorResult& aRv); already_AddRefed<Promise> Has(const nsAString& aKey, ErrorResult& aRv);
already_AddRefed<Promise> Open(const nsAString& aKey, ErrorResult& aRv); already_AddRefed<Promise> Open(const nsAString& aKey, ErrorResult& aRv);
already_AddRefed<Promise> Delete(const nsAString& aKey, ErrorResult& aRv); already_AddRefed<Promise> Delete(const nsAString& aKey, ErrorResult& aRv);

View file

@ -79,7 +79,7 @@ ToHeadersEntryList(nsTArray<HeadersEntry>& aOut, InternalHeaders* aHeaders)
} // namespace } // namespace
already_AddRefed<InternalRequest> already_AddRefed<InternalRequest>
TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn, TypeUtils::ToInternalRequest(JSContext* aCx, const RequestOrUSVString& aIn,
BodyAction aBodyAction, ErrorResult& aRv) BodyAction aBodyAction, ErrorResult& aRv)
{ {
if (aIn.IsRequest()) { if (aIn.IsRequest()) {
@ -87,7 +87,7 @@ TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
// Check and set bodyUsed flag immediately because its on Request // Check and set bodyUsed flag immediately because its on Request
// instead of InternalRequest. // instead of InternalRequest.
CheckAndSetBodyUsed(&request, aBodyAction, aRv); CheckAndSetBodyUsed(aCx, &request, aBodyAction, aRv);
if (aRv.Failed()) { return nullptr; } if (aRv.Failed()) { return nullptr; }
return request.GetInternalRequest(); return request.GetInternalRequest();
@ -97,7 +97,8 @@ TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
} }
already_AddRefed<InternalRequest> already_AddRefed<InternalRequest>
TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn, TypeUtils::ToInternalRequest(JSContext* aCx,
const OwningRequestOrUSVString& aIn,
BodyAction aBodyAction, ErrorResult& aRv) BodyAction aBodyAction, ErrorResult& aRv)
{ {
@ -106,7 +107,7 @@ TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn,
// Check and set bodyUsed flag immediately because its on Request // Check and set bodyUsed flag immediately because its on Request
// instead of InternalRequest. // instead of InternalRequest.
CheckAndSetBodyUsed(request, aBodyAction, aRv); CheckAndSetBodyUsed(aCx, request, aBodyAction, aRv);
if (aRv.Failed()) { return nullptr; } if (aRv.Failed()) { return nullptr; }
return request->GetInternalRequest(); return request->GetInternalRequest();
@ -204,7 +205,7 @@ TypeUtils::ToCacheResponseWithoutBody(CacheResponse& aOut,
} }
void void
TypeUtils::ToCacheResponse(CacheResponse& aOut, Response& aIn, TypeUtils::ToCacheResponse(JSContext* aCx, CacheResponse& aOut, Response& aIn,
nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList, nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
ErrorResult& aRv) ErrorResult& aRv)
{ {
@ -222,7 +223,10 @@ TypeUtils::ToCacheResponse(CacheResponse& aOut, Response& aIn,
nsCOMPtr<nsIInputStream> stream; nsCOMPtr<nsIInputStream> stream;
ir->GetUnfilteredBody(getter_AddRefs(stream)); ir->GetUnfilteredBody(getter_AddRefs(stream));
if (stream) { if (stream) {
aIn.SetBodyUsed(); aIn.SetBodyUsed(aCx, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
} }
SerializeCacheStream(stream, &aOut.body(), aStreamCleanupList, aRv); SerializeCacheStream(stream, &aOut.body(), aStreamCleanupList, aRv);
@ -426,8 +430,8 @@ TypeUtils::ProcessURL(nsACString& aUrl, bool* aSchemeValidOut,
} }
void void
TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction, TypeUtils::CheckAndSetBodyUsed(JSContext* aCx, Request* aRequest,
ErrorResult& aRv) BodyAction aBodyAction, ErrorResult& aRv)
{ {
MOZ_DIAGNOSTIC_ASSERT(aRequest); MOZ_DIAGNOSTIC_ASSERT(aRequest);
@ -443,7 +447,10 @@ TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
nsCOMPtr<nsIInputStream> stream; nsCOMPtr<nsIInputStream> stream;
aRequest->GetBody(getter_AddRefs(stream)); aRequest->GetBody(getter_AddRefs(stream));
if (stream) { if (stream) {
aRequest->SetBodyUsed(); aRequest->SetBodyUsed(aCx, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
} }
} }

12
dom/cache/TypeUtils.h vendored
View file

@ -73,12 +73,12 @@ public:
GetIPCManager() = 0; GetIPCManager() = 0;
already_AddRefed<InternalRequest> already_AddRefed<InternalRequest>
ToInternalRequest(const RequestOrUSVString& aIn, BodyAction aBodyAction, ToInternalRequest(JSContext* aCx, const RequestOrUSVString& aIn,
ErrorResult& aRv); BodyAction aBodyAction, ErrorResult& aRv);
already_AddRefed<InternalRequest> already_AddRefed<InternalRequest>
ToInternalRequest(const OwningRequestOrUSVString& aIn, BodyAction aBodyAction, ToInternalRequest(JSContext* aCx, const OwningRequestOrUSVString& aIn,
ErrorResult& aRv); BodyAction aBodyAction, ErrorResult& aRv);
void void
ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn, ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
@ -91,7 +91,7 @@ public:
ErrorResult& aRv); ErrorResult& aRv);
void void
ToCacheResponse(CacheResponse& aOut, Response& aIn, ToCacheResponse(JSContext* aCx, CacheResponse& aOut, Response& aIn,
nsTArray<UniquePtr<mozilla::ipc::AutoIPCStream>>& aStreamCleanupList, nsTArray<UniquePtr<mozilla::ipc::AutoIPCStream>>& aStreamCleanupList,
ErrorResult& aRv); ErrorResult& aRv);
@ -133,7 +133,7 @@ public:
private: private:
void void
CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction, CheckAndSetBodyUsed(JSContext* aCx, Request* aRequest, BodyAction aBodyAction,
ErrorResult& aRv); ErrorResult& aRv);
already_AddRefed<InternalRequest> already_AddRefed<InternalRequest>

View file

@ -948,6 +948,52 @@ template
bool bool
FetchBody<Response>::BodyUsed() const; FetchBody<Response>::BodyUsed() const;
template <class Derived>
void
FetchBody<Derived>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(mOwner->EventTargetFor(TaskCategory::Other)->IsOnCurrentThread());
if (mBodyUsed) {
return;
}
mBodyUsed = true;
// If we already have a ReadableStreamBody and it has been created by DOM, we
// have to lock it now because it can have been shared with other objects.
if (mReadableStreamBody) {
JS::Rooted<JSObject*> readableStreamObj(aCx, mReadableStreamBody);
if (JS::ReadableStreamGetMode(readableStreamObj) ==
JS::ReadableStreamMode::ExternalSource) {
LockStream(aCx, readableStreamObj, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
} else {
// If this is not a native ReadableStream, let's activate the
// FetchStreamReader.
MOZ_ASSERT(mFetchStreamReader);
JS::Rooted<JSObject*> reader(aCx);
mFetchStreamReader->StartConsuming(aCx, readableStreamObj, &reader, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
mReadableStreamReader = reader;
}
}
}
template
void
FetchBody<Request>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
template
void
FetchBody<Response>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
template <class Derived> template <class Derived>
already_AddRefed<Promise> already_AddRefed<Promise>
FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorResult& aRv) FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorResult& aRv)
@ -963,31 +1009,10 @@ FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorRes
return nullptr; return nullptr;
} }
SetBodyUsed(); SetBodyUsed(aCx, aRv);
// If we already have a ReadableStreamBody and it has been created by DOM, we
// have to lock it now because it can have been shared with other objects.
if (mReadableStreamBody) {
JS::Rooted<JSObject*> readableStreamObj(aCx, mReadableStreamBody);
if (JS::ReadableStreamGetMode(readableStreamObj) ==
JS::ReadableStreamMode::ExternalSource) {
LockStream(aCx, readableStreamObj, aRv);
if (NS_WARN_IF(aRv.Failed())) { if (NS_WARN_IF(aRv.Failed())) {
return nullptr; return nullptr;
} }
} else {
// If this is not a native ReadableStream, let's activate the
// FetchStreamReader.
MOZ_ASSERT(mFetchStreamReader);
JS::Rooted<JSObject*> reader(aCx);
mFetchStreamReader->StartConsuming(aCx, readableStreamObj, &reader, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
mReadableStreamReader = reader;
}
}
nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject(); nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();

View file

@ -190,11 +190,28 @@ public:
// Utility public methods accessed by various runnables. // Utility public methods accessed by various runnables.
// This method _must_ be called in order to set the body as used. If the body
// is a ReadableStream, this method will start reading the stream.
// More in details, this method does:
// 1) It uses an internal flag to track if the body is used. This is tracked
// separately from the ReadableStream disturbed state due to purely native
// streams.
// 2) If there is a ReadableStream reflector for the native stream it is
// Locked.
// 3) If there is a JS ReadableStream then we begin pumping it into the native
// body stream. This effectively locks and disturbs the stream.
//
// Note that JSContext is used only if there is a ReadableStream (this can
// happen because the body is a ReadableStream or because attribute body has
// already been used by content). If something goes wrong using
// ReadableStream, errors will be reported via ErrorResult and not as JS
// exceptions in JSContext. This is done in order to have a centralized error
// reporting way.
//
// Exceptions generated when reading from the ReadableStream are directly sent
// to the Console (NOTE FOR THE REVIEWER: this is part of patch 16)
void void
SetBodyUsed() SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
{
mBodyUsed = true;
}
const nsCString& const nsCString&
MimeType() const MimeType() const

View file

@ -614,7 +614,10 @@ Request::Constructor(const GlobalObject& aGlobal,
inputReq->GetBody(getter_AddRefs(body)); inputReq->GetBody(getter_AddRefs(body));
if (body) { if (body) {
inputReq->SetBody(nullptr); inputReq->SetBody(nullptr);
inputReq->SetBodyUsed(); inputReq->SetBodyUsed(aGlobal.Context(), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
} }
} }
return domRequest.forget(); return domRequest.forget();

View file

@ -701,9 +701,14 @@ private:
request.SetAsUSVString().Rebind(loadInfo.mFullURL.Data(), request.SetAsUSVString().Rebind(loadInfo.mFullURL.Data(),
loadInfo.mFullURL.Length()); loadInfo.mFullURL.Length());
// This JSContext will not end up executing JS code because here there are
// no ReadableStreams involved.
AutoJSAPI jsapi;
jsapi.Init();
ErrorResult error; ErrorResult error;
RefPtr<Promise> cachePromise = RefPtr<Promise> cachePromise =
mCacheCreator->Cache_()->Put(request, *response, error); mCacheCreator->Cache_()->Put(jsapi.cx(), request, *response, error);
if (NS_WARN_IF(error.Failed())) { if (NS_WARN_IF(error.Failed())) {
nsresult rv = error.StealNSResult(); nsresult rv = error.StealNSResult();
channel->Cancel(rv); channel->Cancel(rv);
@ -1668,8 +1673,13 @@ CacheScriptLoader::Load(Cache* aCache)
mozilla::dom::CacheQueryOptions params; mozilla::dom::CacheQueryOptions params;
// This JSContext will not end up executing JS code because here there are
// no ReadableStreams involved.
AutoJSAPI jsapi;
jsapi.Init();
ErrorResult error; ErrorResult error;
RefPtr<Promise> promise = aCache->Match(request, params, error); RefPtr<Promise> promise = aCache->Match(jsapi.cx(), request, params, error);
if (NS_WARN_IF(error.Failed())) { if (NS_WARN_IF(error.Failed())) {
Fail(error.StealNSResult()); Fail(error.StealNSResult());
return; return;

View file

@ -505,6 +505,44 @@ public:
} }
} }
// This function steals the error message from a ErrorResult.
void
SetCancelErrorResult(JSContext* aCx, ErrorResult& aRv)
{
MOZ_DIAGNOSTIC_ASSERT(aRv.Failed());
MOZ_DIAGNOSTIC_ASSERT(!JS_IsExceptionPending(aCx));
// Storing the error as exception in the JSContext.
if (!aRv.MaybeSetPendingException(aCx)) {
return;
}
MOZ_ASSERT(!aRv.Failed());
// Let's take the pending exception.
JS::Rooted<JS::Value> exn(aCx);
if (!JS_GetPendingException(aCx, &exn)) {
return;
}
JS_ClearPendingException(aCx);
// Converting the exception in a js::ErrorReport.
js::ErrorReport report(aCx);
if (!report.init(aCx, exn, js::ErrorReport::WithSideEffects)) {
JS_ClearPendingException(aCx);
return;
}
MOZ_ASSERT(mOwner);
MOZ_ASSERT(mMessageName.EqualsLiteral("InterceptionFailedWithURL"));
MOZ_ASSERT(mParams.Length() == 1);
// Let's store the error message here.
mMessageName.Assign(report.toStringResult().c_str());
mParams.Clear();
}
template<typename... Params> template<typename... Params>
void SetCancelMessage(const nsACString& aMessageName, Params&&... aParams) void SetCancelMessage(const nsACString& aMessageName, Params&&... aParams)
{ {
@ -659,7 +697,12 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
ir->GetUnfilteredBody(getter_AddRefs(body)); ir->GetUnfilteredBody(getter_AddRefs(body));
// Errors and redirects may not have a body. // Errors and redirects may not have a body.
if (body) { if (body) {
response->SetBodyUsed(); IgnoredErrorResult error;
response->SetBodyUsed(aCx, error);
if (NS_WARN_IF(error.Failed())) {
autoCancel.SetCancelErrorResult(aCx, error);
return;
}
nsCOMPtr<nsIOutputStream> responseBody; nsCOMPtr<nsIOutputStream> responseBody;
rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody)); rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody));

View file

@ -395,7 +395,7 @@ public:
return; return;
} }
WriteToCache(cache); WriteToCache(aCx, cache);
return; return;
} }
@ -528,7 +528,7 @@ private:
} }
void void
WriteToCache(Cache* aCache) WriteToCache(JSContext* aCx, Cache* aCache)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
MOZ_ASSERT(aCache); MOZ_ASSERT(aCache);
@ -561,8 +561,10 @@ private:
// For now we have to wait until the Put Promise is fulfilled before we can // For now we have to wait until the Put Promise is fulfilled before we can
// continue since Cache does not yet support starting a read that is being // continue since Cache does not yet support starting a read that is being
// written to. // written to.
RefPtr<Promise> cachePromise = aCache->Put(request, *response, result); RefPtr<Promise> cachePromise = aCache->Put(aCx, request, *response, result);
if (NS_WARN_IF(result.Failed())) { if (NS_WARN_IF(result.Failed())) {
// No exception here because there are no ReadableStreams involved here.
MOZ_ASSERT(!result.IsJSException());
MOZ_ASSERT(!result.IsErrorWithMessage()); MOZ_ASSERT(!result.IsErrorWithMessage());
Fail(result.StealNSResult()); Fail(result.StealNSResult());
return; return;
@ -903,7 +905,7 @@ CompareCache::ManageCacheResult(JSContext* aCx, JS::Handle<JS::Value> aValue)
request.SetAsUSVString().Rebind(mURL.Data(), mURL.Length()); request.SetAsUSVString().Rebind(mURL.Data(), mURL.Length());
ErrorResult error; ErrorResult error;
CacheQueryOptions params; CacheQueryOptions params;
RefPtr<Promise> promise = cache->Match(request, params, error); RefPtr<Promise> promise = cache->Match(aCx, request, params, error);
if (NS_WARN_IF(error.Failed())) { if (NS_WARN_IF(error.Failed())) {
mManager->CacheFinished(error.StealNSResult(), false); mManager->CacheFinished(error.StealNSResult(), false);
return; return;