Issue #1442 - Part 13 - Implement FetchStreamReader. https://bugzilla.mozilla.org/show_bug.cgi?id=1329298

This commit is contained in:
Brian Smith 2023-09-28 17:36:52 -05:00 committed by roytam1
commit ef550b2579
10 changed files with 569 additions and 62 deletions

View file

@ -21,6 +21,7 @@
#include "BodyExtractor.h"
#include "FetchStream.h"
#include "FetchStreamReader.h"
#include "InternalResponse.h"
#include "WorkerPrivate.h"
@ -37,6 +38,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Response)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
tmp->mReadableStreamBody = nullptr;
tmp->mReadableStreamReader = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -48,6 +50,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Response)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamBody)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mReadableStreamReader)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
@ -227,7 +230,7 @@ Response::Constructor(const GlobalObject& aGlobal,
nsCString contentTypeWithCharset;
nsCOMPtr<nsIInputStream> bodyStream;
uint64_t bodySize = 0;
int64_t bodySize = InternalResponse::UNKNOWN_BODY_SIZE;
if (aBody.Value().IsReadableStream()) {
const ReadableStream& readableStream =
@ -245,37 +248,50 @@ Response::Constructor(const GlobalObject& aGlobal,
r->SetReadableStreamBody(readableStreamObj);
// XXXMC: TODO
MOZ_ASSERT(JS::ReadableStreamGetMode(readableStreamObj) !=
JS::ReadableStreamMode::ExternalSource);
if (JS::ReadableStreamGetMode(readableStreamObj) ==
JS::ReadableStreamMode::ExternalSource) {
// If this is a DOM generated ReadableStream, we can extract the
// inputStream directly.
void* underlyingSource = nullptr;
if (!JS::ReadableStreamGetExternalUnderlyingSource(aGlobal.Context(),
readableStreamObj,
&underlyingSource)) {
aRv.StealExceptionFromJSContext(aGlobal.Context());
return nullptr;
}
void* underlyingSource = nullptr;
if (!JS::ReadableStreamGetExternalUnderlyingSource(aGlobal.Context(),
readableStreamObj,
&underlyingSource)) {
aRv.StealExceptionFromJSContext(aGlobal.Context());
return nullptr;
MOZ_ASSERT(underlyingSource);
aRv = FetchStream::RetrieveInputStream(underlyingSource,
getter_AddRefs(bodyStream));
// The 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 {
// If this is a JS-created ReadableStream, let's create a
// FetchStreamReader.
aRv = FetchStreamReader::Create(aGlobal.Context(), global,
getter_AddRefs(r->mFetchStreamReader),
getter_AddRefs(bodyStream));
if (NS_WARN_IF(aRv.Failed())) {
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 {
uint64_t size = 0;
aRv = ExtractByteStreamFromBody(aBody.Value(),
getter_AddRefs(bodyStream),
contentTypeWithCharset,
bodySize);
size);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
bodySize = size;
}
internalResponse->SetBody(bodyStream, bodySize);
@ -306,21 +322,35 @@ Response::Clone(JSContext* aCx, ErrorResult& aRv)
return nullptr;
}
RefPtr<InternalResponse> ir = mInternalResponse->Clone();
RefPtr<Response> response = new Response(mOwner, ir, mSignal);
RefPtr<FetchStreamReader> streamReader;
nsCOMPtr<nsIInputStream> inputStream;
JS::Rooted<JSObject*> body(aCx);
MaybeTeeReadableStreamBody(aCx, &body, aRv);
MaybeTeeReadableStreamBody(aCx, &body,
getter_AddRefs(streamReader),
getter_AddRefs(inputStream), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
MOZ_ASSERT_IF(body, streamReader);
MOZ_ASSERT_IF(body, inputStream);
RefPtr<InternalResponse> ir =
mInternalResponse->Clone(body
? InternalResponse::eDontCloneInputStream
: InternalResponse::eCloneInputStream);
RefPtr<Response> response = new Response(mOwner, ir, 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);
response->mFetchStreamReader = streamReader;
ir->SetBody(inputStream, InternalResponse::UNKNOWN_BODY_SIZE);
}
return response.forget();
@ -334,22 +364,36 @@ Response::CloneUnfiltered(JSContext* aCx, ErrorResult& aRv)
return nullptr;
}
RefPtr<InternalResponse> clone = mInternalResponse->Clone();
RefPtr<InternalResponse> ir = clone->Unfiltered();
RefPtr<Response> ref = new Response(mOwner, ir, mSignal);
RefPtr<FetchStreamReader> streamReader;
nsCOMPtr<nsIInputStream> inputStream;
JS::Rooted<JSObject*> body(aCx);
MaybeTeeReadableStreamBody(aCx, &body, aRv);
MaybeTeeReadableStreamBody(aCx, &body,
getter_AddRefs(streamReader),
getter_AddRefs(inputStream), aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
MOZ_ASSERT_IF(body, streamReader);
MOZ_ASSERT_IF(body, inputStream);
RefPtr<InternalResponse> clone =
mInternalResponse->Clone(body
? InternalResponse::eDontCloneInputStream
: InternalResponse::eCloneInputStream);
RefPtr<InternalResponse> ir = clone->Unfiltered();
RefPtr<Response> ref = new Response(mOwner, ir, 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);
ref->mFetchStreamReader = streamReader;
ir->SetBody(inputStream, InternalResponse::UNKNOWN_BODY_SIZE);
}
return ref.forget();