mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-27 01:27:30 +09:00
Issue #1442 - Part 11 - Response.body handling. https://bugzilla.mozilla.org/show_bug.cgi?id=1329298 Use BufferSource in webIDL. https://bugzilla.mozilla.org/show_bug.cgi?id=1337722
This commit is contained in:
parent
772ab8ac41
commit
a8a75090c0
14 changed files with 413 additions and 72 deletions
|
|
@ -860,7 +860,7 @@ BeaconStreamListener::OnDataAvailable(nsIRequest *aRequest,
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Navigator::SendBeacon(const nsAString& aUrl,
|
Navigator::SendBeacon(const nsAString& aUrl,
|
||||||
const Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aData,
|
const Nullable<fetch::BodyInit>& aData,
|
||||||
ErrorResult& aRv)
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
if (aData.IsNull()) {
|
if (aData.IsNull()) {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#define mozilla_dom_Navigator_h
|
#define mozilla_dom_Navigator_h
|
||||||
|
|
||||||
#include "mozilla/MemoryReporting.h"
|
#include "mozilla/MemoryReporting.h"
|
||||||
|
#include "mozilla/dom/Fetch.h"
|
||||||
#include "mozilla/dom/Nullable.h"
|
#include "mozilla/dom/Nullable.h"
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "nsIDOMNavigator.h"
|
#include "nsIDOMNavigator.h"
|
||||||
|
|
@ -197,7 +198,7 @@ public:
|
||||||
#endif // MOZ_AUDIO_CHANNEL_MANAGER
|
#endif // MOZ_AUDIO_CHANNEL_MANAGER
|
||||||
|
|
||||||
bool SendBeacon(const nsAString& aUrl,
|
bool SendBeacon(const nsAString& aUrl,
|
||||||
const Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& aData,
|
const Nullable<fetch::BodyInit>& aData,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
void MozGetUserMedia(const MediaStreamConstraints& aConstraints,
|
void MozGetUserMedia(const MediaStreamConstraints& aConstraints,
|
||||||
|
|
|
||||||
|
|
@ -747,7 +747,8 @@ DOMInterfaces = {
|
||||||
|
|
||||||
'Response': {
|
'Response': {
|
||||||
'binaryNames': { 'headers': 'headers_' },
|
'binaryNames': { 'headers': 'headers_' },
|
||||||
'implicitJSContext': [ 'arrayBuffer', 'blob', 'formData', 'json', 'text' ],
|
'implicitJSContext': [ 'arrayBuffer', 'blob', 'formData', 'json', 'text',
|
||||||
|
'clone', 'cloneUnfiltered' ],
|
||||||
},
|
},
|
||||||
|
|
||||||
'RGBColor': {
|
'RGBColor': {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsIDOMDocument.h"
|
#include "nsIDOMDocument.h"
|
||||||
#include "nsIDOMSerializer.h"
|
#include "nsIDOMSerializer.h"
|
||||||
|
#include "nsIGlobalObject.h"
|
||||||
#include "nsIInputStream.h"
|
#include "nsIInputStream.h"
|
||||||
#include "nsIOutputStream.h"
|
#include "nsIOutputStream.h"
|
||||||
#include "nsIStorageStream.h"
|
#include "nsIStorageStream.h"
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@
|
||||||
#ifndef mozilla_dom_BodyExtractor_h
|
#ifndef mozilla_dom_BodyExtractor_h
|
||||||
#define mozilla_dom_BodyExtractor_h
|
#define mozilla_dom_BodyExtractor_h
|
||||||
|
|
||||||
|
#include "jsapi.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
|
|
||||||
class nsIInputStream;
|
class nsIInputStream;
|
||||||
|
class nsIGlobalObject;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
@ -25,7 +27,7 @@ public:
|
||||||
|
|
||||||
// The implementation versions of this template are:
|
// The implementation versions of this template are:
|
||||||
// ArrayBuffer, ArrayBufferView, nsIXHRSendable (Blob, FormData,
|
// ArrayBuffer, ArrayBufferView, nsIXHRSendable (Blob, FormData,
|
||||||
// URLSearchParams), nsAString, nsIDocument, nsIInputStream
|
// URLSearchParams), nsAString, nsIDocument, nsIInputStream.
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
class BodyExtractor final : public BodyExtractorBase
|
class BodyExtractor final : public BodyExtractorBase
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -725,7 +725,7 @@ WorkerFetchResolver::FlushConsoleReport()
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
|
||||||
nsIInputStream** aStream,
|
nsIInputStream** aStream,
|
||||||
nsCString& aContentTypeWithCharset,
|
nsCString& aContentTypeWithCharset,
|
||||||
uint64_t& aContentLength)
|
uint64_t& aContentLength)
|
||||||
|
|
@ -773,7 +773,7 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDa
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
|
||||||
nsIInputStream** aStream,
|
nsIInputStream** aStream,
|
||||||
nsCString& aContentTypeWithCharset,
|
nsCString& aContentTypeWithCharset,
|
||||||
uint64_t& aContentLength)
|
uint64_t& aContentLength)
|
||||||
|
|
@ -819,6 +819,63 @@ ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUS
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
|
||||||
|
nsIInputStream** aStream,
|
||||||
|
nsCString& aContentTypeWithCharset,
|
||||||
|
uint64_t& aContentLength)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aStream);
|
||||||
|
MOZ_ASSERT(!*aStream);
|
||||||
|
|
||||||
|
// ReadableStreams should be handled by
|
||||||
|
// BodyExtractorReadableStream::GetAsStream.
|
||||||
|
MOZ_ASSERT(!aBodyInit.IsReadableStream());
|
||||||
|
|
||||||
|
nsAutoCString charset;
|
||||||
|
aContentTypeWithCharset.SetIsVoid(true);
|
||||||
|
|
||||||
|
if (aBodyInit.IsArrayBuffer()) {
|
||||||
|
BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
|
||||||
|
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||||
|
charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aBodyInit.IsArrayBufferView()) {
|
||||||
|
BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
|
||||||
|
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||||
|
charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aBodyInit.IsBlob()) {
|
||||||
|
BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsBlob());
|
||||||
|
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||||
|
charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aBodyInit.IsFormData()) {
|
||||||
|
BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsFormData());
|
||||||
|
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||||
|
charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aBodyInit.IsUSVString()) {
|
||||||
|
BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
|
||||||
|
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||||
|
charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aBodyInit.IsURLSearchParams()) {
|
||||||
|
BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsURLSearchParams());
|
||||||
|
return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
|
||||||
|
charset);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_NOTREACHED("Should never reach here");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
FetchBody<Derived>::FetchBody()
|
FetchBody<Derived>::FetchBody()
|
||||||
: mWorkerPrivate(nullptr)
|
: mWorkerPrivate(nullptr)
|
||||||
|
|
@ -862,7 +919,8 @@ FetchBody<Derived>::BodyUsed() const
|
||||||
|
|
||||||
JS::Rooted<JSObject*> body(cx, mReadableStreamBody);
|
JS::Rooted<JSObject*> body(cx, mReadableStreamBody);
|
||||||
if (JS::ReadableStreamIsDisturbed(body) ||
|
if (JS::ReadableStreamIsDisturbed(body) ||
|
||||||
JS::ReadableStreamIsLocked(body)) {
|
JS::ReadableStreamIsLocked(body) ||
|
||||||
|
!JS::ReadableStreamIsReadable(body)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -895,14 +953,18 @@ FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorRes
|
||||||
|
|
||||||
SetBodyUsed();
|
SetBodyUsed();
|
||||||
|
|
||||||
nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();
|
// If we already created a ReadableStreamBody we have to lock it now because
|
||||||
|
// it may have been shared with other objects..
|
||||||
// If we already created a ReadableStreamBody we have to close it now.
|
|
||||||
if (mReadableStreamBody) {
|
if (mReadableStreamBody) {
|
||||||
JS::Rooted<JSObject*> body(aCx, mReadableStreamBody);
|
JS::Rooted<JSObject*> body(aCx, mReadableStreamBody);
|
||||||
JS::ReadableStreamClose(aCx, body);
|
LockStream(aCx, body, aRv);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();
|
||||||
|
|
||||||
RefPtr<Promise> promise =
|
RefPtr<Promise> promise =
|
||||||
FetchBodyConsumer<Derived>::Create(global, this, signal, aType, aRv);
|
FetchBodyConsumer<Derived>::Create(global, this, signal, aType, aRv);
|
||||||
if (NS_WARN_IF(aRv.Failed())) {
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
|
@ -948,6 +1010,23 @@ template
|
||||||
void
|
void
|
||||||
FetchBody<Response>::SetMimeType();
|
FetchBody<Response>::SetMimeType();
|
||||||
|
|
||||||
|
template <class Derived>
|
||||||
|
void
|
||||||
|
FetchBody<Derived>::SetReadableStreamBody(JSObject* aBody)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(!mReadableStreamBody);
|
||||||
|
MOZ_ASSERT(aBody);
|
||||||
|
mReadableStreamBody = aBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
void
|
||||||
|
FetchBody<Request>::SetReadableStreamBody(JSObject* aBody);
|
||||||
|
|
||||||
|
template
|
||||||
|
void
|
||||||
|
FetchBody<Response>::SetReadableStreamBody(JSObject* aBody);
|
||||||
|
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
void
|
void
|
||||||
FetchBody<Derived>::GetBody(JSContext* aCx,
|
FetchBody<Derived>::GetBody(JSContext* aCx,
|
||||||
|
|
@ -965,6 +1044,7 @@ FetchBody<Derived>::GetBody(JSContext* aCx,
|
||||||
if (!mReadableStreamBody) {
|
if (!mReadableStreamBody) {
|
||||||
JS::Rooted<JSObject*> body(aCx,
|
JS::Rooted<JSObject*> body(aCx,
|
||||||
FetchStream::Create(aCx,
|
FetchStream::Create(aCx,
|
||||||
|
this,
|
||||||
DerivedClass()->GetParentObject(),
|
DerivedClass()->GetParentObject(),
|
||||||
inputStream,
|
inputStream,
|
||||||
aRv));
|
aRv));
|
||||||
|
|
@ -975,9 +1055,11 @@ FetchBody<Derived>::GetBody(JSContext* aCx,
|
||||||
MOZ_ASSERT(body);
|
MOZ_ASSERT(body);
|
||||||
|
|
||||||
// If the body has been already consumed, we close the stream.
|
// If the body has been already consumed, we close the stream.
|
||||||
if (BodyUsed() && !JS::ReadableStreamClose(aCx, body)) {
|
if (BodyUsed()) {
|
||||||
aRv.StealExceptionFromJSContext(aCx);
|
LockStream(aCx, body, aRv);
|
||||||
return;
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mReadableStreamBody = body;
|
mReadableStreamBody = body;
|
||||||
|
|
@ -998,6 +1080,72 @@ FetchBody<Response>::GetBody(JSContext* aCx,
|
||||||
JS::MutableHandle<JSObject*> aMessage,
|
JS::MutableHandle<JSObject*> aMessage,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
template <class Derived>
|
||||||
|
void
|
||||||
|
FetchBody<Derived>::LockStream(JSContext* aCx,
|
||||||
|
JS::HandleObject aStream,
|
||||||
|
ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
// XXXMC: TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
void
|
||||||
|
FetchBody<Request>::LockStream(JSContext* aCx,
|
||||||
|
JS::HandleObject aStream,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
template
|
||||||
|
void
|
||||||
|
FetchBody<Response>::LockStream(JSContext* aCx,
|
||||||
|
JS::HandleObject aStream,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
template <class Derived>
|
||||||
|
void
|
||||||
|
FetchBody<Derived>::MaybeTeeReadableStreamBody(JSContext* aCx,
|
||||||
|
JS::MutableHandle<JSObject*> aBodyOut,
|
||||||
|
ErrorResult& aRv)
|
||||||
|
{
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(!BodyUsed());
|
||||||
|
|
||||||
|
if (!mReadableStreamBody) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> stream(aCx, mReadableStreamBody);
|
||||||
|
|
||||||
|
// If this is a ReadableStream with an external source, this has been
|
||||||
|
// generated by a Fetch. In this case, Fetch will be able to recreate it
|
||||||
|
// again when GetBody() is called.
|
||||||
|
if (JS::ReadableStreamGetMode(stream) == JS::ReadableStreamMode::ExternalSource) {
|
||||||
|
aBodyOut.set(nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> branch1(aCx);
|
||||||
|
JS::Rooted<JSObject*> branch2(aCx);
|
||||||
|
|
||||||
|
if (!JS::ReadableStreamTee(aCx, stream, &branch1, &branch2)) {
|
||||||
|
aRv.StealExceptionFromJSContext(aCx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mReadableStreamBody = branch1;
|
||||||
|
aBodyOut.set(branch2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template
|
||||||
|
void
|
||||||
|
FetchBody<Request>::MaybeTeeReadableStreamBody(JSContext* aCx,
|
||||||
|
JS::MutableHandle<JSObject*> aMessage,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
template
|
||||||
|
void
|
||||||
|
FetchBody<Response>::MaybeTeeReadableStreamBody(JSContext* aCx,
|
||||||
|
JS::MutableHandle<JSObject*> aMessage,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,12 @@ class nsIGlobalObject;
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
|
|
||||||
class ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
|
class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
|
||||||
|
class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString;
|
||||||
class BlobImpl;
|
class BlobImpl;
|
||||||
class InternalRequest;
|
class InternalRequest;
|
||||||
class OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams;
|
class OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
|
||||||
|
struct ReadableStream;
|
||||||
class RequestOrUSVString;
|
class RequestOrUSVString;
|
||||||
|
|
||||||
namespace workers {
|
namespace workers {
|
||||||
|
|
@ -41,13 +43,20 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
||||||
nsresult
|
nsresult
|
||||||
UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest);
|
UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest);
|
||||||
|
|
||||||
|
/* Deal with unwieldy long webIDL-generated type names */
|
||||||
|
namespace fetch {
|
||||||
|
typedef BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString BodyInit;
|
||||||
|
typedef BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString ResponseBodyInit;
|
||||||
|
typedef OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString OwningBodyInit;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates an nsIInputStream based on the fetch specifications 'extract a byte
|
* Creates an nsIInputStream based on the fetch specifications 'extract a byte
|
||||||
* stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
|
* stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
|
||||||
* Stores content type in out param aContentType.
|
* Stores content type in out param aContentType.
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
|
||||||
nsIInputStream** aStream,
|
nsIInputStream** aStream,
|
||||||
nsCString& aContentType,
|
nsCString& aContentType,
|
||||||
uint64_t& aContentLength);
|
uint64_t& aContentLength);
|
||||||
|
|
@ -56,7 +65,17 @@ ExtractByteStreamFromBody(const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDa
|
||||||
* Non-owning version.
|
* Non-owning version.
|
||||||
*/
|
*/
|
||||||
nsresult
|
nsresult
|
||||||
ExtractByteStreamFromBody(const ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& aBodyInit,
|
ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
|
||||||
|
nsIInputStream** aStream,
|
||||||
|
nsCString& aContentType,
|
||||||
|
uint64_t& aContentLength);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Non-owning version. This method should go away when BodyInit will contain
|
||||||
|
* ReadableStream.
|
||||||
|
*/
|
||||||
|
nsresult
|
||||||
|
ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
|
||||||
nsIInputStream** aStream,
|
nsIInputStream** aStream,
|
||||||
nsCString& aContentType,
|
nsCString& aContentType,
|
||||||
uint64_t& aContentLength);
|
uint64_t& aContentLength);
|
||||||
|
|
@ -72,6 +91,15 @@ enum FetchConsumeType
|
||||||
CONSUME_TEXT,
|
CONSUME_TEXT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FetchStreamHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
||||||
|
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
||||||
|
|
||||||
|
virtual void NullifyStream() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FetchBody's body consumption uses nsIInputStreamPump to read from the
|
* FetchBody's body consumption uses nsIInputStreamPump to read from the
|
||||||
* underlying stream to a block of memory, which is then adopted by
|
* underlying stream to a block of memory, which is then adopted by
|
||||||
|
|
@ -106,14 +134,11 @@ enum FetchConsumeType
|
||||||
* The pump is always released on the main thread.
|
* The pump is always released on the main thread.
|
||||||
*/
|
*/
|
||||||
template <class Derived>
|
template <class Derived>
|
||||||
class FetchBody
|
class FetchBody : public FetchStreamHolder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
friend class FetchBodyConsumer<Derived>;
|
friend class FetchBodyConsumer<Derived>;
|
||||||
|
|
||||||
NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0;
|
|
||||||
NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0;
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BodyUsed() const;
|
BodyUsed() const;
|
||||||
|
|
||||||
|
|
@ -152,6 +177,13 @@ public:
|
||||||
JS::MutableHandle<JSObject*> aBodyOut,
|
JS::MutableHandle<JSObject*> aBodyOut,
|
||||||
ErrorResult& aRv);
|
ErrorResult& aRv);
|
||||||
|
|
||||||
|
// If the body contains a ReadableStream body object, this method produces a
|
||||||
|
// tee() of it.
|
||||||
|
void
|
||||||
|
MaybeTeeReadableStreamBody(JSContext* aCx,
|
||||||
|
JS::MutableHandle<JSObject*> aBodyOut,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
// Utility public methods accessed by various runnables.
|
// Utility public methods accessed by various runnables.
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -166,6 +198,12 @@ public:
|
||||||
return mMimeType;
|
return mMimeType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NullifyStream() override
|
||||||
|
{
|
||||||
|
mReadableStreamBody = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
virtual AbortSignal*
|
virtual AbortSignal*
|
||||||
GetSignal() const = 0;
|
GetSignal() const = 0;
|
||||||
|
|
||||||
|
|
@ -182,6 +220,10 @@ protected:
|
||||||
|
|
||||||
void
|
void
|
||||||
SetMimeType();
|
SetMimeType();
|
||||||
|
|
||||||
|
void
|
||||||
|
SetReadableStreamBody(JSObject* aBody);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Derived*
|
Derived*
|
||||||
DerivedClass() const
|
DerivedClass() const
|
||||||
|
|
@ -192,6 +234,9 @@ private:
|
||||||
already_AddRefed<Promise>
|
already_AddRefed<Promise>
|
||||||
ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorResult& aRv);
|
ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorResult& aRv);
|
||||||
|
|
||||||
|
void
|
||||||
|
LockStream(JSContext* aCx, JS::HandleObject aStream, ErrorResult& aRv);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IsOnTargetThread()
|
IsOnTargetThread()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,12 @@ class FetchStreamWorkerHolderShutdown final : public WorkerControlRunnable
|
||||||
public:
|
public:
|
||||||
FetchStreamWorkerHolderShutdown(WorkerPrivate* aWorkerPrivate,
|
FetchStreamWorkerHolderShutdown(WorkerPrivate* aWorkerPrivate,
|
||||||
UniquePtr<WorkerHolder>&& aHolder,
|
UniquePtr<WorkerHolder>&& aHolder,
|
||||||
nsCOMPtr<nsIGlobalObject>&& aGlobal)
|
nsCOMPtr<nsIGlobalObject>&& aGlobal,
|
||||||
: WorkerControlRunnable(aWorkerPrivate)
|
RefPtr<FetchStreamHolder>&& aStreamHolder)
|
||||||
|
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||||
, mHolder(Move(aHolder))
|
, mHolder(Move(aHolder))
|
||||||
, mGlobal(Move(aGlobal))
|
, mGlobal(Move(aGlobal))
|
||||||
|
, mStreamHolder(Move(aStreamHolder))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -71,12 +73,30 @@ public:
|
||||||
{
|
{
|
||||||
mHolder = nullptr;
|
mHolder = nullptr;
|
||||||
mGlobal = nullptr;
|
mGlobal = nullptr;
|
||||||
|
|
||||||
|
mStreamHolder->NullifyStream();
|
||||||
|
mStreamHolder = nullptr;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This runnable starts from a JS Thread. We need to disable a couple of
|
||||||
|
// assertions by overriding the following methods.
|
||||||
|
|
||||||
|
bool
|
||||||
|
PreDispatch(WorkerPrivate* aWorkerPrivate) override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override
|
||||||
|
{}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UniquePtr<WorkerHolder> mHolder;
|
UniquePtr<WorkerHolder> mHolder;
|
||||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||||
|
RefPtr<FetchStreamHolder> mStreamHolder;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous
|
} // anonymous
|
||||||
|
|
@ -85,13 +105,15 @@ NS_IMPL_ISUPPORTS(FetchStream, nsIInputStreamCallback, nsIObserver,
|
||||||
nsISupportsWeakReference)
|
nsISupportsWeakReference)
|
||||||
|
|
||||||
/* static */ JSObject*
|
/* static */ JSObject*
|
||||||
FetchStream::Create(JSContext* aCx, nsIGlobalObject* aGlobal,
|
FetchStream::Create(JSContext* aCx, FetchStreamHolder* aStreamHolder,
|
||||||
nsIInputStream* aInputStream, ErrorResult& aRv)
|
nsIGlobalObject* aGlobal, nsIInputStream* aInputStream,
|
||||||
|
ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aCx);
|
MOZ_DIAGNOSTIC_ASSERT(aCx);
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(aStreamHolder);
|
||||||
|
|
||||||
RefPtr<FetchStream> stream = new FetchStream(aGlobal, aInputStream);
|
RefPtr<FetchStream> stream = new FetchStream(aGlobal, aStreamHolder, aInputStream);
|
||||||
|
|
||||||
if (NS_IsMainThread()) {
|
if (NS_IsMainThread()) {
|
||||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||||
|
|
@ -226,7 +248,7 @@ FetchStream::RequestDataCallback(JSContext* aCx,
|
||||||
MOZ_DIAGNOSTIC_ASSERT(!stream->mOriginalInputStream);
|
MOZ_DIAGNOSTIC_ASSERT(!stream->mOriginalInputStream);
|
||||||
|
|
||||||
nsresult rv =
|
nsresult rv =
|
||||||
stream->mInputStream->AsyncWait(stream, 0, 0, nullptr);
|
stream->mInputStream->AsyncWait(stream, 0, 0, stream->mOwningEventTarget);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
stream->ErrorPropagation(aCx, aStream, rv);
|
stream->ErrorPropagation(aCx, aStream, rv);
|
||||||
return;
|
return;
|
||||||
|
|
@ -264,12 +286,11 @@ FetchStream::WriteIntoReadRequestCallback(JSContext* aCx,
|
||||||
*aByteWritten = written;
|
*aByteWritten = written;
|
||||||
|
|
||||||
if (written == 0) {
|
if (written == 0) {
|
||||||
stream->mState = eClosed;
|
stream->CloseAndReleaseObjects(aCx, aStream);
|
||||||
JS::ReadableStreamClose(aCx, aStream);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = stream->mInputStream->AsyncWait(stream, 0, 0, nullptr);
|
rv = stream->mInputStream->AsyncWait(stream, 0, 0, stream->mOwningEventTarget);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
stream->ErrorPropagation(aCx, aStream, rv);
|
stream->ErrorPropagation(aCx, aStream, rv);
|
||||||
return;
|
return;
|
||||||
|
|
@ -292,7 +313,7 @@ FetchStream::CancelCallback(JSContext* aCx, JS::HandleObject aStream,
|
||||||
stream->mInputStream->CloseWithStatus(NS_BASE_STREAM_CLOSED);
|
stream->mInputStream->CloseWithStatus(NS_BASE_STREAM_CLOSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->mState = eClosed;
|
stream->ReleaseObjects();
|
||||||
|
|
||||||
return JS::UndefinedValue();
|
return JS::UndefinedValue();
|
||||||
}
|
}
|
||||||
|
|
@ -325,22 +346,21 @@ FetchStream::FinalizeCallback(void* aUnderlyingSource, uint8_t aFlags)
|
||||||
RefPtr<FetchStream> stream =
|
RefPtr<FetchStream> stream =
|
||||||
dont_AddRef(static_cast<FetchStream*>(aUnderlyingSource));
|
dont_AddRef(static_cast<FetchStream*>(aUnderlyingSource));
|
||||||
|
|
||||||
if (stream->mState == eClosed) {
|
stream->ReleaseObjects();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream->CloseAndReleaseObjects();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FetchStream::FetchStream(nsIGlobalObject* aGlobal,
|
FetchStream::FetchStream(nsIGlobalObject* aGlobal,
|
||||||
|
FetchStreamHolder* aStreamHolder,
|
||||||
nsIInputStream* aInputStream)
|
nsIInputStream* aInputStream)
|
||||||
: mState(eWaiting)
|
: mState(eWaiting)
|
||||||
, mGlobal(aGlobal)
|
, mGlobal(aGlobal)
|
||||||
|
, mStreamHolder(aStreamHolder)
|
||||||
, mOriginalInputStream(aInputStream)
|
, mOriginalInputStream(aInputStream)
|
||||||
, mOwningEventTarget(nullptr)
|
, mOwningEventTarget(nullptr)
|
||||||
, mReadableStream(nullptr)
|
, mReadableStream(nullptr)
|
||||||
{
|
{
|
||||||
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
MOZ_DIAGNOSTIC_ASSERT(aInputStream);
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(aStreamHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
FetchStream::~FetchStream()
|
FetchStream::~FetchStream()
|
||||||
|
|
@ -356,12 +376,9 @@ FetchStream::ErrorPropagation(JSContext* aCx, JS::HandleObject aStream,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We cannot continue with any other operation.
|
|
||||||
mState = eClosed;
|
|
||||||
|
|
||||||
// Let's close the stream.
|
// Let's close the stream.
|
||||||
if (aError == NS_BASE_STREAM_CLOSED) {
|
if (aError == NS_BASE_STREAM_CLOSED) {
|
||||||
JS::ReadableStreamClose(aCx, aStream);
|
CloseAndReleaseObjects(aCx, aStream);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -428,6 +445,27 @@ FetchStream::OnInputStreamReady(nsIAsyncInputStream* aStream)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ nsresult
|
||||||
|
FetchStream::RetrieveInputStream(void* aUnderlyingReadableStreamSource,
|
||||||
|
nsIInputStream** aInputStream)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(aUnderlyingReadableStreamSource);
|
||||||
|
MOZ_ASSERT(aInputStream);
|
||||||
|
|
||||||
|
RefPtr<FetchStream> stream =
|
||||||
|
static_cast<FetchStream*>(aUnderlyingReadableStreamSource);
|
||||||
|
|
||||||
|
// if mOriginalInputStream is null, the reading already started. We don't want
|
||||||
|
// to expose the internal inputStream.
|
||||||
|
if (NS_WARN_IF(!stream->mOriginalInputStream)) {
|
||||||
|
return NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIInputStream> inputStream = stream->mOriginalInputStream;
|
||||||
|
inputStream.forget(aInputStream);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FetchStream::Close()
|
FetchStream::Close()
|
||||||
{
|
{
|
||||||
|
|
@ -437,27 +475,42 @@ FetchStream::Close()
|
||||||
|
|
||||||
AutoJSAPI jsapi;
|
AutoJSAPI jsapi;
|
||||||
if (NS_WARN_IF(!jsapi.Init(mGlobal))) {
|
if (NS_WARN_IF(!jsapi.Init(mGlobal))) {
|
||||||
|
ReleaseObjects();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JSContext* cx = jsapi.cx();
|
JSContext* cx = jsapi.cx();
|
||||||
JS::Rooted<JSObject*> stream(cx, mReadableStream);
|
JS::Rooted<JSObject*> stream(cx, mReadableStream);
|
||||||
JS::ReadableStreamClose(cx, stream);
|
|
||||||
|
|
||||||
CloseAndReleaseObjects();
|
CloseAndReleaseObjects(cx, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FetchStream::CloseAndReleaseObjects()
|
FetchStream::CloseAndReleaseObjects(JSContext* aCx, JS::HandleObject aStream)
|
||||||
{
|
{
|
||||||
MOZ_DIAGNOSTIC_ASSERT(mState != eClosed);
|
MOZ_DIAGNOSTIC_ASSERT(mState != eClosed);
|
||||||
|
|
||||||
|
ReleaseObjects();
|
||||||
|
|
||||||
|
if (JS::ReadableStreamIsReadable(aStream)) {
|
||||||
|
JS::ReadableStreamClose(aCx, aStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
FetchStream::ReleaseObjects()
|
||||||
|
{
|
||||||
|
if (mState == eClosed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mState = eClosed;
|
mState = eClosed;
|
||||||
|
|
||||||
if (mWorkerHolder) {
|
if (mWorkerHolder) {
|
||||||
RefPtr<FetchStreamWorkerHolderShutdown> r =
|
RefPtr<FetchStreamWorkerHolderShutdown> r =
|
||||||
new FetchStreamWorkerHolderShutdown(
|
new FetchStreamWorkerHolderShutdown(
|
||||||
static_cast<FetchStreamWorkerHolder*>(mWorkerHolder.get())->GetWorkerPrivate(),
|
static_cast<FetchStreamWorkerHolder*>(mWorkerHolder.get())->GetWorkerPrivate(),
|
||||||
Move(mWorkerHolder), Move(mGlobal));
|
Move(mWorkerHolder), Move(mGlobal), Move(mStreamHolder));
|
||||||
r->Dispatch();
|
r->Dispatch();
|
||||||
} else {
|
} else {
|
||||||
RefPtr<FetchStream> self = this;
|
RefPtr<FetchStream> self = this;
|
||||||
|
|
@ -468,6 +521,9 @@ FetchStream::CloseAndReleaseObjects()
|
||||||
os->RemoveObserver(self, DOM_WINDOW_DESTROYED_TOPIC);
|
os->RemoveObserver(self, DOM_WINDOW_DESTROYED_TOPIC);
|
||||||
}
|
}
|
||||||
self->mGlobal = nullptr;
|
self->mGlobal = nullptr;
|
||||||
|
|
||||||
|
self->mStreamHolder->NullifyStream();
|
||||||
|
self->mStreamHolder = nullptr;
|
||||||
});
|
});
|
||||||
|
|
||||||
NS_DispatchToMainThread(r);
|
NS_DispatchToMainThread(r);
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ namespace workers {
|
||||||
class WorkerHolder;
|
class WorkerHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FetchStreamHolder;
|
||||||
|
|
||||||
class FetchStream final : public nsIInputStreamCallback
|
class FetchStream final : public nsIInputStreamCallback
|
||||||
, public nsIObserver
|
, public nsIObserver
|
||||||
, public nsSupportsWeakReference
|
, public nsSupportsWeakReference
|
||||||
|
|
@ -34,14 +36,20 @@ public:
|
||||||
NS_DECL_NSIOBSERVER
|
NS_DECL_NSIOBSERVER
|
||||||
|
|
||||||
static JSObject*
|
static JSObject*
|
||||||
Create(JSContext* aCx, nsIGlobalObject* aGlobal,
|
Create(JSContext* aCx, FetchStreamHolder* aStreamHolder,
|
||||||
nsIInputStream* aInputStream, ErrorResult& aRv);
|
nsIGlobalObject* aGlobal, nsIInputStream* aInputStream,
|
||||||
|
ErrorResult& aRv);
|
||||||
|
|
||||||
void
|
void
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
|
static nsresult
|
||||||
|
RetrieveInputStream(void* aUnderlyingReadableStreamSource,
|
||||||
|
nsIInputStream** aInputStream);
|
||||||
private:
|
private:
|
||||||
FetchStream(nsIGlobalObject* aGlobal, nsIInputStream* aInputStream);
|
FetchStream(nsIGlobalObject* aGlobal,
|
||||||
|
FetchStreamHolder* aStreamHolder,
|
||||||
|
nsIInputStream* aInputStream);
|
||||||
~FetchStream();
|
~FetchStream();
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -76,7 +84,10 @@ private:
|
||||||
ErrorPropagation(JSContext* aCx, JS::HandleObject aStream, nsresult aRv);
|
ErrorPropagation(JSContext* aCx, JS::HandleObject aStream, nsresult aRv);
|
||||||
|
|
||||||
void
|
void
|
||||||
CloseAndReleaseObjects();
|
CloseAndReleaseObjects(JSContext* aCx, JS::HandleObject aStream);
|
||||||
|
|
||||||
|
void
|
||||||
|
ReleaseObjects();
|
||||||
|
|
||||||
// Common methods
|
// Common methods
|
||||||
|
|
||||||
|
|
@ -104,6 +115,8 @@ private:
|
||||||
State mState;
|
State mState;
|
||||||
|
|
||||||
nsCOMPtr<nsIGlobalObject> mGlobal;
|
nsCOMPtr<nsIGlobalObject> mGlobal;
|
||||||
|
RefPtr<FetchStreamHolder> mStreamHolder;
|
||||||
|
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
|
||||||
|
|
||||||
// This is the original inputStream received during the CTOR. It will be
|
// This is the original inputStream received during the CTOR. It will be
|
||||||
// converted into an nsIAsyncInputStream and stored into mInputStream at the
|
// converted into an nsIAsyncInputStream and stored into mInputStream at the
|
||||||
|
|
@ -111,8 +124,6 @@ private:
|
||||||
nsCOMPtr<nsIInputStream> mOriginalInputStream;
|
nsCOMPtr<nsIInputStream> mOriginalInputStream;
|
||||||
nsCOMPtr<nsIAsyncInputStream> mInputStream;
|
nsCOMPtr<nsIAsyncInputStream> mInputStream;
|
||||||
|
|
||||||
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
|
|
||||||
|
|
||||||
UniquePtr<workers::WorkerHolder> mWorkerHolder;
|
UniquePtr<workers::WorkerHolder> mWorkerHolder;
|
||||||
|
|
||||||
JS::Heap<JSObject*> mReadableStream;
|
JS::Heap<JSObject*> mReadableStream;
|
||||||
|
|
|
||||||
|
|
@ -574,11 +574,9 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aInit.mBody.WasPassed()) {
|
if (aInit.mBody.WasPassed()) {
|
||||||
const Nullable<OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>& bodyInitNullable =
|
const Nullable<fetch::OwningBodyInit>& bodyInitNullable = aInit.mBody.Value();
|
||||||
aInit.mBody.Value();
|
|
||||||
if (!bodyInitNullable.IsNull()) {
|
if (!bodyInitNullable.IsNull()) {
|
||||||
const OwningArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams& bodyInit =
|
const fetch::OwningBodyInit& bodyInit = bodyInitNullable.Value();
|
||||||
bodyInitNullable.Value();
|
|
||||||
nsCOMPtr<nsIInputStream> stream;
|
nsCOMPtr<nsIInputStream> stream;
|
||||||
nsAutoCString contentTypeWithCharset;
|
nsAutoCString contentTypeWithCharset;
|
||||||
uint64_t contentLengthUnused;
|
uint64_t contentLengthUnused;
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,15 @@
|
||||||
|
|
||||||
#include "mozilla/ErrorResult.h"
|
#include "mozilla/ErrorResult.h"
|
||||||
#include "mozilla/dom/FetchBinding.h"
|
#include "mozilla/dom/FetchBinding.h"
|
||||||
|
#include "mozilla/dom/ResponseBinding.h"
|
||||||
#include "mozilla/dom/Headers.h"
|
#include "mozilla/dom/Headers.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
#include "mozilla/dom/URL.h"
|
#include "mozilla/dom/URL.h"
|
||||||
|
|
||||||
#include "nsDOMString.h"
|
#include "nsDOMString.h"
|
||||||
|
|
||||||
|
#include "BodyExtractor.h"
|
||||||
|
#include "FetchStream.h"
|
||||||
#include "InternalResponse.h"
|
#include "InternalResponse.h"
|
||||||
#include "WorkerPrivate.h"
|
#include "WorkerPrivate.h"
|
||||||
|
|
||||||
|
|
@ -130,7 +133,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>> body;
|
Optional<fetch::ResponseBodyInit> body;
|
||||||
ResponseInit init;
|
ResponseInit init;
|
||||||
init.mStatus = aStatus;
|
init.mStatus = aStatus;
|
||||||
RefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
|
RefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
|
||||||
|
|
@ -151,7 +154,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||||
|
|
||||||
/*static*/ already_AddRefed<Response>
|
/*static*/ already_AddRefed<Response>
|
||||||
Response::Constructor(const GlobalObject& aGlobal,
|
Response::Constructor(const GlobalObject& aGlobal,
|
||||||
const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody,
|
const Optional<fetch::ResponseBodyInit>& aBody,
|
||||||
const ResponseInit& aInit, ErrorResult& aRv)
|
const ResponseInit& aInit, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||||
|
|
@ -217,22 +220,65 @@ Response::Constructor(const GlobalObject& aGlobal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aBody.WasPassed() && !aBody.Value().IsNull()) {
|
if (aBody.WasPassed()) {
|
||||||
if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) {
|
if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) {
|
||||||
aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>();
|
aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIInputStream> bodyStream;
|
|
||||||
nsCString contentTypeWithCharset;
|
nsCString contentTypeWithCharset;
|
||||||
|
nsCOMPtr<nsIInputStream> bodyStream;
|
||||||
uint64_t bodySize = 0;
|
uint64_t bodySize = 0;
|
||||||
aRv = ExtractByteStreamFromBody(aBody.Value().Value(),
|
|
||||||
getter_AddRefs(bodyStream),
|
if (aBody.Value().IsReadableStream()) {
|
||||||
contentTypeWithCharset,
|
const ReadableStream& readableStream =
|
||||||
bodySize);
|
aBody.Value().GetAsReadableStream();
|
||||||
if (NS_WARN_IF(aRv.Failed())) {
|
|
||||||
return nullptr;
|
JS::Rooted<JSObject*> readableStreamObj(aGlobal.Context(),
|
||||||
|
readableStream.Obj());
|
||||||
|
|
||||||
|
if (JS::ReadableStreamIsDisturbed(readableStreamObj) ||
|
||||||
|
JS::ReadableStreamIsLocked(readableStreamObj) ||
|
||||||
|
!JS::ReadableStreamIsReadable(readableStreamObj)) {
|
||||||
|
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->SetReadableStreamBody(readableStreamObj);
|
||||||
|
|
||||||
|
// XXXMC: TODO
|
||||||
|
MOZ_ASSERT(JS::ReadableStreamGetMode(readableStreamObj) !=
|
||||||
|
JS::ReadableStreamMode::ExternalSource);
|
||||||
|
|
||||||
|
void* underlyingSource = nullptr;
|
||||||
|
if (!JS::ReadableStreamGetExternalUnderlyingSource(aGlobal.Context(),
|
||||||
|
readableStreamObj,
|
||||||
|
&underlyingSource)) {
|
||||||
|
aRv.StealExceptionFromJSContext(aGlobal.Context());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bodySize = InternalResponse::UNKNOWN_BODY_SIZE;
|
||||||
|
|
||||||
|
MOZ_ASSERT(underlyingSource);
|
||||||
|
aRv = FetchStream::RetrieveInputStream(underlyingSource,
|
||||||
|
getter_AddRefs(bodyStream));
|
||||||
|
|
||||||
|
// Releasing of the external source is needed in order to avoid an extra stream lock.
|
||||||
|
JS::ReadableStreamReleaseExternalUnderlyingSource(readableStreamObj);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
aRv = ExtractByteStreamFromBody(aBody.Value(),
|
||||||
|
getter_AddRefs(bodyStream),
|
||||||
|
contentTypeWithCharset,
|
||||||
|
bodySize);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internalResponse->SetBody(bodyStream, bodySize);
|
internalResponse->SetBody(bodyStream, bodySize);
|
||||||
|
|
||||||
if (!contentTypeWithCharset.IsVoid() &&
|
if (!contentTypeWithCharset.IsVoid() &&
|
||||||
|
|
@ -254,7 +300,7 @@ Response::Constructor(const GlobalObject& aGlobal,
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Response>
|
already_AddRefed<Response>
|
||||||
Response::Clone(ErrorResult& aRv) const
|
Response::Clone(JSContext* aCx, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
if (BodyUsed()) {
|
if (BodyUsed()) {
|
||||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||||
|
|
@ -263,11 +309,26 @@ Response::Clone(ErrorResult& aRv) const
|
||||||
|
|
||||||
RefPtr<InternalResponse> ir = mInternalResponse->Clone();
|
RefPtr<InternalResponse> ir = mInternalResponse->Clone();
|
||||||
RefPtr<Response> response = new Response(mOwner, ir, mSignal);
|
RefPtr<Response> response = new Response(mOwner, ir, mSignal);
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> body(aCx);
|
||||||
|
MaybeTeeReadableStreamBody(aCx, &body, aRv);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body) {
|
||||||
|
// Maybe we have a body, but we receive null from MaybeTeeReadableStreamBody
|
||||||
|
// if this body is a native stream. In this case, the InternalResponse will
|
||||||
|
// have a clone of the native body and the ReadableStream will be created
|
||||||
|
// lazily if needed.
|
||||||
|
response->SetReadableStreamBody(body);
|
||||||
|
}
|
||||||
|
|
||||||
return response.forget();
|
return response.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Response>
|
already_AddRefed<Response>
|
||||||
Response::CloneUnfiltered(ErrorResult& aRv) const
|
Response::CloneUnfiltered(JSContext* aCx, ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
if (BodyUsed()) {
|
if (BodyUsed()) {
|
||||||
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
|
||||||
|
|
@ -277,6 +338,21 @@ Response::CloneUnfiltered(ErrorResult& aRv) const
|
||||||
RefPtr<InternalResponse> clone = mInternalResponse->Clone();
|
RefPtr<InternalResponse> clone = mInternalResponse->Clone();
|
||||||
RefPtr<InternalResponse> ir = clone->Unfiltered();
|
RefPtr<InternalResponse> ir = clone->Unfiltered();
|
||||||
RefPtr<Response> ref = new Response(mOwner, ir, mSignal);
|
RefPtr<Response> ref = new Response(mOwner, ir, mSignal);
|
||||||
|
|
||||||
|
JS::Rooted<JSObject*> body(aCx);
|
||||||
|
MaybeTeeReadableStreamBody(aCx, &body, aRv);
|
||||||
|
if (NS_WARN_IF(aRv.Failed())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (body) {
|
||||||
|
// Maybe we have a body, but we receive null from MaybeTeeReadableStreamBody
|
||||||
|
// if this body is a native stream. In this case, the InternalResponse will
|
||||||
|
// have a clone of the native body and the ReadableStream will be created
|
||||||
|
// lazily if needed.
|
||||||
|
ref->SetReadableStreamBody(body);
|
||||||
|
}
|
||||||
|
|
||||||
return ref.forget();
|
return ref.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ public:
|
||||||
|
|
||||||
static already_AddRefed<Response>
|
static already_AddRefed<Response>
|
||||||
Constructor(const GlobalObject& aGlobal,
|
Constructor(const GlobalObject& aGlobal,
|
||||||
const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody,
|
const Optional<fetch::ResponseBodyInit>& aBody,
|
||||||
const ResponseInit& aInit, ErrorResult& rv);
|
const ResponseInit& aInit, ErrorResult& rv);
|
||||||
|
|
||||||
nsIGlobalObject* GetParentObject() const
|
nsIGlobalObject* GetParentObject() const
|
||||||
|
|
@ -124,10 +124,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<Response>
|
already_AddRefed<Response>
|
||||||
Clone(ErrorResult& aRv) const;
|
Clone(JSContext* aCx, ErrorResult& aRv);
|
||||||
|
|
||||||
already_AddRefed<Response>
|
already_AddRefed<Response>
|
||||||
CloneUnfiltered(ErrorResult& aRv) const;
|
CloneUnfiltered(JSContext* aCx, ErrorResult& aRv);
|
||||||
|
|
||||||
void
|
void
|
||||||
SetBody(nsIInputStream* aBody, int64_t aBodySize);
|
SetBody(nsIInputStream* aBody, int64_t aBodySize);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef object JSON;
|
typedef object JSON;
|
||||||
typedef (ArrayBuffer or ArrayBufferView or Blob or FormData or USVString or URLSearchParams) BodyInit;
|
typedef (Blob or BufferSource or FormData or URLSearchParams or USVString) BodyInit;
|
||||||
|
|
||||||
[NoInterfaceObject, Exposed=(Window,Worker)]
|
[NoInterfaceObject, Exposed=(Window,Worker)]
|
||||||
interface Body {
|
interface Body {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@
|
||||||
* https://fetch.spec.whatwg.org/#response-class
|
* https://fetch.spec.whatwg.org/#response-class
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[Constructor(optional BodyInit? body, optional ResponseInit init),
|
// This should be Constructor(optional BodyInit... but BodyInit doesn't include
|
||||||
|
// ReadableStream yet because we don't want to expose the Streams API to Request.
|
||||||
|
[Constructor(optional (Blob or BufferSource or FormData or URLSearchParams or ReadableStream or USVString) body, optional ResponseInit init),
|
||||||
Exposed=(Window,Worker)]
|
Exposed=(Window,Worker)]
|
||||||
interface Response {
|
interface Response {
|
||||||
[NewObject] static Response error();
|
[NewObject] static Response error();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue