summaryrefslogtreecommitdiff
path: root/dom/fetch/Response.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/fetch/Response.cpp')
-rw-r--r--dom/fetch/Response.cpp95
1 files changed, 85 insertions, 10 deletions
diff --git a/dom/fetch/Response.cpp b/dom/fetch/Response.cpp
index de38fa3e53..bc3d543663 100644
--- a/dom/fetch/Response.cpp
+++ b/dom/fetch/Response.cpp
@@ -12,12 +12,14 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/FetchBinding.h"
+#include "mozilla/dom/ResponseBinding.h"
#include "mozilla/dom/Headers.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/URL.h"
#include "nsDOMString.h"
+#include "FetchStream.h"
#include "InternalResponse.h"
#include "WorkerPrivate.h"
@@ -129,7 +131,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
return nullptr;
}
- Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>> body;
+ Optional<Nullable<fetch::ResponseBodyInit>> body;
ResponseInit init;
init.mStatus = aStatus;
RefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
@@ -150,7 +152,7 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
/*static*/ already_AddRefed<Response>
Response::Constructor(const GlobalObject& aGlobal,
- const Optional<Nullable<ArrayBufferOrArrayBufferViewOrBlobOrFormDataOrUSVStringOrURLSearchParams>>& aBody,
+ const Optional<Nullable<fetch::ResponseBodyInit>>& aBody,
const ResponseInit& aInit, ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
@@ -225,13 +227,56 @@ Response::Constructor(const GlobalObject& aGlobal,
nsCOMPtr<nsIInputStream> bodyStream;
nsCString contentType;
uint64_t bodySize = 0;
- aRv = ExtractByteStreamFromBody(aBody.Value().Value(),
- getter_AddRefs(bodyStream),
- contentType,
- bodySize);
- if (NS_WARN_IF(aRv.Failed())) {
- return nullptr;
+
+ if (aBody.Value().IsReadableStream()) {
+ const ReadableStream& readableStream =
+ aBody.Value().GetAsReadableStream();
+
+ 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().Value(),
+ getter_AddRefs(bodyStream),
+ contentType,
+ bodySize);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return nullptr;
+ }
}
+
internalResponse->SetBody(bodyStream, bodySize);
if (!contentType.IsVoid() &&
@@ -252,7 +297,7 @@ Response::Constructor(const GlobalObject& aGlobal,
}
already_AddRefed<Response>
-Response::Clone(ErrorResult& aRv) const
+Response::Clone(JSContext* aCx, ErrorResult& aRv) const
{
if (BodyUsed()) {
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
@@ -261,11 +306,26 @@ Response::Clone(ErrorResult& aRv) const
RefPtr<InternalResponse> ir = mInternalResponse->Clone();
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();
}
already_AddRefed<Response>
-Response::CloneUnfiltered(ErrorResult& aRv) const
+Response::CloneUnfiltered(JSContext* aCx, ErrorResult& aRv) const
{
if (BodyUsed()) {
aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
@@ -275,6 +335,21 @@ Response::CloneUnfiltered(ErrorResult& aRv) const
RefPtr<InternalResponse> clone = mInternalResponse->Clone();
RefPtr<InternalResponse> ir = clone->Unfiltered();
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();
}