Skip to content

Commit 8f38e26

Browse files
authored
net: Set Response::cache_state appropriately. (servo#40277)
`Response::cache_state` is populated upon fetch. Testing: Net tests have been added. Fixes: servo#40236 Signed-off-by: Mark Buer <[email protected]>
1 parent b31b8a7 commit 8f38e26

File tree

2 files changed

+87
-3
lines changed

2 files changed

+87
-3
lines changed

components/net/http_loader.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use net_traits::request::{
5353
is_cors_non_wildcard_request_header_name, is_cors_safelisted_method,
5454
is_cors_safelisted_request_header,
5555
};
56-
use net_traits::response::{HttpsState, Response, ResponseBody, ResponseType};
56+
use net_traits::response::{CacheState, HttpsState, Response, ResponseBody, ResponseType};
5757
use net_traits::{
5858
CookieSource, DOCUMENT_ACCEPT_HEADER_VALUE, FetchMetadata, NetworkError, RedirectEndValue,
5959
RedirectStartValue, ReferrerPolicy, ResourceAttribute, ResourceFetchTiming, ResourceTimeValue,
@@ -1573,6 +1573,9 @@ async fn http_network_or_cache_fetch(
15731573
} else {
15741574
// Substep 6
15751575
response = cached_response;
1576+
if let Some(response) = &mut response {
1577+
response.cache_state = CacheState::Local;
1578+
}
15761579
}
15771580
if response.is_none() {
15781581
// Ensure the done chan is not set if we're not using the cached response,
@@ -1690,6 +1693,9 @@ async fn http_network_or_cache_fetch(
16901693
response = http_cache.refresh(http_request, forward_response.clone(), done_chan);
16911694
}
16921695
wait_for_cached_response(done_chan, &mut response).await;
1696+
if let Some(response) = &mut response {
1697+
response.cache_state = CacheState::Validated;
1698+
}
16931699
}
16941700

16951701
// Step 10.5 If response is null, then:

components/net/tests/fetch.rs

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use std::fs;
88
use std::iter::FromIterator;
99
use std::path::Path;
10+
use std::str::FromStr;
1011
use std::sync::atomic::{AtomicUsize, Ordering};
1112
use std::sync::{Arc, Mutex, Weak};
1213
use std::time::{Duration, SystemTime};
@@ -18,8 +19,8 @@ use crossbeam_channel::{Sender, unbounded};
1819
use devtools_traits::{HttpRequest as DevtoolsHttpRequest, HttpResponse as DevtoolsHttpResponse};
1920
use headers::{
2021
AccessControlAllowCredentials, AccessControlAllowHeaders, AccessControlAllowMethods,
21-
AccessControlAllowOrigin, AccessControlMaxAge, CacheControl, ContentLength, ContentType,
22-
Expires, HeaderMapExt, LastModified, Pragma, StrictTransportSecurity, UserAgent,
22+
AccessControlAllowOrigin, AccessControlMaxAge, CacheControl, ContentLength, ContentType, ETag,
23+
Expires, HeaderMapExt, IfNoneMatch, LastModified, Pragma, StrictTransportSecurity, UserAgent,
2324
};
2425
use http::header::{self, HeaderMap, HeaderName, HeaderValue};
2526
use http::{Method, StatusCode};
@@ -1260,6 +1261,83 @@ fn test_fetch_async_returns_complete_response() {
12601261
assert_eq!(response_is_done(&fetch_response), true);
12611262
}
12621263

1264+
#[test]
1265+
fn test_response_cache_status_is_local() {
1266+
static MESSAGE: &'static [u8] = b"cacheable content";
1267+
let handler =
1268+
move |_: HyperRequest<Incoming>,
1269+
response: &mut HyperResponse<BoxBody<Bytes, hyper::Error>>| {
1270+
// Mark this response as cacheable.
1271+
response
1272+
.headers_mut()
1273+
.typed_insert(CacheControl::new().with_max_age(Duration::from_secs(604800)));
1274+
*response.body_mut() = make_body(MESSAGE.to_vec());
1275+
};
1276+
let (server, url) = make_server(handler);
1277+
1278+
let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
1279+
.origin(url.origin())
1280+
.policy_container(Default::default())
1281+
.build();
1282+
1283+
// Use the same HttpCache for both fetches.
1284+
let mut context = new_fetch_context(None, None, None);
1285+
1286+
// Cold request - response should come from the server.
1287+
let initial_response = fetch_with_context(request.clone(), &mut context);
1288+
assert!(matches!(initial_response.cache_state, CacheState::None));
1289+
1290+
// Warm request - response should come from the cache.
1291+
let cached_response = fetch_with_context(request.clone(), &mut context);
1292+
assert!(matches!(cached_response.cache_state, CacheState::Local));
1293+
1294+
let _ = server.close();
1295+
}
1296+
1297+
#[test]
1298+
fn test_response_cache_status_is_validated() {
1299+
static MESSAGE: &'static [u8] = b"cacheable content";
1300+
let handler =
1301+
move |request: HyperRequest<Incoming>,
1302+
response: &mut HyperResponse<BoxBody<Bytes, hyper::Error>>| {
1303+
// Check for the revalidation request.
1304+
if let Some(_) = request.headers().typed_get::<IfNoneMatch>() {
1305+
*response.status_mut() = StatusCode::NOT_MODIFIED;
1306+
return;
1307+
}
1308+
// Mark this cacheable reponse as requiring revalidation upon refetch.
1309+
response
1310+
.headers_mut()
1311+
.typed_insert(CacheControl::new().with_no_cache());
1312+
response
1313+
.headers_mut()
1314+
.typed_insert(ETag::from_str("\"1234abcd\"").unwrap());
1315+
*response.body_mut() = make_body(MESSAGE.to_vec());
1316+
};
1317+
let (server, url) = make_server(handler);
1318+
1319+
let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
1320+
.origin(url.origin())
1321+
.policy_container(Default::default())
1322+
.build();
1323+
1324+
// Use the same HttpCache for both fetches.
1325+
let mut context = new_fetch_context(None, None, None);
1326+
1327+
// Cold request - response should come from the server.
1328+
let initial_response = fetch_with_context(request.clone(), &mut context);
1329+
assert!(matches!(initial_response.cache_state, CacheState::None));
1330+
1331+
// Warm request - response should come from the cache after revalidation with server.
1332+
let revalidated_response = fetch_with_context(request, &mut context);
1333+
assert!(matches!(
1334+
revalidated_response.cache_state,
1335+
CacheState::Validated
1336+
));
1337+
1338+
let _ = server.close();
1339+
}
1340+
12631341
#[test]
12641342
fn test_opaque_filtered_fetch_async_returns_complete_response() {
12651343
static MESSAGE: &'static [u8] = b"";

0 commit comments

Comments
 (0)