replace TryInto with Into

This commit is contained in:
Yoshua Wuyts 2020-05-13 19:56:12 +02:00
parent 0a33fc784a
commit db616d55d3
11 changed files with 100 additions and 137 deletions

View File

@ -63,11 +63,9 @@ impl FromStr for HeaderName {
}
}
impl<'a> std::convert::TryFrom<&'a str> for HeaderName {
type Error = Error;
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
Self::from_str(value)
impl<'a> From<&'a str> for HeaderName {
fn from(value: &'a str) -> Self {
Self::from_str(value).unwrap()
}
}

View File

@ -95,6 +95,12 @@ impl<'a> PartialEq<&'a str> for HeaderValues {
}
}
impl<'a> PartialEq<[&'a str]> for HeaderValues {
fn eq(&self, other: &[&'a str]) -> bool {
self.inner.iter().eq(other.iter())
}
}
impl PartialEq<String> for HeaderValues {
fn eq(&self, other: &String) -> bool {
self.inner.len() == 1 && &self.inner[0] == other

View File

@ -1,7 +1,7 @@
//! HTTP headers.
use std::collections::HashMap;
use std::convert::TryInto;
use std::convert::Into;
use std::iter::IntoIterator;
use std::ops::Index;
use std::str::FromStr;
@ -23,7 +23,7 @@ use crate::headers::{
/// use http_types::{Response, StatusCode};
///
/// let mut res = Response::new(StatusCode::Ok);
/// res.insert_header("hello", "foo0").unwrap();
/// res.insert_header("hello", "foo0");
/// assert_eq!(res["hello"], "foo0");
/// ```
#[derive(Debug, Clone)]
@ -46,14 +46,12 @@ impl Headers {
/// use `Headers::append`
pub fn insert(
&mut self,
name: impl TryInto<HeaderName>,
name: impl Into<HeaderName>,
values: impl ToHeaderValues,
) -> crate::Result<Option<HeaderValues>> {
let name = name
.try_into()
.map_err(|_| crate::format_err!("Could not convert into header name"))?;
let values: HeaderValues = values.to_header_values()?.collect();
Ok(self.headers.insert(name, values))
) -> Option<HeaderValues> {
let name = name.into();
let values: HeaderValues = values.to_header_values().unwrap().collect();
self.headers.insert(name, values)
}
/// Append a header to the headers.
@ -62,27 +60,25 @@ impl Headers {
/// header if there aren't any. Or else append to the existing list of headers.
pub fn append(
&mut self,
name: impl TryInto<HeaderName>,
name: impl Into<HeaderName>,
values: impl ToHeaderValues,
) -> crate::Result<()> {
let name = name
.try_into()
.map_err(|_| crate::format_err!("Could not convert into header name"))?;
let name = name.into();
match self.get_mut(&name) {
Some(headers) => {
let mut values: HeaderValues = values.to_header_values()?.collect();
headers.append(&mut values);
}
None => {
self.insert(name, values)?;
self.insert(name, values);
}
}
Ok(())
}
/// Get a reference to a header.
pub fn get(&self, name: &HeaderName) -> Option<&HeaderValues> {
self.headers.get(name)
pub fn get(&self, name: impl Into<HeaderName>) -> Option<&HeaderValues> {
self.headers.get(&name.into())
}
/// Get a mutable reference to a header.
@ -123,7 +119,7 @@ impl Headers {
}
}
impl Index<&HeaderName> for Headers {
impl Index<HeaderName> for Headers {
type Output = HeaderValues;
/// Returns a reference to the value corresponding to the supplied name.
@ -132,7 +128,7 @@ impl Index<&HeaderName> for Headers {
///
/// Panics if the name is not present in `Headers`.
#[inline]
fn index(&self, name: &HeaderName) -> &HeaderValues {
fn index(&self, name: HeaderName) -> &HeaderValues {
self.get(name).expect("no entry found for name")
}
}
@ -148,7 +144,7 @@ impl Index<&str> for Headers {
#[inline]
fn index(&self, name: &str) -> &HeaderValues {
let name = HeaderName::from_str(name).expect("string slice needs to be valid ASCII");
self.get(&name).expect("no entry found for name")
self.get(name).expect("no entry found for name")
}
}
@ -202,20 +198,9 @@ mod tests {
headers.append(static_header.clone(), "foo1")?;
headers.append(non_static_header.clone(), "foo2")?;
assert_eq!(
&headers.get(&STATIC_HEADER).unwrap()[..],
&["foo0", "foo1", "foo2",][..]
);
assert_eq!(
&headers.get(&static_header).unwrap()[..],
&["foo0", "foo1", "foo2",][..]
);
assert_eq!(
&headers.get(&non_static_header).unwrap()[..],
&["foo0", "foo1", "foo2",][..]
);
assert_eq!(headers[STATIC_HEADER], ["foo0", "foo1", "foo2",][..]);
assert_eq!(headers[static_header], ["foo0", "foo1", "foo2",][..]);
assert_eq!(headers[non_static_header], ["foo0", "foo1", "foo2",][..]);
Ok(())
}
@ -223,7 +208,8 @@ mod tests {
#[test]
fn index_into_headers() {
let mut headers = Headers::new();
headers.insert("hello", "foo0").unwrap();
headers.insert("hello", "foo0");
assert_eq!(headers["hello"], "foo0");
assert_eq!(headers.get("hello").unwrap(), "foo0");
}
}

View File

@ -1,7 +1,7 @@
use async_std::io::{self, BufRead, Read};
use async_std::sync;
use std::convert::TryInto;
use std::convert::Into;
use std::mem;
use std::ops::Index;
use std::pin::Pin;
@ -93,7 +93,7 @@ impl Request {
}
fn forwarded_for(&self) -> Option<&str> {
if let Some(header) = self.header(&"Forwarded".parse().unwrap()) {
if let Some(header) = self.header("Forwarded") {
header.as_str().split(";").find_map(|key_equals_value| {
let parts = key_equals_value.split("=").collect::<Vec<_>>();
if parts.len() == 2 && parts[0].eq_ignore_ascii_case("for") {
@ -102,7 +102,7 @@ impl Request {
None
}
})
} else if let Some(header) = self.header(&"X-Forwarded-For".parse().unwrap()) {
} else if let Some(header) = self.header("X-Forwarded-For") {
header.as_str().split(",").next()
} else {
None
@ -364,7 +364,7 @@ impl Request {
}
/// Get an HTTP header.
pub fn header(&self, name: &HeaderName) -> Option<&HeaderValues> {
pub fn header(&self, name: impl Into<HeaderName>) -> Option<&HeaderValues> {
self.headers.get(name)
}
@ -388,15 +388,15 @@ impl Request {
/// use http_types::{Url, Method, Request};
///
/// let mut req = Request::new(Method::Get, Url::parse("https://example.com")?);
/// req.insert_header("Content-Type", "text/plain")?;
/// req.insert_header("Content-Type", "text/plain");
/// #
/// # Ok(()) }
/// ```
pub fn insert_header(
&mut self,
name: impl TryInto<HeaderName>,
name: impl Into<HeaderName>,
values: impl ToHeaderValues,
) -> crate::Result<Option<HeaderValues>> {
) -> Option<HeaderValues> {
self.headers.insert(name, values)
}
@ -419,7 +419,7 @@ impl Request {
/// ```
pub fn append_header(
&mut self,
name: impl TryInto<HeaderName>,
name: impl Into<HeaderName>,
values: impl ToHeaderValues,
) -> crate::Result<()> {
self.headers.append(name, values)
@ -431,19 +431,19 @@ impl Request {
let value: HeaderValue = mime.into();
// A Mime instance is guaranteed to be valid header name.
self.insert_header(CONTENT_TYPE, value).unwrap()
self.insert_header(CONTENT_TYPE, value)
}
/// Copy MIME data from the body.
fn copy_content_type_from_body(&mut self) {
if self.header(&CONTENT_TYPE).is_none() {
if self.header(CONTENT_TYPE).is_none() {
self.set_content_type(self.body.mime().clone());
}
}
/// Get the current content type
pub fn content_type(&self) -> Option<Mime> {
self.header(&CONTENT_TYPE)?.last().as_str().parse().ok()
self.header(CONTENT_TYPE)?.last().as_str().parse().ok()
}
/// Get the length of the body stream, if it has been set.
@ -623,7 +623,7 @@ impl From<Request> for Body {
}
}
impl Index<&HeaderName> for Request {
impl Index<HeaderName> for Request {
type Output = HeaderValues;
/// Returns a reference to the value corresponding to the supplied name.
@ -632,7 +632,7 @@ impl Index<&HeaderName> for Request {
///
/// Panics if the name is not present in `Request`.
#[inline]
fn index(&self, name: &HeaderName) -> &HeaderValues {
fn index(&self, name: HeaderName) -> &HeaderValues {
self.headers.index(name)
}
}
@ -691,21 +691,17 @@ mod tests {
}
fn set_x_forwarded_for(request: &mut Request, client: &'static str) {
request
.insert_header(
"x-forwarded-for",
format!("{},proxy.com,other-proxy.com", client),
)
.unwrap();
request.insert_header(
"x-forwarded-for",
format!("{},proxy.com,other-proxy.com", client),
);
}
fn set_forwarded(request: &mut Request, client: &'static str) {
request
.insert_header(
"Forwarded",
format!("by=something.com;for={};host=host.com;proto=http", client),
)
.unwrap();
request.insert_header(
"Forwarded",
format!("by=something.com;for={};host=host.com;proto=http", client),
);
}
#[test]
@ -725,9 +721,7 @@ mod tests {
"127.0.0.1:8000".parse::<std::net::SocketAddr>().unwrap(),
));
request
.insert_header("Forwarded", "this is an improperly ;;; formatted header")
.unwrap();
request.insert_header("Forwarded", "this is an improperly ;;; formatted header");
assert_eq!(request.forwarded_for(), None);
assert_eq!(request.remote(), Some("127.0.0.1:8000"));

View File

@ -1,7 +1,7 @@
use async_std::io::{self, BufRead, Read};
use async_std::sync;
use std::convert::TryInto;
use std::convert::Into;
use std::mem;
use std::ops::Index;
use std::pin::Pin;
@ -74,7 +74,7 @@ impl Response {
}
/// Get an HTTP header.
pub fn header(&self, name: &HeaderName) -> Option<&HeaderValues> {
pub fn header(&self, name: impl Into<HeaderName>) -> Option<&HeaderValues> {
self.headers.get(name)
}
@ -93,15 +93,15 @@ impl Response {
/// use http_types::{Url, Method, Response, StatusCode};
///
/// let mut req = Response::new(StatusCode::Ok);
/// req.insert_header("Content-Type", "text/plain")?;
/// req.insert_header("Content-Type", "text/plain");
/// #
/// # Ok(()) }
/// ```
pub fn insert_header(
&mut self,
name: impl TryInto<HeaderName>,
name: impl Into<HeaderName>,
values: impl ToHeaderValues,
) -> crate::Result<Option<HeaderValues>> {
) -> Option<HeaderValues> {
self.headers.insert(name, values)
}
@ -124,7 +124,7 @@ impl Response {
/// ```
pub fn append_header(
&mut self,
name: impl TryInto<HeaderName>,
name: impl Into<HeaderName>,
values: impl ToHeaderValues,
) -> crate::Result<()> {
self.headers.append(name, values)
@ -349,12 +349,12 @@ impl Response {
let value: HeaderValue = mime.into();
// A Mime instance is guaranteed to be valid header name.
self.insert_header(CONTENT_TYPE, value).unwrap()
self.insert_header(CONTENT_TYPE, value)
}
/// Copy MIME data from the body.
fn copy_content_type_from_body(&mut self) {
if self.header(&CONTENT_TYPE).is_none() {
if self.header(CONTENT_TYPE).is_none() {
self.set_content_type(self.body.mime().clone());
}
}
@ -563,7 +563,7 @@ impl From<()> for Response {
Response::new(StatusCode::NoContent)
}
}
impl Index<&HeaderName> for Response {
impl Index<HeaderName> for Response {
type Output = HeaderValues;
/// Returns a reference to the value corresponding to the supplied name.
@ -572,7 +572,7 @@ impl Index<&HeaderName> for Response {
///
/// Panics if the name is not present in `Response`.
#[inline]
fn index(&self, name: &HeaderName) -> &HeaderValues {
fn index(&self, name: HeaderName) -> &HeaderValues {
self.headers.index(name)
}
}

View File

@ -121,11 +121,7 @@ pub struct ReportToEndpoint {
/// security::default(&mut res);
/// policy.apply(&mut res);
///
/// let name =
/// headers::HeaderName::from_ascii("content-security-policy".to_owned().into_bytes()).unwrap();
/// let headers = res.header(&name).unwrap();
/// let header = headers.iter().next().unwrap();
/// assert_eq!(header, "base-uri 'none'; default-src 'self' areweasyncyet.rs; object-src 'none'; script-src 'self' 'unsafe-inline'; upgrade-insecure-requests");
/// assert_eq!(res["content-security-policy"], "base-uri 'none'; default-src 'self' areweasyncyet.rs; object-src 'none'; script-src 'self' 'unsafe-inline'; upgrade-insecure-requests");
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContentSecurityPolicy {
@ -358,9 +354,6 @@ impl ContentSecurityPolicy {
} else {
"Content-Security-Policy"
};
headers
.as_mut()
.insert(name, self.value().to_owned())
.unwrap();
headers.as_mut().insert(name, self.value().to_owned());
}
}

View File

@ -50,10 +50,7 @@ pub fn default(mut headers: impl AsMut<Headers>) {
// /// ```
#[inline]
pub fn dns_prefetch_control(mut headers: impl AsMut<Headers>) {
headers
.as_mut()
.insert("X-DNS-Prefetch-Control", "on")
.unwrap();
headers.as_mut().insert("X-DNS-Prefetch-Control", "on");
}
/// Set the frameguard level.
@ -83,7 +80,7 @@ pub fn frameguard(mut headers: impl AsMut<Headers>, guard: Option<FrameOptions>)
None | Some(FrameOptions::SameOrigin) => "sameorigin",
Some(FrameOptions::Deny) => "deny",
};
headers.as_mut().insert("X-Frame-Options", kind).unwrap();
headers.as_mut().insert("X-Frame-Options", kind);
}
/// Removes the `X-Powered-By` header to make it slightly harder for attackers to see what
@ -96,7 +93,7 @@ pub fn frameguard(mut headers: impl AsMut<Headers>, guard: Option<FrameOptions>)
// /// use http_types::Response;
// ///
// /// let mut res = Response::new(StatusCode::Ok);
// /// headers.as_mut().insert("X-Powered-By", "Tide/Rust".parse().unwrap());
// /// headers.as_mut().insert("X-Powered-By", "Tide/Rust".parse());
// /// http_types::security::hide_powered_by(&mut headers);
// /// assert_eq!(headers.get("X-Powered-By"), None);
// /// ```
@ -105,7 +102,7 @@ pub fn powered_by(mut headers: impl AsMut<Headers>, value: Option<HeaderValue>)
let name = HeaderName::from_lowercase_str("X-Powered-By");
match value {
Some(value) => {
headers.as_mut().insert(name, value).unwrap();
headers.as_mut().insert(name, value);
}
None => {
headers.as_mut().remove(&name);
@ -132,8 +129,7 @@ pub fn powered_by(mut headers: impl AsMut<Headers>, value: Option<HeaderValue>)
pub fn hsts(mut headers: impl AsMut<Headers>) {
headers
.as_mut()
.insert("Strict-Transport-Security", "max-age=5184000")
.unwrap();
.insert("Strict-Transport-Security", "max-age=5184000");
}
/// Prevent browsers from trying to guess (“sniff”) the MIME type, which can have security
@ -151,10 +147,7 @@ pub fn hsts(mut headers: impl AsMut<Headers>) {
// /// ```
#[inline]
pub fn nosniff(mut headers: impl AsMut<Headers>) {
headers
.as_mut()
.insert("X-Content-Type-Options", "nosniff")
.unwrap();
headers.as_mut().insert("X-Content-Type-Options", "nosniff");
}
/// Sets the `X-XSS-Protection` header to prevent reflected XSS attacks.
@ -171,10 +164,7 @@ pub fn nosniff(mut headers: impl AsMut<Headers>) {
// /// ```
#[inline]
pub fn xss_filter(mut headers: impl AsMut<Headers>) {
headers
.as_mut()
.insert("X-XSS-Protection", "1; mode=block")
.unwrap();
headers.as_mut().insert("X-XSS-Protection", "1; mode=block");
}
/// Set the Referrer-Policy level

View File

@ -1,5 +1,5 @@
use crate::{Error, StatusCode};
use core::convert::{Infallible, TryInto};
use core::convert::{Infallible, Into};
use std::error::Error as StdError;
/// Provides the `status` method for `Result` and `Option`.
@ -9,15 +9,13 @@ pub trait Status<T, E>: private::Sealed {
/// Wrap the error value with an additional status code.
fn status<S>(self, status: S) -> Result<T, Error>
where
S: TryInto<StatusCode>,
S::Error: std::fmt::Debug;
S: Into<StatusCode>;
/// Wrap the error value with an additional status code that is evaluated
/// lazily only once an error does occur.
fn with_status<S, F>(self, f: F) -> Result<T, Error>
where
S: TryInto<StatusCode>,
S::Error: std::fmt::Debug,
S: Into<StatusCode>,
F: FnOnce() -> S;
}
@ -27,23 +25,21 @@ where
{
fn status<S>(self, status: S) -> Result<T, Error>
where
S: TryInto<StatusCode>,
S::Error: std::fmt::Debug,
S: Into<StatusCode>,
{
self.map_err(|error| {
let status = status.try_into().unwrap();
let status = status.into();
Error::new(status, error)
})
}
fn with_status<S, F>(self, f: F) -> Result<T, Error>
where
S: TryInto<StatusCode>,
S::Error: std::fmt::Debug,
S: Into<StatusCode>,
F: FnOnce() -> S,
{
self.map_err(|error| {
let status = f().try_into().unwrap();
let status = f().into();
Error::new(status, error)
})
}
@ -52,23 +48,21 @@ where
impl<T> Status<T, Infallible> for Option<T> {
fn status<S>(self, status: S) -> Result<T, Error>
where
S: TryInto<StatusCode>,
S::Error: std::fmt::Debug,
S: Into<StatusCode>,
{
self.ok_or_else(|| {
let status = status.try_into().unwrap();
let status = status.into();
Error::from_str(status, "NoneError")
})
}
fn with_status<S, F>(self, f: F) -> Result<T, Error>
where
S: TryInto<StatusCode>,
S::Error: std::fmt::Debug,
S: Into<StatusCode>,
F: FnOnce() -> S,
{
self.ok_or_else(|| {
let status = f().try_into().unwrap();
let status = f().into();
Error::from_str(status, "NoneError")
})
}

View File

@ -31,7 +31,7 @@
//!
//! let sender = req.send_trailers();
//! let mut trailers = Trailers::new();
//! trailers.insert("Content-Type", "text/plain")?;
//! trailers.insert("Content-Type", "text/plain");
//!
//! task::spawn(async move {
//! let trailers = req.recv_trailers().await;
@ -53,7 +53,7 @@ use crate::headers::{
use async_std::prelude::*;
use async_std::sync;
use std::convert::TryInto;
use std::convert::Into;
use std::future::Future;
use std::ops::{Deref, DerefMut, Index};
use std::pin::Pin;
@ -83,15 +83,15 @@ impl Trailers {
/// use http_types::Trailers;
///
/// let mut trailers = Trailers::new();
/// trailers.insert("Content-Type", "text/plain")?;
/// trailers.insert("Content-Type", "text/plain");
/// #
/// # Ok(()) }
/// ```
pub fn insert(
&mut self,
name: impl TryInto<HeaderName>,
name: impl Into<HeaderName>,
values: impl ToHeaderValues,
) -> crate::Result<Option<HeaderValues>> {
) -> Option<HeaderValues> {
self.headers.insert(name, values)
}
@ -114,14 +114,14 @@ impl Trailers {
/// ```
pub fn append(
&mut self,
name: impl TryInto<HeaderName>,
name: impl Into<HeaderName>,
values: impl ToHeaderValues,
) -> crate::Result<()> {
self.headers.append(name, values)
}
/// Get a reference to a header.
pub fn get(&self, name: &HeaderName) -> Option<&HeaderValues> {
pub fn get(&self, name: impl Into<HeaderName>) -> Option<&HeaderValues> {
self.headers.get(name)
}
@ -181,7 +181,7 @@ impl DerefMut for Trailers {
}
}
impl Index<&HeaderName> for Trailers {
impl Index<HeaderName> for Trailers {
type Output = HeaderValues;
/// Returns a reference to the value corresponding to the supplied name.
@ -190,7 +190,7 @@ impl Index<&HeaderName> for Trailers {
///
/// Panics if the name is not present in `Trailers`.
#[inline]
fn index(&self, name: &HeaderName) -> &HeaderValues {
fn index(&self, name: HeaderName) -> &HeaderValues {
self.headers.index(name)
}
}

8
tests/headers.rs Normal file
View File

@ -0,0 +1,8 @@
// use http_types::{Response, StatusCode};
// #[test]
// fn headers_cmp() {
// let mut res = Response::new(StatusCode::Ok);
// res.insert_header("content-type", "application/json");
// assert_eq!(res.header("content-type").unwrap(), "application/json");
// }

View File

@ -1,4 +1,4 @@
use http_types::{headers::HeaderName, security, Response, StatusCode};
use http_types::{security, Response, StatusCode};
#[test]
fn security_test() {
@ -18,11 +18,5 @@ fn security_test() {
security::default(&mut res);
policy.apply(&mut res);
let header = res
.header(&HeaderName::from_ascii("content-security-policy".to_owned().into_bytes()).unwrap())
.unwrap()
.iter()
.next()
.unwrap();
assert_eq!(header, "base-uri 'none'; default-src 'self' areweasyncyet.rs; object-src 'none'; script-src 'self' 'unsafe-inline'; upgrade-insecure-requests");
assert_eq!(res["content-security-policy"], "base-uri 'none'; default-src 'self' areweasyncyet.rs; object-src 'none'; script-src 'self' 'unsafe-inline'; upgrade-insecure-requests");
}