1+ // Copyright 2018-2025 the Deno authors. MIT license.
2+
3+ use std:: borrow:: Cow ;
4+
5+ use url:: Url ;
6+
7+ use super :: FetchCachedError ;
8+ use super :: FetchCachedErrorKind ;
9+ use super :: FetchCachedNoFollowError ;
10+ use super :: FetchCachedNoFollowErrorKind ;
11+ use super :: FileOrRedirect ;
12+ use super :: File ;
13+ use super :: TooManyRedirectsError ;
14+ use crate :: Checksum ;
15+
16+ pub trait AsyncFileFetcherExt {
17+ /// Fetch cached remote file asynchronously.
18+ ///
19+ /// This is a recursive operation if source file has redirections.
20+ async fn fetch_cached_async (
21+ & self ,
22+ url : & Url ,
23+ redirect_limit : i64 ,
24+ ) -> Result < Option < File > , FetchCachedError > ;
25+
26+ /// Fetches from cache without following redirects asynchronously.
27+ async fn fetch_cached_no_follow_async (
28+ & self ,
29+ url : & Url ,
30+ maybe_checksum : Option < Checksum < ' _ > > ,
31+ ) -> Result < Option < FileOrRedirect > , FetchCachedNoFollowError > ;
32+ }
33+
34+ #[ cfg( feature = "async-module-loading" ) ]
35+ impl < TBlobStore , TSys , THttpClient > AsyncFileFetcherExt for super :: FileFetcher < TBlobStore , TSys , THttpClient >
36+ where
37+ TBlobStore : super :: BlobStore + Clone ,
38+ TSys : crate :: sync:: MaybeSend + crate :: sync:: MaybeSync + sys_traits:: FsRead + sys_traits:: SystemTimeNow + Clone ,
39+ THttpClient : super :: HttpClient + Clone ,
40+ {
41+ async fn fetch_cached_async (
42+ & self ,
43+ url : & Url ,
44+ redirect_limit : i64 ,
45+ ) -> Result < Option < File > , FetchCachedError > {
46+ if !matches ! ( url. scheme( ) , "http" | "https" ) {
47+ return Ok ( None ) ;
48+ }
49+
50+ let mut url = Cow :: Borrowed ( url) ;
51+ for _ in 0 ..=redirect_limit {
52+ match self . fetch_cached_no_follow_async ( & url, None ) . await ? {
53+ Some ( FileOrRedirect :: File ( file) ) => {
54+ return Ok ( Some ( file) ) ;
55+ }
56+ Some ( FileOrRedirect :: Redirect ( redirect_url) ) => {
57+ url = Cow :: Owned ( redirect_url) ;
58+ }
59+ None => {
60+ return Ok ( None ) ;
61+ }
62+ }
63+ }
64+ Err (
65+ FetchCachedErrorKind :: TooManyRedirects ( TooManyRedirectsError (
66+ url. into_owned ( ) ,
67+ ) )
68+ . into_box ( ) ,
69+ )
70+ }
71+
72+ async fn fetch_cached_no_follow_async (
73+ & self ,
74+ url : & Url ,
75+ maybe_checksum : Option < Checksum < ' _ > > ,
76+ ) -> Result < Option < FileOrRedirect > , FetchCachedNoFollowError > {
77+ let url = url. clone ( ) ;
78+ let maybe_checksum_owned = maybe_checksum. map ( |checksum| Checksum :: new ( checksum. as_str ( ) ) ) ;
79+ let this = self . clone ( ) ;
80+
81+ // Run in a blocking task to avoid holding the JS thread
82+ tokio:: task:: spawn_blocking ( move || {
83+ this. fetch_cached_no_follow ( & url, maybe_checksum_owned)
84+ } )
85+ . await
86+ . unwrap ( )
87+ }
88+ }
89+
90+ #[ cfg( not( feature = "async-module-loading" ) ) ]
91+ impl < TBlobStore , TSys , THttpClient > AsyncFileFetcherExt for super :: FileFetcher < TBlobStore , TSys , THttpClient >
92+ where
93+ TBlobStore : super :: BlobStore + Clone ,
94+ TSys : crate :: sync:: MaybeSend + crate :: sync:: MaybeSync + sys_traits:: FsRead + sys_traits:: SystemTimeNow + Clone ,
95+ THttpClient : super :: HttpClient + Clone ,
96+ {
97+ async fn fetch_cached_async (
98+ & self ,
99+ url : & Url ,
100+ redirect_limit : i64 ,
101+ ) -> Result < Option < File > , FetchCachedError > {
102+ self . fetch_cached ( url, redirect_limit)
103+ }
104+
105+ async fn fetch_cached_no_follow_async (
106+ & self ,
107+ url : & Url ,
108+ maybe_checksum : Option < Checksum < ' _ > > ,
109+ ) -> Result < Option < FileOrRedirect > , FetchCachedNoFollowError > {
110+ self . fetch_cached_no_follow ( url, maybe_checksum)
111+ }
112+ }
0 commit comments