/src/serenity/Userland/Libraries/LibWeb/Fetch/Fetching/FetchedDataReceiver.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <LibJS/Heap/HeapFunction.h> |
8 | | #include <LibWeb/Bindings/ExceptionOrUtils.h> |
9 | | #include <LibWeb/Bindings/HostDefined.h> |
10 | | #include <LibWeb/Fetch/Fetching/FetchedDataReceiver.h> |
11 | | #include <LibWeb/Fetch/Infrastructure/FetchParams.h> |
12 | | #include <LibWeb/Fetch/Infrastructure/Task.h> |
13 | | #include <LibWeb/HTML/Scripting/ExceptionReporter.h> |
14 | | #include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h> |
15 | | #include <LibWeb/Streams/AbstractOperations.h> |
16 | | #include <LibWeb/WebIDL/Promise.h> |
17 | | |
18 | | namespace Web::Fetch::Fetching { |
19 | | |
20 | | JS_DEFINE_ALLOCATOR(FetchedDataReceiver); |
21 | | |
22 | | FetchedDataReceiver::FetchedDataReceiver(JS::NonnullGCPtr<Infrastructure::FetchParams const> fetch_params, JS::NonnullGCPtr<Streams::ReadableStream> stream) |
23 | 0 | : m_fetch_params(fetch_params) |
24 | 0 | , m_stream(stream) |
25 | 0 | { |
26 | 0 | } |
27 | | |
28 | 0 | FetchedDataReceiver::~FetchedDataReceiver() = default; |
29 | | |
30 | | void FetchedDataReceiver::visit_edges(Visitor& visitor) |
31 | 0 | { |
32 | 0 | Base::visit_edges(visitor); |
33 | 0 | visitor.visit(m_fetch_params); |
34 | 0 | visitor.visit(m_stream); |
35 | 0 | visitor.visit(m_pending_promise); |
36 | 0 | } |
37 | | |
38 | | void FetchedDataReceiver::set_pending_promise(JS::NonnullGCPtr<WebIDL::Promise> promise) |
39 | 0 | { |
40 | 0 | auto had_pending_promise = m_pending_promise != nullptr; |
41 | 0 | m_pending_promise = promise; |
42 | |
|
43 | 0 | if (!had_pending_promise && !m_buffer.is_empty()) { |
44 | 0 | on_data_received(m_buffer); |
45 | 0 | m_buffer.clear(); |
46 | 0 | } |
47 | 0 | } |
48 | | |
49 | | // This implements the parallel steps of the pullAlgorithm in HTTP-network-fetch. |
50 | | // https://fetch.spec.whatwg.org/#ref-for-in-parallel④ |
51 | | void FetchedDataReceiver::on_data_received(ReadonlyBytes bytes) |
52 | 0 | { |
53 | | // FIXME: 1. If the size of buffer is smaller than a lower limit chosen by the user agent and the ongoing fetch |
54 | | // is suspended, resume the fetch. |
55 | | // FIXME: 2. Wait until buffer is not empty. |
56 | | |
57 | | // If the remote end sends data immediately after we receive headers, we will often get that data here before the |
58 | | // stream tasks have all been queued internally. Just hold onto that data. |
59 | 0 | if (!m_pending_promise) { |
60 | 0 | m_buffer.append(bytes); |
61 | 0 | return; |
62 | 0 | } |
63 | | |
64 | | // 3. Queue a fetch task to run the following steps, with fetchParams’s task destination. |
65 | 0 | Infrastructure::queue_fetch_task( |
66 | 0 | m_fetch_params->controller(), |
67 | 0 | m_fetch_params->task_destination().get<JS::NonnullGCPtr<JS::Object>>(), |
68 | 0 | JS::create_heap_function(heap(), [this, bytes = MUST(ByteBuffer::copy(bytes))]() mutable { |
69 | 0 | HTML::TemporaryExecutionContext execution_context { Bindings::host_defined_environment_settings_object(m_stream->realm()), HTML::TemporaryExecutionContext::CallbacksEnabled::Yes }; |
70 | | |
71 | | // 1. Pull from bytes buffer into stream. |
72 | 0 | if (auto result = Streams::readable_stream_pull_from_bytes(m_stream, move(bytes)); result.is_error()) { |
73 | 0 | auto throw_completion = Bindings::dom_exception_to_throw_completion(m_stream->vm(), result.release_error()); |
74 | |
|
75 | 0 | dbgln("FetchedDataReceiver: Stream error pulling bytes"); |
76 | 0 | HTML::report_exception(throw_completion, m_stream->realm()); |
77 | |
|
78 | 0 | return; |
79 | 0 | } |
80 | | |
81 | | // 2. If stream is errored, then terminate fetchParams’s controller. |
82 | 0 | if (m_stream->is_errored()) |
83 | 0 | m_fetch_params->controller()->terminate(); |
84 | | |
85 | | // 3. Resolve promise with undefined. |
86 | 0 | WebIDL::resolve_promise(m_stream->realm(), *m_pending_promise, JS::js_undefined()); |
87 | 0 | })); |
88 | 0 | } |
89 | | |
90 | | } |