LibWeb: Implement a slightly better ad-hoc Body::clone method

Just creating a stream on the JS heap isn't enough, as we will later
crash when trying to read from that stream as it hasn't been properly
initialized. Instead, until we have teeing implemented (which is a
rather huge part of the Streams spec), create streams using proper AOs
that do initialize the stream.
This commit is contained in:
Timothy Flynn 2024-01-27 09:16:09 -05:00 committed by Andreas Kling
parent c8c3866101
commit 9272d185ad
3 changed files with 34 additions and 2 deletions

View file

@ -0,0 +1 @@
Was able to create a reader from a cloned Fetch response!

View file

@ -0,0 +1,17 @@
<script src="../include.js"></script>
<script>
asyncTest(async done => {
fetch("./../basic.html", { mode: "no-cors" })
.then(response => {
const clonedResponse = response.clone();
return clonedResponse.body;
})
.then(body => {
const reader = body.getReader();
reader.read();
println("Was able to create a reader from a cloned Fetch response!");
done();
});
});
</script>

View file

@ -9,6 +9,8 @@
#include <LibWeb/Fetch/BodyInit.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
#include <LibWeb/Fetch/Infrastructure/Task.h>
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
#include <LibWeb/Streams/AbstractOperations.h>
#include <LibWeb/WebIDL/Promise.h>
namespace Web::Fetch::Infrastructure {
@ -46,13 +48,25 @@ void Body::visit_edges(Cell::Visitor& visitor)
// https://fetch.spec.whatwg.org/#concept-body-clone
JS::NonnullGCPtr<Body> Body::clone(JS::Realm& realm) const
{
HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(realm), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes };
// To clone a body body, run these steps:
// FIXME: 1. Let « out1, out2 » be the result of teeing bodys stream.
// FIXME: 2. Set bodys stream to out1.
auto out2 = realm.heap().allocate<Streams::ReadableStream>(realm, realm);
JS::GCPtr<Streams::ReadableStream> out2;
Streams::StartAlgorithm start_algorithm = []() { return JS::js_undefined(); };
Streams::PullAlgorithm pull_algorithm = [&realm]() { return WebIDL::create_resolved_promise(realm, JS::js_undefined()); };
Streams::CancelAlgorithm cancel_algorithm = [&realm](auto) { return WebIDL::create_resolved_promise(realm, JS::js_undefined()); };
if (m_stream->controller()->has<JS::NonnullGCPtr<Streams::ReadableStreamDefaultController>>()) {
out2 = Streams::create_readable_stream(realm, move(start_algorithm), move(pull_algorithm), move(cancel_algorithm)).release_value_but_fixme_should_propagate_errors();
} else {
out2 = Streams::create_readable_byte_stream(realm, move(start_algorithm), move(pull_algorithm), move(cancel_algorithm)).release_value_but_fixme_should_propagate_errors();
}
// 3. Return a body whose stream is out2 and other members are copied from body.
return Body::create(realm.vm(), out2, m_source, m_length);
return Body::create(realm.vm(), *out2, m_source, m_length);
}
// https://fetch.spec.whatwg.org/#body-fully-read