@@ -2,6 +2,8 @@ use fastly::http::{Method, StatusCode};
2
2
use fastly:: { Error , Request , Response } ;
3
3
use log:: { info, warn, LevelFilter } ;
4
4
use log_fastly:: Logger ;
5
+ use once_cell:: sync:: Lazy ;
6
+ use regex:: Regex ;
5
7
use serde_json:: json;
6
8
use time:: OffsetDateTime ;
7
9
@@ -74,6 +76,7 @@ fn handle_request(config: &Config, mut request: Request) -> Result<Response, Err
74
76
75
77
set_ttl ( config, & mut request) ;
76
78
rewrite_urls_with_plus_character ( & mut request) ;
79
+ rewrite_download_urls ( & mut request) ;
77
80
78
81
// Database dump is too big to cache on Fastly
79
82
if request. get_url_str ( ) . ends_with ( "db-dump.tar.gz" ) {
@@ -127,6 +130,28 @@ fn rewrite_urls_with_plus_character(request: &mut Request) {
127
130
}
128
131
}
129
132
133
+ /// Rewrite `/crates/{crate}/{version}/download` URLs to
134
+ /// `/crates/{crate}/{crate}-{version}.crate`
135
+ ///
136
+ /// cargo versions before 1.24 don't support placeholders in the `dl` field
137
+ /// of the index, so we need to rewrite the download URL to point to the
138
+ /// crate file instead.
139
+ fn rewrite_download_urls ( request : & mut Request ) {
140
+ static RE : Lazy < Regex > = Lazy :: new ( || {
141
+ Regex :: new ( r"^/crates/(?P<crate>[^/]+)/(?P<version>[^/]+)/download$" ) . unwrap ( )
142
+ } ) ;
143
+
144
+ let url = request. get_url_mut ( ) ;
145
+ let path = url. path ( ) ;
146
+
147
+ if let Some ( captures) = RE . captures ( path) {
148
+ let krate = captures. name ( "crate" ) . unwrap ( ) . as_str ( ) ;
149
+ let version = captures. name ( "version" ) . unwrap ( ) . as_str ( ) ;
150
+ let new_path = format ! ( "/crates/{krate}/{krate}-{version}.crate" ) ;
151
+ url. set_path ( & new_path) ;
152
+ }
153
+ }
154
+
130
155
/// Redirect request to CloudFront
131
156
///
132
157
/// As of early 2023, certain files are too large to be served through Fastly. One of those is the
@@ -199,3 +224,34 @@ fn build_and_send_log(log_line: LogLineV1Builder, config: &Config) {
199
224
}
200
225
} ;
201
226
}
227
+
228
+ #[ cfg( test) ]
229
+ mod tests {
230
+ use super :: * ;
231
+
232
+ #[ test]
233
+ fn test_rewrite_download_urls ( ) {
234
+ fn test ( url : & str , expected : & str ) {
235
+ let mut request = Request :: get ( url) ;
236
+ rewrite_download_urls ( & mut request) ;
237
+ assert_eq ! ( request. get_url_str( ) , expected) ;
238
+ }
239
+
240
+ test (
241
+ "https://static.crates.io/unrelated" ,
242
+ "https://static.crates.io/unrelated" ,
243
+ ) ;
244
+ test (
245
+ "https://static.crates.io/crates/serde/serde-1.0.0.crate" ,
246
+ "https://static.crates.io/crates/serde/serde-1.0.0.crate" ,
247
+ ) ;
248
+ test (
249
+ "https://static.crates.io/crates/serde/1.0.0/download" ,
250
+ "https://static.crates.io/crates/serde/serde-1.0.0.crate" ,
251
+ ) ;
252
+ test (
253
+ "https://static.crates.io/crates/serde/1.0.0-alpha.1+foo-bar/download" ,
254
+ "https://static.crates.io/crates/serde/serde-1.0.0-alpha.1+foo-bar.crate" ,
255
+ ) ;
256
+ }
257
+ }
0 commit comments