@@ -91,6 +91,7 @@ mod statics;
91
91
92
92
use crate :: { impl_webpage, Context } ;
93
93
use chrono:: { DateTime , Utc } ;
94
+ use error:: Nope ;
94
95
use extensions:: InjectExtensions ;
95
96
use failure:: Error ;
96
97
use iron:: {
@@ -177,13 +178,14 @@ impl Handler for CratesfyiHandler {
177
178
}
178
179
} ;
179
180
180
- // try serving shared rustdoc resources first, then router, then db/static file handler
181
- // return 404 if none of them return Ok
181
+ // try serving shared rustdoc resources first, then db/static file handler and last router
182
+ // return 404 if none of them return Ok. It is important that the router comes last,
183
+ // because it gives the most specific errors, e.g. CrateNotFound or VersionNotFound
182
184
self . shared_resource_handler
183
185
. handle ( req)
184
- . or_else ( |e| if_404 ( e, || self . router_handler . handle ( req) ) )
185
186
. or_else ( |e| if_404 ( e, || self . database_file_handler . handle ( req) ) )
186
187
. or_else ( |e| if_404 ( e, || self . static_handler . handle ( req) ) )
188
+ . or_else ( |e| if_404 ( e, || self . router_handler . handle ( req) ) )
187
189
. or_else ( |e| {
188
190
let err = if let Some ( err) = e. error . downcast :: < error:: Nope > ( ) {
189
191
* err
@@ -245,12 +247,12 @@ struct MatchVersion {
245
247
impl MatchVersion {
246
248
/// If the matched version was an exact match to the requested crate name, returns the
247
249
/// `MatchSemver` for the query. If the lookup required a dash/underscore conversion, returns
248
- /// `None `.
249
- fn assume_exact ( self ) -> Option < MatchSemver > {
250
+ /// `Nope::CrateNotFound `.
251
+ fn assume_exact ( self ) -> Result < MatchSemver , Nope > {
250
252
if self . corrected_name . is_none ( ) {
251
- Some ( self . version )
253
+ Ok ( self . version )
252
254
} else {
253
- None
255
+ Err ( Nope :: CrateNotFound )
254
256
}
255
257
}
256
258
}
@@ -284,7 +286,11 @@ impl MatchSemver {
284
286
/// This function will also check for crates where dashes in the name (`-`) have been replaced with
285
287
/// underscores (`_`) and vice-versa. The return value will indicate whether the crate name has
286
288
/// been matched exactly, or if there has been a "correction" in the name that matched instead.
287
- fn match_version ( conn : & mut Client , name : & str , version : Option < & str > ) -> Option < MatchVersion > {
289
+ fn match_version (
290
+ conn : & mut Client ,
291
+ name : & str ,
292
+ version : Option < & str > ,
293
+ ) -> Result < MatchVersion , Nope > {
288
294
// version is an Option<&str> from router::Router::get, need to decode first
289
295
use iron:: url:: percent_encoding:: percent_decode;
290
296
@@ -320,24 +326,31 @@ fn match_version(conn: &mut Client, name: &str, version: Option<&str>) -> Option
320
326
. collect ( )
321
327
} ;
322
328
329
+ if versions. is_empty ( ) {
330
+ return Err ( Nope :: CrateNotFound ) ;
331
+ }
332
+
323
333
// first check for exact match, we can't expect users to use semver in query
324
334
if let Some ( ( version, id, _) ) = versions. iter ( ) . find ( |( vers, _, _) | vers == & req_version) {
325
- return Some ( MatchVersion {
335
+ return Ok ( MatchVersion {
326
336
corrected_name,
327
337
version : MatchSemver :: Exact ( ( version. to_owned ( ) , * id) ) ,
328
338
} ) ;
329
339
}
330
340
331
341
// Now try to match with semver
332
- let req_sem_ver = VersionReq :: parse ( & req_version) . ok ( ) ?;
342
+ let req_sem_ver = VersionReq :: parse ( & req_version) . map_err ( |_| Nope :: CrateNotFound ) ?;
333
343
334
344
// we need to sort versions first
335
345
let versions_sem = {
336
346
let mut versions_sem: Vec < ( Version , i32 ) > = Vec :: with_capacity ( versions. len ( ) ) ;
337
347
338
348
for version in versions. iter ( ) . filter ( |( _, _, yanked) | !yanked) {
339
349
// in theory a crate must always have a semver compatible version, but check result just in case
340
- versions_sem. push ( ( Version :: parse ( & version. 0 ) . ok ( ) ?, version. 1 ) ) ;
350
+ versions_sem. push ( (
351
+ Version :: parse ( & version. 0 ) . map_err ( |_| Nope :: InternalServerError ) ?,
352
+ version. 1 ,
353
+ ) ) ;
341
354
}
342
355
343
356
versions_sem. sort ( ) ;
@@ -349,7 +362,7 @@ fn match_version(conn: &mut Client, name: &str, version: Option<&str>) -> Option
349
362
. iter ( )
350
363
. find ( |( vers, _) | req_sem_ver. matches ( vers) )
351
364
{
352
- return Some ( MatchVersion {
365
+ return Ok ( MatchVersion {
353
366
corrected_name,
354
367
version : MatchSemver :: Semver ( ( version. to_string ( ) , * id) ) ,
355
368
} ) ;
@@ -358,13 +371,18 @@ fn match_version(conn: &mut Client, name: &str, version: Option<&str>) -> Option
358
371
// semver is acting weird for '*' (any) range if a crate only have pre-release versions
359
372
// return first non-yanked version if requested version is '*'
360
373
if req_version == "*" {
361
- return versions_sem. first ( ) . map ( |v| MatchVersion {
362
- corrected_name,
363
- version : MatchSemver :: Semver ( ( v. 0 . to_string ( ) , v. 1 ) ) ,
364
- } ) ;
374
+ return versions_sem
375
+ . first ( )
376
+ . map ( |v| MatchVersion {
377
+ corrected_name,
378
+ version : MatchSemver :: Semver ( ( v. 0 . to_string ( ) , v. 1 ) ) ,
379
+ } )
380
+ . ok_or ( Nope :: CrateNotFound ) ;
365
381
}
366
382
367
- None
383
+ // Since we return with a CrateNotFound earlier if the db reply is empty,
384
+ // we know that versions were returned but none satisfied the version requirement
385
+ Err ( Nope :: VersionNotFound )
368
386
}
369
387
370
388
/// Wrapper around the Markdown parser and renderer to render markdown
@@ -581,7 +599,13 @@ mod test {
581
599
582
600
fn version ( v : Option < & str > , db : & TestDatabase ) -> Option < String > {
583
601
match_version ( & mut db. conn ( ) , "foo" , v)
584
- . and_then ( |version| version. assume_exact ( ) . map ( |semver| semver. into_parts ( ) . 0 ) )
602
+ . ok ( )
603
+ . and_then ( |version| {
604
+ version
605
+ . assume_exact ( )
606
+ . ok ( )
607
+ . map ( |semver| semver. into_parts ( ) . 0 )
608
+ } )
585
609
}
586
610
587
611
fn semver ( version : & ' static str ) -> Option < String > {
0 commit comments