Remove unused reason phrase in 'Status'.

Closes #534.

Co-authored-by: YetAnotherMinion <yam@thinkalexandria.com>
This commit is contained in:
Sergio Benitez 2021-04-28 04:54:06 -07:00
parent 336a03e27f
commit ad8d80907b
7 changed files with 162 additions and 172 deletions

View File

@ -26,14 +26,14 @@ impl FromMeta for Status {
return Err(meta.value_span().error("status must be in range [100, 599]"));
}
Ok(Status(http::Status::raw(num as u16)))
Ok(Status(http::Status::new(num as u16)))
}
}
impl ToTokens for Status {
fn to_tokens(&self, tokens: &mut TokenStream) {
let (code, reason) = (self.0.code, self.0.reason);
tokens.extend(quote!(rocket::http::Status { code: #code, reason: #reason }));
let code = self.0.code;
tokens.extend(quote!(rocket::http::Status { code: #code }));
}
}

View File

@ -303,7 +303,7 @@ route_attribute!(options => Method::Options);
///
/// #[catch(default)]
/// fn default(status: Status, req: &Request) -> String {
/// format!("{} - {} ({})", status.code, status.reason, req.uri())
/// format!("{} ({})", status, req.uri())
/// }
/// ```
///

View File

@ -53,7 +53,7 @@ async fn responder_foo() {
.respond_to(req)
.expect("response okay");
assert_eq!(r.status(), Status::raw(105));
assert_eq!(r.status().code, 105);
assert_eq!(r.content_type(), Some(ContentType::JSON));
assert_eq!(r.body_mut().to_string().await.unwrap(), "goodbye");
}

View File

@ -42,20 +42,43 @@ impl StatusClass {
class_check_fn!(is_unknown, "`Unknown`.", Unknown);
}
/// Structure representing an HTTP status: an integer code and a reason phrase.
/// Structure representing an HTTP status: an integer code.
///
/// # Usage
/// A `Status` should rarely be created directly. Instead, an associated
/// constant should be used; one is declared for every status defined in the
/// HTTP standard. If a custom status code _must_ be created, note that it is
/// not possible to set a custom reason phrase.
///
/// Status classes should rarely be created directly. Instead, an associated
/// constant should be used; one is declared for every status defined
/// in the HTTP standard.
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// // Create a status from a known constant.
/// let ok = Status::Ok;
/// assert_eq!(ok.code, 200);
/// assert_eq!(ok.reason(), Some("OK"));
///
/// let not_found = Status::NotFound;
/// assert_eq!(not_found.code, 404);
/// assert_eq!(not_found.reason(), Some("Not Found"));
///
/// // Or from a status code: `reason()` returns the phrase when known.
/// let gone = Status::new(410);
/// assert_eq!(gone.code, 410);
/// assert_eq!(gone.reason(), Some("Gone"));
///
/// // `reason()` returns `None` when unknown.
/// let custom = Status::new(599);
/// assert_eq!(custom.code, 599);
/// assert_eq!(custom.reason(), None);
/// ```
///
/// # Responding
///
/// To set a custom `Status` on a response, use a [`response::status`]
/// responder. Alternatively, respond with `(Status, T)` where `T: Responder`, but
/// note that the response may require additional headers to be valid as
/// enforced by the types in [`response::status`].
/// responder, which enforces correct status-based responses. Alternatively,
/// respond with `(Status, T)` where `T: Responder`, but beware that the
/// response may be invalid if it requires additional headers.
///
/// ```rust
/// # extern crate rocket;
@ -69,47 +92,10 @@ impl StatusClass {
/// ```
///
/// [`response::status`]: ../response/status/index.html
///
/// ## Example
///
/// A status of `200 OK` can be instantiated via the `Ok` constant:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// # #[allow(unused_variables)]
/// let ok = Status::Ok;
/// ```
///
/// A status of `404 Not Found` can be instantiated via the `NotFound` constant:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// # #[allow(unused_variables)]
/// let not_found = Status::NotFound;
/// ```
///
/// The code and phrase can be retrieved directly:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// let not_found = Status::NotFound;
///
/// assert_eq!(not_found.code, 404);
/// assert_eq!(not_found.reason, "Not Found");
/// assert_eq!(not_found.to_string(), "404 Not Found".to_string());
/// ```
#[derive(Debug, Clone, Copy)]
pub struct Status {
/// The HTTP status code associated with this status.
pub code: u16,
/// The HTTP reason phrase associated with this status.
pub reason: &'static str
}
impl Default for Status {
@ -123,65 +109,28 @@ macro_rules! ctrs {
$(
#[doc="[`Status`] with code <b>"]
#[doc=$code_str]
#[doc="</b> and reason <i>"]
#[doc=$reason]
#[doc="</i>."]
#[doc="</b>."]
#[allow(non_upper_case_globals)]
pub const $name: Status = Status { code: $code, reason: $reason };
pub const $name: Status = Status { code: $code };
)+
/// Returns a Status given a standard status code `code`. If `code` is
/// not a known status code, `None` is returned.
///
/// # Example
///
/// Create a `Status` from a known `code`:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// let not_found = Status::from_code(404);
/// assert_eq!(not_found, Some(Status::NotFound));
/// ```
///
/// Create a `Status` from an unknown `code`:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// let not_found = Status::from_code(600);
/// assert!(not_found.is_none());
/// ```
pub fn from_code(code: u16) -> Option<Status> {
match code {
$($code => Some(Status::$name),)+
_ => None
}
}
};
}
impl Status {
/// Creates a new `Status` with `code` and `reason`. This should be used _only_
/// to construct non-standard HTTP statuses. Use an associated constant for
/// Creates a new `Status` with `code`. This should be used _only_ to
/// construct non-standard HTTP statuses. Use an associated constant for
/// standard statuses.
///
/// # Example
///
/// Create a custom `299 Somewhat Successful` status:
/// Create a custom `299` status:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// let custom = Status::new(299, "Somewhat Successful");
/// assert_eq!(custom.to_string(), "299 Somewhat Successful".to_string());
/// let custom = Status::new(299);
/// assert_eq!(custom.code, 299);
/// ```
#[inline(always)]
pub const fn new(code: u16, reason: &'static str) -> Status {
Status { code, reason }
pub const fn new(code: u16) -> Status {
Status { code }
}
/// Returns the class of a given status.
@ -207,10 +156,10 @@ impl Status {
/// let internal_error = Status::InternalServerError;
/// assert_eq!(internal_error.class(), StatusClass::ServerError);
///
/// let custom = Status::new(600, "Bizarre");
/// let custom = Status::new(600);
/// assert_eq!(custom.class(), StatusClass::Unknown);
/// ```
pub fn class(self) -> StatusClass {
pub const fn class(self) -> StatusClass {
match self.code / 100 {
1 => StatusClass::Informational,
2 => StatusClass::Success,
@ -221,18 +170,99 @@ impl Status {
}
}
/// Returns a status from a given status code. If the status code is a
/// standard code, then the reason phrase is populated accordingly.
/// Otherwise the reason phrase is set to "<unknown code>".
#[inline]
#[doc(hidden)]
pub fn raw(code: u16) -> Status {
match Status::from_code(code) {
Some(status) => status,
None => Status::new(code, "<unknown code>")
/// Returns a Status given a standard status code `code`. If `code` is
/// not a known status code, `None` is returned.
///
/// # Example
///
/// Create a `Status` from a known `code`:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// let not_found = Status::from_code(404);
/// assert_eq!(not_found, Some(Status::NotFound));
/// ```
///
/// Create a `Status` from an unknown `code`:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// let unknown = Status::from_code(600);
/// assert!(unknown.is_none());
/// ```
pub const fn from_code(code: u16) -> Option<Status> {
match code {
$($code => Some(Status::$name),)+
_ => None
}
}
/// Returns the canonical reason phrase if `self` corresponds to a
/// canonical, known status code. Otherwise, returns `None`.
///
/// # Example
///
/// Reason phrase from a known `code`:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// assert_eq!(Status::Created.reason(), Some("Created"));
/// assert_eq!(Status::new(200).reason(), Some("OK"));
/// ```
///
/// Absent phrase from an unknown `code`:
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// assert_eq!(Status::new(499).reason(), None);
/// ```
pub const fn reason(&self) -> Option<&'static str> {
match self.code {
$($code => Some($reason),)+
_ => None
}
}
/// Returns the canonical reason phrase if `self` corresponds to a
/// canonical, known status code, or an unspecified but relevant reason
/// phrase otherwise.
///
/// # Example
///
/// ```rust
/// # extern crate rocket;
/// use rocket::http::Status;
///
/// assert_eq!(Status::NotFound.reason_lossy(), "Not Found");
/// assert_eq!(Status::new(100).reason_lossy(), "Continue");
/// assert!(!Status::new(699).reason_lossy().is_empty());
/// ```
pub const fn reason_lossy(&self) -> &'static str {
if let Some(lossless) = self.reason() {
return lossless;
}
match self.class() {
StatusClass::Informational => "Informational",
StatusClass::Success => "Success",
StatusClass::Redirection => "Redirection",
StatusClass::ClientError => "Client Error",
StatusClass::ServerError => "Server Error",
StatusClass::Unknown => "Unknown"
}
}
};
}
impl Status {
ctrs! {
100, "100", Continue => "Continue",
101, "101", SwitchingProtocols => "Switching Protocols",
@ -300,7 +330,7 @@ impl Status {
impl fmt::Display for Status {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.code, self.reason)
write!(f, "{} {}", self.code, self.reason_lossy())
}
}

View File

@ -106,27 +106,6 @@ impl<'r> Builder<'r> {
self
}
/// Sets the status of the `Response` being built to a custom status
/// constructed from the `code` and `reason` phrase.
///
/// # Example
///
/// ```rust
/// use rocket::Response;
/// use rocket::http::Status;
///
/// let response = Response::build()
/// .raw_status(699, "Alien Encounter")
/// .finalize();
///
/// assert_eq!(response.status(), Status::new(699, "Alien Encounter"));
/// ```
#[inline(always)]
pub fn raw_status(&mut self, code: u16, reason: &'static str) -> &mut Builder<'r> {
self.response.set_raw_status(code, reason);
self
}
/// Adds `header` to the `Response`, replacing any header with the same name
/// that already exists in the response. If multiple headers with
/// the same name exist, they are all removed, and only the new header and
@ -544,25 +523,6 @@ impl<'r> Response<'r> {
self.headers().get_one("Content-Type").and_then(|v| v.parse().ok())
}
/// Sets the status of `self` to a custom `status` with status code `code`
/// and reason phrase `reason`. This method should be used sparingly; prefer
/// to use [set_status](#method.set_status) instead.
///
/// # Example
///
/// ```rust
/// use rocket::Response;
/// use rocket::http::Status;
///
/// let mut response = Response::new();
/// response.set_raw_status(699, "Tripped a Wire");
/// assert_eq!(response.status(), Status::new(699, "Tripped a Wire"));
/// ```
#[inline(always)]
pub fn set_raw_status(&mut self, code: u16, reason: &'static str) {
self.status = Some(Status::new(code, reason));
}
/// Returns an iterator over the cookies in `self` as identified by the
/// `Set-Cookie` header. Malformed cookies are skipped.
///

View File

@ -13,7 +13,7 @@ fn hello(name: &str, age: i8) -> String {
#[get("/<code>")]
fn forced_error(code: u16) -> Status {
Status::raw(code)
Status::new(code)
}
#[catch(404)]
@ -39,7 +39,7 @@ fn sergio_error() -> &'static str {
#[catch(default)]
fn default_catcher(status: Status, req: &Request<'_>) -> status::Custom<String> {
let msg = format!("{} - {} ({})", status.code, status.reason, req.uri());
let msg = format!("{} ({})", status, req.uri());
status::Custom(status, msg)
}

View File

@ -30,9 +30,9 @@ fn forced_error() {
assert_eq!(response.into_string().unwrap(), expected.1);
let request = client.get("/533");
let expected = super::default_catcher(Status::raw(533), request.inner());
let expected = super::default_catcher(Status::new(533), request.inner());
let response = request.dispatch();
assert_eq!(response.status(), Status::raw(533));
assert_eq!(response.status(), Status::new(533));
assert_eq!(response.into_string().unwrap(), expected.1);
let request = client.get("/700");