1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-28 19:25:10 +00:00

LibWeb: Add definitions from '2.2.5 Requests' in the Fetch spec

This commit is contained in:
Linus Groh 2022-07-14 00:51:42 +01:00 committed by Andreas Kling
parent 4f02bac39c
commit 7116a7d2bf
4 changed files with 671 additions and 0 deletions

View file

@ -0,0 +1,230 @@
/*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Array.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Requests.h>
namespace Web::Fetch {
// https://fetch.spec.whatwg.org/#concept-request-url
AK::URL const& Request::url() const
{
// A request has an associated URL (a URL).
// NOTE: Implementations are encouraged to make this a pointer to the first URL in requests URL list. It is provided as a distinct field solely for the convenience of other standards hooking into Fetch.
VERIFY(!m_url_list.is_empty());
return m_url_list.first();
}
// https://fetch.spec.whatwg.org/#concept-request-current-url
AK::URL const& Request::current_url()
{
// A request has an associated current URL. It is a pointer to the last URL in requests URL list.
VERIFY(!m_url_list.is_empty());
return m_url_list.last();
}
void Request::set_url(AK::URL url)
{
// Sometimes setting the URL and URL list are done as two distinct steps in the spec,
// but since we know the URL is always the URL list's first item and doesn't change later
// on, we can combine them.
VERIFY(m_url_list.is_empty());
m_url_list.append(move(url));
}
// https://fetch.spec.whatwg.org/#request-destination-script-like
bool Request::destination_is_script_like() const
{
// A requests destination is script-like if it is "audioworklet", "paintworklet", "script", "serviceworker", "sharedworker", or "worker".
static constexpr Array script_like_destinations = {
Destination::AudioWorklet,
Destination::PaintWorklet,
Destination::Script,
Destination::ServiceWorker,
Destination::SharedWorker,
Destination::Worker,
};
return any_of(script_like_destinations, [this](auto destination) {
return m_destination == destination;
});
}
// https://fetch.spec.whatwg.org/#subresource-request
bool Request::is_subresource_request() const
{
// A subresource request is a request whose destination is "audio", "audioworklet", "font", "image", "manifest", "paintworklet", "script", "style", "track", "video", "xslt", or the empty string.
static constexpr Array subresource_request_destinations = {
Destination::Audio,
Destination::AudioWorklet,
Destination::Font,
Destination::Image,
Destination::Manifest,
Destination::PaintWorklet,
Destination::Script,
Destination::Style,
Destination::Track,
Destination::Video,
Destination::XSLT,
};
return any_of(subresource_request_destinations, [this](auto destination) {
return m_destination == destination;
}) || !m_destination.has_value();
}
// https://fetch.spec.whatwg.org/#non-subresource-request
bool Request::is_non_subresource_request() const
{
// A non-subresource request is a request whose destination is "document", "embed", "frame", "iframe", "object", "report", "serviceworker", "sharedworker", or "worker".
static constexpr Array non_subresource_request_destinations = {
Destination::Document,
Destination::Embed,
Destination::Frame,
Destination::IFrame,
Destination::Object,
Destination::Report,
Destination::ServiceWorker,
Destination::SharedWorker,
Destination::Worker,
};
return any_of(non_subresource_request_destinations, [this](auto destination) {
return m_destination == destination;
});
}
// https://fetch.spec.whatwg.org/#navigation-request
bool Request::is_navigation_request() const
{
// A navigation request is a request whose destination is "document", "embed", "frame", "iframe", or "object".
static constexpr Array navigation_request_destinations = {
Destination::Document,
Destination::Embed,
Destination::Frame,
Destination::IFrame,
Destination::Object,
};
return any_of(navigation_request_destinations, [this](auto destination) {
return m_destination == destination;
});
}
// https://fetch.spec.whatwg.org/#concept-request-tainted-origin
bool Request::has_redirect_tainted_origin() const
{
// A request request has a redirect-tainted origin if these steps return true:
// 1. Let lastURL be null.
Optional<AK::URL const&> last_url;
// 2. For each url in requests URL list:
for (auto const& url : m_url_list) {
// 1. If lastURL is null, then set lastURL to url and continue.
if (!last_url.has_value()) {
last_url = url;
continue;
}
// 2. If urls origin is not same origin with lastURLs origin and requests origin is not same origin with lastURLs origin, then return true.
// FIXME: Actually use the given origins once we have https://url.spec.whatwg.org/#concept-url-origin.
if (!HTML::Origin().is_same_origin(HTML::Origin()) && HTML::Origin().is_same_origin(HTML::Origin()))
return true;
// 3. Set lastURL to url.
last_url = url;
}
// 3. Return false.
return false;
}
// https://fetch.spec.whatwg.org/#serializing-a-request-origin
String Request::serialize_origin() const
{
// 1. If request has a redirect-tainted origin, then return "null".
if (has_redirect_tainted_origin())
return "null"sv;
// 2. Return requests origin, serialized.
return m_origin.get<HTML::Origin>().serialize();
}
// https://fetch.spec.whatwg.org/#byte-serializing-a-request-origin
ErrorOr<ByteBuffer> Request::byte_serialize_origin() const
{
// Byte-serializing a request origin, given a request request, is to return the result of serializing a request origin with request, isomorphic encoded.
return ByteBuffer::copy(serialize_origin().bytes());
}
// https://fetch.spec.whatwg.org/#concept-request-clone
Request Request::clone() const
{
// To clone a request request, run these steps:
// 1. Let newRequest be a copy of request, except for its body.
BodyType body;
swap(body, const_cast<BodyType&>(m_body));
auto new_request = *this;
swap(body, const_cast<BodyType&>(m_body));
// FIXME: 2. If requests body is non-null, set newRequests body to the result of cloning requests body.
// 3. Return newRequest.
return new_request;
}
// https://fetch.spec.whatwg.org/#concept-request-add-range-header
ErrorOr<void> Request::add_range_reader(u64 first, Optional<u64> const& last)
{
// To add a range header to a request request, with an integer first, and an optional integer last, run these steps:
// 1. Assert: last is not given, or first is less than or equal to last.
VERIFY(!last.has_value() || first <= last.value());
// 2. Let rangeValue be `bytes=`.
auto range_value = TRY(ByteBuffer::copy("bytes"sv.bytes()));
// 3. Serialize and isomorphic encode first, and append the result to rangeValue.
TRY(range_value.try_append(String::number(first).bytes()));
// 4. Append 0x2D (-) to rangeValue.
TRY(range_value.try_append('-'));
// 5. If last is given, then serialize and isomorphic encode it, and append the result to rangeValue.
if (last.has_value())
TRY(range_value.try_append(String::number(*last).bytes()));
// 6. Append (`Range`, rangeValue) to requests header list.
auto header = Header {
.name = TRY(ByteBuffer::copy("Range"sv.bytes())),
.value = move(range_value),
};
TRY(m_header_list.append(move(header)));
return {};
}
// https://fetch.spec.whatwg.org/#cross-origin-embedder-policy-allows-credentials
bool Request::cross_origin_embedder_policy_allows_credentials() const
{
// 1. If requests mode is not "no-cors", then return true.
if (m_mode != Mode::NoCORS)
return true;
// 2. If requests client is null, then return true.
if (m_client == nullptr)
return true;
// FIXME: 3. If requests clients policy containers embedder policys value is not "credentialless", then return true.
// 4. If requests origin is same origin with requests current URLs origin and request does not have a redirect-tainted origin, then return true.
// FIXME: Actually use the given origins once we have https://url.spec.whatwg.org/#concept-url-origin.
if (HTML::Origin().is_same_origin(HTML::Origin()) && !has_redirect_tainted_origin())
return true;
// 5. Return false.
return false;
}
}