Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: split the Header trait into three traits #110

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions headers-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,36 @@ pub use http::header::{self, HeaderName, HeaderValue};
use std::error;
use std::fmt::{self, Display, Formatter};

/// Associates a header name with a Rust type.
pub trait Named {
/// The name of this header.
fn name() -> &'static HeaderName;
}

/// Decodes a header into a Rust type.
pub trait Decodable: Named {
/// Decode this type from an iterator of `HeaderValue`s.
fn decode<'i, I>(values: &mut I) -> Result<Self, Error>
where
Self: Sized,
I: Iterator<Item = &'i HeaderValue>;
}

/// Encodes a header into a Rust type.
pub trait Encodable: Named {
/// Encode this type to a `HeaderMap`.
///
/// This function should be infallible. Any errors converting to a
/// `HeaderValue` should have been caught when parsing or constructing
/// this value.
fn encode<E: Extend<HeaderValue>>(&self, values: &mut E);
}

/// A trait for any object that will represent a header field and value.
///
/// This trait represents the construction and identification of headers,
/// and contains trait-object unsafe methods.
#[deprecated]
pub trait Header {
/// The name of this header.
fn name() -> &'static HeaderName;
Expand All @@ -37,6 +63,31 @@ pub trait Header {
fn encode<E: Extend<HeaderValue>>(&self, values: &mut E);
}

#[allow(deprecated)]
impl<T: Header> Named for T {
fn name() -> &'static HeaderName {
T::name()
}
}

#[allow(deprecated)]
impl<T: Header> Decodable for T {
fn decode<'i, I>(values: &mut I) -> Result<Self, Error>
where
Self: Sized,
I: Iterator<Item = &'i HeaderValue>,
{
T::decode(values)
}
}

#[allow(deprecated)]
impl<T: Header> Encodable for T {
fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
self.encode(values)
}
}

/// Errors trying to decode a header.
#[derive(Debug)]
pub struct Error {
Expand Down
9 changes: 7 additions & 2 deletions src/common/access_control_allow_credentials.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use {Header, HeaderName, HeaderValue};
use crate::core::{Decodable, Encodable, Named};
use crate::{HeaderName, HeaderValue};

/// `Access-Control-Allow-Credentials` header, part of
/// [CORS](http://www.w3.org/TR/cors/#access-control-allow-headers-response-header)
Expand Down Expand Up @@ -33,11 +34,13 @@ use {Header, HeaderName, HeaderValue};
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AccessControlAllowCredentials;

impl Header for AccessControlAllowCredentials {
impl Named for AccessControlAllowCredentials {
fn name() -> &'static HeaderName {
&::http::header::ACCESS_CONTROL_ALLOW_CREDENTIALS
}
}

impl Decodable for AccessControlAllowCredentials {
fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
values
.next()
Expand All @@ -50,7 +53,9 @@ impl Header for AccessControlAllowCredentials {
})
.ok_or_else(::Error::invalid)
}
}

impl Encodable for AccessControlAllowCredentials {
fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
values.extend(::std::iter::once(HeaderValue::from_static("true")));
}
Expand Down
10 changes: 8 additions & 2 deletions src/common/access_control_request_method.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::core::{Decodable, Encodable, Named};
use crate::{HeaderName, HeaderValue};

use http::Method;
use {Header, HeaderName, HeaderValue};

/// `Access-Control-Request-Method` header, part of
/// [CORS](http://www.w3.org/TR/cors/#access-control-request-method-request-header)
Expand Down Expand Up @@ -28,19 +30,23 @@ use {Header, HeaderName, HeaderValue};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AccessControlRequestMethod(Method);

impl Header for AccessControlRequestMethod {
impl Named for AccessControlRequestMethod {
fn name() -> &'static HeaderName {
&::http::header::ACCESS_CONTROL_REQUEST_METHOD
}
}

impl Decodable for AccessControlRequestMethod {
fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
values
.next()
.and_then(|value| Method::from_bytes(value.as_bytes()).ok())
.map(AccessControlRequestMethod)
.ok_or_else(::Error::invalid)
}
}

impl Encodable for AccessControlRequestMethod {
fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
// For the more common methods, try to use a static string.
let s = match self.0 {
Expand Down
11 changes: 9 additions & 2 deletions src/common/authorization.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Authorization header and types.

use crate::core::{Decodable, Encodable, Named};

use base64;
use bytes::Bytes;

Expand Down Expand Up @@ -71,11 +73,13 @@ impl Authorization<Bearer> {
}
}

impl<C: Credentials> ::Header for Authorization<C> {
impl<C: Credentials> Named for Authorization<C> {
fn name() -> &'static ::HeaderName {
&::http::header::AUTHORIZATION
}
}

impl<C: Credentials> Decodable for Authorization<C> {
fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
values
.next()
Expand All @@ -92,7 +96,9 @@ impl<C: Credentials> ::Header for Authorization<C> {
})
.ok_or_else(::Error::invalid)
}
}

impl<C: Credentials> Encodable for Authorization<C> {
fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
let value = self.0.encode();
debug_assert!(
Expand Down Expand Up @@ -171,7 +177,8 @@ impl Credentials for Basic {
base64::encode_config_buf(&self.decoded, base64::STANDARD, &mut encoded);

let bytes = Bytes::from(encoded);
HeaderValue::from_maybe_shared(bytes).expect("base64 encoding is always a valid HeaderValue")
HeaderValue::from_maybe_shared(bytes)
.expect("base64 encoding is always a valid HeaderValue")
}
}

Expand Down
8 changes: 7 additions & 1 deletion src/common/cache_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::iter::FromIterator;
use std::str::FromStr;
use std::time::Duration;

use crate::core::{Decodable, Encodable, Named};

use util::{self, csv, Seconds};
use HeaderValue;

Expand Down Expand Up @@ -183,15 +185,19 @@ impl CacheControl {
}
}

impl ::Header for CacheControl {
impl Named for CacheControl {
fn name() -> &'static ::HeaderName {
&::http::header::CACHE_CONTROL
}
}

impl Decodable for CacheControl {
fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
csv::from_comma_delimited(values).map(|FromIter(cc)| cc)
}
}

impl Encodable for CacheControl {
fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
values.extend(::std::iter::once(util::fmt(Fmt(self))));
}
Expand Down
8 changes: 7 additions & 1 deletion src/common/content_disposition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// Browser conformance tests at: http://greenbytes.de/tech/tc2231/
// IANA assignment: http://www.iana.org/assignments/cont-disp/cont-disp.xhtml

use crate::core::{Decodable, Encodable, Named};

/// A `Content-Disposition` header, (re)defined in [RFC6266](https://tools.ietf.org/html/rfc6266).
///
/// The Content-Disposition response header field is used to convey
Expand Down Expand Up @@ -89,11 +91,13 @@ impl ContentDisposition {
}
}

impl ::Header for ContentDisposition {
impl Named for ContentDisposition {
fn name() -> &'static ::HeaderName {
&::http::header::CONTENT_DISPOSITION
}
}

impl Decodable for ContentDisposition {
fn decode<'i, I: Iterator<Item = &'i ::HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
//TODO: parse harder
values
Expand All @@ -102,7 +106,9 @@ impl ::Header for ContentDisposition {
.map(ContentDisposition)
.ok_or_else(::Error::invalid)
}
}

impl Encodable for ContentDisposition {
fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
values.extend(::std::iter::once(self.0.clone()));
}
Expand Down
9 changes: 7 additions & 2 deletions src/common/content_length.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use {Header, HeaderValue};
use crate::core::{Decodable, Encodable, Named};
use crate::HeaderValue;

/// `Content-Length` header, defined in
/// [RFC7230](http://tools.ietf.org/html/rfc7230#section-3.3.2)
Expand Down Expand Up @@ -40,11 +41,13 @@ use {Header, HeaderValue};
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ContentLength(pub u64);

impl Header for ContentLength {
impl Named for ContentLength {
fn name() -> &'static ::http::header::HeaderName {
&::http::header::CONTENT_LENGTH
}
}

impl Decodable for ContentLength {
fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
// If multiple Content-Length headers were sent, everything can still
// be alright if they all contain the same value, and all parse
Expand All @@ -68,7 +71,9 @@ impl Header for ContentLength {

len.map(ContentLength).ok_or_else(::Error::invalid)
}
}

impl Encodable for ContentLength {
fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
values.extend(::std::iter::once(self.0.into()));
}
Expand Down
42 changes: 24 additions & 18 deletions src/common/content_range.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::fmt;
use std::ops::{Bound, RangeBounds};

use {util, HeaderValue};
use crate::core::{Decodable, Encodable, Named};
use crate::{util, HeaderValue};

/// Content-Range, described in [RFC7233](https://tools.ietf.org/html/rfc7233#section-4.2)
///
Expand Down Expand Up @@ -98,11 +99,13 @@ impl ContentRange {
}
}

impl ::Header for ContentRange {
impl Named for ContentRange {
fn name() -> &'static ::HeaderName {
&::http::header::CONTENT_RANGE
}
}

impl Decodable for ContentRange {
fn decode<'i, I: Iterator<Item = &'i HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
values
.next()
Expand Down Expand Up @@ -141,7 +144,9 @@ impl ::Header for ContentRange {
})
.ok_or_else(::Error::invalid)
}
}

impl Encodable for ContentRange {
fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
struct Adapter<'a>(&'a ContentRange);

Expand Down Expand Up @@ -178,22 +183,23 @@ fn split_in_two(s: &str, separator: char) -> Option<(&str, &str)> {
}

/*
test_header!(test_bytes,
vec![b"bytes 0-499/500"],
Some(ContentRange(ContentRangeSpec::Bytes {
range: Some((0, 499)),
complete_length: Some(500)
})));

test_header!(test_bytes_unknown_len,
vec![b"bytes 0-499/*"],
Some(ContentRange(ContentRangeSpec::Bytes {
range: Some((0, 499)),
complete_length: None
})));

test_header!(test_bytes_unknown_range,
vec![b"bytes */500"],
test_header!(test_bytes,
vec![b"bytes 0-499/500"],
Some(ContentRange(ContentRangeSpec::Bytes {
range: Some((0, 499)),
complete_length: Some(500)
})));

test_header!(test_bytes_unknown_len,
vec![b"bytes 0-499/*"],
Some(ContentRange(ContentRangeSpec::Bytes {
range: Some((0, 499)),
complete_length: None
})));

test_header!(test_bytes_unknown_range,
vec![b"bytes */
500"],
Some(ContentRange(ContentRangeSpec::Bytes {
range: None,
complete_length: Some(500)
Expand Down
8 changes: 7 additions & 1 deletion src/common/content_type.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::fmt;

use crate::core::{Decodable, Encodable, Named};

use mime::{self, Mime};

/// `Content-Type` header, defined in
Expand Down Expand Up @@ -94,19 +96,23 @@ impl ContentType {
}
}

impl ::Header for ContentType {
impl Named for ContentType {
fn name() -> &'static ::HeaderName {
&::http::header::CONTENT_TYPE
}
}

impl Decodable for ContentType {
fn decode<'i, I: Iterator<Item = &'i ::HeaderValue>>(values: &mut I) -> Result<Self, ::Error> {
values
.next()
.and_then(|v| v.to_str().ok()?.parse().ok())
.map(ContentType)
.ok_or_else(::Error::invalid)
}
}

impl Encodable for ContentType {
fn encode<E: Extend<::HeaderValue>>(&self, values: &mut E) {
let value = self
.0
Expand Down
Loading