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

Make IsLocked() take an ExceptionState& argument

Modify blink::ReadableStreamOperations::IsLocked() to take an
ExceptionState& parameter. Modify all callers so that the ExceptionState
is passed through all the way from the bindings layer.

Make Body::IsBodyLocked() return an enum { kLocked, kUnlocked, kBroken }
similar to IsBodyUsed.

Bug: 853189
Change-Id: I3b2350c845bfa57c0123c4426ef8c0b2e3eb6ddc
Reviewed-on: https://chromium-review.googlesource.com/1114938Reviewed-by: default avatarYuki Shiino <yukishiino@chromium.org>
Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarTsuyoshi Horo <horo@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Commit-Position: refs/heads/master@{#571025}
parent 830112b0
......@@ -171,7 +171,7 @@ void CompileFromResponseCallback(
return;
}
if (response->IsBodyLocked() ||
if (response->IsBodyLocked(exception_state) == Body::BodyLocked::kLocked ||
response->IsBodyUsed(exception_state) == Body::BodyUsed::kUsed) {
DCHECK(!exception_state.HadException());
exception_state.ThrowTypeError(
......
......@@ -308,9 +308,14 @@ Body::BodyUsed Body::IsBodyUsed(ExceptionState& exception_state) {
return stream_disturbed.value() ? BodyUsed::kUsed : BodyUsed::kUnused;
}
bool Body::IsBodyLocked() {
Body::BodyLocked Body::IsBodyLocked(ExceptionState& exception_state) {
auto* body_buffer = BodyBuffer();
return body_buffer && body_buffer->IsStreamLocked();
if (!body_buffer)
return BodyLocked::kUnlocked;
base::Optional<bool> is_locked = body_buffer->IsStreamLocked(exception_state);
if (exception_state.HadException())
return BodyLocked::kBroken;
return is_locked.value() ? BodyLocked::kLocked : BodyLocked::kUnlocked;
}
bool Body::HasPendingActivity() const {
......@@ -337,8 +342,12 @@ void Body::RejectInvalidConsumption(ScriptState* script_state,
}
DCHECK_NE(used, BodyUsed::kBroken);
if (IsBodyLocked())
if (IsBodyLocked(exception_state) == BodyLocked::kLocked) {
DCHECK(!exception_state.HadException());
exception_state.ThrowTypeError("body stream is locked");
}
if (exception_state.HadException())
return;
if (used == BodyUsed::kUsed)
exception_state.ThrowTypeError("body stream already read");
......
......@@ -36,6 +36,7 @@ class CORE_EXPORT Body : public ScriptWrappable,
public:
enum class BodyUsed { kUsed, kUnused, kBroken };
enum class BodyLocked { kLocked, kUnlocked, kBroken };
explicit Body(ExecutionContext*);
......@@ -58,7 +59,9 @@ class CORE_EXPORT Body : public ScriptWrappable,
// pending and the caller should return to JavaScript immediately.
virtual BodyUsed IsBodyUsed(ExceptionState&);
bool IsBodyLocked();
// Returns kLocked, kUnlocked or kBroken. kBroken implies there is an
// exception pending and the caller should return to JavaScript immediately.
BodyLocked IsBodyLocked(ExceptionState&);
// ScriptWrappable override.
bool HasPendingActivity() const override;
......
......@@ -175,7 +175,7 @@ ScriptValue BodyStreamBuffer::Stream() {
scoped_refptr<BlobDataHandle> BodyStreamBuffer::DrainAsBlobDataHandle(
BytesConsumer::BlobSizePolicy policy,
ExceptionState& exception_state) {
DCHECK(!IsStreamLocked());
DCHECK(!IsStreamLockedForDCheck());
DCHECK(!IsStreamDisturbedForDCheck());
if (IsStreamClosed() || IsStreamErrored())
return nullptr;
......@@ -196,7 +196,7 @@ scoped_refptr<BlobDataHandle> BodyStreamBuffer::DrainAsBlobDataHandle(
scoped_refptr<EncodedFormData> BodyStreamBuffer::DrainAsFormData(
ExceptionState& exception_state) {
DCHECK(!IsStreamLocked());
DCHECK(!IsStreamLockedForDCheck());
DCHECK(!IsStreamDisturbedForDCheck());
if (IsStreamClosed() || IsStreamErrored())
return nullptr;
......@@ -239,7 +239,7 @@ void BodyStreamBuffer::StartLoading(FetchDataLoader* loader,
void BodyStreamBuffer::Tee(BodyStreamBuffer** branch1,
BodyStreamBuffer** branch2,
ExceptionState& exception_state) {
DCHECK(!IsStreamLocked());
DCHECK(!IsStreamLockedForDCheck());
DCHECK(!IsStreamDisturbedForDCheck());
*branch1 = nullptr;
*branch2 = nullptr;
......@@ -359,9 +359,15 @@ bool BodyStreamBuffer::IsStreamErrored() {
true);
}
bool BodyStreamBuffer::IsStreamLocked() {
return BooleanStreamOperationOrFallback(ReadableStreamOperations::IsLocked,
true);
base::Optional<bool> BodyStreamBuffer::IsStreamLocked(
ExceptionState& exception_state) {
return BooleanStreamOperation(ReadableStreamOperations::IsLocked,
exception_state);
}
bool BodyStreamBuffer::IsStreamLockedForDCheck() {
return ReadableStreamOperations::IsLockedForDCheck(script_state_.get(),
Stream());
}
base::Optional<bool> BodyStreamBuffer::IsStreamDisturbed(
......@@ -521,7 +527,7 @@ base::Optional<bool> BodyStreamBuffer::BooleanStreamOperation(
BytesConsumer* BodyStreamBuffer::ReleaseHandle(
ExceptionState& exception_state) {
DCHECK(!IsStreamLocked());
DCHECK(!IsStreamLockedForDCheck());
DCHECK(!IsStreamDisturbedForDCheck());
if (stream_broken_) {
......
......@@ -65,7 +65,8 @@ class CORE_EXPORT BodyStreamBuffer final : public UnderlyingSourceBase,
base::Optional<bool> IsStreamReadable(ExceptionState&);
bool IsStreamClosed();
bool IsStreamErrored();
bool IsStreamLocked();
base::Optional<bool> IsStreamLocked(ExceptionState&);
bool IsStreamLockedForDCheck();
base::Optional<bool> IsStreamDisturbed(ExceptionState&);
bool IsStreamDisturbedForDCheck();
void CloseAndLockAndDisturb(ExceptionState&);
......
......@@ -844,7 +844,8 @@ bool Request::isHistoryNavigation() const {
Request* Request::clone(ScriptState* script_state,
ExceptionState& exception_state) {
if (IsBodyLocked() || IsBodyUsed(exception_state) == BodyUsed::kUsed) {
if (IsBodyLocked(exception_state) == BodyLocked::kLocked ||
IsBodyUsed(exception_state) == BodyUsed::kUsed) {
DCHECK(!exception_state.HadException());
exception_state.ThrowTypeError("Request body is already used");
return nullptr;
......
......@@ -452,7 +452,8 @@ Headers* Response::headers() const {
Response* Response::clone(ScriptState* script_state,
ExceptionState& exception_state) {
if (IsBodyLocked() || IsBodyUsed(exception_state) == BodyUsed::kUsed) {
if (IsBodyLocked(exception_state) == BodyLocked::kLocked ||
IsBodyUsed(exception_state) == BodyUsed::kUsed) {
DCHECK(!exception_state.HadException());
exception_state.ThrowTypeError("Response body is already used");
return nullptr;
......
......@@ -77,13 +77,6 @@ bool BooleanOperationForDCheck(ScriptState* script_state,
return result.value();
}
// Performs IsReadableStreamLocked(stream), catching exceptions. Should only be
// used in DCHECK(). Returns false on exception.
bool IsLockedForDCheck(ScriptState* script_state, ScriptValue stream) {
return BooleanOperationForDCheck(script_state, stream,
"IsReadableStreamLocked", false);
}
// Performs IsReadableStreamDefaultReader(value), catching exceptions. Should
// only be used in DCHECK(). Returns true on exception.
bool IsDefaultReaderForDCheck(ScriptState* script_state, ScriptValue value) {
......@@ -175,9 +168,18 @@ bool ReadableStreamOperations::IsDisturbedForDCheck(ScriptState* script_state,
base::Optional<bool> ReadableStreamOperations::IsLocked(
ScriptState* script_state,
ScriptValue stream) {
ScriptValue stream,
ExceptionState& exception_state) {
DCHECK(IsReadableStreamForDCheck(script_state, stream));
return BooleanOperationWithRethrow(script_state, stream,
"IsReadableStreamLocked", exception_state);
}
bool ReadableStreamOperations::IsLockedForDCheck(ScriptState* script_state,
ScriptValue stream) {
DCHECK(IsReadableStreamForDCheck(script_state, stream));
return BooleanOperation(script_state, stream, "IsReadableStreamLocked");
return BooleanOperationForDCheck(script_state, stream,
"IsReadableStreamLocked", false);
}
base::Optional<bool> ReadableStreamOperations::IsReadable(
......
......@@ -82,7 +82,14 @@ class CORE_EXPORT ReadableStreamOperations {
// IsReadableStreamLocked.
// This function assumes |IsReadableStream(stream)|.
static base::Optional<bool> IsLocked(ScriptState*, ScriptValue stream);
static base::Optional<bool> IsLocked(ScriptState*,
ScriptValue stream,
ExceptionState&);
// Performs IsReadableStreamLocked.
// Catches exceptions, and returns false if there are any. Should only be used
// in a DCHECK statement that passes when the return value is false.
static bool IsLockedForDCheck(ScriptState*, ScriptValue stream);
// IsReadableStreamReadable.
// This function assumes |IsReadableStream(stream)|.
......
......@@ -171,12 +171,13 @@ TEST(ReadableStreamOperationsTest, GetReader) {
ScriptValue stream = EvalWithPrintingError(&scope, "new ReadableStream()");
EXPECT_FALSE(stream.IsEmpty());
EXPECT_FALSE(
ReadableStreamOperations::IsLocked(scope.GetScriptState(), stream)
.value_or(true));
EXPECT_FALSE(ReadableStreamOperations::IsLocked(scope.GetScriptState(),
stream, ASSERT_NO_EXCEPTION)
.value_or(true));
ScriptValue reader;
reader = ReadableStreamOperations::GetReader(scope.GetScriptState(), stream);
EXPECT_TRUE(ReadableStreamOperations::IsLocked(scope.GetScriptState(), stream)
EXPECT_TRUE(ReadableStreamOperations::IsLocked(scope.GetScriptState(), stream,
ASSERT_NO_EXCEPTION)
.value_or(false));
ASSERT_FALSE(reader.IsEmpty());
......
......@@ -747,7 +747,8 @@ ScriptPromise Cache::PutImpl(ScriptState* script_state,
"Partial response (status code 206) is unsupported");
return promise;
}
if (responses[i]->IsBodyLocked() ||
if (responses[i]->IsBodyLocked(exception_state) ==
Body::BodyLocked::kLocked ||
responses[i]->IsBodyUsed(exception_state) == Body::BodyUsed::kUsed) {
DCHECK(!exception_state.HadException());
barrier_callback->OnError("Response body is already used");
......
......@@ -241,13 +241,20 @@ void FetchRespondWithObserver::OnResponseFulfilled(
ServiceWorkerResponseError::kRedirectedResponseForNotFollowRequest);
return;
}
if (response->IsBodyLocked()) {
ExceptionState exception_state(value.GetScriptState()->GetIsolate(),
context_type, interface_name, property_name);
if (response->IsBodyLocked(exception_state) == Body::BodyLocked::kLocked) {
DCHECK(!exception_state.HadException());
OnResponseRejected(ServiceWorkerResponseError::kBodyLocked);
return;
}
ExceptionState exception_state(value.GetScriptState()->GetIsolate(),
context_type, interface_name, property_name);
if (exception_state.HadException()) {
OnResponseRejected(ServiceWorkerResponseError::kResponseBodyBroken);
return;
}
if (response->IsBodyUsed(exception_state) == Body::BodyUsed::kUsed) {
DCHECK(!exception_state.HadException());
OnResponseRejected(ServiceWorkerResponseError::kBodyUsed);
......
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