Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions Libraries/LibWeb/Fetch/Fetching/Fetching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -545,9 +545,8 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> main_fetch(JS::Realm& realm, Infra
if (internal_response->url_list().is_empty())
internal_response->set_url_list(request->url_list());

// 17. If request has a redirect-tainted origin, then set internalResponse’s has-cross-origin-redirects to true.
if (request->has_redirect_tainted_origin())
internal_response->set_has_cross_origin_redirects(true);
// 17. Set internalResponse’s redirect taint to request’s redirect-taint.
internal_response->set_redirect_taint(request->redirect_taint());

// 18. If request’s timing allow failed flag is unset, then set internalResponse’s timing allow passed flag.
if (!request->timing_allow_failed())
Expand Down Expand Up @@ -706,8 +705,8 @@ void fetch_response_handover(JS::Realm& realm, Infrastructure::FetchParams const
// 6. Let responseStatus be 0.
auto response_status = 0;

// 7. If fetchParams’s request’s mode is not "navigate" or response’s has-cross-origin-redirects is false:
if (fetch_params.request()->mode() != Infrastructure::Request::Mode::Navigate || !response.has_cross_origin_redirects()) {
// 7. If fetchParams’s request’s mode is not "navigate" or response’s redirect taint is "same-origin":
if (fetch_params.request()->mode() != Infrastructure::Request::Mode::Navigate || response.redirect_taint() == Infrastructure::RedirectTaint::SameOrigin) {
// 1. Set responseStatus to response’s status.
response_status = response.status();

Expand Down
6 changes: 6 additions & 0 deletions Libraries/LibWeb/Fetch/Infrastructure/HTTP.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ enum class HttpQuotedStringExtractValue {
Yes,
};

enum class RedirectTaint {
SameOrigin,
SameSite,
CrossSite,
};

[[nodiscard]] String collect_an_http_quoted_string(GenericLexer& lexer, HttpQuotedStringExtractValue extract_value = HttpQuotedStringExtractValue::No);

}
58 changes: 40 additions & 18 deletions Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,44 +164,61 @@ bool Request::is_navigation_request() const
}

// https://fetch.spec.whatwg.org/#concept-request-tainted-origin
bool Request::has_redirect_tainted_origin() const
RedirectTaint Request::redirect_taint() const
{
// A request request has a redirect-tainted origin if these steps return true:
// 1. Assert: request’s origin is not "client".
if (auto const* origin = m_origin.get_pointer<Origin>())
VERIFY(*origin != Origin::Client);

// 1. Let lastURL be null.
// 2. Let lastURL be null.
Optional<URL::URL const&> last_url;

// 2. For each url of request’s URL list:
// 3. Let taint be "same-origin".
auto taint = RedirectTaint::SameOrigin;

// 4. For each url of request’s 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 url’s origin is not same origin with lastURL’s origin and request’s origin is not same origin with lastURL’s origin, then return true.
// 2. If url’s origin is not same site with lastURL’s origin and request’s origin is not same site with
// lastURL’s origin, then return "cross-site".
auto const* request_origin = m_origin.get_pointer<URL::Origin>();
if (!url.origin().is_same_site(last_url->origin())
&& (request_origin == nullptr || !request_origin->is_same_site(last_url->origin()))) {
return RedirectTaint::CrossSite;
}

// 3. If url’s origin is not same origin with lastURL’s origin and request’s origin is not same origin with
// lastURL’s origin, then set taint to "same-site".
if (!url.origin().is_same_origin(last_url->origin())
&& (request_origin == nullptr || !request_origin->is_same_origin(last_url->origin()))) {
return true;
taint = RedirectTaint::SameSite;
}

// 3. Set lastURL to url.
// 4. Set lastURL to url.
last_url = url;
}

// 3. Return false.
return false;
// 5. Return taint.
return taint;
}

// 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())
// 1. Assert: request’s origin is not "client".
if (auto const* origin = m_origin.get_pointer<Origin>())
VERIFY(*origin != Origin::Client);

// 2. If request’s redirect-taint is not "same-origin", then return "null".
if (redirect_taint() != RedirectTaint::SameOrigin)
return "null"_string;

// 2. Return request’s origin, serialized.
// 3. Return request’s origin, serialized.
return m_origin.get<URL::Origin>().serialize();
}

Expand Down Expand Up @@ -358,25 +375,30 @@ void Request::add_origin_header()
// https://fetch.spec.whatwg.org/#cross-origin-embedder-policy-allows-credentials
bool Request::cross_origin_embedder_policy_allows_credentials() const
{
// 1. If request’s mode is not "no-cors", then return true.
// 1. Assert: request’s origin is not "client".
if (auto const* origin = m_origin.get_pointer<Origin>())
VERIFY(*origin != Origin::Client);

// 2. If request’s mode is not "no-cors", then return true.
if (m_mode != Mode::NoCORS)
return true;

// 2. If request’s client is null, then return true.
// 3. If request’s client is null, then return true.
if (m_client == nullptr)
return true;

// 3. If request’s client’s policy container’s embedder policy’s value is not "credentialless", then return true.
// 4. If request’s client’s policy container’s embedder policy’s value is not "credentialless", then return true.
if (m_policy_container.has<GC::Ref<HTML::PolicyContainer>>() && m_policy_container.get<GC::Ref<HTML::PolicyContainer>>()->embedder_policy.value != HTML::EmbedderPolicyValue::Credentialless)
return true;

// 4. If request’s origin is same origin with request’s current URL’s origin and request does not have a redirect-tainted origin, then return true.
// 5. Return false.
// 5. If request’s origin is same origin with request’s current URL’s origin and request’s redirect-taint is not
// "same-origin", then return true.
// 6. Return false.
auto const* request_origin = m_origin.get_pointer<URL::Origin>();
if (request_origin == nullptr)
return false;

return request_origin->is_same_origin(current_url().origin()) && !has_redirect_tainted_origin();
return request_origin->is_same_origin(current_url().origin()) && redirect_taint() != RedirectTaint::SameOrigin;
}

StringView request_destination_to_string(Request::Destination destination)
Expand Down
10 changes: 9 additions & 1 deletion Libraries/LibWeb/Fetch/Infrastructure/HTTP/Requests.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <LibJS/Heap/Cell.h>
#include <LibURL/Origin.h>
#include <LibURL/URL.h>
#include <LibWeb/Fetch/Infrastructure/HTTP.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h>
#include <LibWeb/HTML/PolicyContainers.h>
Expand Down Expand Up @@ -228,6 +229,9 @@ class Request final : public JS::Cell {
[[nodiscard]] OriginType const& origin() const { return m_origin; }
void set_origin(OriginType origin) { m_origin = move(origin); }

[[nodiscard]] Optional<URL::Origin> const& top_level_navigation_initiator_origin() const { return m_top_level_navigation_initiator_origin; }
void set_top_level_navigation_initiator_origin(Optional<URL::Origin> top_level_navigation_initiator_origin) { m_top_level_navigation_initiator_origin = move(top_level_navigation_initiator_origin); }

[[nodiscard]] PolicyContainerType const& policy_container() const { return m_policy_container; }
void set_policy_container(PolicyContainerType policy_container) { m_policy_container = move(policy_container); }

Expand Down Expand Up @@ -307,7 +311,7 @@ class Request final : public JS::Cell {
[[nodiscard]] bool is_non_subresource_request() const;
[[nodiscard]] bool is_navigation_request() const;

[[nodiscard]] bool has_redirect_tainted_origin() const;
[[nodiscard]] RedirectTaint redirect_taint() const;

[[nodiscard]] String serialize_origin() const;
[[nodiscard]] ByteBuffer byte_serialize_origin() const;
Expand Down Expand Up @@ -417,6 +421,10 @@ class Request final : public JS::Cell {
// A request has an associated origin, which is "client" or an origin. Unless stated otherwise it is "client".
OriginType m_origin { Origin::Client };

// https://fetch.spec.whatwg.org/#request-top-level-navigation-initiator-origin
// A request has an associated top-level navigation initiator origin, which is an origin or null. Unless stated otherwise it is null.
Optional<URL::Origin> m_top_level_navigation_initiator_origin;

// https://fetch.spec.whatwg.org/#concept-request-policy-container
// A request has an associated policy container, which is "client" or a policy container. Unless stated otherwise
// it is "client".
Expand Down
11 changes: 6 additions & 5 deletions Libraries/LibWeb/Fetch/Infrastructure/HTTP/Responses.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <LibJS/Forward.h>
#include <LibJS/Heap/Cell.h>
#include <LibURL/URL.h>
#include <LibWeb/Fetch/Infrastructure/HTTP.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Bodies.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Headers.h>
#include <LibWeb/Fetch/Infrastructure/HTTP/Statuses.h>
Expand Down Expand Up @@ -103,8 +104,8 @@ class Response : public JS::Cell {
[[nodiscard]] virtual BodyInfo const& body_info() const { return m_body_info; }
virtual void set_body_info(BodyInfo body_info) { m_body_info = body_info; }

[[nodiscard]] bool has_cross_origin_redirects() const { return m_has_cross_origin_redirects; }
void set_has_cross_origin_redirects(bool has_cross_origin_redirects) { m_has_cross_origin_redirects = has_cross_origin_redirects; }
[[nodiscard]] RedirectTaint redirect_taint() const { return m_redirect_taint; }
void set_redirect_taint(RedirectTaint redirect_taint) { m_redirect_taint = move(redirect_taint); }

[[nodiscard]] bool is_aborted_network_error() const;
[[nodiscard]] bool is_network_error() const;
Expand Down Expand Up @@ -188,9 +189,9 @@ class Response : public JS::Cell {
// https://fetch.spec.whatwg.org/#response-service-worker-timing-info
// FIXME: A response has an associated service worker timing info (null or a service worker timing info), which is initially null.

// https://fetch.spec.whatwg.org/#response-has-cross-origin-redirects
// A response has an associated has-cross-origin-redirects (a boolean), which is initially false.
bool m_has_cross_origin_redirects { false };
// https://fetch.spec.whatwg.org/#response-redirect-taint
// A response has an associated redirect taint ("same-origin", "same-site", or "cross-site"), which is initially "same-origin".
RedirectTaint m_redirect_taint { RedirectTaint::SameOrigin };

// FIXME is the type correct?
u64 current_age() const;
Expand Down
5 changes: 4 additions & 1 deletion Libraries/LibWeb/HTML/Navigable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,10 @@ static WebIDL::ExceptionOr<Navigable::NavigationParamsVariant> create_navigation
request->set_referrer(entry->document_state()->request_referrer());
request->set_policy_container(source_snapshot_params.source_policy_container);

// FIXME: 4. If navigable is a top-level traversable, then set request's top-level navigation initiator origin to entry's document state's initiator origin.
// 4. If navigable is a top-level traversable, then set request's top-level navigation initiator origin to entry's
// document state's initiator origin.
if (navigable->top_level_traversable()->parent() == nullptr)
request->set_top_level_navigation_initiator_origin(entry->document_state()->origin());

// 5. If request's client is null:
if (request->client() == nullptr) {
Expand Down
Loading