Skip to content

Commit 75a3eec

Browse files
committed
Rename errors::http to errors::json
The remaining helper structs that build json errors were also moved to this module.
1 parent b35f59f commit 75a3eec

File tree

3 files changed

+169
-172
lines changed

3 files changed

+169
-172
lines changed

src/util/errors.rs

Lines changed: 8 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,22 @@ use std::any::{Any, TypeId};
1616
use std::error::Error;
1717
use std::fmt;
1818

19-
use chrono::NaiveDateTime;
20-
use conduit::{header, StatusCode};
2119
use diesel::result::Error as DieselError;
2220

23-
use crate::util::{json_response, AppResponse};
21+
use crate::util::AppResponse;
2422

2523
pub(super) mod concrete;
26-
mod http;
24+
mod json;
2725

28-
pub(crate) use self::http::NotFound;
26+
pub(crate) use json::{NotFound, ReadOnlyMode, TooManyRequests};
2927

3028
/// Returns an error with status 200 and the provided description as JSON
3129
///
3230
/// This is for backwards compatibility with cargo endpoints. For all other
3331
/// endpoints, use helpers like `bad_request` or `server_error` which set a
3432
/// correct status code.
3533
pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
36-
Box::new(http::Ok(error.to_string()))
34+
Box::new(json::Ok(error.to_string()))
3735
}
3836

3937
// The following are intended to be used for errors being sent back to the Ember
@@ -43,38 +41,20 @@ pub fn cargo_err<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
4341

4442
/// Return an error with status 400 and the provided description as JSON
4543
pub fn bad_request<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
46-
Box::new(http::BadRequest(error.to_string()))
44+
Box::new(json::BadRequest(error.to_string()))
4745
}
4846

4947
pub fn forbidden() -> Box<dyn AppError> {
50-
Box::new(http::Forbidden)
48+
Box::new(json::Forbidden)
5149
}
5250

5351
pub fn not_found() -> Box<dyn AppError> {
54-
Box::new(http::NotFound)
52+
Box::new(json::NotFound)
5553
}
5654

5755
/// Returns an error with status 500 and the provided description as JSON
5856
pub fn server_error<S: ToString + ?Sized>(error: &S) -> Box<dyn AppError> {
59-
Box::new(http::ServerError(error.to_string()))
60-
}
61-
62-
#[derive(Serialize)]
63-
struct StringError<'a> {
64-
detail: &'a str,
65-
}
66-
#[derive(Serialize)]
67-
struct Bad<'a> {
68-
errors: Vec<StringError<'a>>,
69-
}
70-
71-
/// Generates a response with the provided status and description as JSON
72-
fn json_error(detail: &str, status: StatusCode) -> AppResponse {
73-
let mut response = json_response(&Bad {
74-
errors: vec![StringError { detail }],
75-
});
76-
*response.status_mut() = status;
77-
response
57+
Box::new(json::ServerError(error.to_string()))
7858
}
7959

8060
// =============================================================================
@@ -248,59 +228,6 @@ pub(crate) fn std_error(e: Box<dyn AppError>) -> Box<dyn Error + Send> {
248228
Box::new(AppErrToStdErr(e))
249229
}
250230

251-
#[derive(Debug, Clone, Copy)]
252-
pub struct ReadOnlyMode;
253-
254-
impl AppError for ReadOnlyMode {
255-
fn response(&self) -> Option<AppResponse> {
256-
let detail = "Crates.io is currently in read-only mode for maintenance. \
257-
Please try again later.";
258-
Some(json_error(detail, StatusCode::SERVICE_UNAVAILABLE))
259-
}
260-
}
261-
262-
impl fmt::Display for ReadOnlyMode {
263-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264-
"Tried to write in read only mode".fmt(f)
265-
}
266-
}
267-
268-
#[derive(Debug, Clone, Copy)]
269-
pub struct TooManyRequests {
270-
pub retry_after: NaiveDateTime,
271-
}
272-
273-
impl AppError for TooManyRequests {
274-
fn response(&self) -> Option<AppResponse> {
275-
use std::convert::TryInto;
276-
277-
const HTTP_DATE_FORMAT: &str = "%a, %d %b %Y %H:%M:%S GMT";
278-
let retry_after = self.retry_after.format(HTTP_DATE_FORMAT);
279-
280-
let detail = format!(
281-
"You have published too many crates in a \
282-
short period of time. Please try again after {} or email \
283-
[email protected] to have your limit increased.",
284-
retry_after
285-
);
286-
let mut response = json_error(&detail, StatusCode::TOO_MANY_REQUESTS);
287-
response.headers_mut().insert(
288-
header::RETRY_AFTER,
289-
retry_after
290-
.to_string()
291-
.try_into()
292-
.expect("HTTP_DATE_FORMAT contains invalid char"),
293-
);
294-
Some(response)
295-
}
296-
}
297-
298-
impl fmt::Display for TooManyRequests {
299-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300-
"Too many requests".fmt(f)
301-
}
302-
}
303-
304231
#[test]
305232
fn chain_error_internal() {
306233
assert_eq!(

src/util/errors/http.rs

Lines changed: 0 additions & 91 deletions
This file was deleted.

src/util/errors/json.rs

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
use std::fmt;
2+
3+
use super::AppError;
4+
use crate::util::{json_response, AppResponse};
5+
6+
use chrono::NaiveDateTime;
7+
use conduit::{header, StatusCode};
8+
9+
/// Generates a response with the provided status and description as JSON
10+
fn json_error(detail: &str, status: StatusCode) -> AppResponse {
11+
#[derive(Serialize)]
12+
struct StringError<'a> {
13+
detail: &'a str,
14+
}
15+
#[derive(Serialize)]
16+
struct Bad<'a> {
17+
errors: Vec<StringError<'a>>,
18+
}
19+
20+
let mut response = json_response(&Bad {
21+
errors: vec![StringError { detail }],
22+
});
23+
*response.status_mut() = status;
24+
response
25+
}
26+
27+
// The following structs are emtpy and do not provide a custom message to the user
28+
29+
#[derive(Debug)]
30+
pub(crate) struct NotFound;
31+
32+
// This struct has this helper impl for use as `NotFound.into()`
33+
impl From<NotFound> for AppResponse {
34+
fn from(_: NotFound) -> AppResponse {
35+
json_error("Not Found", StatusCode::NOT_FOUND)
36+
}
37+
}
38+
39+
impl AppError for NotFound {
40+
fn response(&self) -> Option<AppResponse> {
41+
Some(Self.into())
42+
}
43+
}
44+
45+
impl fmt::Display for NotFound {
46+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47+
"Not Found".fmt(f)
48+
}
49+
}
50+
51+
#[derive(Debug)]
52+
pub(super) struct Forbidden;
53+
#[derive(Debug)]
54+
pub(crate) struct ReadOnlyMode;
55+
56+
impl AppError for Forbidden {
57+
fn response(&self) -> Option<AppResponse> {
58+
let detail = "must be logged in to perform that action";
59+
Some(json_error(detail, StatusCode::FORBIDDEN))
60+
}
61+
}
62+
63+
impl fmt::Display for Forbidden {
64+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65+
"must be logged in to perform that action".fmt(f)
66+
}
67+
}
68+
69+
impl AppError for ReadOnlyMode {
70+
fn response(&self) -> Option<AppResponse> {
71+
let detail = "Crates.io is currently in read-only mode for maintenance. \
72+
Please try again later.";
73+
Some(json_error(detail, StatusCode::SERVICE_UNAVAILABLE))
74+
}
75+
}
76+
77+
impl fmt::Display for ReadOnlyMode {
78+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79+
"Tried to write in read only mode".fmt(f)
80+
}
81+
}
82+
83+
// The following structs wrap owned data and provide a custom message to the user
84+
85+
#[derive(Debug)]
86+
pub(super) struct Ok(pub(super) String);
87+
#[derive(Debug)]
88+
pub(super) struct BadRequest(pub(super) String);
89+
#[derive(Debug)]
90+
pub(super) struct ServerError(pub(super) String);
91+
#[derive(Debug)]
92+
pub(crate) struct TooManyRequests {
93+
pub retry_after: NaiveDateTime,
94+
}
95+
96+
impl AppError for Ok {
97+
fn response(&self) -> Option<AppResponse> {
98+
Some(json_error(&self.0, StatusCode::OK))
99+
}
100+
}
101+
102+
impl fmt::Display for Ok {
103+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104+
self.0.fmt(f)
105+
}
106+
}
107+
108+
impl AppError for BadRequest {
109+
fn response(&self) -> Option<AppResponse> {
110+
Some(json_error(&self.0, StatusCode::BAD_REQUEST))
111+
}
112+
}
113+
114+
impl fmt::Display for BadRequest {
115+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116+
self.0.fmt(f)
117+
}
118+
}
119+
120+
impl AppError for ServerError {
121+
fn response(&self) -> Option<AppResponse> {
122+
Some(json_error(&self.0, StatusCode::INTERNAL_SERVER_ERROR))
123+
}
124+
}
125+
126+
impl fmt::Display for ServerError {
127+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128+
self.0.fmt(f)
129+
}
130+
}
131+
132+
impl AppError for TooManyRequests {
133+
fn response(&self) -> Option<AppResponse> {
134+
use std::convert::TryInto;
135+
136+
const HTTP_DATE_FORMAT: &str = "%a, %d %b %Y %H:%M:%S GMT";
137+
let retry_after = self.retry_after.format(HTTP_DATE_FORMAT);
138+
139+
let detail = format!(
140+
"You have published too many crates in a \
141+
short period of time. Please try again after {} or email \
142+
[email protected] to have your limit increased.",
143+
retry_after
144+
);
145+
let mut response = json_error(&detail, StatusCode::TOO_MANY_REQUESTS);
146+
response.headers_mut().insert(
147+
header::RETRY_AFTER,
148+
retry_after
149+
.to_string()
150+
.try_into()
151+
.expect("HTTP_DATE_FORMAT contains invalid char"),
152+
);
153+
Some(response)
154+
}
155+
}
156+
157+
impl fmt::Display for TooManyRequests {
158+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159+
"Too many requests".fmt(f)
160+
}
161+
}

0 commit comments

Comments
 (0)