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

[Fetch] Prevent cloning body with no execution context

Attempting to Tee() a BodyStreamBuffer object when the execution context
was destroyed would crash the render process. Instead, explicitly throw
an exception.

This makes Request and Response clone() throw when there is a body.
clone() is still permitted when there is no body, which is convenient
for Request.

Bug: 1082688
Change-Id: I2d18f7a13b74caa89a9bd6c56eb9241bb2f5513d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2217753Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Commit-Position: refs/heads/master@{#773037}
parent c9b650e1
......@@ -486,8 +486,6 @@ BytesConsumer* BodyStreamBuffer::ReleaseHandle(
DCHECK(!IsStreamLocked());
DCHECK(!IsStreamDisturbed());
side_data_blob_.reset();
if (stream_broken_) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
......@@ -495,6 +493,18 @@ BytesConsumer* BodyStreamBuffer::ReleaseHandle(
return nullptr;
}
if (!GetExecutionContext()) {
// Avoid crashing if ContextDestroyed() has been called.
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Cannot release body in a window or worker than has been detached");
return nullptr;
}
// Do this after state checks to avoid side-effects when the method does
// nothing.
side_data_blob_.reset();
if (made_from_readable_stream_) {
ScriptState::Scope scope(script_state_);
auto* consumer = MakeGarbageCollected<ReadableStreamBytesConsumer>(
......
// Verify that calling Response clone() in a detached iframe doesn't crash.
// Regression test for https://crbug.com/1082688.
'use strict';
promise_test(async () => {
// Wait for the document body to be available.
await new Promise(resolve => {
onload = resolve;
});
window.iframe = document.createElement('iframe');
document.body.appendChild(iframe);
iframe.srcdoc = `<!doctype html>
<script>
const response = new Response('body');
window.parent.postMessage('okay', '*');
window.parent.iframe.remove();
response.clone();
</script>
`;
await new Promise(resolve => {
onmessage = evt => {
if (evt.data === 'okay') {
resolve();
}
};
});
// If it got here without crashing, the test passed.
}, 'clone within removed iframe should not crash');
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