/* * Copyright (c) 2026-present, the Ladybird developers. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include static URL::URL parse_url(StringView url) { return URL::Parser::basic_parse(url).release_value(); } static NonnullRefPtr create_cacheable_request_headers() { return HTTP::HeaderList::create({ { "Accept"sv, "*/*"sv }, }); } static NonnullRefPtr create_cacheable_response_headers() { return HTTP::HeaderList::create({ { "Cache-Control"sv, "max-age=60"sv }, }); } static NonnullRefPtr create_vary_user_agent_response_headers() { return HTTP::HeaderList::create({ { "Cache-Control"sv, "max-age=60"sv }, { "Vary"sv, "User-Agent"sv }, }); } static Core::ImmutableBytes immutable_bytes(StringView bytes) { return MUST(Core::ImmutableBytes::copy(bytes.bytes())); } TEST_CASE(javascript_bytecode_cache_round_trips_with_memory_cache_entry) { auto cache = HTTP::MemoryCache::create(); auto url = parse_url("https://example.com/script.js"sv); auto request_headers = create_cacheable_request_headers(); auto response_headers = create_cacheable_response_headers(); auto bytecode = immutable_bytes("cached bytecode"sv); cache->create_entry(url, "GET"sv, *request_headers, UnixDateTime::now(), 200, "OK"sv, *response_headers, bytecode, 0); cache->finalize_entry(url, "GET"sv, *request_headers, 200, *response_headers, immutable_bytes("console.log('hello');"sv)); auto entry = cache->open_entry(url, "GET"sv, *request_headers, HTTP::CacheMode::Default); VERIFY(entry.has_value()); VERIFY(entry->javascript_bytecode_cache.has_value()); EXPECT_EQ(entry->javascript_bytecode_cache->bytes(), bytecode.bytes()); EXPECT_EQ(entry->javascript_bytecode_cache_vary_key, Optional { 0 }); } TEST_CASE(javascript_bytecode_cache_update_matches_memory_cache_vary_headers) { auto cache = HTTP::MemoryCache::create(); auto url = parse_url("https://example.com/script.js"sv); auto script_request_headers = create_cacheable_request_headers(); auto cache_request_headers = HTTP::HeaderList::create({ { "Accept"sv, "*/*"sv }, { "User-Agent"sv, "Ladybird"sv }, }); auto response_headers = create_vary_user_agent_response_headers(); auto bytecode = immutable_bytes("generated bytecode"sv); auto vary_key = HTTP::create_vary_key(*cache_request_headers, *response_headers); cache->create_entry(url, "GET"sv, *cache_request_headers, UnixDateTime::now(), 200, "OK"sv, *response_headers); cache->finalize_entry(url, "GET"sv, *cache_request_headers, 200, *response_headers, immutable_bytes("console.log('hello');"sv)); cache->update_javascript_bytecode_cache(url, "GET"sv, *script_request_headers, vary_key, bytecode); auto entry = cache->open_entry(url, "GET"sv, *cache_request_headers, HTTP::CacheMode::Default); VERIFY(entry.has_value()); EXPECT(!entry->javascript_bytecode_cache.has_value()); EXPECT(!entry->javascript_bytecode_cache_vary_key.has_value()); cache->update_javascript_bytecode_cache(url, "GET"sv, *cache_request_headers, vary_key, bytecode); entry = cache->open_entry(url, "GET"sv, *cache_request_headers, HTTP::CacheMode::Default); VERIFY(entry.has_value()); VERIFY(entry->javascript_bytecode_cache.has_value()); EXPECT_EQ(entry->javascript_bytecode_cache->bytes(), bytecode.bytes()); EXPECT_EQ(entry->javascript_bytecode_cache_vary_key, Optional { vary_key }); } TEST_CASE(javascript_bytecode_cache_can_be_added_after_memory_cache_entry_is_complete) { auto cache = HTTP::MemoryCache::create(); auto url = parse_url("https://example.com/script.js"sv); auto request_headers = create_cacheable_request_headers(); auto response_headers = create_cacheable_response_headers(); auto bytecode = immutable_bytes("generated bytecode"sv); cache->create_entry(url, "GET"sv, *request_headers, UnixDateTime::now(), 200, "OK"sv, *response_headers); cache->finalize_entry(url, "GET"sv, *request_headers, 200, *response_headers, immutable_bytes("console.log('hello');"sv)); auto entry = cache->open_entry(url, "GET"sv, *request_headers, HTTP::CacheMode::Default); VERIFY(entry.has_value()); EXPECT(!entry->javascript_bytecode_cache.has_value()); EXPECT(!entry->javascript_bytecode_cache_vary_key.has_value()); cache->update_javascript_bytecode_cache(url, "GET"sv, *request_headers, 0, bytecode); entry = cache->open_entry(url, "GET"sv, *request_headers, HTTP::CacheMode::Default); VERIFY(entry.has_value()); VERIFY(entry->javascript_bytecode_cache.has_value()); EXPECT_EQ(entry->javascript_bytecode_cache->bytes(), bytecode.bytes()); EXPECT_EQ(entry->javascript_bytecode_cache_vary_key, Optional { 0 }); }