Skip to content

Commit ee0cb4f

Browse files
authored
Merge pull request #50 from yoshuawuyts/updates
Fixes from integration with tide
2 parents 9c61051 + afefe2f commit ee0cb4f

File tree

13 files changed

+173
-74
lines changed

13 files changed

+173
-74
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ readme = "README.md"
1212
edition = "2018"
1313

1414
[features]
15+
default = []
1516
hyperium_http = ["http"]
1617

1718
[dependencies]
18-
async-std = { version = "0.99.12", default-features = false, features = ["std"] }
19+
async-std = { version = "1.4.0", default-features = false, features = ["std"] }
1920
cookie = "0.12.0"
2021
infer = "0.1.2"
2122
pin-project-lite = "0.1.0"
22-
pin-utils = "0.1.0-alpha.4"
2323
url = "2.1.0"
2424
omnom = "2.1.1"
2525

src/body.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pin_project_lite::pin_project! {
5151
/// and not rely on the fallback mechanisms. However, they're still there if you need them.
5252
pub struct Body {
5353
#[pin]
54-
reader: Box<dyn BufRead + Unpin + Send + 'static>,
54+
reader: Box<dyn BufRead + Unpin + Send + Sync + 'static>,
5555
mime: Option<Mime>,
5656
length: Option<usize>,
5757
}
@@ -98,7 +98,10 @@ impl Body {
9898
/// let len = 10;
9999
/// req.set_body(Body::from_reader(cursor, Some(len)));
100100
/// ```
101-
pub fn from_reader(reader: impl BufRead + Unpin + Send + 'static, len: Option<usize>) -> Self {
101+
pub fn from_reader(
102+
reader: impl BufRead + Unpin + Send + Sync + 'static,
103+
len: Option<usize>,
104+
) -> Self {
102105
Self {
103106
reader: Box::new(reader),
104107
mime: Some(mime::BYTE_STREAM),
@@ -144,12 +147,9 @@ impl Body {
144147
self.reader
145148
}
146149

147-
/// Get the recommended mime type.
148-
///
149-
/// This methods exists because Body is instantiated with a MIME type,
150-
/// and when passing it to the request / response we don't want to clone it.
150+
/// Return the mime type.
151151
pub(crate) fn take_mime(&mut self) -> Mime {
152-
self.mime.take().unwrap()
152+
self.mime.take().expect("internal error: missing mime")
153153
}
154154
}
155155

src/error.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,6 @@ impl fmt::Display for Error {
168168
}
169169

170170
impl error::Error for Error {
171-
fn description(&self) -> &str {
172-
match self.repr {
173-
Repr::Simple(..) => self.kind().as_str(),
174-
Repr::Custom(ref c) => c.error.description(),
175-
}
176-
}
177-
178171
#[allow(deprecated)]
179172
fn cause(&self) -> Option<&dyn error::Error> {
180173
match self.repr {

src/headers/constants.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ pub const COOKIE: HeaderName = HeaderName::from_lowercase_str("cookie");
1111

1212
/// The `Set-Cookie` Header
1313
pub const SET_COOKIE: HeaderName = HeaderName::from_lowercase_str("set-cookie");
14+
15+
/// The `Transfer-Encoding` Header
16+
pub const TRANSFER_ENCODING: HeaderName = HeaderName::from_lowercase_str("transfer-encoding");

src/headers/header_name.rs

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1+
use std::borrow::Cow;
12
use std::fmt::{self, Debug, Display};
23
use std::str::FromStr;
34

45
use crate::headers::ParseError;
56

67
/// A header name.
7-
#[derive(Eq, PartialEq, Hash)]
8-
pub struct HeaderName {
9-
/// The inner representation of the string.
10-
pub(crate) string: String,
11-
/// A const-friendly string. Useful because `String::from` cannot be used in const contexts.
12-
pub(crate) static_str: Option<&'static str>,
13-
}
8+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
9+
pub struct HeaderName(Cow<'static, str>);
1410

1511
impl HeaderName {
1612
/// Create a new `HeaderName`.
@@ -20,10 +16,12 @@ impl HeaderName {
2016
}
2117
bytes.make_ascii_lowercase();
2218
let string = String::from_utf8(bytes).map_err(|_| ParseError::new())?;
23-
Ok(Self {
24-
string: string,
25-
static_str: None,
26-
})
19+
Ok(HeaderName(Cow::Owned(string)))
20+
}
21+
22+
/// Returns the header name as a `&str`.
23+
pub fn as_str(&self) -> &'_ str {
24+
&self.0
2725
}
2826

2927
/// Converts a vector of bytes to a `HeaderName` without checking that the string contains
@@ -38,38 +36,18 @@ impl HeaderName {
3836
pub unsafe fn from_ascii_unchecked(mut bytes: Vec<u8>) -> Self {
3937
bytes.make_ascii_lowercase();
4038
let string = String::from_utf8_unchecked(bytes);
41-
Self {
42-
string,
43-
static_str: None,
44-
}
39+
HeaderName(Cow::Owned(string))
4540
}
4641

4742
/// Converts a string assumed to lowercase into a `HeaderName`
4843
pub(crate) const fn from_lowercase_str(str: &'static str) -> Self {
49-
Self {
50-
string: String::new(),
51-
static_str: Some(str),
52-
}
44+
HeaderName(Cow::Borrowed(str))
5345
}
5446
}
5547

5648
impl Display for HeaderName {
5749
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58-
if let Some(string) = self.static_str {
59-
Display::fmt(string, f)
60-
} else {
61-
Display::fmt(&self.string, f)
62-
}
63-
}
64-
}
65-
66-
impl Debug for HeaderName {
67-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68-
if let Some(string) = self.static_str {
69-
Debug::fmt(string, f)
70-
} else {
71-
Debug::fmt(&self.string, f)
72-
}
50+
write!(f, "{}", self.0)
7351
}
7452
}
7553

@@ -83,9 +61,25 @@ impl FromStr for HeaderName {
8361
if !s.is_ascii() {
8462
return Err(ParseError::new());
8563
}
86-
Ok(Self {
87-
string: s.to_ascii_lowercase(),
88-
static_str: None,
89-
})
64+
Ok(HeaderName(Cow::Owned(s.to_ascii_lowercase())))
65+
}
66+
}
67+
68+
#[cfg(test)]
69+
mod tests {
70+
use super::*;
71+
72+
#[test]
73+
fn test_header_name_static_non_static() {
74+
let static_header = HeaderName::from_lowercase_str("hello");
75+
let non_static_header = HeaderName::from_str("hello").unwrap();
76+
77+
assert_eq!(&static_header, &non_static_header);
78+
assert_eq!(&static_header, &static_header);
79+
assert_eq!(&non_static_header, &non_static_header);
80+
81+
assert_eq!(static_header, non_static_header);
82+
assert_eq!(static_header, static_header);
83+
assert_eq!(non_static_header, non_static_header);
9084
}
9185
}

src/headers/mod.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub use values::Values;
3030
/// A collection of HTTP Headers.
3131
#[derive(Debug)]
3232
pub struct Headers {
33-
headers: HashMap<HeaderName, Vec<HeaderValue>>,
33+
pub(crate) headers: HashMap<HeaderName, Vec<HeaderValue>>,
3434
}
3535

3636
impl Headers {
@@ -143,3 +143,55 @@ impl<'a> IntoIterator for &'a mut Headers {
143143
self.iter_mut()
144144
}
145145
}
146+
147+
#[cfg(test)]
148+
mod tests {
149+
use super::*;
150+
use std::str::FromStr;
151+
152+
const STATIC_HEADER: HeaderName = HeaderName::from_lowercase_str("hello");
153+
154+
#[test]
155+
fn test_header_name_static_non_static() {
156+
let static_header = HeaderName::from_lowercase_str("hello");
157+
let non_static_header = HeaderName::from_str("hello").unwrap();
158+
159+
let mut headers = Headers::new();
160+
headers
161+
.append(STATIC_HEADER, &["foo0".parse().unwrap()][..])
162+
.unwrap();
163+
headers
164+
.append(static_header.clone(), &["foo1".parse().unwrap()][..])
165+
.unwrap();
166+
headers
167+
.append(non_static_header.clone(), &["foo2".parse().unwrap()][..])
168+
.unwrap();
169+
170+
assert_eq!(
171+
&headers.get(&STATIC_HEADER).unwrap()[..],
172+
&[
173+
"foo0".parse().unwrap(),
174+
"foo1".parse().unwrap(),
175+
"foo2".parse().unwrap()
176+
][..]
177+
);
178+
179+
assert_eq!(
180+
&headers.get(&static_header).unwrap()[..],
181+
&[
182+
"foo0".parse().unwrap(),
183+
"foo1".parse().unwrap(),
184+
"foo2".parse().unwrap()
185+
][..]
186+
);
187+
188+
assert_eq!(
189+
&headers.get(&non_static_header).unwrap()[..],
190+
&[
191+
"foo0".parse().unwrap(),
192+
"foo1".parse().unwrap(),
193+
"foo2".parse().unwrap()
194+
][..]
195+
);
196+
}
197+
}

src/headers/to_header_values.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,14 @@ impl<'a> ToHeaderValues for &'a [HeaderValue] {
2929
Ok(self.iter().cloned())
3030
}
3131
}
32+
33+
impl<'a> ToHeaderValues for &'a str {
34+
type Iter = option::IntoIter<HeaderValue>;
35+
36+
fn to_header_values(&self) -> io::Result<Self::Iter> {
37+
let value = self
38+
.parse()
39+
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
40+
Ok(Some(value).into_iter())
41+
}
42+
}

src/hyperium_http.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ impl From<http::Method> for Method {
1111
}
1212
}
1313

14-
impl From<&Method> for http::Method {
15-
fn from(method: &Method) -> Self {
14+
impl From<Method> for http::Method {
15+
fn from(method: Method) -> Self {
1616
http::Method::from_str(&format!("{}", method)).unwrap()
1717
}
1818
}

src/method.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ pub enum Method {
3838
Patch,
3939
}
4040

41+
impl Method {
42+
/// Whether a method is considered "safe", meaning the request is
43+
/// essentially read-only.
44+
///
45+
/// See [the spec](https://tools.ietf.org/html/rfc7231#section-4.2.1) for more details.
46+
pub fn is_safe(&self) -> bool {
47+
match self {
48+
Method::Get | Method::Head | Method::Options | Method::Trace => true,
49+
_ => false,
50+
}
51+
}
52+
}
53+
4154
impl Display for Method {
4255
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
4356
match self {

src/mime/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use infer::Infer;
2020
/// An IANA media type.
2121
// NOTE: we cannot statically initialize Strings with values yet, so we keep dedicated static
2222
// fields for the static strings.
23+
#[derive(Clone)]
2324
pub struct Mime {
2425
pub(crate) essence: String,
2526
pub(crate) basetype: String,

0 commit comments

Comments
 (0)