LibWeb: Use last promise to wait for pending writes ReadableStreamPipeTo

ReadableStreamPipeTo is used in fetching, and previously requests with
large bodies could lead to tens of thousands of pending write promises
being accumulated in `m_pending_writes`.

With this change, instead of accumulating all pending write promises up
until pipe shutdown, we only keep track of the last one and use it to
determine whether there are pending writes when we need to shut down the
pipe.
This commit is contained in:
Aliaksandr Kalenik
2025-12-08 16:11:07 +01:00
committed by Tim Flynn
parent 77cab84620
commit 18089937a5
Notes: github-actions[bot] 2025-12-08 16:46:22 +00:00
2 changed files with 14 additions and 10 deletions

View File

@@ -100,7 +100,7 @@ void ReadableStreamPipeTo::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_reader);
visitor.visit(m_writer);
visitor.visit(m_signal);
visitor.visit(m_pending_writes);
visitor.visit(m_last_write_promise);
visitor.visit(m_unwritten_chunks);
}
@@ -258,7 +258,7 @@ void ReadableStreamPipeTo::write_chunk()
auto promise = writable_stream_default_writer_write(m_writer, m_unwritten_chunks.take_first());
WebIDL::mark_promise_as_handled(promise);
m_pending_writes.append(promise);
m_last_write_promise = promise;
}
void ReadableStreamPipeTo::write_unwritten_chunks()
@@ -269,15 +269,19 @@ void ReadableStreamPipeTo::write_unwritten_chunks()
void ReadableStreamPipeTo::wait_for_pending_writes_to_complete(Function<void()> on_complete)
{
auto handler = GC::create_function(heap(), [this, on_complete = move(on_complete)]() {
m_pending_writes.clear();
auto last_write_promise = m_last_write_promise;
m_last_write_promise = {};
if (!last_write_promise) {
HTML::queue_a_microtask(nullptr, GC::create_function(heap(), [on_complete = move(on_complete)]() {
on_complete();
}));
return;
}
auto run_complete_steps = GC::create_function(heap(), [on_complete = move(on_complete)](JS::Value) -> WebIDL::ExceptionOr<JS::Value> {
on_complete();
return JS::js_undefined();
});
auto success_steps = [handler](Vector<JS::Value> const&) { handler->function()(); };
auto failure_steps = [handler](JS::Value) { handler->function()(); };
WebIDL::wait_for_all(m_realm, m_pending_writes, move(success_steps), move(failure_steps));
WebIDL::react_to_promise(*last_write_promise, run_complete_steps, run_complete_steps);
}
// https://streams.spec.whatwg.org/#rs-pipeTo-finalize