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

Make trailers module a submodle of transfer #309

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
13 changes: 13 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
language: rust
rust:
- stable

before_script: |
rustup component add rustfmt-preview &&
rustup component add clippy-preview
script: |
cargo fmt -- --check &&
cargo clippy -- -D clippy &&
cargo build --verbose &&
cargo test --verbose
cache: cargo
9 changes: 3 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "http-types"
version = "3.0.0"
version = "2.9.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/http-rs/http-types"
documentation = "https://docs.rs/http-types"
Expand All @@ -21,8 +21,7 @@ docs = ["unstable"]
unstable = []
hyperium_http = ["http"]
async_std = ["fs"]
cookies = ["cookie"]
cookie-secure = ["cookies", "cookie/secure"]
cookie-secure = ["cookie/secure"]
fs = ["async-std"]

[dependencies]
Expand All @@ -35,9 +34,7 @@ async-channel = "1.5.1"
http = { version = "0.2.0", optional = true }

anyhow = "1.0.26"

# features: cookies
cookie = { version = "0.14.0", features = ["percent-encode"], optional = true }
cookie = { version = "0.14.0", features = ["percent-encode"] }
infer = "0.2.3"
pin-project-lite = "0.2.0"
url = { version = "2.1.1", features = ["serde"] }
Expand Down
2 changes: 1 addition & 1 deletion src/conditional/etag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl ETag {

if !s
.bytes()
.all(|c| c == 0x21 || (0x23..=0x7E).contains(&c) || c >= 0x80)
.all(|c| c == 0x21 || (c >= 0x23 && c <= 0x7E) || c >= 0x80)
{
return Err(Error::from_str(
StatusCode::BadRequest,
Expand Down
1 change: 0 additions & 1 deletion src/headers/header_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ mod tests {
use super::*;

#[test]
#[allow(clippy::eq_op)]
fn test_header_name_static_non_static() {
let static_header = HeaderName::from_lowercase_str("hello");
let non_static_header = HeaderName::from_str("hello").unwrap();
Expand Down
1 change: 0 additions & 1 deletion src/headers/header_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ impl From<Mime> for HeaderValue {
}
}

#[cfg(feature = "cookies")]
impl From<Cookie<'_>> for HeaderValue {
fn from(cookie: Cookie<'_>) -> Self {
HeaderValue {
Expand Down
18 changes: 14 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
//! ```
//! # fn main() -> Result<(), http_types::url::ParseError> {
//! #
//! use http_types::{Method, Request, Response, StatusCode};
//! use http_types::{Url, Method, Request, Response, StatusCode};
//!
//! let mut req = Request::new(Method::Get, "https://example.com");
//! let mut req = Request::new(Method::Get, Url::parse("https://example.com")?);
//! req.set_body("Hello, Nori!");
//!
//! let mut res = Response::new(StatusCode::Ok);
Expand Down Expand Up @@ -102,7 +102,6 @@
#![doc(html_logo_url = "https://yoshuawuyts.com/assets/http-rs/logo-rounded.png")]

/// HTTP cookies.
#[cfg(feature = "cookies")]
pub mod cookies {
pub use cookie::*;
}
Expand Down Expand Up @@ -152,11 +151,22 @@ pub use status::Status;
pub use status_code::StatusCode;
pub use version::Version;

#[doc(inline)]
pub use transfer::trailers::Trailers;

#[doc(inline)]
pub use mime::Mime;

#[doc(inline)]
pub use headers::Headers;

#[doc(inline)]
pub use crate::url::Url;

#[doc(inline)]
pub use crate::cookies::Cookie;

pub mod security;
pub mod trailers;

#[cfg(feature = "hyperium_http")]
mod hyperium_http;
Expand Down
41 changes: 27 additions & 14 deletions src/mime/constants.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::mime::Mime;
use std::borrow::Cow;
use super::ParamKind;
use crate::Mime;

macro_rules! utf8_mime_const {
($name:ident, $desc:expr, $base:expr, $sub:expr) => {
Expand All @@ -9,34 +9,47 @@ macro_rules! utf8_mime_const {
$desc,
$base,
$sub,
true,
Some(ParamKind::Utf8),
";charset=utf-8"
);
};
}
macro_rules! mime_const {
($name:ident, $desc:expr, $base:expr, $sub:expr) => {
mime_const!(with_params, $name, $desc, $base, $sub, false, "");
mime_const!(with_params, $name, $desc, $base, $sub, None, "");
};

(with_params, $name:ident, $desc:expr, $base:expr, $sub:expr, $is_utf8:expr, $doccomment:expr) => {
mime_const!(doc_expanded, $name, $desc, $base, $sub, $is_utf8,
concat!(
(with_params, $name:ident, $desc:expr, $base:expr, $sub:expr, $params:expr, $doccomment:expr) => {
mime_const!(
doc_expanded,
$name,
$desc,
$base,
$sub,
$params,
concat!(
"Content-Type for ",
$desc,
".\n\n# Mime Type\n\n```text\n",
$base, "/", $sub, $doccomment, "\n```")
$base,
"/",
$sub,
$doccomment,
"\n```"
)
);
};

(doc_expanded, $name:ident, $desc:expr, $base:expr, $sub:expr, $is_utf8:expr, $doccomment:expr) => {
(doc_expanded, $name:ident, $desc:expr, $base:expr, $sub:expr, $params:expr, $doccomment:expr) => {
#[doc = $doccomment]
pub const $name: Mime = Mime {
essence: Cow::Borrowed(concat!($base, "/", $sub)),
basetype: Cow::Borrowed($base),
subtype: Cow::Borrowed($sub),
is_utf8: $is_utf8,
params: vec![],
essence: String::new(),
basetype: String::new(),
subtype: String::new(),
params: $params,
static_essence: Some(concat!($base, "/", $sub)),
static_basetype: Some($base),
static_subtype: Some($sub),
};
};
}
Expand Down
116 changes: 87 additions & 29 deletions src/mime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ use infer::Infer;
/// ```
// NOTE: we cannot statically initialize Strings with values yet, so we keep dedicated static
// fields for the static strings.
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone)]
pub struct Mime {
pub(crate) essence: Cow<'static, str>,
pub(crate) basetype: Cow<'static, str>,
pub(crate) subtype: Cow<'static, str>,
// NOTE(yosh): this is a hack because we can't populate vecs in const yet.
// This enables us to encode media types as utf-8 at compilation.
pub(crate) is_utf8: bool,
pub(crate) params: Vec<(ParamName, ParamValue)>,
pub(crate) essence: String,
pub(crate) basetype: String,
pub(crate) subtype: String,
pub(crate) static_essence: Option<&'static str>,
pub(crate) static_basetype: Option<&'static str>,
pub(crate) static_subtype: Option<&'static str>,
pub(crate) params: Option<ParamKind>,
}

impl Mime {
Expand Down Expand Up @@ -68,40 +68,87 @@ impl Mime {
/// According to the spec this method should be named `type`, but that's a reserved keyword in
/// Rust so hence prefix with `base` instead.
pub fn basetype(&self) -> &str {
&self.basetype
if let Some(basetype) = self.static_basetype {
&basetype
} else {
&self.basetype
}
}

/// Access the Mime's `subtype` value.
pub fn subtype(&self) -> &str {
&self.subtype
if let Some(subtype) = self.static_subtype {
&subtype
} else {
&self.subtype
}
}

/// Access the Mime's `essence` value.
pub fn essence(&self) -> &str {
&self.essence
if let Some(essence) = self.static_essence {
&essence
} else {
&self.essence
}
}

/// Get a reference to a param.
pub fn param(&self, name: impl Into<ParamName>) -> Option<&ParamValue> {
let name: ParamName = name.into();
if name.as_str() == "charset" && self.is_utf8 {
return Some(&ParamValue(Cow::Borrowed("utf-8")));
}

self.params.iter().find(|(k, _)| k == &name).map(|(_, v)| v)
self.params
.as_ref()
.map(|inner| match inner {
ParamKind::Vec(v) => v
.iter()
.find_map(|(k, v)| if k == &name { Some(v) } else { None }),
ParamKind::Utf8 => match name {
ParamName(Cow::Borrowed("charset")) => Some(&ParamValue(Cow::Borrowed("utf8"))),
_ => None,
},
})
.flatten()
}

/// Remove a param from the set. Returns the `ParamValue` if it was contained within the set.
pub fn remove_param(&mut self, name: impl Into<ParamName>) -> Option<ParamValue> {
let name: ParamName = name.into();
if name.as_str() == "charset" && self.is_utf8 {
self.is_utf8 = false;
return Some(ParamValue(Cow::Borrowed("utf-8")));
let mut unset_params = false;
let ret = self
.params
.as_mut()
.map(|inner| match inner {
ParamKind::Vec(v) => match v.iter().position(|(k, _)| k == &name) {
Some(index) => Some(v.remove(index).1),
None => None,
},
ParamKind::Utf8 => match name {
ParamName(Cow::Borrowed("charset")) => {
unset_params = true;
Some(ParamValue(Cow::Borrowed("utf8")))
}
_ => None,
},
})
.flatten();
if unset_params {
self.params = None;
}
self.params
.iter()
.position(|(k, _)| k == &name)
.map(|pos| self.params.remove(pos).1)
ret
}
}

impl PartialEq<Mime> for Mime {
fn eq(&self, other: &Mime) -> bool {
let left = match self.static_essence {
Some(essence) => essence,
None => &self.essence,
};
let right = match other.static_essence {
Some(essence) => essence,
None => &other.essence,
};
left == right
}
}

Expand All @@ -111,11 +158,15 @@ impl Display for Mime {
}
}

// impl Debug for Mime {
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Debug::fmt(&self.essence, f)
// }
// }
impl Debug for Mime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(essence) = self.static_essence {
Debug::fmt(essence, f)
} else {
Debug::fmt(&self.essence, f)
}
}
}

impl FromStr for Mime {
type Err = crate::Error;
Expand Down Expand Up @@ -145,7 +196,6 @@ impl ToHeaderValues for Mime {
Ok(header.to_header_values().unwrap())
}
}

/// A parameter name.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ParamName(Cow<'static, str>);
Expand Down Expand Up @@ -209,3 +259,11 @@ impl PartialEq<str> for ParamValue {
self.0 == other
}
}

/// This is a hack that allows us to mark a trait as utf8 during compilation. We
/// can remove this once we can construct HashMap during compilation.
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum ParamKind {
Utf8,
Vec(Vec<(ParamName, ParamValue)>),
}
Loading