@@ -16,22 +16,22 @@ use std::any::{Any, TypeId};
16
16
use std:: error:: Error ;
17
17
use std:: fmt;
18
18
19
- use chrono:: NaiveDateTime ;
20
- use conduit:: { header, StatusCode } ;
21
19
use diesel:: result:: Error as DieselError ;
22
20
23
- use crate :: util:: { json_response , AppResponse } ;
21
+ use crate :: util:: AppResponse ;
24
22
25
23
pub ( super ) mod concrete;
26
- mod http;
24
+ mod json;
25
+
26
+ pub ( crate ) use json:: { NotFound , ReadOnlyMode , TooManyRequests } ;
27
27
28
28
/// Returns an error with status 200 and the provided description as JSON
29
29
///
30
30
/// This is for backwards compatibility with cargo endpoints. For all other
31
31
/// endpoints, use helpers like `bad_request` or `server_error` which set a
32
32
/// correct status code.
33
33
pub fn cargo_err < S : ToString + ?Sized > ( error : & S ) -> Box < dyn AppError > {
34
- Box :: new ( http :: Ok ( error. to_string ( ) ) )
34
+ Box :: new ( json :: Ok ( error. to_string ( ) ) )
35
35
}
36
36
37
37
// The following are intended to be used for errors being sent back to the Ember
@@ -41,30 +41,20 @@ pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
41
41
42
42
/// Return an error with status 400 and the provided description as JSON
43
43
pub fn bad_request < S : ToString + ?Sized > ( error : & S ) -> Box < dyn AppError > {
44
- Box :: new ( http :: BadRequest ( error. to_string ( ) ) )
44
+ Box :: new ( json :: BadRequest ( error. to_string ( ) ) )
45
45
}
46
46
47
- /// Returns an error with status 500 and the provided description as JSON
48
- pub fn server_error < S : ToString + ?Sized > ( error : & S ) -> Box < dyn AppError > {
49
- Box :: new ( http:: ServerError ( error. to_string ( ) ) )
47
+ pub fn forbidden ( ) -> Box < dyn AppError > {
48
+ Box :: new ( json:: Forbidden )
50
49
}
51
50
52
- #[ derive( Serialize ) ]
53
- struct StringError < ' a > {
54
- detail : & ' a str ,
55
- }
56
- #[ derive( Serialize ) ]
57
- struct Bad < ' a > {
58
- errors : Vec < StringError < ' a > > ,
51
+ pub fn not_found ( ) -> Box < dyn AppError > {
52
+ Box :: new ( json:: NotFound )
59
53
}
60
54
61
- /// Generates a response with the provided status and description as JSON
62
- fn json_error ( detail : & str , status : StatusCode ) -> AppResponse {
63
- let mut response = json_response ( & Bad {
64
- errors : vec ! [ StringError { detail } ] ,
65
- } ) ;
66
- * response. status_mut ( ) = status;
67
- response
55
+ /// Returns an error with status 500 and the provided description as JSON
56
+ pub fn server_error < S : ToString + ?Sized > ( error : & S ) -> Box < dyn AppError > {
57
+ Box :: new ( json:: ServerError ( error. to_string ( ) ) )
68
58
}
69
59
70
60
// =============================================================================
@@ -99,7 +89,7 @@ impl dyn AppError {
99
89
100
90
fn try_convert ( err : & ( dyn Error + Send + ' static ) ) -> Option < Box < Self > > {
101
91
match err. downcast_ref ( ) {
102
- Some ( DieselError :: NotFound ) => Some ( Box :: new ( NotFound ) ) ,
92
+ Some ( DieselError :: NotFound ) => Some ( not_found ( ) ) ,
103
93
Some ( DieselError :: DatabaseError ( _, info) )
104
94
if info. message ( ) . ends_with ( "read-only transaction" ) =>
105
95
{
@@ -217,45 +207,6 @@ impl AppError for InternalAppError {
217
207
}
218
208
}
219
209
220
- // TODO: The remaining can probably move under `http`
221
-
222
- #[ derive( Debug , Clone , Copy ) ]
223
- pub struct NotFound ;
224
-
225
- impl From < NotFound > for AppResponse {
226
- fn from ( _: NotFound ) -> AppResponse {
227
- json_error ( "Not Found" , StatusCode :: NOT_FOUND )
228
- }
229
- }
230
-
231
- impl AppError for NotFound {
232
- fn response ( & self ) -> Option < AppResponse > {
233
- Some ( NotFound . into ( ) )
234
- }
235
- }
236
-
237
- impl fmt:: Display for NotFound {
238
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
239
- "Not Found" . fmt ( f)
240
- }
241
- }
242
-
243
- #[ derive( Debug , Clone , Copy ) ]
244
- pub struct Unauthorized ;
245
-
246
- impl AppError for Unauthorized {
247
- fn response ( & self ) -> Option < AppResponse > {
248
- let detail = "must be logged in to perform that action" ;
249
- Some ( json_error ( detail, StatusCode :: FORBIDDEN ) )
250
- }
251
- }
252
-
253
- impl fmt:: Display for Unauthorized {
254
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
255
- "must be logged in to perform that action" . fmt ( f)
256
- }
257
- }
258
-
259
210
pub fn internal < S : ToString + ?Sized > ( error : & S ) -> Box < dyn AppError > {
260
211
Box :: new ( InternalAppError {
261
212
description : error. to_string ( ) ,
@@ -277,59 +228,6 @@ pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
277
228
Box :: new ( AppErrToStdErr ( e) )
278
229
}
279
230
280
- #[ derive( Debug , Clone , Copy ) ]
281
- pub struct ReadOnlyMode ;
282
-
283
- impl AppError for ReadOnlyMode {
284
- fn response ( & self ) -> Option < AppResponse > {
285
- let detail = "Crates.io is currently in read-only mode for maintenance. \
286
- Please try again later.";
287
- Some ( json_error ( detail, StatusCode :: SERVICE_UNAVAILABLE ) )
288
- }
289
- }
290
-
291
- impl fmt:: Display for ReadOnlyMode {
292
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
293
- "Tried to write in read only mode" . fmt ( f)
294
- }
295
- }
296
-
297
- #[ derive( Debug , Clone , Copy ) ]
298
- pub struct TooManyRequests {
299
- pub retry_after : NaiveDateTime ,
300
- }
301
-
302
- impl AppError for TooManyRequests {
303
- fn response ( & self ) -> Option < AppResponse > {
304
- use std:: convert:: TryInto ;
305
-
306
- const HTTP_DATE_FORMAT : & str = "%a, %d %b %Y %H:%M:%S GMT" ;
307
- let retry_after = self . retry_after . format ( HTTP_DATE_FORMAT ) ;
308
-
309
- let detail = format ! (
310
- "You have published too many crates in a \
311
- short period of time. Please try again after {} or email \
312
- [email protected] to have your limit increased.",
313
- retry_after
314
- ) ;
315
- let mut response = json_error ( & detail, StatusCode :: TOO_MANY_REQUESTS ) ;
316
- response. headers_mut ( ) . insert (
317
- header:: RETRY_AFTER ,
318
- retry_after
319
- . to_string ( )
320
- . try_into ( )
321
- . expect ( "HTTP_DATE_FORMAT contains invalid char" ) ,
322
- ) ;
323
- Some ( response)
324
- }
325
- }
326
-
327
- impl fmt:: Display for TooManyRequests {
328
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
329
- "Too many requests" . fmt ( f)
330
- }
331
- }
332
-
333
231
#[ test]
334
232
fn chain_error_internal ( ) {
335
233
assert_eq ! (
@@ -358,7 +256,7 @@ fn chain_error_internal() {
358
256
"outer caused by inner"
359
257
) ;
360
258
assert_eq ! (
361
- Err :: <( ) , _>( Unauthorized )
259
+ Err :: <( ) , _>( forbidden ( ) )
362
260
. chain_error( || internal( "outer" ) )
363
261
. unwrap_err( )
364
262
. to_string( ) ,
0 commit comments