зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1128959 - Implement the WHATWG Streams spec - part 12 - starting body consuming and passing the JSContext down from the binding entrypoints to where the ReadableStream could be read, r=bz
This patch does 2 things: . when SetBodyUsed() is called, the pump for the stream reading is activated. . Just because of the reading of the stream could end up executing JS code, we need to pass the JSContext in the correct state down to SetBodyUsed.
This commit is contained in:
Родитель
4928cd7694
Коммит
cb3c4dda07
|
@ -112,11 +112,13 @@ DOMInterfaces = {
|
|||
},
|
||||
|
||||
'Cache': {
|
||||
'implicitJSContext': [ 'add', 'addAll' ],
|
||||
'implicitJSContext': [ 'add', 'addAll', 'match', 'matchAll', 'put',
|
||||
'delete', 'keys' ],
|
||||
'nativeType': 'mozilla::dom::cache::Cache',
|
||||
},
|
||||
|
||||
'CacheStorage': {
|
||||
'implicitJSContext': [ 'match' ],
|
||||
'nativeType': 'mozilla::dom::cache::CacheStorage',
|
||||
},
|
||||
|
||||
|
|
|
@ -290,9 +290,9 @@ MatchInPutList(InternalRequest* aRequest,
|
|||
} // namespace
|
||||
|
||||
void
|
||||
AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
SchemeAction aSchemeAction, Response& aResponse,
|
||||
ErrorResult& aRv)
|
||||
AutoChildOpArgs::Add(JSContext* aCx, InternalRequest* aRequest,
|
||||
BodyAction aBodyAction, SchemeAction aSchemeAction,
|
||||
Response& aResponse, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mSent);
|
||||
|
||||
|
@ -330,7 +330,7 @@ AutoChildOpArgs::Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
|||
mTypeUtils->ToCacheRequest(pair.request(), aRequest, aBodyAction,
|
||||
aSchemeAction, mStreamCleanupList, aRv);
|
||||
if (!aRv.Failed()) {
|
||||
mTypeUtils->ToCacheResponse(pair.response(), aResponse,
|
||||
mTypeUtils->ToCacheResponse(aCx, pair.response(), aResponse,
|
||||
mStreamCleanupList, aRv);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
SchemeAction aSchemeAction, ErrorResult& aRv);
|
||||
void Add(InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
void Add(JSContext* aCx, InternalRequest* aRequest, BodyAction aBodyAction,
|
||||
SchemeAction aSchemeAction, Response& aResponse, ErrorResult& aRv);
|
||||
|
||||
const CacheOpArgs& SendAsOpArgs();
|
||||
|
|
|
@ -202,7 +202,10 @@ public:
|
|||
|
||||
// Now store the unwrapped Response list in the Cache.
|
||||
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())) {
|
||||
// TODO: abort the fetch requests we have running (bug 1157434)
|
||||
mPromise->MaybeReject(result);
|
||||
|
@ -263,7 +266,7 @@ Cache::Cache(nsIGlobalObject* aGlobal, CacheChild* aActor)
|
|||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::Match(const RequestOrUSVString& aRequest,
|
||||
Cache::Match(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
|
@ -273,7 +276,8 @@ Cache::Match(const RequestOrUSVString& aRequest,
|
|||
|
||||
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())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -292,7 +296,7 @@ Cache::Match(const RequestOrUSVString& aRequest,
|
|||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
Cache::MatchAll(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
|
@ -308,8 +312,8 @@ Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
|||
AutoChildOpArgs args(this, CacheMatchAllArgs(void_t(), params), 1);
|
||||
|
||||
if (aRequest.WasPassed()) {
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
|
||||
IgnoreBody, aRv);
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aCx, aRequest.Value(),
|
||||
IgnoreBody, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -409,8 +413,8 @@ Cache::AddAll(JSContext* aContext,
|
|||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
ErrorResult& aRv)
|
||||
Cache::Put(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
Response& aResponse, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
|
@ -427,14 +431,14 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aCx, aRequest, ReadBody, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AutoChildOpArgs args(this, CachePutAllArgs(), 1);
|
||||
|
||||
args.Add(ir, ReadBody, TypeErrorOnInvalidScheme,
|
||||
args.Add(aCx, ir, ReadBody, TypeErrorOnInvalidScheme,
|
||||
aResponse, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
|
@ -444,7 +448,7 @@ Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
|||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::Delete(const RequestOrUSVString& aRequest,
|
||||
Cache::Delete(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
|
@ -454,7 +458,8 @@ Cache::Delete(const RequestOrUSVString& aRequest,
|
|||
|
||||
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())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -473,7 +478,7 @@ Cache::Delete(const RequestOrUSVString& aRequest,
|
|||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||
Cache::Keys(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
if (NS_WARN_IF(!mActor)) {
|
||||
|
@ -489,8 +494,8 @@ Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
|
|||
AutoChildOpArgs args(this, CacheKeysArgs(void_t(), params), 1);
|
||||
|
||||
if (aRequest.WasPassed()) {
|
||||
RefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
|
||||
IgnoreBody, aRv);
|
||||
RefPtr<InternalRequest> ir =
|
||||
ToInternalRequest(aCx, aRequest.Value(), IgnoreBody, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -651,7 +656,7 @@ Cache::AddAll(const GlobalObject& aGlobal,
|
|||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Cache::PutAll(const nsTArray<RefPtr<Request>>& aRequestList,
|
||||
Cache::PutAll(JSContext* aCx, const nsTArray<RefPtr<Request>>& aRequestList,
|
||||
const nsTArray<RefPtr<Response>>& aResponseList,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
|
@ -668,7 +673,8 @@ Cache::PutAll(const nsTArray<RefPtr<Request>>& aRequestList,
|
|||
|
||||
for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
|
||||
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())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -45,10 +45,10 @@ public:
|
|||
|
||||
// webidl interface methods
|
||||
already_AddRefed<Promise>
|
||||
Match(const RequestOrUSVString& aRequest, const CacheQueryOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
Match(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
MatchAll(const Optional<RequestOrUSVString>& aRequest,
|
||||
MatchAll(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Add(JSContext* aContext, const RequestOrUSVString& aRequest,
|
||||
|
@ -58,13 +58,13 @@ public:
|
|||
const Sequence<OwningRequestOrUSVString>& aRequests,
|
||||
CallerType aCallerType, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Put(const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
Put(JSContext* aCx, const RequestOrUSVString& aRequest, Response& aResponse,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Delete(const RequestOrUSVString& aRequest, const CacheQueryOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
Delete(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Keys(const Optional<RequestOrUSVString>& aRequest,
|
||||
Keys(JSContext* aCx, const Optional<RequestOrUSVString>& aRequest,
|
||||
const CacheQueryOptions& aParams, ErrorResult& aRv);
|
||||
|
||||
// binding methods
|
||||
|
@ -103,7 +103,7 @@ private:
|
|||
CallerType aCallerType, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
PutAll(const nsTArray<RefPtr<Request>>& aRequestList,
|
||||
PutAll(JSContext* aCx, const nsTArray<RefPtr<Request>>& aRequestList,
|
||||
const nsTArray<RefPtr<Response>>& aResponseList,
|
||||
ErrorResult& aRv);
|
||||
|
||||
|
|
|
@ -307,7 +307,7 @@ CacheStorage::CacheStorage(nsresult aFailureResult)
|
|||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
CacheStorage::Match(const RequestOrUSVString& aRequest,
|
||||
CacheStorage::Match(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(CacheStorage);
|
||||
|
@ -317,8 +317,8 @@ CacheStorage::Match(const RequestOrUSVString& aRequest,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<InternalRequest> request = ToInternalRequest(aRequest, IgnoreBody,
|
||||
aRv);
|
||||
RefPtr<InternalRequest> request =
|
||||
ToInternalRequest(aCx, aRequest, IgnoreBody, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -60,9 +60,9 @@ public:
|
|||
DefineCaches(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
|
||||
|
||||
// webidl interface methods
|
||||
already_AddRefed<Promise> Match(const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions,
|
||||
ErrorResult& aRv);
|
||||
already_AddRefed<Promise>
|
||||
Match(JSContext* aCx, const RequestOrUSVString& aRequest,
|
||||
const CacheQueryOptions& aOptions, ErrorResult& aRv);
|
||||
already_AddRefed<Promise> Has(const nsAString& aKey, ErrorResult& aRv);
|
||||
already_AddRefed<Promise> Open(const nsAString& aKey, ErrorResult& aRv);
|
||||
already_AddRefed<Promise> Delete(const nsAString& aKey, ErrorResult& aRv);
|
||||
|
|
|
@ -78,7 +78,7 @@ ToHeadersEntryList(nsTArray<HeadersEntry>& aOut, InternalHeaders* aHeaders)
|
|||
} // namespace
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
|
||||
TypeUtils::ToInternalRequest(JSContext* aCx, const RequestOrUSVString& aIn,
|
||||
BodyAction aBodyAction, ErrorResult& aRv)
|
||||
{
|
||||
if (aIn.IsRequest()) {
|
||||
|
@ -86,7 +86,7 @@ TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
|
|||
|
||||
// Check and set bodyUsed flag immediately because its on Request
|
||||
// instead of InternalRequest.
|
||||
CheckAndSetBodyUsed(&request, aBodyAction, aRv);
|
||||
CheckAndSetBodyUsed(aCx, &request, aBodyAction, aRv);
|
||||
if (aRv.Failed()) { return nullptr; }
|
||||
|
||||
return request.GetInternalRequest();
|
||||
|
@ -96,7 +96,8 @@ TypeUtils::ToInternalRequest(const RequestOrUSVString& aIn,
|
|||
}
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn,
|
||||
TypeUtils::ToInternalRequest(JSContext* aCx,
|
||||
const OwningRequestOrUSVString& aIn,
|
||||
BodyAction aBodyAction, ErrorResult& aRv)
|
||||
{
|
||||
|
||||
|
@ -105,7 +106,7 @@ TypeUtils::ToInternalRequest(const OwningRequestOrUSVString& aIn,
|
|||
|
||||
// Check and set bodyUsed flag immediately because its on Request
|
||||
// instead of InternalRequest.
|
||||
CheckAndSetBodyUsed(request, aBodyAction, aRv);
|
||||
CheckAndSetBodyUsed(aCx, request, aBodyAction, aRv);
|
||||
if (aRv.Failed()) { return nullptr; }
|
||||
|
||||
return request->GetInternalRequest();
|
||||
|
@ -203,7 +204,7 @@ TypeUtils::ToCacheResponseWithoutBody(CacheResponse& aOut,
|
|||
}
|
||||
|
||||
void
|
||||
TypeUtils::ToCacheResponse(CacheResponse& aOut, Response& aIn,
|
||||
TypeUtils::ToCacheResponse(JSContext* aCx, CacheResponse& aOut, Response& aIn,
|
||||
nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
|
@ -221,7 +222,10 @@ TypeUtils::ToCacheResponse(CacheResponse& aOut, Response& aIn,
|
|||
nsCOMPtr<nsIInputStream> stream;
|
||||
ir->GetUnfilteredBody(getter_AddRefs(stream));
|
||||
if (stream) {
|
||||
aIn.SetBodyUsed();
|
||||
aIn.SetBodyUsed(aCx, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SerializeCacheStream(stream, &aOut.body(), aStreamCleanupList, aRv);
|
||||
|
@ -425,8 +429,8 @@ TypeUtils::ProcessURL(nsACString& aUrl, bool* aSchemeValidOut,
|
|||
}
|
||||
|
||||
void
|
||||
TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
||||
ErrorResult& aRv)
|
||||
TypeUtils::CheckAndSetBodyUsed(JSContext* aCx, Request* aRequest,
|
||||
BodyAction aBodyAction, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(aRequest);
|
||||
|
||||
|
@ -442,7 +446,10 @@ TypeUtils::CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
|||
nsCOMPtr<nsIInputStream> stream;
|
||||
aRequest->GetBody(getter_AddRefs(stream));
|
||||
if (stream) {
|
||||
aRequest->SetBodyUsed();
|
||||
aRequest->SetBodyUsed(aCx, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,12 +73,12 @@ public:
|
|||
GetIPCManager() = 0;
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
ToInternalRequest(const RequestOrUSVString& aIn, BodyAction aBodyAction,
|
||||
ErrorResult& aRv);
|
||||
ToInternalRequest(JSContext* aCx, const RequestOrUSVString& aIn,
|
||||
BodyAction aBodyAction, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
ToInternalRequest(const OwningRequestOrUSVString& aIn, BodyAction aBodyAction,
|
||||
ErrorResult& aRv);
|
||||
ToInternalRequest(JSContext* aCx, const OwningRequestOrUSVString& aIn,
|
||||
BodyAction aBodyAction, ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToCacheRequest(CacheRequest& aOut, InternalRequest* aIn,
|
||||
|
@ -91,7 +91,7 @@ public:
|
|||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
ToCacheResponse(CacheResponse& aOut, Response& aIn,
|
||||
ToCacheResponse(JSContext* aCx, CacheResponse& aOut, Response& aIn,
|
||||
nsTArray<UniquePtr<mozilla::ipc::AutoIPCStream>>& aStreamCleanupList,
|
||||
ErrorResult& aRv);
|
||||
|
||||
|
@ -133,7 +133,7 @@ public:
|
|||
|
||||
private:
|
||||
void
|
||||
CheckAndSetBodyUsed(Request* aRequest, BodyAction aBodyAction,
|
||||
CheckAndSetBodyUsed(JSContext* aCx, Request* aRequest, BodyAction aBodyAction,
|
||||
ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<InternalRequest>
|
||||
|
|
|
@ -970,16 +970,17 @@ bool
|
|||
FetchBody<Response>::BodyUsed() const;
|
||||
|
||||
template <class Derived>
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType,
|
||||
ErrorResult& aRv)
|
||||
void
|
||||
FetchBody<Derived>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv)
|
||||
{
|
||||
if (BodyUsed()) {
|
||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||
return nullptr;
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(mOwner->EventTargetFor(TaskCategory::Other)->IsOnCurrentThread());
|
||||
|
||||
if (mBodyUsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetBodyUsed();
|
||||
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.
|
||||
|
@ -989,7 +990,7 @@ FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType,
|
|||
JS::ReadableStreamMode::ExternalSource) {
|
||||
LockStream(aCx, readableStreamObj, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// If this is not a native ReadableStream, let's activate the
|
||||
|
@ -998,12 +999,36 @@ FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType,
|
|||
JS::Rooted<JSObject*> reader(aCx);
|
||||
mFetchStreamReader->StartConsuming(aCx, readableStreamObj, &reader, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mReadableStreamReader = reader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Request>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
|
||||
|
||||
template
|
||||
void
|
||||
FetchBody<Response>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
|
||||
|
||||
template <class Derived>
|
||||
already_AddRefed<Promise>
|
||||
FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (BodyUsed()) {
|
||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SetBodyUsed(aCx, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();
|
||||
|
||||
|
|
|
@ -192,11 +192,28 @@ public:
|
|||
|
||||
// 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
|
||||
SetBodyUsed()
|
||||
{
|
||||
mBodyUsed = true;
|
||||
}
|
||||
SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
|
||||
|
||||
const nsCString&
|
||||
MimeType() const
|
||||
|
|
|
@ -606,7 +606,10 @@ Request::Constructor(const GlobalObject& aGlobal,
|
|||
inputReq->GetBody(getter_AddRefs(body));
|
||||
if (body) {
|
||||
inputReq->SetBody(nullptr);
|
||||
inputReq->SetBodyUsed();
|
||||
inputReq->SetBodyUsed(aGlobal.Context(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return domRequest.forget();
|
||||
|
|
|
@ -87,7 +87,13 @@ FlyWebFetchEvent::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
|||
if (response && response->Type() != ResponseType::Opaque) {
|
||||
intResponse = response->GetInternalResponse();
|
||||
|
||||
response->SetBodyUsed();
|
||||
IgnoredErrorResult rv;
|
||||
response->SetBodyUsed(aCx, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
// Let's nullify the response. In this way we end up using a NetworkError
|
||||
// response.
|
||||
intResponse = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!intResponse) {
|
||||
|
|
|
@ -80,6 +80,63 @@ function test_pendingStream() {
|
|||
});
|
||||
}
|
||||
|
||||
async function test_nativeStream_cache() {
|
||||
info("test_nativeStream_cache");
|
||||
|
||||
let origBody = '123456789abcdef';
|
||||
let url = '/nativeStream';
|
||||
|
||||
let cache = await caches.open('nativeStream');
|
||||
|
||||
info("Storing a body as a string");
|
||||
await cache.put(url, new Response(origBody));
|
||||
|
||||
info("Retrieving the stored value");
|
||||
let cacheResponse = await cache.match(url);
|
||||
|
||||
info("Converting the response to text");
|
||||
let cacheBody = await cacheResponse.text();
|
||||
|
||||
is(origBody, cacheBody, "Bodies match");
|
||||
|
||||
await caches.delete('nativeStream');
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
async function test_nonNativeStream_cache() {
|
||||
info("test_nonNativeStream_cache");
|
||||
|
||||
let url = '/nonNativeStream';
|
||||
|
||||
let cache = await caches.open('nonNativeStream');
|
||||
|
||||
info("Storing a body as a string");
|
||||
let r = new Response(new ReadableStream({start : controller => {
|
||||
controller.enqueue(new Uint8Array([0x01, 0x02, 0x03]));
|
||||
controller.close();
|
||||
}}));
|
||||
|
||||
await cache.put(url, r);
|
||||
|
||||
info("Retrieving the stored value");
|
||||
let cacheResponse = await cache.match(url);
|
||||
|
||||
info("Converting the response to text");
|
||||
let cacheBody = await cacheResponse.arrayBuffer();
|
||||
|
||||
ok(cacheBody instanceof ArrayBuffer, "Body is an array buffer");
|
||||
is(cacheBody.byteLength, 3, "Body length is correct");
|
||||
|
||||
is(new Uint8Array(cacheBody)[0], 0x01, "First byte is correct");
|
||||
is(new Uint8Array(cacheBody)[1], 0x02, "Second byte is correct");
|
||||
is(new Uint8Array(cacheBody)[2], 0x03, "Third byte is correct");
|
||||
|
||||
await caches.delete('nonNativeStream');
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
function workify(func) {
|
||||
info("Workifing " + func);
|
||||
|
||||
|
|
|
@ -11,16 +11,31 @@
|
|||
<script type="application/javascript">
|
||||
|
||||
let tests = [
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [["dom.caches.enabled", true],
|
||||
["dom.caches.testing.enabled", true],
|
||||
["dom.quotaManager.testing", true]]
|
||||
}, next);
|
||||
},
|
||||
|
||||
test_nativeStream,
|
||||
function() { workify('test_nativeStream'); },
|
||||
|
||||
test_nonNativeStream,
|
||||
function() { workify('test_nonNativeStream'); },
|
||||
|
||||
test_pendingStream,
|
||||
function() { workify('test_pendingStream'); },
|
||||
|
||||
test_noUint8Array,
|
||||
function() { workify('test_noUint8Array'); },
|
||||
|
||||
test_nativeStream_cache,
|
||||
function() { workify('test_nativeStream_cache'); },
|
||||
|
||||
test_nonNativeStream_cache,
|
||||
function() { workify('test_nonNativeStream_cache'); },
|
||||
];
|
||||
|
||||
function next() {
|
||||
|
|
|
@ -8,6 +8,10 @@ function ok(a, message) {
|
|||
postMessage({type: 'test', test: !!a, message });
|
||||
}
|
||||
|
||||
function is(a, b, message) {
|
||||
ok(a === b, message);
|
||||
}
|
||||
|
||||
function next() {
|
||||
postMessage({type: 'done'});
|
||||
}
|
||||
|
|
|
@ -726,9 +726,14 @@ private:
|
|||
request.SetAsUSVString().Rebind(loadInfo.mFullURL.Data(),
|
||||
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;
|
||||
RefPtr<Promise> cachePromise =
|
||||
mCacheCreator->Cache_()->Put(request, *response, error);
|
||||
mCacheCreator->Cache_()->Put(jsapi.cx(), request, *response, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
nsresult rv = error.StealNSResult();
|
||||
channel->Cancel(rv);
|
||||
|
@ -1619,8 +1624,13 @@ CacheScriptLoader::Load(Cache* aCache)
|
|||
|
||||
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;
|
||||
RefPtr<Promise> promise = aCache->Match(request, params, error);
|
||||
RefPtr<Promise> promise = aCache->Match(jsapi.cx(), request, params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
Fail(error.StealNSResult());
|
||||
return;
|
||||
|
|
|
@ -515,6 +515,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>
|
||||
void SetCancelMessage(const nsACString& aMessageName, Params&&... aParams)
|
||||
{
|
||||
|
@ -670,7 +708,12 @@ RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValu
|
|||
ir->GetUnfilteredBody(getter_AddRefs(body));
|
||||
// Errors and redirects may not have a 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;
|
||||
rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody));
|
||||
|
|
|
@ -423,8 +423,10 @@ private:
|
|||
Optional<RequestOrUSVString> request;
|
||||
CacheQueryOptions options;
|
||||
ErrorResult error;
|
||||
RefPtr<Promise> promise = mOldCache->Keys(request, options, error);
|
||||
RefPtr<Promise> promise = mOldCache->Keys(aCx, request, options, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
// No exception here because there are no ReadableStreams involved here.
|
||||
MOZ_ASSERT(!error.IsJSException());
|
||||
rv = error.StealNSResult();
|
||||
return;
|
||||
}
|
||||
|
@ -521,7 +523,7 @@ private:
|
|||
MOZ_ASSERT(mPendingCount == 0);
|
||||
for (uint32_t i = 0; i < mCNList.Length(); ++i) {
|
||||
// We bail out immediately when something goes wrong.
|
||||
rv = WriteToCache(cache, mCNList[i]);
|
||||
rv = WriteToCache(aCx, cache, mCNList[i]);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
@ -559,7 +561,7 @@ private:
|
|||
}
|
||||
|
||||
nsresult
|
||||
WriteToCache(Cache* aCache, CompareNetwork* aCN)
|
||||
WriteToCache(JSContext* aCx, Cache* aCache, CompareNetwork* aCN)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aCache);
|
||||
|
@ -602,8 +604,10 @@ private:
|
|||
// 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
|
||||
// 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())) {
|
||||
// No exception here because there are no ReadableStreams involved here.
|
||||
MOZ_ASSERT(!result.IsJSException());
|
||||
MOZ_ASSERT(!result.IsErrorWithMessage());
|
||||
return result.StealNSResult();
|
||||
}
|
||||
|
@ -1003,12 +1007,19 @@ CompareCache::Initialize(Cache* const aCache, const nsAString& aURL)
|
|||
MOZ_ASSERT(aCache);
|
||||
MOZ_DIAGNOSTIC_ASSERT(mState == WaitingForInitialization);
|
||||
|
||||
// This JSContext will not end up executing JS code because here there are
|
||||
// no ReadableStreams involved.
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
|
||||
RequestOrUSVString request;
|
||||
request.SetAsUSVString().Rebind(aURL.Data(), aURL.Length());
|
||||
ErrorResult error;
|
||||
CacheQueryOptions params;
|
||||
RefPtr<Promise> promise = aCache->Match(request, params, error);
|
||||
RefPtr<Promise> promise = aCache->Match(jsapi.cx(), request, params, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
// No exception here because there are no ReadableStreams involved here.
|
||||
MOZ_ASSERT(!error.IsJSException());
|
||||
mState = Finished;
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
|
|
@ -127,6 +127,36 @@ fetchXHR('http://user:pass@mochi.test:8888/user-pass', function(xhr) {
|
|||
finish();
|
||||
});
|
||||
|
||||
fetchXHR('readable-stream.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "loading completed");
|
||||
my_ok(xhr.responseText == 'Hello!', "The message is correct!");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetchXHR('readable-stream-locked.txt', function(xhr) {
|
||||
my_ok(false, "This should not be called!");
|
||||
finish();
|
||||
}, function() {
|
||||
my_ok(true, "The exception has been correctly handled!");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetchXHR('readable-stream-with-exception.txt', function(xhr) {
|
||||
my_ok(false, "This should not be called!");
|
||||
finish();
|
||||
}, function() {
|
||||
my_ok(true, "The exception has been correctly handled!");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetchXHR('readable-stream-already-consumed.txt', function(xhr) {
|
||||
my_ok(false, "This should not be called!");
|
||||
finish();
|
||||
}, function() {
|
||||
my_ok(true, "The exception has been correctly handled!");
|
||||
finish();
|
||||
});
|
||||
|
||||
var expectedUncompressedResponse = "";
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
expectedUncompressedResponse += "hello";
|
||||
|
|
|
@ -99,6 +99,58 @@ onfetch = function(ev) {
|
|||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("readable-stream.txt")) {
|
||||
ev.respondWith(
|
||||
new Response(
|
||||
new ReadableStream({
|
||||
start: function(controller) {
|
||||
controller.enqueue(new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21]));
|
||||
controller.close();
|
||||
}
|
||||
})
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("readable-stream-locked.txt")) {
|
||||
let stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21]));
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
|
||||
ev.respondWith(new Response(stream));
|
||||
|
||||
// This locks the stream.
|
||||
stream.getReader();
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("readable-stream-with-exception.txt")) {
|
||||
ev.respondWith(
|
||||
new Response(
|
||||
new ReadableStream({
|
||||
start(controller) {},
|
||||
pull() {
|
||||
throw "EXCEPTION!";
|
||||
}
|
||||
})
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes("readable-stream-already-consumed.txt")) {
|
||||
let r = new Response(
|
||||
new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21]));
|
||||
controller.close();
|
||||
}
|
||||
}));
|
||||
|
||||
r.blob();
|
||||
|
||||
ev.respondWith(r);
|
||||
}
|
||||
|
||||
else if (ev.request.url.includes('user-pass')) {
|
||||
ev.respondWith(new Response(ev.request.url));
|
||||
}
|
||||
|
|
|
@ -74,6 +74,8 @@
|
|||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["javascript.options.streams", true],
|
||||
["dom.streams.enabled", true],
|
||||
]}, runTest);
|
||||
</script>
|
||||
</pre>
|
||||
|
|
Загрузка…
Ссылка в новой задаче