From b30c361b0877ee4f67ce70f766495c398a307a30 Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Tue, 21 May 2024 20:16:45 -0400 Subject: [PATCH] LibWeb/Fetch: Implement logic to process a response from HTTP's cache Co-Authored-By: Andrew Kaster --- .../LibWeb/Fetch/Fetching/Fetching.cpp | 58 ++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp index f3c0c7ddf5d..df51fabb8cd 100644 --- a/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp +++ b/Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp @@ -1662,8 +1662,62 @@ WebIDL::ExceptionOr> http_network_or_cache_fet stored_response = Infrastructure::Response::create(vm); stored_response->set_body(body); - // FIXME: Caching is not implemented yet. - VERIFY_NOT_REACHED(); + // 1. If cache mode is "default", storedResponse is a stale-while-revalidate response, + // and httpRequest’s client is non-null, then: + if (http_request->cache_mode() == Infrastructure::Request::CacheMode::Default + && stored_response->is_stale_while_revalidate() + && http_request->client() != nullptr) { + + // 1. Set response to storedResponse. + response = stored_response; + + // 2. Set response’s cache state to "local". + response->set_cache_state(Infrastructure::Response::CacheState::Local); + + // 3. Let revalidateRequest be a clone of request. + auto revalidate_request = request->clone(realm); + + // 4. Set revalidateRequest’s cache mode set to "no-cache". + revalidate_request->set_cache_mode(Infrastructure::Request::CacheMode::NoCache); + + // 5. Set revalidateRequest’s prevent no-cache cache-control header modification flag. + revalidate_request->set_prevent_no_cache_cache_control_header_modification(true); + + // 6. Set revalidateRequest’s service-workers mode set to "none". + revalidate_request->set_service_workers_mode(Infrastructure::Request::ServiceWorkersMode::None); + + // 7. In parallel, run main fetch given a new fetch params whose request is revalidateRequest. + Platform::EventLoopPlugin::the().deferred_invoke([&vm, &realm, revalidate_request, fetch_params = JS::NonnullGCPtr(fetch_params)] { + (void)main_fetch(realm, Infrastructure::FetchParams::create(vm, revalidate_request, fetch_params->timing_info())); + }); + } + // 2. Otherwise: + else { + // 1. If storedResponse is a stale response, then set the revalidatingFlag. + if (stored_response->is_stale()) + revalidating_flag->set_value(true); + + // 2. If the revalidatingFlag is set and httpRequest’s cache mode is neither "force-cache" nor "only-if-cached", then: + if (revalidating_flag->value() + && http_request->cache_mode() != Infrastructure::Request::CacheMode::ForceCache + && http_request->cache_mode() != Infrastructure::Request::CacheMode::OnlyIfCached) { + + // 1. If storedResponse’s header list contains `ETag`, then append (`If-None-Match`, `ETag`'s value) to httpRequest’s header list. + if (auto etag = stored_response->header_list()->get("ETag"sv.bytes()); etag.has_value()) { + stored_response->header_list()->append(Infrastructure::Header::from_string_pair("If-None-Match"sv, *etag)); + } + + // 2. If storedResponse’s header list contains `Last-Modified`, then append (`If-Modified-Since`, `Last-Modified`'s value) to httpRequest’s header list. + if (auto last_modified = stored_response->header_list()->get("Last-Modified"sv.bytes()); last_modified.has_value()) { + stored_response->header_list()->append(Infrastructure::Header::from_string_pair("If-Modified-Since"sv, *last_modified)); + } + } + // 3. Otherwise, set response to storedResponse and set response’s cache state to "local". + else { + response = stored_response; + response->set_cache_state(Infrastructure::Response::CacheState::Local); + } + } } } }