Skip to content

Commit 72f0944

Browse files
authored
fix: cache bust on http checksum failure (#567)
1 parent cd8f47e commit 72f0944

File tree

4 files changed

+153
-24
lines changed

4 files changed

+153
-24
lines changed

Cargo.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ members = ["lib"]
1616
deno_unsync = { version = "0.4.0", default-features = false }
1717
thiserror = "2"
1818
deno_error = "0.5.3"
19-
sys_traits = "0.1.0"
19+
sys_traits = "0.1.8"
2020

2121
[lib]
2222
name = "deno_graph"

src/graph.rs

+68-21
Original file line numberDiff line numberDiff line change
@@ -4765,6 +4765,22 @@ impl<'a, 'graph> Builder<'a, 'graph> {
47654765
jsr_url_provider: &dyn JsrUrlProvider,
47664766
module_analyzer: &dyn ModuleAnalyzer,
47674767
) -> Result<PendingInfoResponse, ModuleError> {
4768+
async fn handle_success(
4769+
module_analyzer: &dyn ModuleAnalyzer,
4770+
specifier: Url,
4771+
options: ParseModuleAndSourceInfoOptions<'_>,
4772+
) -> Result<PendingInfoResponse, ModuleError> {
4773+
let is_root = options.is_root;
4774+
parse_module_source_and_info(module_analyzer, options)
4775+
.await
4776+
.map(|module_source_and_info| PendingInfoResponse::Module {
4777+
specifier: specifier.clone(),
4778+
module_source_and_info,
4779+
pending_load: None,
4780+
is_root,
4781+
})
4782+
}
4783+
47684784
if let Some((package_nv, fut)) = maybe_version_load_fut {
47694785
let inner = fut.await.map_err(|err| {
47704786
ModuleError::LoadingErr(
@@ -4854,33 +4870,64 @@ impl<'a, 'graph> Builder<'a, 'graph> {
48544870
content,
48554871
specifier,
48564872
maybe_headers,
4857-
} => parse_module_source_and_info(
4858-
module_analyzer,
4859-
ParseModuleAndSourceInfoOptions {
4860-
specifier: specifier.clone(),
4861-
maybe_headers,
4862-
content,
4863-
maybe_attribute_type: maybe_attribute_type.as_ref(),
4864-
maybe_referrer: maybe_range,
4865-
is_root,
4866-
is_dynamic_branch: is_dynamic,
4867-
},
4868-
)
4869-
.await
4870-
.map(|module_source_and_info| {
4871-
PendingInfoResponse::Module {
4872-
specifier: specifier.clone(),
4873-
module_source_and_info,
4874-
pending_load: None,
4875-
is_root,
4876-
}
4877-
}),
4873+
} => {
4874+
handle_success(
4875+
module_analyzer,
4876+
specifier.clone(),
4877+
ParseModuleAndSourceInfoOptions {
4878+
specifier,
4879+
maybe_headers,
4880+
content,
4881+
maybe_attribute_type: maybe_attribute_type.as_ref(),
4882+
maybe_referrer: maybe_range,
4883+
is_root,
4884+
is_dynamic_branch: is_dynamic,
4885+
},
4886+
)
4887+
.await
4888+
}
48784889
},
48794890
Ok(None) => Err(ModuleError::Missing(
48804891
load_specifier.clone(),
48814892
maybe_range.cloned(),
48824893
)),
48834894
Err(LoadError::ChecksumIntegrity(err)) => {
4895+
if maybe_version_info.is_none() {
4896+
// attempt to cache bust because the remote server might have changed
4897+
let result = loader
4898+
.load(
4899+
&load_specifier,
4900+
LoadOptions {
4901+
is_dynamic,
4902+
was_dynamic_root,
4903+
cache_setting: CacheSetting::Reload,
4904+
maybe_checksum: maybe_checksum.clone(),
4905+
},
4906+
)
4907+
.await;
4908+
if let Ok(Some(LoadResponse::Module {
4909+
content,
4910+
specifier,
4911+
maybe_headers,
4912+
})) = result
4913+
{
4914+
return handle_success(
4915+
module_analyzer,
4916+
specifier.clone(),
4917+
ParseModuleAndSourceInfoOptions {
4918+
specifier,
4919+
maybe_headers,
4920+
content,
4921+
maybe_attribute_type: maybe_attribute_type.as_ref(),
4922+
maybe_referrer: maybe_range,
4923+
is_root,
4924+
is_dynamic_branch: is_dynamic,
4925+
},
4926+
)
4927+
.await;
4928+
}
4929+
}
4930+
48844931
Err(ModuleError::LoadingErr(
48854932
load_specifier.clone(),
48864933
maybe_range.cloned(),

tests/integration_test.rs

+82
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use deno_graph::packages::JsrPackageInfo;
1313
use deno_graph::packages::JsrPackageInfoVersion;
1414
use deno_graph::packages::JsrPackageVersionInfo;
1515
use deno_graph::source::CacheSetting;
16+
use deno_graph::source::ChecksumIntegrityError;
17+
use deno_graph::source::LoadError;
1618
use deno_graph::source::LoadFuture;
1719
use deno_graph::source::LoadOptions;
1820
use deno_graph::source::LoadResponse;
@@ -388,6 +390,86 @@ async fn test_jsr_wasm_module() {
388390
}
389391
}
390392

393+
#[tokio::test]
394+
async fn test_checksum_error_force_refresh() {
395+
#[derive(Default)]
396+
struct TestLoader {
397+
requests: RefCell<Vec<(String, CacheSetting)>>,
398+
}
399+
400+
impl deno_graph::source::Loader for TestLoader {
401+
fn load(
402+
&self,
403+
specifier: &ModuleSpecifier,
404+
options: LoadOptions,
405+
) -> LoadFuture {
406+
self
407+
.requests
408+
.borrow_mut()
409+
.push((specifier.to_string(), options.cache_setting));
410+
let specifier = specifier.clone();
411+
match specifier.as_str() {
412+
"https://deno.land/mod.ts" => Box::pin(async move {
413+
match options.cache_setting {
414+
CacheSetting::Only => unreachable!(),
415+
CacheSetting::Use => {
416+
Err(LoadError::ChecksumIntegrity(ChecksumIntegrityError {
417+
actual: "actual".to_string(),
418+
expected: "expected".to_string(),
419+
}))
420+
}
421+
CacheSetting::Reload => Ok(Some(LoadResponse::Module {
422+
specifier: specifier.clone(),
423+
maybe_headers: None,
424+
content: b"import './other.js';".to_vec().into(),
425+
})),
426+
}
427+
}),
428+
"https://deno.land/other.js" => Box::pin(async move {
429+
match options.cache_setting {
430+
CacheSetting::Only => unreachable!(),
431+
CacheSetting::Use => {
432+
Err(LoadError::ChecksumIntegrity(ChecksumIntegrityError {
433+
actual: "actual".to_string(),
434+
expected: "expected".to_string(),
435+
}))
436+
}
437+
CacheSetting::Reload => Ok(Some(LoadResponse::Module {
438+
specifier: specifier.clone(),
439+
maybe_headers: None,
440+
content: b"console.log(1);".to_vec().into(),
441+
})),
442+
}
443+
}),
444+
_ => unreachable!(),
445+
}
446+
}
447+
}
448+
449+
let loader = TestLoader::default();
450+
let mut graph = ModuleGraph::new(GraphKind::All);
451+
graph
452+
.build(
453+
vec![Url::parse("https://deno.land/mod.ts").unwrap()],
454+
&loader,
455+
Default::default(),
456+
)
457+
.await;
458+
graph.valid().unwrap();
459+
assert_eq!(
460+
*loader.requests.borrow(),
461+
vec![
462+
("https://deno.land/mod.ts".to_string(), CacheSetting::Use),
463+
("https://deno.land/mod.ts".to_string(), CacheSetting::Reload),
464+
("https://deno.land/other.js".to_string(), CacheSetting::Use),
465+
(
466+
"https://deno.land/other.js".to_string(),
467+
CacheSetting::Reload
468+
),
469+
]
470+
);
471+
}
472+
391473
#[tokio::test]
392474
async fn test_dynamic_imports_with_template_arg() {
393475
async fn run_test(

0 commit comments

Comments
 (0)