1
- use super :: { cache:: CachePolicy , match_version , redirect_base , MatchSemver } ;
1
+ use super :: { cache:: CachePolicy , MatchSemver } ;
2
2
use crate :: {
3
3
db:: Pool ,
4
4
docbuilder:: Limits ,
5
- impl_webpage,
6
- web:: { page:: WebPage , MetaData } ,
5
+ impl_axum_webpage,
6
+ utils:: spawn_blocking,
7
+ web:: { error:: AxumResult , match_version_axum, MetaData } ,
7
8
} ;
8
- use chrono:: { DateTime , Utc } ;
9
- use iron:: {
10
- headers:: { AccessControlAllowOrigin , ContentType } ,
11
- status, IronResult , Request , Response , Url ,
9
+ use anyhow:: Result ;
10
+ use axum:: {
11
+ extract:: { Extension , Path } ,
12
+ http:: header:: ACCESS_CONTROL_ALLOW_ORIGIN ,
13
+ response:: IntoResponse ,
14
+ Json ,
12
15
} ;
13
- use router :: Router ;
16
+ use chrono :: { DateTime , Utc } ;
14
17
use serde:: Serialize ;
15
18
16
19
#[ derive( Debug , Clone , PartialEq , Eq , Serialize ) ]
@@ -30,49 +33,89 @@ struct BuildsPage {
30
33
canonical_url : String ,
31
34
}
32
35
33
- impl_webpage ! {
36
+ impl_axum_webpage ! {
34
37
BuildsPage = "crate/builds.html" ,
35
38
}
36
39
37
- pub fn build_list_handler ( req : & mut Request ) -> IronResult < Response > {
38
- let router = extension ! ( req, Router ) ;
39
- let name = cexpect ! ( req, router. find( "name" ) ) ;
40
- let req_version = router. find ( "version" ) ;
41
-
42
- let mut conn = extension ! ( req, Pool ) . get ( ) ?;
43
- let limits = ctry ! ( req, Limits :: for_crate( & mut conn, name) ) ;
44
-
45
- let is_json = req
46
- . url
47
- . path ( )
48
- . last ( )
49
- . map_or ( false , |segment| segment. ends_with ( ".json" ) ) ;
50
-
51
- let ( version, version_or_latest) =
52
- match match_version ( & mut conn, name, req_version) . and_then ( |m| m. assume_exact ( ) ) ? {
53
- MatchSemver :: Exact ( ( version, _) ) => ( version. clone ( ) , version) ,
54
- MatchSemver :: Latest ( ( version, _) ) => ( version, "latest" . to_string ( ) ) ,
55
-
56
- MatchSemver :: Semver ( ( version, _) ) => {
57
- let ext = if is_json { ".json" } else { "" } ;
58
- let url = ctry ! (
59
- req,
60
- Url :: parse( & format!(
61
- "{}/crate/{}/{}/builds{}" ,
62
- redirect_base( req) ,
63
- name,
64
- version,
65
- ext,
66
- ) ) ,
67
- ) ;
68
-
69
- return Ok ( super :: redirect ( url) ) ;
70
- }
71
- } ;
72
-
73
- let query = ctry ! (
74
- req,
75
- conn. query(
40
+ pub ( crate ) async fn build_list_handler (
41
+ Path ( ( name, req_version) ) : Path < ( String , String ) > ,
42
+ Extension ( pool) : Extension < Pool > ,
43
+ ) -> AxumResult < impl IntoResponse > {
44
+ let ( version, version_or_latest) = match match_version_axum ( & pool, & name, Some ( & req_version) )
45
+ . await ?
46
+ . assume_exact ( ) ?
47
+ {
48
+ MatchSemver :: Exact ( ( version, _) ) => ( version. clone ( ) , version) ,
49
+ MatchSemver :: Latest ( ( version, _) ) => ( version, "latest" . to_string ( ) ) ,
50
+
51
+ MatchSemver :: Semver ( ( version, _) ) => {
52
+ return Ok ( super :: axum_cached_redirect (
53
+ & format ! ( "/crate/{}/{}/builds" , name, version) ,
54
+ CachePolicy :: ForeverInCdn ,
55
+ ) ?
56
+ . into_response ( ) ) ;
57
+ }
58
+ } ;
59
+
60
+ let ( limits, builds, metadata) = spawn_blocking ( {
61
+ let name = name. clone ( ) ;
62
+ move || {
63
+ let mut conn = pool. get ( ) ?;
64
+ Ok ( (
65
+ Limits :: for_crate ( & mut conn, & name) ?,
66
+ get_builds ( & mut conn, & name, & version) ?,
67
+ MetaData :: from_crate ( & mut conn, & name, & version, & version_or_latest) ?,
68
+ ) )
69
+ }
70
+ } )
71
+ . await ?;
72
+
73
+ Ok ( BuildsPage {
74
+ metadata,
75
+ builds,
76
+ limits,
77
+ canonical_url : format ! ( "https://docs.rs/crate/{}/latest/builds" , name) ,
78
+ }
79
+ . into_response ( ) )
80
+ }
81
+
82
+ pub ( crate ) async fn build_list_json_handler (
83
+ Path ( ( name, req_version) ) : Path < ( String , String ) > ,
84
+ Extension ( pool) : Extension < Pool > ,
85
+ ) -> AxumResult < impl IntoResponse > {
86
+ let version = match match_version_axum ( & pool, & name, Some ( & req_version) )
87
+ . await ?
88
+ . assume_exact ( ) ?
89
+ {
90
+ MatchSemver :: Exact ( ( version, _) ) | MatchSemver :: Latest ( ( version, _) ) => version,
91
+ MatchSemver :: Semver ( ( version, _) ) => {
92
+ return Ok ( super :: axum_cached_redirect (
93
+ & format ! ( "/crate/{}/{}/builds.json" , name, version) ,
94
+ CachePolicy :: ForeverInCdn ,
95
+ ) ?
96
+ . into_response ( ) ) ;
97
+ }
98
+ } ;
99
+
100
+ let builds = spawn_blocking ( {
101
+ move || {
102
+ let mut conn = pool. get ( ) ?;
103
+ get_builds ( & mut conn, & name, & version)
104
+ }
105
+ } )
106
+ . await ?;
107
+
108
+ Ok ( (
109
+ Extension ( CachePolicy :: NoStoreMustRevalidate ) ,
110
+ [ ( ACCESS_CONTROL_ALLOW_ORIGIN , "*" ) ] ,
111
+ Json ( builds) ,
112
+ )
113
+ . into_response ( ) )
114
+ }
115
+
116
+ fn get_builds ( conn : & mut postgres:: Client , name : & str , version : & str ) -> Result < Vec < Build > > {
117
+ Ok ( conn
118
+ . query (
76
119
"SELECT crates.name,
77
120
releases.version,
78
121
releases.description,
@@ -88,41 +131,17 @@ pub fn build_list_handler(req: &mut Request) -> IronResult<Response> {
88
131
INNER JOIN crates ON releases.crate_id = crates.id
89
132
WHERE crates.name = $1 AND releases.version = $2
90
133
ORDER BY id DESC" ,
91
- & [ & name, & version]
92
- )
93
- ) ;
94
-
95
- let builds: Vec < _ > = query
96
- . into_iter ( )
134
+ & [ & name, & version] ,
135
+ ) ?
136
+ . iter ( )
97
137
. map ( |row| Build {
98
138
id : row. get ( "id" ) ,
99
139
rustc_version : row. get ( "rustc_version" ) ,
100
140
docsrs_version : row. get ( "docsrs_version" ) ,
101
141
build_status : row. get ( "build_status" ) ,
102
142
build_time : row. get ( "build_time" ) ,
103
143
} )
104
- . collect ( ) ;
105
-
106
- if is_json {
107
- let mut resp = Response :: with ( ( status:: Ok , serde_json:: to_string ( & builds) . unwrap ( ) ) ) ;
108
- resp. headers . set ( ContentType :: json ( ) ) ;
109
- resp. extensions
110
- . insert :: < CachePolicy > ( CachePolicy :: NoStoreMustRevalidate ) ;
111
- resp. headers . set ( AccessControlAllowOrigin :: Any ) ;
112
-
113
- Ok ( resp)
114
- } else {
115
- BuildsPage {
116
- metadata : cexpect ! (
117
- req,
118
- MetaData :: from_crate( & mut conn, name, & version, & version_or_latest)
119
- ) ,
120
- builds,
121
- limits,
122
- canonical_url : format ! ( "https://docs.rs/crate/{}/latest/builds" , name) ,
123
- }
124
- . into_response ( req)
125
- }
144
+ . collect ( ) )
126
145
}
127
146
128
147
#[ cfg( test) ]
0 commit comments