Commit b4462270 authored by Adam Rice's avatar Adam Rice Committed by Commit Bot

[ReadableStream] Remove ExceptionState& from two methods

ReadableStream::LockAndDisturb() can no longer throw now that the V8
Extras implementation has been removed. Remove the ExceptionState&
argument. Also remove the ScriptState::Scope from the method which is
not needed.

ReadableStream::GetReaderNotForAuthorCode() is never called on a
locked stream, so it cannot throw. Remove the ExceptionState&
argument.

In order to ensure that ReadableStream::GetReaderNotForAuthorCode() is
not called on a locked stream, check in
BodyStreamBuffer::ExtractBody() whether the stream is locked or
disturbed and throw an exception. This is only done when
FetchUploadStreaing is enabled. This actually improves our alignment
with the Fetch Standard and improves our test pass rate.

Many fetch-related methods no longer need an
ExceptionState& argument either, so remove those unneeded arguments too.

Bug: 1010794

Change-Id: I6c84f8bff006c696edca13b7a46fcbc10c142201
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2217830
Commit-Queue: Adam Rice <ricea@chromium.org>
Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Reviewed-by: default avatarYoichi Osato <yoichio@chromium.org>
Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790089}
parent 55d4d3cd
......@@ -168,11 +168,10 @@ BodyStreamBuffer::BodyStreamBuffer(ScriptState* script_state,
}
scoped_refptr<BlobDataHandle> BodyStreamBuffer::DrainAsBlobDataHandle(
BytesConsumer::BlobSizePolicy policy,
ExceptionState& exception_state) {
BytesConsumer::BlobSizePolicy policy) {
DCHECK(!IsStreamLocked());
DCHECK(!IsStreamDisturbed());
if (IsStreamClosed() || IsStreamErrored())
if (IsStreamClosed() || IsStreamErrored() || stream_broken_)
return nullptr;
if (made_from_readable_stream_)
......@@ -181,19 +180,16 @@ scoped_refptr<BlobDataHandle> BodyStreamBuffer::DrainAsBlobDataHandle(
scoped_refptr<BlobDataHandle> blob_data_handle =
consumer_->DrainAsBlobDataHandle(policy);
if (blob_data_handle) {
CloseAndLockAndDisturb(exception_state);
if (exception_state.HadException())
return nullptr;
CloseAndLockAndDisturb();
return blob_data_handle;
}
return nullptr;
}
scoped_refptr<EncodedFormData> BodyStreamBuffer::DrainAsFormData(
ExceptionState& exception_state) {
scoped_refptr<EncodedFormData> BodyStreamBuffer::DrainAsFormData() {
DCHECK(!IsStreamLocked());
DCHECK(!IsStreamDisturbed());
if (IsStreamClosed() || IsStreamErrored())
if (IsStreamClosed() || IsStreamErrored() || stream_broken_)
return nullptr;
if (made_from_readable_stream_)
......@@ -201,9 +197,7 @@ scoped_refptr<EncodedFormData> BodyStreamBuffer::DrainAsFormData(
scoped_refptr<EncodedFormData> form_data = consumer_->DrainAsFormData();
if (form_data) {
CloseAndLockAndDisturb(exception_state);
if (exception_state.HadException())
return nullptr;
CloseAndLockAndDisturb();
return form_data;
}
return nullptr;
......@@ -212,13 +206,10 @@ scoped_refptr<EncodedFormData> BodyStreamBuffer::DrainAsFormData(
void BodyStreamBuffer::DrainAsChunkedDataPipeGetter(
ScriptState* script_state,
mojo::PendingReceiver<network::mojom::blink::ChunkedDataPipeGetter>
pending_receiver,
ExceptionState& exception_state) {
pending_receiver) {
DCHECK(!IsStreamLocked());
auto* consumer = MakeGarbageCollected<ReadableStreamBytesConsumer>(
script_state, stream_, exception_state);
if (exception_state.HadException())
return;
auto* consumer =
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream_);
stream_uploader_ = MakeGarbageCollected<BytesUploader>(
consumer, std::move(pending_receiver),
ExecutionContext::From(script_state)
......@@ -368,13 +359,8 @@ bool BodyStreamBuffer::IsStreamDisturbed() const {
return stream_->IsDisturbed();
}
void BodyStreamBuffer::CloseAndLockAndDisturb(ExceptionState& exception_state) {
if (stream_broken_) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Body stream has suffered a fatal error and cannot be disturbed");
return;
}
void BodyStreamBuffer::CloseAndLockAndDisturb() {
DCHECK(!stream_broken_);
if (IsStreamReadable()) {
// Note that the stream cannot be "draining", because it doesn't have
......@@ -382,7 +368,7 @@ void BodyStreamBuffer::CloseAndLockAndDisturb(ExceptionState& exception_state) {
Close();
}
stream_->LockAndDisturb(script_state_, exception_state);
stream_->LockAndDisturb(script_state_);
}
bool BodyStreamBuffer::IsAborted() {
......@@ -524,14 +510,10 @@ BytesConsumer* BodyStreamBuffer::ReleaseHandle(
side_data_blob_.reset();
if (made_from_readable_stream_) {
DCHECK(script_state_->ContextIsValid());
ScriptState::Scope scope(script_state_);
auto* consumer = MakeGarbageCollected<ReadableStreamBytesConsumer>(
script_state_, stream_, exception_state);
if (exception_state.HadException()) {
stream_broken_ = true;
return nullptr;
}
return consumer;
return MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state_,
stream_);
}
// We need to call these before calling CloseAndLockAndDisturb.
const bool is_closed = IsStreamClosed();
......@@ -539,9 +521,7 @@ BytesConsumer* BodyStreamBuffer::ReleaseHandle(
BytesConsumer* consumer = consumer_.Release();
CloseAndLockAndDisturb(exception_state);
if (exception_state.HadException())
return nullptr;
CloseAndLockAndDisturb();
if (is_closed) {
// Note that the stream cannot be "draining", because it doesn't have
......
......@@ -61,13 +61,11 @@ class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
// Callable only when neither locked nor disturbed.
scoped_refptr<BlobDataHandle> DrainAsBlobDataHandle(
BytesConsumer::BlobSizePolicy,
ExceptionState&);
scoped_refptr<EncodedFormData> DrainAsFormData(ExceptionState&);
BytesConsumer::BlobSizePolicy);
scoped_refptr<EncodedFormData> DrainAsFormData();
void DrainAsChunkedDataPipeGetter(
ScriptState*,
mojo::PendingReceiver<network::mojom::blink::ChunkedDataPipeGetter>,
ExceptionState&);
mojo::PendingReceiver<network::mojom::blink::ChunkedDataPipeGetter>);
void StartLoading(FetchDataLoader*,
FetchDataLoader::Client* /* client */,
ExceptionState&);
......@@ -88,7 +86,11 @@ class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
bool IsStreamErrored() const;
bool IsStreamLocked() const;
bool IsStreamDisturbed() const;
void CloseAndLockAndDisturb(ExceptionState&);
// Closes the stream if necessary, and then locks and disturbs it. Should not
// be called if |stream_broken_| is true.
void CloseAndLockAndDisturb();
ScriptState* GetScriptState() { return script_state_; }
bool IsAborted();
......
......@@ -244,8 +244,7 @@ TEST_F(BodyStreamBufferTest, DrainAsBlobDataHandle) {
EXPECT_EQ(side_data_blob, buffer->GetSideDataBlobForTest());
scoped_refptr<BlobDataHandle> output_blob_data_handle =
buffer->DrainAsBlobDataHandle(
BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize,
ASSERT_NO_EXCEPTION);
BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize);
EXPECT_TRUE(buffer->IsStreamLocked());
EXPECT_TRUE(buffer->IsStreamDisturbed());
......@@ -270,8 +269,7 @@ TEST_F(BodyStreamBufferTest, DrainAsBlobDataHandleReturnsNull) {
EXPECT_EQ(side_data_blob, buffer->GetSideDataBlobForTest());
EXPECT_FALSE(buffer->DrainAsBlobDataHandle(
BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize,
ASSERT_NO_EXCEPTION));
BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize));
EXPECT_FALSE(buffer->IsStreamLocked());
EXPECT_FALSE(buffer->IsStreamDisturbed());
......@@ -295,8 +293,7 @@ TEST_F(BodyStreamBufferTest,
EXPECT_TRUE(buffer->IsStreamReadable());
EXPECT_FALSE(buffer->DrainAsBlobDataHandle(
BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize,
exception_state));
BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize));
EXPECT_FALSE(buffer->HasPendingActivity());
EXPECT_FALSE(buffer->IsStreamLocked());
......@@ -323,8 +320,7 @@ TEST_F(BodyStreamBufferTest, DrainAsFormData) {
EXPECT_FALSE(buffer->IsStreamDisturbed());
EXPECT_FALSE(buffer->HasPendingActivity());
EXPECT_EQ(side_data_blob, buffer->GetSideDataBlobForTest());
scoped_refptr<EncodedFormData> output_form_data =
buffer->DrainAsFormData(ASSERT_NO_EXCEPTION);
scoped_refptr<EncodedFormData> output_form_data = buffer->DrainAsFormData();
EXPECT_TRUE(buffer->IsStreamLocked());
EXPECT_TRUE(buffer->IsStreamDisturbed());
......@@ -349,7 +345,7 @@ TEST_F(BodyStreamBufferTest, DrainAsFormDataReturnsNull) {
EXPECT_FALSE(buffer->HasPendingActivity());
EXPECT_EQ(side_data_blob, buffer->GetSideDataBlobForTest());
EXPECT_FALSE(buffer->DrainAsFormData(ASSERT_NO_EXCEPTION));
EXPECT_FALSE(buffer->DrainAsFormData());
EXPECT_FALSE(buffer->IsStreamLocked());
EXPECT_FALSE(buffer->IsStreamDisturbed());
......@@ -371,7 +367,7 @@ TEST_F(BodyStreamBufferTest,
EXPECT_FALSE(buffer->IsStreamDisturbed());
EXPECT_TRUE(buffer->IsStreamReadable());
EXPECT_FALSE(buffer->DrainAsFormData(exception_state));
EXPECT_FALSE(buffer->DrainAsFormData());
EXPECT_FALSE(buffer->HasPendingActivity());
EXPECT_FALSE(buffer->IsStreamLocked());
......
......@@ -113,7 +113,7 @@ class FetchManager::Loader final
void DidFail(const ResourceError&) override;
void DidFailRedirectCheck() override;
void Start(ExceptionState&);
void Start();
void Dispose();
void Abort();
......@@ -226,9 +226,9 @@ class FetchManager::Loader final
};
private:
void PerformSchemeFetch(ExceptionState&);
void PerformSchemeFetch();
void PerformNetworkError(const String& message);
void PerformHTTPFetch(ExceptionState&);
void PerformHTTPFetch();
void PerformDataFetch();
// If |dom_exception| is provided, throws the specified DOMException instead
// of the usual "Failed to fetch" TypeError.
......@@ -527,7 +527,7 @@ void FetchManager::Loader::DidFailRedirectCheck() {
Failed(String(), nullptr);
}
void FetchManager::Loader::Start(ExceptionState& exception_state) {
void FetchManager::Loader::Start() {
// "1. If |request|'s url contains a Known HSTS Host, modify it per the
// requirements of the 'URI [sic] Loading and Port Mapping' chapter of HTTP
// Strict Transport Security."
......@@ -573,7 +573,7 @@ void FetchManager::Loader::Start(ExceptionState& exception_state) {
fetch_request_data_->IsolatedWorldOrigin()->CanReadContent(url)) ||
fetch_request_data_->Mode() == network::mojom::RequestMode::kNavigate) {
// "The result of performing a scheme fetch using request."
PerformSchemeFetch(exception_state);
PerformSchemeFetch();
return;
}
......@@ -603,7 +603,7 @@ void FetchManager::Loader::Start(ExceptionState& exception_state) {
// "Set |request|'s response tainting to |opaque|."
fetch_request_data_->SetResponseTainting(FetchRequestData::kOpaqueTainting);
// "The result of performing a scheme fetch using |request|."
PerformSchemeFetch(exception_state);
PerformSchemeFetch();
return;
}
......@@ -624,7 +624,7 @@ void FetchManager::Loader::Start(ExceptionState& exception_state) {
// "The result of performing an HTTP fetch using |request| with the
// |CORS flag| set."
PerformHTTPFetch(exception_state);
PerformHTTPFetch();
}
void FetchManager::Loader::Dispose() {
......@@ -660,16 +660,14 @@ void FetchManager::Loader::Abort() {
NotifyFinished();
}
void FetchManager::Loader::PerformSchemeFetch(ExceptionState& exception_state) {
void FetchManager::Loader::PerformSchemeFetch() {
// "To perform a scheme fetch using |request|, switch on |request|'s url's
// scheme, and run the associated steps:"
if (SchemeRegistry::ShouldTreatURLSchemeAsSupportingFetchAPI(
fetch_request_data_->Url().Protocol()) ||
fetch_request_data_->Url().ProtocolIs("blob")) {
// "Return the result of performing an HTTP fetch using |request|."
PerformHTTPFetch(exception_state);
if (exception_state.HadException())
return;
PerformHTTPFetch();
} else if (fetch_request_data_->Url().ProtocolIsData()) {
PerformDataFetch();
} else {
......@@ -685,7 +683,7 @@ void FetchManager::Loader::PerformNetworkError(const String& message) {
Failed(message, nullptr);
}
void FetchManager::Loader::PerformHTTPFetch(ExceptionState& exception_state) {
void FetchManager::Loader::PerformHTTPFetch() {
// CORS preflight fetch procedure is implemented inside ThreadableLoader.
// "1. Let |HTTPRequest| be a copy of |request|, except that |HTTPRequest|'s
......@@ -732,10 +730,7 @@ void FetchManager::Loader::PerformHTTPFetch(ExceptionState& exception_state) {
fetch_request_data_->Method() != http_names::kHEAD) {
if (fetch_request_data_->Buffer()) {
scoped_refptr<EncodedFormData> form_data =
fetch_request_data_->Buffer()->DrainAsFormData(exception_state);
if (exception_state.HadException())
return;
fetch_request_data_->Buffer()->DrainAsFormData();
if (form_data) {
request.SetHttpBody(form_data);
} else if (RuntimeEnabledFeatures::OutOfBlinkCorsEnabled() &&
......@@ -743,13 +738,12 @@ void FetchManager::Loader::PerformHTTPFetch(ExceptionState& exception_state) {
execution_context_)) {
UseCounter::Count(execution_context_,
WebFeature::kFetchUploadStreaming);
DCHECK(!fetch_request_data_->Buffer()->IsStreamLocked());
mojo::PendingRemote<network::mojom::blink::ChunkedDataPipeGetter>
pending_remote;
fetch_request_data_->Buffer()->DrainAsChunkedDataPipeGetter(
resolver_->GetScriptState(),
pending_remote.InitWithNewPipeAndPassReceiver(), exception_state);
if (exception_state.HadException())
return;
pending_remote.InitWithNewPipeAndPassReceiver());
request.MutableBody().SetStreamBody(std::move(pending_remote));
request.SetAllowHTTP1ForStreamingUpload(
fetch_request_data_->AllowHTTP1ForStreamingUpload());
......@@ -881,28 +875,26 @@ ScriptPromise FetchManager::Fetch(ScriptState* script_state,
FetchRequestData* request,
AbortSignal* signal,
ExceptionState& exception_state) {
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
DCHECK(signal);
if (signal->aborted()) {
resolver->Reject(
MakeGarbageCollected<DOMException>(DOMExceptionCode::kAbortError));
return promise;
exception_state.ThrowDOMException(DOMExceptionCode::kAbortError,
"The user aborted a request.");
return ScriptPromise();
}
request->SetContext(mojom::RequestContextType::FETCH);
request->SetDestination(network::mojom::RequestDestination::kEmpty);
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
ScriptPromise promise = resolver->Promise();
auto* loader =
MakeGarbageCollected<Loader>(GetExecutionContext(), this, resolver,
request, &script_state->World(), signal);
loaders_.insert(loader);
signal->AddAlgorithm(WTF::Bind(&Loader::Abort, WrapWeakPersistent(loader)));
// TODO(ricea): Reject the Response body with AbortError, not TypeError.
loader->Start(exception_state);
if (exception_state.HadException())
return ScriptPromise();
loader->Start();
return promise;
}
......
......@@ -234,16 +234,13 @@ FetchRequestData* FetchRequestData::Clone(ScriptState* script_state,
return request;
}
FetchRequestData* FetchRequestData::Pass(ScriptState* script_state,
ExceptionState& exception_state) {
FetchRequestData* FetchRequestData::Pass(ScriptState* script_state) {
FetchRequestData* request = FetchRequestData::CloneExceptBody();
if (buffer_) {
request->buffer_ = buffer_;
buffer_ = BodyStreamBuffer::Create(
script_state, BytesConsumer::CreateClosed(), nullptr /* AbortSignal */);
buffer_->CloseAndLockAndDisturb(exception_state);
if (exception_state.HadException())
return nullptr;
buffer_->CloseAndLockAndDisturb();
}
request->url_loader_factory_ = std::move(url_loader_factory_);
return request;
......
......@@ -43,7 +43,7 @@ class CORE_EXPORT FetchRequestData final
mojom::blink::FetchAPIRequestPtr,
ForServiceWorkerFetchEvent);
FetchRequestData* Clone(ScriptState*, ExceptionState&);
FetchRequestData* Pass(ScriptState*, ExceptionState&);
FetchRequestData* Pass(ScriptState*);
explicit FetchRequestData(ExecutionContext* execution_context);
~FetchRequestData();
......
......@@ -75,11 +75,8 @@ class GlobalFetchImpl final : public GarbageCollected<GlobalFetchImpl<T>>,
return ScriptPromise();
probe::WillSendXMLHttpOrFetchNetworkRequest(execution_context, r->url());
FetchRequestData* request_data =
r->PassRequestData(script_state, exception_state);
FetchRequestData* request_data = r->PassRequestData(script_state);
MeasureFetchProperties(execution_context, request_data);
if (exception_state.HadException())
return ScriptPromise();
auto promise = fetch_manager_->Fetch(script_state, request_data,
r->signal(), exception_state);
if (exception_state.HadException())
......
......@@ -95,9 +95,8 @@ class ReadableStreamBytesConsumer::OnRejected final : public ScriptFunction {
ReadableStreamBytesConsumer::ReadableStreamBytesConsumer(
ScriptState* script_state,
ReadableStream* stream,
ExceptionState& exception_state)
: reader_(stream->GetReaderNotForAuthorCode(script_state, exception_state)),
ReadableStream* stream)
: reader_(stream->GetReaderNotForAuthorCode(script_state)),
script_state_(script_state) {}
ReadableStreamBytesConsumer::~ReadableStreamBytesConsumer() {}
......
......@@ -22,10 +22,10 @@ class ScriptState;
// This class is a BytesConsumer pulling bytes from a ReadableStream.
// The stream will be immediately locked by the consumer and will never be
// released.
// released. The stream must not be locked before this object is created.
class CORE_EXPORT ReadableStreamBytesConsumer final : public BytesConsumer {
public:
ReadableStreamBytesConsumer(ScriptState*, ReadableStream*, ExceptionState&);
ReadableStreamBytesConsumer(ScriptState*, ReadableStream*);
~ReadableStreamBytesConsumer() override;
Result BeginRead(const char** buffer, size_t* available) override;
......
......@@ -52,8 +52,7 @@ TEST(ReadableStreamBytesConsumerTest, Create) {
ASSERT_FALSE(exception_state.HadException());
Persistent<BytesConsumer> consumer =
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
ASSERT_NO_EXCEPTION);
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream);
EXPECT_EQ(PublicState::kReadableOrWaiting, consumer->GetPublicState());
}
......@@ -69,8 +68,7 @@ TEST(ReadableStreamBytesConsumerTest, EmptyStream) {
underlying_source->Close();
Persistent<BytesConsumer> consumer =
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
ASSERT_NO_EXCEPTION);
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream);
Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
consumer->SetClient(client);
......@@ -109,8 +107,7 @@ TEST(ReadableStreamBytesConsumerTest, ErroredStream) {
script_state->GetIsolate(), v8::Undefined(script_state->GetIsolate())));
Persistent<BytesConsumer> consumer =
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
ASSERT_NO_EXCEPTION);
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream);
Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
consumer->SetClient(client);
Checkpoint checkpoint;
......@@ -166,8 +163,7 @@ TEST(ReadableStreamBytesConsumerTest, TwoPhaseRead) {
}
Persistent<BytesConsumer> consumer =
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
ASSERT_NO_EXCEPTION);
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream);
Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
consumer->SetClient(client);
Checkpoint checkpoint;
......@@ -258,8 +254,7 @@ TEST(ReadableStreamBytesConsumerTest, EnqueueUndefined) {
underlying_source->Close();
Persistent<BytesConsumer> consumer =
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
ASSERT_NO_EXCEPTION);
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream);
Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
consumer->SetClient(client);
Checkpoint checkpoint;
......@@ -298,8 +293,7 @@ TEST(ReadableStreamBytesConsumerTest, EnqueueNull) {
underlying_source->Close();
Persistent<BytesConsumer> consumer =
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
ASSERT_NO_EXCEPTION);
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream);
Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
consumer->SetClient(client);
Checkpoint checkpoint;
......@@ -339,8 +333,7 @@ TEST(ReadableStreamBytesConsumerTest, EnqueueString) {
underlying_source->Close();
Persistent<BytesConsumer> consumer =
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream,
ASSERT_NO_EXCEPTION);
MakeGarbageCollected<ReadableStreamBytesConsumer>(script_state, stream);
Persistent<MockClient> client = MakeGarbageCollected<MockClient>();
consumer->SetClient(client);
Checkpoint checkpoint;
......
......@@ -183,6 +183,20 @@ static BodyStreamBuffer* ExtractBody(ScriptState* script_state,
V8ReadableStream::HasInstance(body, isolate)) {
ReadableStream* readable_stream =
V8ReadableStream::ToImpl(body.As<v8::Object>());
// This is implemented in Request::CreateRequestWithRequestOrString():
// "If the |keepalive| flag is set, then throw a TypeError."
// "If |object| is disturbed or locked, then throw a TypeError."
if (readable_stream->IsDisturbed()) {
exception_state.ThrowTypeError(
"The provided ReadableStream is disturbed");
return nullptr;
}
if (readable_stream->IsLocked()) {
exception_state.ThrowTypeError("The provided ReadableStream is locked");
return nullptr;
}
// "Set |stream| to |object|."
return_buffer =
MakeGarbageCollected<BodyStreamBuffer>(script_state, readable_stream);
} else {
......@@ -688,9 +702,7 @@ Request* Request::CreateRequestWithRequestOrString(
input_request->request_->SetBuffer(dummy_stream);
// "Let |reader| be the result of getting reader from |dummyStream|."
// "Read all bytes from |dummyStream| with |reader|."
input_request->BodyBuffer()->CloseAndLockAndDisturb(exception_state);
if (exception_state.HadException())
return nullptr;
input_request->BodyBuffer()->CloseAndLockAndDisturb();
}
// "Return |r|."
......@@ -931,12 +943,9 @@ Request* Request::clone(ScriptState* script_state,
return MakeGarbageCollected<Request>(script_state, request, headers, signal);
}
FetchRequestData* Request::PassRequestData(ScriptState* script_state,
ExceptionState& exception_state) {
FetchRequestData* Request::PassRequestData(ScriptState* script_state) {
DCHECK(!IsBodyUsed());
FetchRequestData* data = request_->Pass(script_state, exception_state);
if (exception_state.HadException())
return nullptr;
FetchRequestData* data = request_->Pass(script_state);
// |data|'s buffer('s js wrapper) has no retainer, but it's OK because
// the only caller is the fetch function and it uses the body buffer
// immediately.
......
......@@ -93,7 +93,7 @@ class CORE_EXPORT Request final : public ScriptWrappable,
return Body::HasPendingActivity();
}
FetchRequestData* PassRequestData(ScriptState*, ExceptionState&);
FetchRequestData* PassRequestData(ScriptState*);
mojom::blink::FetchAPIRequestPtr CreateFetchAPIRequest() const;
bool HasBody() const;
BodyStreamBuffer* BodyBuffer() override { return request_->Buffer(); }
......
......@@ -1581,19 +1581,13 @@ void ReadableStream::Tee(ScriptState* script_state,
*branch2 = engine->Branch2();
}
void ReadableStream::LockAndDisturb(ScriptState* script_state,
ExceptionState& exception_state) {
ScriptState::Scope scope(script_state);
void ReadableStream::LockAndDisturb(ScriptState* script_state) {
if (reader_) {
return;
}
ReadableStreamReader* reader =
AcquireDefaultReader(script_state, this, false, exception_state);
if (!reader) {
return;
}
ReadableStreamReader* reader = GetReaderNotForAuthorCode(script_state);
DCHECK(reader);
is_disturbed_ = true;
}
......@@ -1633,8 +1627,11 @@ ReadableStream* ReadableStream::Deserialize(ScriptState* script_state,
}
ReadableStreamDefaultReader* ReadableStream::GetReaderNotForAuthorCode(
ScriptState* script_state,
ExceptionState& exception_state) {
ScriptState* script_state) {
DCHECK(!IsLocked(this));
// Since the stream is not locked, AcquireDefaultReader cannot fail.
NonThrowableExceptionState exception_state(__FILE__, __LINE__);
return AcquireDefaultReader(script_state, this, false, exception_state);
}
......
......@@ -153,7 +153,7 @@ class CORE_EXPORT ReadableStream : public ScriptWrappable {
bool IsErrored() const { return IsErrored(this); }
void LockAndDisturb(ScriptState*, ExceptionState&);
void LockAndDisturb(ScriptState*);
void Serialize(ScriptState*, MessagePort* port, ExceptionState&);
......@@ -164,9 +164,9 @@ class CORE_EXPORT ReadableStream : public ScriptWrappable {
// Returns a reader that doesn't have the |for_author_code_| flag set. This is
// used in contexts where reads should not be interceptable by user code. This
// corresponds to calling AcquireReadableStreamDefaultReader(stream, false) in
// specification language.
ReadableStreamDefaultReader* GetReaderNotForAuthorCode(ScriptState*,
ExceptionState&);
// specification language. The caller must ensure that the stream is not
// locked.
ReadableStreamDefaultReader* GetReaderNotForAuthorCode(ScriptState*);
//
// Readable stream abstract operations
......
......@@ -336,7 +336,6 @@ TEST_F(ReadableStreamTest, Error) {
TEST_F(ReadableStreamTest, LockAndDisturb) {
V8TestingScope scope;
ScriptState* script_state = scope.GetScriptState();
ExceptionState& exception_state = scope.GetExceptionState();
auto* underlying_source =
MakeGarbageCollected<TestUnderlyingSource>(script_state);
......@@ -348,8 +347,7 @@ TEST_F(ReadableStreamTest, LockAndDisturb) {
EXPECT_FALSE(stream->IsLocked());
EXPECT_FALSE(stream->IsDisturbed());
stream->LockAndDisturb(script_state, exception_state);
ASSERT_FALSE(exception_state.HadException());
stream->LockAndDisturb(script_state);
EXPECT_TRUE(stream->IsLocked());
EXPECT_TRUE(stream->IsDisturbed());
......
......@@ -143,10 +143,7 @@ scoped_refptr<BlobDataHandle> ExtractBlobHandle(
return nullptr;
auto blob_handle = buffer->DrainAsBlobDataHandle(
BytesConsumer::BlobSizePolicy::kDisallowBlobWithInvalidSize,
exception_state);
if (exception_state.HadException())
return nullptr;
BytesConsumer::BlobSizePolicy::kDisallowBlobWithInvalidSize);
return blob_handle;
}
......
......@@ -327,12 +327,8 @@ void FetchRespondWithObserver::OnResponseFulfilled(
scoped_refptr<BlobDataHandle> blob_data_handle =
buffer->DrainAsBlobDataHandle(
BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize,
exception_state);
if (exception_state.HadException()) {
OnResponseRejected(ServiceWorkerResponseError::kResponseBodyBroken);
return;
}
BytesConsumer::BlobSizePolicy::kAllowBlobWithInvalidSize);
if (blob_data_handle) {
// Handle the blob response body.
fetch_api_response->blob = blob_data_handle;
......
......@@ -75,10 +75,14 @@ ImageDecoderExternal::ImageDecoderExternal(ScriptState* script_state,
prefer_animation_ = init->preferAnimation();
if (init->data().IsReadableStream()) {
consumer_ = MakeGarbageCollected<ReadableStreamBytesConsumer>(
script_state, init->data().GetAsReadableStream(), exception_state);
if (exception_state.HadException())
if (init->data().GetAsReadableStream()->IsLocked()) {
exception_state.ThrowTypeError(
"ImageDecoder can only accept readable streams that are not yet "
"locked to a reader");
return;
}
consumer_ = MakeGarbageCollected<ReadableStreamBytesConsumer>(
script_state, init->data().GetAsReadableStream());
stream_buffer_ = WTF::SharedBuffer::Create();
CreateImageDecoder();
......
This is a testharness.js-based test.
PASS Constructing a Request with a stream holds the original object.
FAIL Constructing a Request with a stream on which getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() and releaseLock() are called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
PASS Constructing a Request with a stream on which getReader() is called
PASS Constructing a Request with a stream on which read() is called
PASS Constructing a Request with a stream on which read() and releaseLock() are called
FAIL Constructing a Request with a Request on which body.getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a Request on which body.getReader().read() is called promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'Request': Cannot construct a Request with a Request object that has already been used."
FAIL Constructing a Request with a Request on which read() and releaseLock() are called promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'Request': Cannot construct a Request with a Request object that has already been used."
......
This is a testharness.js-based test.
PASS Constructing a Request with a stream holds the original object.
FAIL Constructing a Request with a stream on which getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() and releaseLock() are called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
PASS Constructing a Request with a stream on which getReader() is called
PASS Constructing a Request with a stream on which read() is called
PASS Constructing a Request with a stream on which read() and releaseLock() are called
FAIL Constructing a Request with a Request on which body.getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a Request on which body.getReader().read() is called promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'Request': Cannot construct a Request with a Request object that has already been used."
FAIL Constructing a Request with a Request on which read() and releaseLock() are called promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'Request': Cannot construct a Request with a Request object that has already been used."
......
This is a testharness.js-based test.
PASS Constructing a Request with a stream holds the original object.
FAIL Constructing a Request with a stream on which getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() and releaseLock() are called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
PASS Constructing a Request with a stream on which getReader() is called
PASS Constructing a Request with a stream on which read() is called
PASS Constructing a Request with a stream on which read() and releaseLock() are called
FAIL Constructing a Request with a Request on which body.getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a Request on which body.getReader().read() is called promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'Request': Cannot construct a Request with a Request object that has already been used."
FAIL Constructing a Request with a Request on which read() and releaseLock() are called promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'Request': Cannot construct a Request with a Request object that has already been used."
......
This is a testharness.js-based test.
PASS Constructing a Request with a stream holds the original object.
FAIL Constructing a Request with a stream on which getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() and releaseLock() are called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
PASS Constructing a Request with a stream on which getReader() is called
PASS Constructing a Request with a stream on which read() is called
PASS Constructing a Request with a stream on which read() and releaseLock() are called
FAIL Constructing a Request with a Request on which body.getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a Request on which body.getReader().read() is called promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'Request': Cannot construct a Request with a Request object that has already been used."
FAIL Constructing a Request with a Request on which read() and releaseLock() are called promise_test: Unhandled rejection with value: object "TypeError: Failed to construct 'Request': Cannot construct a Request with a Request object that has already been used."
......
This is a testharness.js-based test.
FAIL Constructing a Request with a stream on which getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() and releaseLock() are called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a Request on which body.getReader() is called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
FAIL Constructing a Request with a Request on which body.getReader().read() is called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
FAIL Constructing a Request with a Request on which read() and releaseLock() are called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Constructing a Request with a stream on which getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() and releaseLock() are called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a Request on which body.getReader() is called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
FAIL Constructing a Request with a Request on which body.getReader().read() is called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
FAIL Constructing a Request with a Request on which read() and releaseLock() are called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Constructing a Request with a stream on which getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() and releaseLock() are called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a Request on which body.getReader() is called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
FAIL Constructing a Request with a Request on which body.getReader().read() is called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
FAIL Constructing a Request with a Request on which read() and releaseLock() are called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
Harness: the test ran to completion.
This is a testharness.js-based test.
FAIL Constructing a Request with a stream on which getReader() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() is called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a stream on which read() and releaseLock() are called assert_throws_js: new Request() function "() => new Request(input, init)" did not throw
FAIL Constructing a Request with a Request on which body.getReader() is called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
FAIL Constructing a Request with a Request on which body.getReader().read() is called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
FAIL Constructing a Request with a Request on which read() and releaseLock() are called promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'getReader' of undefined"
Harness: the test ran to completion.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment