Skip to content

Commit c8d121f

Browse files
committed
LibWeb: Implement most of the 'Fetching' AOs
This implements the following operations from section 4 of the Fetch spec (https://fetch.spec.whatwg.org/#fetching): - Fetch - Main fetch - Fetch response handover - Scheme fetch - HTTP fetch - HTTP-redirect fetch - HTTP-network-or-cache fetch (without caching) It does *not* implement: - HTTP-network fetch - CORS-preflight fetch Instead, we let ResourceLoader handle the actual networking for now, which isn't ideal, but certainly enough to get enough functionality up and running for most websites to not complain.
1 parent 4db8549 commit c8d121f

File tree

9 files changed

+1833
-0
lines changed

9 files changed

+1833
-0
lines changed

Userland/Libraries/LibWeb/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ set(SOURCES
123123
Fetch/BodyInit.cpp
124124
Fetch/Enums.cpp
125125
Fetch/Fetching/Checks.cpp
126+
Fetch/Fetching/Fetching.cpp
127+
Fetch/Fetching/PendingResponse.cpp
128+
Fetch/Fetching/RefCountedFlag.cpp
126129
Fetch/Headers.cpp
127130
Fetch/HeadersIterator.cpp
128131
Fetch/Infrastructure/ConnectionTimingInfo.cpp

Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp

Lines changed: 1629 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#pragma once
8+
9+
#include <AK/Forward.h>
10+
#include <LibJS/Forward.h>
11+
#include <LibWeb/Forward.h>
12+
13+
namespace Web::Fetch::Fetching {
14+
15+
#define ENUMERATE_BOOL_PARAMS \
16+
__ENUMERATE_BOOL_PARAM(IncludeCredentials) \
17+
__ENUMERATE_BOOL_PARAM(IsAuthenticationFetch) \
18+
__ENUMERATE_BOOL_PARAM(IsNewConnectionFetch) \
19+
__ENUMERATE_BOOL_PARAM(MakeCORSPreflight) \
20+
__ENUMERATE_BOOL_PARAM(Recursive) \
21+
__ENUMERATE_BOOL_PARAM(UseParallelQueue)
22+
23+
#define __ENUMERATE_BOOL_PARAM(Name) \
24+
enum class Name { \
25+
Yes, \
26+
No, \
27+
};
28+
ENUMERATE_BOOL_PARAMS
29+
#undef __ENUMERATE_BOOL_PARAM
30+
31+
WebIDL::ExceptionOr<JS::NonnullGCPtr<Infrastructure::FetchController>> fetch(JS::Realm&, Infrastructure::Request&, Infrastructure::FetchAlgorithms const&, UseParallelQueue use_parallel_queue = UseParallelQueue::No);
32+
WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::Realm&, Infrastructure::FetchParams const&, Recursive recursive = Recursive::No);
33+
WebIDL::ExceptionOr<void> fetch_response_handover(JS::Realm&, Infrastructure::FetchParams const&, Infrastructure::Response const&);
34+
WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> scheme_fetch(JS::Realm&, Infrastructure::FetchParams const&);
35+
WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_fetch(JS::Realm&, Infrastructure::FetchParams const&, MakeCORSPreflight make_cors_preflight = MakeCORSPreflight::No);
36+
WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_redirect_fetch(JS::Realm&, Infrastructure::FetchParams const&, Infrastructure::Response const&);
37+
WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> http_network_or_cache_fetch(JS::Realm&, Infrastructure::FetchParams const&, IsAuthenticationFetch is_authentication_fetch = IsAuthenticationFetch::No, IsNewConnectionFetch is_new_connection_fetch = IsNewConnectionFetch::No);
38+
WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_loader_http_network_fetch(JS::Realm&, Infrastructure::FetchParams const&, IncludeCredentials include_credentials = IncludeCredentials::No, IsNewConnectionFetch is_new_connection_fetch = IsNewConnectionFetch::No);
39+
40+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#include <LibJS/Heap/Heap.h>
8+
#include <LibJS/Runtime/VM.h>
9+
#include <LibWeb/Fetch/Fetching/PendingResponse.h>
10+
#include <LibWeb/Platform/EventLoopPlugin.h>
11+
12+
namespace Web::Fetch::Fetching {
13+
14+
JS::NonnullGCPtr<PendingResponse> PendingResponse::create(JS::VM& vm)
15+
{
16+
return { *vm.heap().allocate_without_realm<PendingResponse>() };
17+
}
18+
19+
JS::NonnullGCPtr<PendingResponse> PendingResponse::create(JS::VM& vm, JS::NonnullGCPtr<Infrastructure::Response> response)
20+
{
21+
return { *vm.heap().allocate_without_realm<PendingResponse>(response) };
22+
}
23+
24+
PendingResponse::PendingResponse(JS::NonnullGCPtr<Infrastructure::Response> response)
25+
: m_response(response)
26+
{
27+
}
28+
29+
void PendingResponse::visit_edges(JS::Cell::Visitor& visitor)
30+
{
31+
Base::visit_edges(visitor);
32+
visitor.visit(m_response);
33+
}
34+
35+
void PendingResponse::when_loaded(Callback callback)
36+
{
37+
VERIFY(!m_callback);
38+
m_callback = move(callback);
39+
if (m_response)
40+
run_callback();
41+
}
42+
43+
void PendingResponse::resolve(JS::NonnullGCPtr<Infrastructure::Response> response)
44+
{
45+
VERIFY(!m_response);
46+
m_response = response;
47+
if (m_callback)
48+
run_callback();
49+
}
50+
51+
void PendingResponse::run_callback() const
52+
{
53+
VERIFY(m_callback);
54+
VERIFY(m_response);
55+
Platform::EventLoopPlugin::the().deferred_invoke([strong_this = JS::make_handle(const_cast<PendingResponse&>(*this))]() {
56+
strong_this->m_callback(*strong_this->m_response);
57+
});
58+
}
59+
60+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#pragma once
8+
9+
#include <LibJS/Forward.h>
10+
#include <LibJS/Heap/Cell.h>
11+
#include <LibJS/SafeFunction.h>
12+
#include <LibWeb/Fetch/Infrastructure/HTTP/Responses.h>
13+
14+
namespace Web::Fetch::Fetching {
15+
16+
// Non-standard wrapper around a possibly pending Infrastructure::Response.
17+
// This is needed to fit the asynchronous nature of ResourceLoader into the synchronous expectations
18+
// of the Fetch spec - we run 'in parallel' as a deferred_invoke(), which is still on the main thread;
19+
// therefore we use callbacks to run portions of the spec that require waiting for an HTTP load.
20+
class PendingResponse : public JS::Cell {
21+
JS_CELL(PendingResponse, JS::Cell);
22+
23+
public:
24+
using Callback = JS::SafeFunction<void(JS::NonnullGCPtr<Infrastructure::Response>)>;
25+
26+
[[nodiscard]] static JS::NonnullGCPtr<PendingResponse> create(JS::VM&);
27+
[[nodiscard]] static JS::NonnullGCPtr<PendingResponse> create(JS::VM&, JS::NonnullGCPtr<Infrastructure::Response>);
28+
29+
void when_loaded(Callback);
30+
void resolve(JS::NonnullGCPtr<Infrastructure::Response>);
31+
32+
private:
33+
PendingResponse() = default;
34+
explicit PendingResponse(JS::NonnullGCPtr<Infrastructure::Response>);
35+
36+
virtual void visit_edges(JS::Cell::Visitor&) override;
37+
38+
void run_callback() const;
39+
40+
Callback m_callback;
41+
JS::GCPtr<Infrastructure::Response> m_response;
42+
};
43+
44+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#include <AK/NonnullRefPtr.h>
8+
#include <LibWeb/Fetch/Fetching/RefCountedFlag.h>
9+
10+
namespace Web::Fetch::Fetching {
11+
12+
NonnullRefPtr<RefCountedFlag> RefCountedFlag::create(bool value)
13+
{
14+
return adopt_ref(*new RefCountedFlag(value));
15+
}
16+
17+
RefCountedFlag::RefCountedFlag(bool value)
18+
: m_value(value)
19+
{
20+
}
21+
22+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#pragma once
8+
9+
#include <AK/RefCounted.h>
10+
11+
namespace Web::Fetch::Fetching {
12+
13+
/// A ref-counted boolean flag.
14+
/// This is used to share flags between multiple callback closures.
15+
class RefCountedFlag : public RefCounted<RefCountedFlag> {
16+
public:
17+
static NonnullRefPtr<RefCountedFlag> create(bool);
18+
19+
[[nodiscard]] bool value() const { return m_value; }
20+
void set_value(bool value) { m_value = value; }
21+
22+
private:
23+
explicit RefCountedFlag(bool);
24+
25+
bool m_value { false };
26+
};
27+
28+
}

Userland/Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* SPDX-License-Identifier: BSD-2-Clause
55
*/
66

7+
#include <AK/Debug.h>
78
#include <AK/URLParser.h>
89
#include <LibJS/Heap/Heap.h>
910
#include <LibJS/Runtime/VM.h>
@@ -43,6 +44,7 @@ JS::NonnullGCPtr<Response> Response::aborted_network_error(JS::VM& vm)
4344

4445
JS::NonnullGCPtr<Response> Response::network_error(JS::VM& vm, String message)
4546
{
47+
dbgln_if(WEB_FETCH_DEBUG, "Fetch: Creating network error response with message: {}", message);
4648
auto response = Response::create(vm);
4749
response->set_status(0);
4850
response->set_type(Type::Error);

Userland/Libraries/LibWeb/Forward.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,11 @@ class Request;
189189
class Response;
190190
}
191191

192+
namespace Web::Fetch::Fetching {
193+
class PendingResponse;
194+
class RefCountedFlag;
195+
}
196+
192197
namespace Web::Fetch::Infrastructure {
193198
class Body;
194199
struct BodyWithType;

0 commit comments

Comments
 (0)