Skip to content

Commit 7a7b358

Browse files
authored
Merge pull request #105 from jbr/update-http-types
async-h1 update for http-types 2.0.0
2 parents 428fb9e + 12f4ace commit 7a7b358

13 files changed

+57
-84
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ edition = "2018"
1515
url = "2.1.0"
1616
httparse = "1.3.3"
1717
async-std = { version = "1.5.0", features = ["unstable"] }
18-
http-types = "1.2.0"
18+
http-types = "2.0.0"
1919
pin-project-lite = "0.1.1"
2020
byte-pool = "0.2.1"
2121
lazy_static = "1.4.0"

examples/server.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ async fn accept(stream: TcpStream) -> http_types::Result<()> {
2828
println!("starting new connection from {}", stream.peer_addr()?);
2929
async_h1::accept(stream.clone(), |_req| async move {
3030
let mut res = Response::new(StatusCode::Ok);
31-
res.insert_header("Content-Type", "text/plain")?;
31+
res.insert_header("Content-Type", "text/plain");
3232
res.set_body("Hello world");
3333
Ok(res)
3434
})

src/chunked/decoder.rs

+11-19
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::task::{Context, Poll};
77
use async_std::io::{self, Read};
88
use async_std::sync::Arc;
99
use byte_pool::{Block, BytePool};
10-
use http_types::trailers::{Trailers, TrailersSender};
10+
use http_types::trailers::{Sender, Trailers};
1111

1212
const INITIAL_CAPACITY: usize = 1024 * 4;
1313
const MAX_CAPACITY: usize = 512 * 1024 * 1024; // 512 MiB
@@ -32,11 +32,11 @@ pub(crate) struct ChunkedDecoder<R: Read> {
3232
/// Current state.
3333
state: State,
3434
/// Trailer channel sender.
35-
trailer_sender: Option<TrailersSender>,
35+
trailer_sender: Option<Sender>,
3636
}
3737

3838
impl<R: Read> ChunkedDecoder<R> {
39-
pub(crate) fn new(inner: R, trailer_sender: TrailersSender) -> Self {
39+
pub(crate) fn new(inner: R, trailer_sender: Sender) -> Self {
4040
ChunkedDecoder {
4141
inner,
4242
buffer: POOL.alloc(INITIAL_CAPACITY),
@@ -156,7 +156,7 @@ impl<R: Read + Unpin> ChunkedDecoder<R> {
156156
let sender =
157157
sender.expect("invalid chunked state, tried sending multiple trailers");
158158

159-
let fut = Box::pin(sender.send(Ok(headers)));
159+
let fut = Box::pin(sender.send(headers));
160160
Ok(DecodeResult::Some {
161161
read: 0,
162162
new_state: Some(State::TrailerSending(fut)),
@@ -483,10 +483,7 @@ fn decode_trailer(buffer: Block<'static>, pos: &Range<usize>) -> io::Result<Deco
483483
Ok(Status::Complete((used, headers))) => {
484484
let mut trailers = Trailers::new();
485485
for header in headers {
486-
let value = std::string::String::from_utf8_lossy(header.value).to_string();
487-
if let Err(err) = trailers.insert(header.name, value) {
488-
return Err(io::Error::new(io::ErrorKind::Other, err.to_string()));
489-
}
486+
trailers.insert(header.name, String::from_utf8_lossy(header.value).as_ref());
490487
}
491488

492489
Ok(DecodeResult::Some {
@@ -527,7 +524,7 @@ mod tests {
527524
);
528525

529526
let (s, _r) = async_std::sync::channel(1);
530-
let sender = TrailersSender::new(s);
527+
let sender = Sender::new(s);
531528
let mut decoder = ChunkedDecoder::new(input, sender);
532529

533530
let mut output = String::new();
@@ -553,7 +550,7 @@ mod tests {
553550
input.extend("\r\n0\r\n\r\n".as_bytes());
554551

555552
let (s, _r) = async_std::sync::channel(1);
556-
let sender = TrailersSender::new(s);
553+
let sender = Sender::new(s);
557554
let mut decoder = ChunkedDecoder::new(async_std::io::Cursor::new(input), sender);
558555

559556
let mut output = String::new();
@@ -583,21 +580,16 @@ mod tests {
583580
.as_bytes(),
584581
);
585582
let (s, r) = async_std::sync::channel(1);
586-
let sender = TrailersSender::new(s);
583+
let sender = Sender::new(s);
587584
let mut decoder = ChunkedDecoder::new(input, sender);
588585

589586
let mut output = String::new();
590587
decoder.read_to_string(&mut output).await.unwrap();
591588
assert_eq!(output, "MozillaDeveloperNetwork");
592589

593-
let trailer = r.recv().await.unwrap().unwrap();
594-
assert_eq!(
595-
trailer.iter().collect::<Vec<_>>(),
596-
vec![(
597-
&"Expires".parse().unwrap(),
598-
&vec!["Wed, 21 Oct 2015 07:28:00 GMT".parse().unwrap()],
599-
)]
600-
);
590+
let trailers = r.recv().await.unwrap();
591+
assert_eq!(trailers.iter().count(), 1);
592+
assert_eq!(trailers["Expires"], "Wed, 21 Oct 2015 07:28:00 GMT");
601593
});
602594
}
603595
}

src/client/decode.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ use async_std::io::{BufReader, Read};
22
use async_std::prelude::*;
33
use http_types::{ensure, ensure_eq, format_err};
44
use http_types::{
5-
headers::{HeaderName, HeaderValue, CONTENT_LENGTH, DATE, TRANSFER_ENCODING},
5+
headers::{CONTENT_LENGTH, DATE, TRANSFER_ENCODING},
66
Body, Response, StatusCode,
77
};
88

99
use std::convert::TryFrom;
10-
use std::str::FromStr;
1110

1211
use crate::chunked::ChunkedDecoder;
1312
use crate::date::fmt_http_date;
@@ -63,26 +62,24 @@ where
6362

6463
let mut res = Response::new(StatusCode::try_from(code)?);
6564
for header in httparse_res.headers.iter() {
66-
let name = HeaderName::from_str(header.name)?;
67-
let value = HeaderValue::from_str(std::str::from_utf8(header.value)?)?;
68-
res.append_header(name, value)?;
65+
res.append_header(header.name, std::str::from_utf8(header.value)?);
6966
}
7067

71-
if res.header(&DATE).is_none() {
68+
if res.header(DATE).is_none() {
7269
let date = fmt_http_date(std::time::SystemTime::now());
73-
res.insert_header(DATE, &format!("date: {}\r\n", date)[..])?;
70+
res.insert_header(DATE, &format!("date: {}\r\n", date)[..]);
7471
}
7572

76-
let content_length = res.header(&CONTENT_LENGTH);
77-
let transfer_encoding = res.header(&TRANSFER_ENCODING);
73+
let content_length = res.header(CONTENT_LENGTH);
74+
let transfer_encoding = res.header(TRANSFER_ENCODING);
7875

7976
ensure!(
8077
content_length.is_none() || transfer_encoding.is_none(),
8178
"Unexpected Content-Length header"
8279
);
8380

8481
if let Some(encoding) = transfer_encoding {
85-
if !encoding.is_empty() && encoding.last().unwrap().as_str() == "chunked" {
82+
if encoding.last().as_str() == "chunked" {
8683
let trailers_sender = res.send_trailers();
8784
let reader = BufReader::new(ChunkedDecoder::new(reader, trailers_sender));
8885
res.set_body(Body::from_reader(reader, None));
@@ -94,7 +91,7 @@ where
9491

9592
// Check for Content-Length.
9693
if let Some(len) = content_length {
97-
let len = len.last().unwrap().as_str().parse::<usize>()?;
94+
let len = len.last().as_str().parse::<usize>()?;
9895
res.set_body(Body::from_reader(reader.take(len as u64), Some(len)));
9996
}
10097

src/client/encode.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use async_std::io::{self, Read};
22
use async_std::prelude::*;
33
use async_std::task::{Context, Poll};
44
use http_types::format_err;
5-
use http_types::{Method, Request};
5+
use http_types::{headers::HOST, Method, Request};
66

77
use std::pin::Pin;
88

@@ -54,7 +54,7 @@ impl Encoder {
5454
log::trace!("> {}", &val);
5555
buf.write_all(val.as_bytes()).await?;
5656

57-
if req.header(&http_types::headers::HOST).is_none() {
57+
if req.header(HOST).is_none() {
5858
// Insert Host header
5959
// Insert host
6060
let host = req.url().host_str();

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
//! println!("starting new connection from {}", stream.peer_addr()?);
8080
//! async_h1::accept(stream.clone(), |_req| async move {
8181
//! let mut res = Response::new(StatusCode::Ok);
82-
//! res.insert_header("Content-Type", "text/plain")?;
82+
//! res.insert_header("Content-Type", "text/plain");
8383
//! res.set_body("Hello");
8484
//! Ok(res)
8585
//! })

src/server/decode.rs

+23-37
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::str::FromStr;
44

55
use async_std::io::{BufReader, Read, Write};
66
use async_std::prelude::*;
7-
use http_types::headers::{HeaderName, HeaderValue, CONTENT_LENGTH, HOST, TRANSFER_ENCODING};
7+
use http_types::headers::{CONTENT_LENGTH, EXPECT, HOST, TRANSFER_ENCODING};
88
use http_types::{ensure, ensure_eq, format_err};
99
use http_types::{Body, Method, Request};
1010

@@ -75,16 +75,14 @@ where
7575
);
7676

7777
for header in httparse_req.headers.iter() {
78-
let name = HeaderName::from_str(header.name)?;
79-
let value = HeaderValue::from_str(std::str::from_utf8(header.value)?)?;
80-
req.insert_header(name, value)?;
78+
req.insert_header(header.name, std::str::from_utf8(header.value)?);
8179
}
8280

8381
set_url_and_port_from_host_header(&mut req)?;
8482
handle_100_continue(&req, &mut io).await?;
8583

86-
let content_length = req.header(&CONTENT_LENGTH);
87-
let transfer_encoding = req.header(&TRANSFER_ENCODING);
84+
let content_length = req.header(CONTENT_LENGTH);
85+
let transfer_encoding = req.header(TRANSFER_ENCODING);
8886

8987
http_types::ensure!(
9088
content_length.is_none() || transfer_encoding.is_none(),
@@ -93,7 +91,7 @@ where
9391

9492
// Check for Transfer-Encoding
9593
if let Some(encoding) = transfer_encoding {
96-
if !encoding.is_empty() && encoding.last().unwrap().as_str() == "chunked" {
94+
if encoding.last().as_str() == "chunked" {
9795
let trailer_sender = req.send_trailers();
9896
let reader = BufReader::new(ChunkedDecoder::new(reader, trailer_sender));
9997
req.set_body(Body::from_reader(reader, None));
@@ -104,7 +102,7 @@ where
104102

105103
// Check for Content-Length.
106104
if let Some(len) = content_length {
107-
let len = len.last().unwrap().as_str().parse::<usize>()?;
105+
let len = len.last().as_str().parse::<usize>()?;
108106
req.set_body(Body::from_reader(reader.take(len as u64), Some(len)));
109107
}
110108

@@ -113,11 +111,11 @@ where
113111

114112
fn set_url_and_port_from_host_header(req: &mut Request) -> http_types::Result<()> {
115113
let host = req
116-
.header(&HOST)
117-
.and_then(|header| header.last()) // There must only exactly one Host header, so this is permissive
118-
.ok_or_else(|| format_err!("Mandatory Host header missing"))?; // https://tools.ietf.org/html/rfc7230#section-5.4
114+
.header(HOST)
115+
.map(|header| header.last()) // There must only exactly one Host header, so this is permissive
116+
.ok_or_else(|| format_err!("Mandatory Host header missing"))? // https://tools.ietf.org/html/rfc7230#section-5.4
117+
.to_string();
119118

120-
let host = host.to_string();
121119
if let Some(colon) = host.find(":") {
122120
req.url_mut().set_host(Some(&host[0..colon]))?;
123121
req.url_mut()
@@ -130,17 +128,15 @@ fn set_url_and_port_from_host_header(req: &mut Request) -> http_types::Result<()
130128
Ok(())
131129
}
132130

133-
async fn handle_100_continue<IO: Write + Unpin>(
134-
req: &Request,
135-
io: &mut IO,
136-
) -> http_types::Result<()> {
137-
let expect_header_value = req
138-
.header(&HeaderName::from_str("expect").unwrap())
139-
.and_then(|v| v.last())
140-
.map(|v| v.as_str());
141-
142-
if let Some("100-continue") = expect_header_value {
143-
io.write_all("HTTP/1.1 100 Continue\r\n".as_bytes()).await?;
131+
const EXPECT_HEADER_VALUE: &str = "100-continue";
132+
const EXPECT_RESPONSE: &[u8] = b"HTTP/1.1 100 Continue\r\n";
133+
134+
async fn handle_100_continue<IO>(req: &Request, io: &mut IO) -> http_types::Result<()>
135+
where
136+
IO: Write + Unpin,
137+
{
138+
if let Some(EXPECT_HEADER_VALUE) = req.header(EXPECT).map(|h| h.as_str()) {
139+
io.write_all(EXPECT_RESPONSE).await?;
144140
}
145141

146142
Ok(())
@@ -162,7 +158,7 @@ mod tests {
162158
#[test]
163159
fn handle_100_continue_sends_header_if_expects_is_exactly_right() {
164160
let mut request = Request::new(Method::Get, url::Url::parse("x:").unwrap());
165-
request.append_header("expect", "100-continue").unwrap();
161+
request.append_header("expect", "100-continue");
166162
let mut io = async_std::io::Cursor::new(vec![]);
167163
let result = async_std::task::block_on(handle_100_continue(&request, &mut io));
168164
assert_eq!(
@@ -175,9 +171,7 @@ mod tests {
175171
#[test]
176172
fn handle_100_continue_does_nothing_if_expects_header_is_wrong() {
177173
let mut request = Request::new(Method::Get, url::Url::parse("x:").unwrap());
178-
request
179-
.append_header("expect", "110-extensions-not-allowed")
180-
.unwrap();
174+
request.append_header("expect", "110-extensions-not-allowed");
181175
let mut io = async_std::io::Cursor::new(vec![]);
182176
let result = async_std::task::block_on(handle_100_continue(&request, &mut io));
183177
assert_eq!(std::str::from_utf8(&io.into_inner()).unwrap(), "");
@@ -247,16 +241,8 @@ mod tests {
247241
}
248242

249243
fn request_with_host_header(host: &str) -> Request {
250-
let mut req = Request::new(
251-
Method::Get,
252-
url::Url::parse("http://_")
253-
.unwrap()
254-
.join("/some/path")
255-
.unwrap(),
256-
);
257-
258-
req.insert_header(HOST, host).unwrap();
259-
244+
let mut req = Request::new(Method::Get, url::Url::parse("http://_/some/path").unwrap());
245+
req.insert_header(HOST, host);
260246
req
261247
}
262248
}

src/server/encode.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::pin::Pin;
55
use async_std::io;
66
use async_std::io::prelude::*;
77
use async_std::task::{Context, Poll};
8+
use http_types::headers::{CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
89
use http_types::Response;
910

1011
use crate::chunked::ChunkedEncoder;
@@ -138,16 +139,16 @@ impl Encoder {
138139
)?;
139140
}
140141

141-
if self.res.header(&http_types::headers::DATE).is_none() {
142+
if self.res.header(DATE).is_none() {
142143
let date = fmt_http_date(std::time::SystemTime::now());
143144
std::io::Write::write_fmt(&mut self.head, format_args!("date: {}\r\n", date))?;
144145
}
145146

146147
let iter = self
147148
.res
148149
.iter()
149-
.filter(|(h, _)| h != &&http_types::headers::CONTENT_LENGTH)
150-
.filter(|(h, _)| h != &&http_types::headers::TRANSFER_ENCODING);
150+
.filter(|(h, _)| h != &&CONTENT_LENGTH)
151+
.filter(|(h, _)| h != &&TRANSFER_ENCODING);
151152
for (header, values) in iter {
152153
for value in values.iter() {
153154
std::io::Write::write_fmt(

tests/client.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ async fn test_multiple_header_values_for_same_header_name() {
4545

4646
let res = client::decode(response_fixture).await.unwrap();
4747

48-
pretty_assertions::assert_eq!(res.header(&headers::SET_COOKIE).unwrap().len(), 2);
48+
pretty_assertions::assert_eq!(res.header(&headers::SET_COOKIE).unwrap().iter().count(), 2);
4949
}
5050

5151
#[async_std::test]
@@ -57,10 +57,7 @@ async fn test_response_newlines() {
5757
let res = client::decode(response_fixture).await.unwrap();
5858

5959
pretty_assertions::assert_eq!(
60-
res.header(&headers::CONTENT_LENGTH)
61-
.unwrap()
62-
.last()
63-
.unwrap()
60+
res[headers::CONTENT_LENGTH]
6461
.as_str()
6562
.parse::<usize>()
6663
.unwrap(),

tests/fixtures/request-add-date.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
POST / HTTP/1.1
22
host: localhost:8080
33
content-length: 5
4-
content-type: text/plain; charset=utf-8
4+
content-type: text/plain;charset=utf-8
55

66
hello

tests/fixtures/response-add-date.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
HTTP/1.1 200 OK
22
content-length: 0
33
date: {DATE}
4-
content-type: text/plain; charset=utf-8
4+
content-type: text/plain;charset=utf-8
55

tests/fixtures/response-chunked-basic.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
HTTP/1.1 200 OK
22
transfer-encoding: chunked
33
date: {DATE}
4-
content-type: text/plain
4+
content-type: text/plain;charset=utf-8
55

66
7
77
Mozilla

0 commit comments

Comments
 (0)