1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:47:34 +00:00

Browser+WebContent+WebDriver: Move Get All Cookies to WebContent

There are a couple changes here from the existing Get All Cookies
implementation.

1. Previously, WebDriver actually returned *all* cookies in the cookie
   jar. The spec dictates that we only return cookies that match the
   document's URL. Specifically, it calls out that we must run just the
   first step of RFC 6265 section 5.4 to perform domain matching.

   This change adds a special mode to our implementation of that section
   to skip the remaining steps.

2. We now fill in the SameSite cookie attribute when serializing the
   cookie to JSON (this was a trival FIXME that didn't get picked up
   when SameSite was implemented).
This commit is contained in:
Timothy Flynn 2022-11-11 09:24:07 -05:00 committed by Linus Groh
parent d2c1957d8f
commit c77260c480
11 changed files with 89 additions and 29 deletions

View file

@ -575,6 +575,10 @@ void BrowserWindow::create_new_tab(URL url, bool activate)
}); });
}; };
new_tab.on_get_all_cookies = [this](auto& url) {
return m_cookie_jar.get_all_cookies(url);
};
new_tab.on_get_cookie = [this](auto& url, auto source) -> String { new_tab.on_get_cookie = [this](auto& url, auto source) -> String {
return m_cookie_jar.get_cookie(url, source); return m_cookie_jar.get_cookie(url, source);
}; };

View file

@ -116,6 +116,24 @@ Vector<Web::Cookie::Cookie> CookieJar::get_all_cookies() const
return cookies; return cookies;
} }
// https://w3c.github.io/webdriver/#dfn-associated-cookies
Vector<Web::Cookie::Cookie> CookieJar::get_all_cookies(URL const& url)
{
auto domain = canonicalize_domain(url);
if (!domain.has_value())
return {};
auto cookie_list = get_matching_cookies(url, domain.value(), Web::Cookie::Source::Http, MatchingCookiesSpecMode::WebDriver);
Vector<Web::Cookie::Cookie> cookies;
cookies.ensure_capacity(cookie_list.size());
for (auto const& cookie : cookie_list)
cookies.unchecked_append(cookie);
return cookies;
}
Optional<String> CookieJar::canonicalize_domain(const URL& url) Optional<String> CookieJar::canonicalize_domain(const URL& url)
{ {
// https://tools.ietf.org/html/rfc6265#section-5.1.2 // https://tools.ietf.org/html/rfc6265#section-5.1.2
@ -281,7 +299,7 @@ void CookieJar::store_cookie(Web::Cookie::ParsedCookie const& parsed_cookie, con
m_cookies.set(key, move(cookie)); m_cookies.set(key, move(cookie));
} }
Vector<Web::Cookie::Cookie&> CookieJar::get_matching_cookies(const URL& url, String const& canonicalized_domain, Web::Cookie::Source source) Vector<Web::Cookie::Cookie&> CookieJar::get_matching_cookies(const URL& url, String const& canonicalized_domain, Web::Cookie::Source source, MatchingCookiesSpecMode mode)
{ {
// https://tools.ietf.org/html/rfc6265#section-5.4 // https://tools.ietf.org/html/rfc6265#section-5.4
@ -310,6 +328,12 @@ Vector<Web::Cookie::Cookie&> CookieJar::get_matching_cookies(const URL& url, Str
if (cookie.value.http_only && (source != Web::Cookie::Source::Http)) if (cookie.value.http_only && (source != Web::Cookie::Source::Http))
continue; continue;
// NOTE: The WebDriver spec expects only step 1 above to be executed to match cookies.
if (mode == MatchingCookiesSpecMode::WebDriver) {
cookie_list.append(cookie.value);
continue;
}
// 2. The user agent SHOULD sort the cookie-list in the following order: // 2. The user agent SHOULD sort the cookie-list in the following order:
// - Cookies with longer paths are listed before cookies with shorter paths. // - Cookies with longer paths are listed before cookies with shorter paths.
// - Among cookies that have equal-length path fields, cookies with earlier creation-times are listed before cookies with later creation-times. // - Among cookies that have equal-length path fields, cookies with earlier creation-times are listed before cookies with later creation-times.

View file

@ -31,6 +31,7 @@ public:
void update_cookie(URL const&, Web::Cookie::Cookie); void update_cookie(URL const&, Web::Cookie::Cookie);
void dump_cookies() const; void dump_cookies() const;
Vector<Web::Cookie::Cookie> get_all_cookies() const; Vector<Web::Cookie::Cookie> get_all_cookies() const;
Vector<Web::Cookie::Cookie> get_all_cookies(URL const& url);
private: private:
static Optional<String> canonicalize_domain(const URL& url); static Optional<String> canonicalize_domain(const URL& url);
@ -38,8 +39,13 @@ private:
static bool path_matches(String const& request_path, String const& cookie_path); static bool path_matches(String const& request_path, String const& cookie_path);
static String default_path(const URL& url); static String default_path(const URL& url);
enum class MatchingCookiesSpecMode {
RFC6265,
WebDriver,
};
void store_cookie(Web::Cookie::ParsedCookie const& parsed_cookie, const URL& url, String canonicalized_domain, Web::Cookie::Source source); void store_cookie(Web::Cookie::ParsedCookie const& parsed_cookie, const URL& url, String canonicalized_domain, Web::Cookie::Source source);
Vector<Web::Cookie::Cookie&> get_matching_cookies(const URL& url, String const& canonicalized_domain, Web::Cookie::Source source); Vector<Web::Cookie::Cookie&> get_matching_cookies(const URL& url, String const& canonicalized_domain, Web::Cookie::Source source, MatchingCookiesSpecMode mode = MatchingCookiesSpecMode::RFC6265);
void purge_expired_cookies(); void purge_expired_cookies();
HashMap<CookieStorageKey, Web::Cookie::Cookie> m_cookies; HashMap<CookieStorageKey, Web::Cookie::Cookie> m_cookies;

View file

@ -351,6 +351,12 @@ Tab::Tab(BrowserWindow& window)
on_favicon_change(icon); on_favicon_change(icon);
}; };
view().on_get_all_cookies = [this](auto& url) -> Vector<Web::Cookie::Cookie> {
if (on_get_all_cookies)
return on_get_all_cookies(url);
return {};
};
view().on_get_cookie = [this](auto& url, auto source) -> String { view().on_get_cookie = [this](auto& url, auto source) -> String {
if (on_get_cookie) if (on_get_cookie)
return on_get_cookie(url, source); return on_get_cookie(url, source);

View file

@ -64,6 +64,7 @@ public:
Function<void(Tab&)> on_tab_close_request; Function<void(Tab&)> on_tab_close_request;
Function<void(Tab&)> on_tab_close_other_request; Function<void(Tab&)> on_tab_close_other_request;
Function<void(Gfx::Bitmap const&)> on_favicon_change; Function<void(Gfx::Bitmap const&)> on_favicon_change;
Function<Vector<Web::Cookie::Cookie>(AK::URL const& url)> on_get_all_cookies;
Function<String(const URL&, Web::Cookie::Source source)> on_get_cookie; Function<String(const URL&, Web::Cookie::Source source)> on_get_cookie;
Function<void(const URL&, Web::Cookie::ParsedCookie const& cookie, Web::Cookie::Source source)> on_set_cookie; Function<void(const URL&, Web::Cookie::ParsedCookie const& cookie, Web::Cookie::Source source)> on_set_cookie;
Function<void()> on_dump_cookies; Function<void()> on_dump_cookies;

View file

@ -24,6 +24,7 @@ endpoint WebDriverClient {
get_source() => (Web::WebDriver::Response response) get_source() => (Web::WebDriver::Response response)
execute_script(JsonValue payload) => (Web::WebDriver::Response response) execute_script(JsonValue payload) => (Web::WebDriver::Response response)
execute_async_script(JsonValue payload) => (Web::WebDriver::Response response) execute_async_script(JsonValue payload) => (Web::WebDriver::Response response)
get_all_cookies() => (Web::WebDriver::Response response)
take_screenshot() => (Web::WebDriver::Response response) take_screenshot() => (Web::WebDriver::Response response)
take_element_screenshot(String element_id) => (Web::WebDriver::Response response) take_element_screenshot(String element_id) => (Web::WebDriver::Response response)
} }

View file

@ -16,6 +16,7 @@
#include <LibWeb/CSS/PropertyID.h> #include <LibWeb/CSS/PropertyID.h>
#include <LibWeb/CSS/StyleProperties.h> #include <LibWeb/CSS/StyleProperties.h>
#include <LibWeb/CSS/StyleValue.h> #include <LibWeb/CSS/StyleValue.h>
#include <LibWeb/Cookie/Cookie.h>
#include <LibWeb/DOM/Document.h> #include <LibWeb/DOM/Document.h>
#include <LibWeb/DOM/Element.h> #include <LibWeb/DOM/Element.h>
#include <LibWeb/Geometry/DOMRect.h> #include <LibWeb/Geometry/DOMRect.h>
@ -41,6 +42,22 @@ static JsonValue make_success_response(JsonValue value)
return result; return result;
} }
// https://w3c.github.io/webdriver/#dfn-serialized-cookie
static JsonValue serialize_cookie(Web::Cookie::Cookie const& cookie)
{
JsonObject serialized_cookie;
serialized_cookie.set("name"sv, cookie.name);
serialized_cookie.set("value"sv, cookie.value);
serialized_cookie.set("path"sv, cookie.path);
serialized_cookie.set("domain"sv, cookie.domain);
serialized_cookie.set("secure"sv, cookie.secure);
serialized_cookie.set("httpOnly"sv, cookie.http_only);
serialized_cookie.set("expiry"sv, cookie.expiry_time.timestamp());
serialized_cookie.set("sameSite"sv, Web::Cookie::same_site_to_string(cookie.same_site));
return serialized_cookie;
}
static JsonValue serialize_rect(Gfx::IntRect const& rect) static JsonValue serialize_rect(Gfx::IntRect const& rect)
{ {
JsonObject serialized_rect = {}; JsonObject serialized_rect = {};
@ -829,6 +846,32 @@ Messages::WebDriverClient::ExecuteAsyncScriptResponse WebDriverConnection::execu
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
// 14.1 Get All Cookies, https://w3c.github.io/webdriver/#dfn-get-all-cookies
Messages::WebDriverClient::GetAllCookiesResponse WebDriverConnection::get_all_cookies()
{
// 1. If the current browsing context is no longer open, return error with error code no such window.
TRY(ensure_open_top_level_browsing_context());
// FIXME: 2. Handle any user prompts, and return its value if it is an error.
// 3. Let cookies be a new JSON List.
JsonArray cookies;
// 4. For each cookie in all associated cookies of the current browsing contexts active document:
auto* document = m_page_host.page().top_level_browsing_context().active_document();
for (auto const& cookie : m_web_content_client.did_request_all_cookies(document->url())) {
// 1. Let serialized cookie be the result of serializing cookie.
auto serialized_cookie = serialize_cookie(cookie);
// 2. Append serialized cookie to cookies
cookies.append(move(serialized_cookie));
}
// 5. Return success with data cookies.
return make_success_response(move(cookies));
}
// 17.1 Take Screenshot, https://w3c.github.io/webdriver/#take-screenshot // 17.1 Take Screenshot, https://w3c.github.io/webdriver/#take-screenshot
Messages::WebDriverClient::TakeScreenshotResponse WebDriverConnection::take_screenshot() Messages::WebDriverClient::TakeScreenshotResponse WebDriverConnection::take_screenshot()
{ {

View file

@ -56,6 +56,7 @@ private:
virtual Messages::WebDriverClient::GetSourceResponse get_source() override; virtual Messages::WebDriverClient::GetSourceResponse get_source() override;
virtual Messages::WebDriverClient::ExecuteScriptResponse execute_script(JsonValue const& payload) override; virtual Messages::WebDriverClient::ExecuteScriptResponse execute_script(JsonValue const& payload) override;
virtual Messages::WebDriverClient::ExecuteAsyncScriptResponse execute_async_script(JsonValue const& payload) override; virtual Messages::WebDriverClient::ExecuteAsyncScriptResponse execute_async_script(JsonValue const& payload) override;
virtual Messages::WebDriverClient::GetAllCookiesResponse get_all_cookies() override;
virtual Messages::WebDriverClient::TakeScreenshotResponse take_screenshot() override; virtual Messages::WebDriverClient::TakeScreenshotResponse take_screenshot() override;
virtual Messages::WebDriverClient::TakeElementScreenshotResponse take_element_screenshot(String const& element_id) override; virtual Messages::WebDriverClient::TakeElementScreenshotResponse take_element_screenshot(String const& element_id) override;

View file

@ -753,8 +753,7 @@ Web::WebDriver::Response Client::handle_get_all_cookies(Vector<StringView> const
{ {
dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/cookie"); dbgln_if(WEBDRIVER_DEBUG, "Handling GET /session/<session_id>/cookie");
auto* session = TRY(find_session_with_id(parameters[0])); auto* session = TRY(find_session_with_id(parameters[0]));
auto cookies = TRY(session->get_all_cookies()); return session->web_content_connection().get_all_cookies();
return make_json_value(cookies);
} }
// 14.2 Get Named Cookie, https://w3c.github.io/webdriver/#dfn-get-named-cookie // 14.2 Get Named Cookie, https://w3c.github.io/webdriver/#dfn-get-named-cookie

View file

@ -313,30 +313,6 @@ static JsonObject serialize_cookie(Web::Cookie::Cookie const& cookie)
return serialized_cookie; return serialized_cookie;
} }
// 14.1 Get All Cookies, https://w3c.github.io/webdriver/#dfn-get-all-cookies
Web::WebDriver::Response Session::get_all_cookies()
{
// 1. If the current browsing context is no longer open, return error with error code no such window.
TRY(check_for_open_top_level_browsing_context_or_return_error());
// FIXME: 2. Handle any user prompts, and return its value if it is an error.
// 3. Let cookies be a new JSON List.
JsonArray cookies = {};
// 4. For each cookie in all associated cookies of the current browsing contexts active document:
for (auto const& cookie : m_browser_connection->get_all_cookies()) {
// 1. Let serialized cookie be the result of serializing cookie.
auto serialized_cookie = serialize_cookie(cookie);
// 2. Append serialized cookie to cookies
cookies.append(serialized_cookie);
}
// 5. Return success with data cookies.
return JsonValue(cookies);
}
// 14.2 Get Named Cookie, https://w3c.github.io/webdriver/#dfn-get-named-cookie // 14.2 Get Named Cookie, https://w3c.github.io/webdriver/#dfn-get-named-cookie
Web::WebDriver::Response Session::get_named_cookie(String const& name) Web::WebDriver::Response Session::get_named_cookie(String const& name)
{ {

View file

@ -58,7 +58,6 @@ public:
Web::WebDriver::Response get_window_handle(); Web::WebDriver::Response get_window_handle();
ErrorOr<void, Variant<Web::WebDriver::Error, Error>> close_window(); ErrorOr<void, Variant<Web::WebDriver::Error, Error>> close_window();
Web::WebDriver::Response get_window_handles() const; Web::WebDriver::Response get_window_handles() const;
Web::WebDriver::Response get_all_cookies();
Web::WebDriver::Response get_named_cookie(String const& name); Web::WebDriver::Response get_named_cookie(String const& name);
Web::WebDriver::Response add_cookie(JsonValue const& payload); Web::WebDriver::Response add_cookie(JsonValue const& payload);
Web::WebDriver::Response delete_cookie(StringView name); Web::WebDriver::Response delete_cookie(StringView name);