From 6253fe8004c6add3d0851dade9b2cc3a3c43ff73 Mon Sep 17 00:00:00 2001 From: Alec Murphy Date: Fri, 10 Oct 2025 11:40:00 -0400 Subject: [PATCH] Applications/Internet/Cyberia: Initial support for cookies --- Applications/Internet/Cyberia.app/Cyberia.HC | 135 ++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/Applications/Internet/Cyberia.app/Cyberia.HC b/Applications/Internet/Cyberia.app/Cyberia.HC index 545ca29..7b2bd02 100644 --- a/Applications/Internet/Cyberia.app/Cyberia.HC +++ b/Applications/Internet/Cyberia.app/Cyberia.HC @@ -469,6 +469,116 @@ U0 @cyberia_msgbox_error_wrapper(U8* msg) } } +U0 @cyberia_get_key_value(U8* s, U64* key_ptr, U64* value_ptr) +{ + I64 i; + I64 len = StrLen(s); + for (i = 0; i < len; i++) { + if (!(*key_ptr)) { + switch (s[i]) { + case ' ': + case '\t': + case '\r': + case '\n': + break; + default: + *key_ptr = s + i; + break; + } + } else { + switch (s[i]) { + case '=': + s[i] = NULL; + *value_ptr = s + i + 1; + return; + default: + break; + } + } + } +} + +U0 @cyberia_set_cookie_baked(U8* domain, U8* key, U8* value) +{ + if (!cyberia->o("cookies")->@(domain)) { + cyberia->o("cookies")->set(domain, Json.CreateObject(erythros_mem_task), JSON_OBJECT); + } + cyberia->o("cookies")->o(domain)->set(key, value, JSON_STRING); +} + +U0 @cyberia_set_cookie_raw(@browser* browser, U8* s) +{ + // - Parse key=value pairs from value + // by default, Set-Cookie or Clear-Site-Data effects domain.tld as well as ...*.*.*.*.domain.tld + + if (!browser || !s || !StrLen(s)) { + return; + } + + U8* domain = browser->renderer->current_url->host; + + // A user agent MUST use an algorithm equivalent to the following algorithm to parse a set-cookie-string: + + // If the set-cookie-string contains a %x00-08 / %x0A-1F / %x7F character (CTL characters excluding HTAB): + // Abort this algorithm and ignore the set-cookie-string entirely. + + I64 i; + I64 len = StrLen(s); + for (i = 0; i < len; i++) { + switch (s[i]) { + case 0x00...0x08: + case 0x0a...0x1f: + case 0x7f: + return; + default: + break; + } + } + + // FIXME: For now, we are going to ignore unparsed-attributes, and match against domain.tld + U8* t = StrFind(";", s); + if (t) { + *t = NULL; + } + + U64 key = NULL; + U64 value = NULL; + + @cyberia_get_key_value(s, &key, &value); + + if (domain && key && value) { + @cyberia_set_cookie_baked(domain, key, value); + } +} + +U0 @cyberia_set_cookies(@browser* browser, @http_response* resp) +{ + if (!browser || !resp || !browser->renderer || !resp->headers) { + return; + } + + I64 i = 0; + U8* value = NULL; + JsonArray* a = NULL; + JsonKey* keys = resp->headers->keys; + while (keys) { + if (!StrICmp(keys->name, "set-cookie")) { + switch (keys->type) { + case JSON_ARRAY: + a = keys->value; + for (i = 0; i < a->length; i++) { + @cyberia_set_cookie_raw(browser, a->@(i)); + } + break; + default: + @cyberia_set_cookie_raw(browser, keys->value); + break; + } + } + keys = keys->next; + } +} + U0 @cyberia_navigate(Bool refresh = FALSE) { win->focused_widget = NULL; @@ -546,6 +656,10 @@ U0 @cyberia_navigate(Bool refresh = FALSE) MemSet(buffer, 0, HTTP_FETCH_BUFFER_SIZE); @http_response* resp = NULL; + JsonObject* headers = NULL; + U8* domain = renderer->current_url->host; + JsonKey* cookie_keys = NULL; + U8 cookie_buf[2048]; if (!StrCmp(&addressbar1->text, "about:newtab")) { resp = CAlloc(sizeof(@http_response)); @@ -556,7 +670,26 @@ U0 @cyberia_navigate(Bool refresh = FALSE) StrCpy(&addressbar1->text, ""); win->focused_widget = addressbar1; } else { - resp = Http.Get(renderer->current_url, buffer); + if (cyberia->o("cookies")->@(domain)) { + headers = Json.CreateObject(browser_task); + cookie_keys = cyberia->o("cookies")->o(domain)->keys; + StrCpy(cookie_buf, ""); + while (cookie_keys) { + StrPrint(cookie_buf + StrLen(cookie_buf), "%s=%s", cookie_keys->name, cookie_keys->value); + if (cookie_keys->next) { + StrCpy(cookie_buf + StrLen(cookie_buf), "; "); + } + cookie_keys = cookie_keys->next; + } + headers->set("Cookie", cookie_buf, JSON_STRING); + } + if (renderer->form_data_str) { + resp = Http.Post(renderer->current_url, buffer, renderer->form_data_str, headers); + // FIXME: form_data_str should be freed + renderer->form_data_str = NULL; + } else { + resp = Http.Get(renderer->current_url, buffer, NULL, headers); + } } while (resp->state != HTTP_STATE_DONE) {