mirror of https://github.com/http-rs/async-h1
update http-types to master
This commit is contained in:
parent
428fb9e8c6
commit
9fd5ea0574
|
@ -15,7 +15,7 @@ edition = "2018"
|
|||
url = "2.1.0"
|
||||
httparse = "1.3.3"
|
||||
async-std = { version = "1.5.0", features = ["unstable"] }
|
||||
http-types = "1.2.0"
|
||||
http-types = { git = "https://github.com/http-rs/http-types.git", branch = "master" }
|
||||
pin-project-lite = "0.1.1"
|
||||
byte-pool = "0.2.1"
|
||||
lazy_static = "1.4.0"
|
||||
|
|
|
@ -28,7 +28,7 @@ async fn accept(stream: TcpStream) -> http_types::Result<()> {
|
|||
println!("starting new connection from {}", stream.peer_addr()?);
|
||||
async_h1::accept(stream.clone(), |_req| async move {
|
||||
let mut res = Response::new(StatusCode::Ok);
|
||||
res.insert_header("Content-Type", "text/plain")?;
|
||||
res.insert_header("Content-Type", "text/plain");
|
||||
res.set_body("Hello world");
|
||||
Ok(res)
|
||||
})
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::task::{Context, Poll};
|
|||
use async_std::io::{self, Read};
|
||||
use async_std::sync::Arc;
|
||||
use byte_pool::{Block, BytePool};
|
||||
use http_types::trailers::{Trailers, TrailersSender};
|
||||
use http_types::trailers::{Sender, Trailers};
|
||||
|
||||
const INITIAL_CAPACITY: usize = 1024 * 4;
|
||||
const MAX_CAPACITY: usize = 512 * 1024 * 1024; // 512 MiB
|
||||
|
@ -32,11 +32,11 @@ pub(crate) struct ChunkedDecoder<R: Read> {
|
|||
/// Current state.
|
||||
state: State,
|
||||
/// Trailer channel sender.
|
||||
trailer_sender: Option<TrailersSender>,
|
||||
trailer_sender: Option<Sender>,
|
||||
}
|
||||
|
||||
impl<R: Read> ChunkedDecoder<R> {
|
||||
pub(crate) fn new(inner: R, trailer_sender: TrailersSender) -> Self {
|
||||
pub(crate) fn new(inner: R, trailer_sender: Sender) -> Self {
|
||||
ChunkedDecoder {
|
||||
inner,
|
||||
buffer: POOL.alloc(INITIAL_CAPACITY),
|
||||
|
@ -156,7 +156,7 @@ impl<R: Read + Unpin> ChunkedDecoder<R> {
|
|||
let sender =
|
||||
sender.expect("invalid chunked state, tried sending multiple trailers");
|
||||
|
||||
let fut = Box::pin(sender.send(Ok(headers)));
|
||||
let fut = Box::pin(sender.send(headers));
|
||||
Ok(DecodeResult::Some {
|
||||
read: 0,
|
||||
new_state: Some(State::TrailerSending(fut)),
|
||||
|
@ -483,10 +483,7 @@ fn decode_trailer(buffer: Block<'static>, pos: &Range<usize>) -> io::Result<Deco
|
|||
Ok(Status::Complete((used, headers))) => {
|
||||
let mut trailers = Trailers::new();
|
||||
for header in headers {
|
||||
let value = std::string::String::from_utf8_lossy(header.value).to_string();
|
||||
if let Err(err) = trailers.insert(header.name, value) {
|
||||
return Err(io::Error::new(io::ErrorKind::Other, err.to_string()));
|
||||
}
|
||||
trailers.insert(header.name, String::from_utf8_lossy(header.value).as_ref());
|
||||
}
|
||||
|
||||
Ok(DecodeResult::Some {
|
||||
|
@ -527,7 +524,7 @@ mod tests {
|
|||
);
|
||||
|
||||
let (s, _r) = async_std::sync::channel(1);
|
||||
let sender = TrailersSender::new(s);
|
||||
let sender = Sender::new(s);
|
||||
let mut decoder = ChunkedDecoder::new(input, sender);
|
||||
|
||||
let mut output = String::new();
|
||||
|
@ -553,7 +550,7 @@ mod tests {
|
|||
input.extend("\r\n0\r\n\r\n".as_bytes());
|
||||
|
||||
let (s, _r) = async_std::sync::channel(1);
|
||||
let sender = TrailersSender::new(s);
|
||||
let sender = Sender::new(s);
|
||||
let mut decoder = ChunkedDecoder::new(async_std::io::Cursor::new(input), sender);
|
||||
|
||||
let mut output = String::new();
|
||||
|
@ -583,20 +580,30 @@ mod tests {
|
|||
.as_bytes(),
|
||||
);
|
||||
let (s, r) = async_std::sync::channel(1);
|
||||
let sender = TrailersSender::new(s);
|
||||
let sender = Sender::new(s);
|
||||
let mut decoder = ChunkedDecoder::new(input, sender);
|
||||
|
||||
let mut output = String::new();
|
||||
decoder.read_to_string(&mut output).await.unwrap();
|
||||
assert_eq!(output, "MozillaDeveloperNetwork");
|
||||
|
||||
let trailer = r.recv().await.unwrap().unwrap();
|
||||
let trailers = r.recv().await.unwrap();
|
||||
let as_vec = trailers.iter().collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(as_vec.len(), 1);
|
||||
let (header_name, header_values) = as_vec[0];
|
||||
assert_eq!(
|
||||
trailer.iter().collect::<Vec<_>>(),
|
||||
vec![(
|
||||
&"Expires".parse().unwrap(),
|
||||
&vec!["Wed, 21 Oct 2015 07:28:00 GMT".parse().unwrap()],
|
||||
)]
|
||||
header_name,
|
||||
&"Expires"
|
||||
.parse::<http_types::headers::HeaderName>()
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(header_values.iter().collect::<Vec<_>>().len(), 1);
|
||||
assert_eq!(
|
||||
header_values.last(),
|
||||
&"Wed, 21 Oct 2015 07:28:00 GMT"
|
||||
.parse::<http_types::headers::HeaderValue>()
|
||||
.unwrap()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,12 +2,11 @@ use async_std::io::{BufReader, Read};
|
|||
use async_std::prelude::*;
|
||||
use http_types::{ensure, ensure_eq, format_err};
|
||||
use http_types::{
|
||||
headers::{HeaderName, HeaderValue, CONTENT_LENGTH, DATE, TRANSFER_ENCODING},
|
||||
headers::{CONTENT_LENGTH, DATE, TRANSFER_ENCODING},
|
||||
Body, Response, StatusCode,
|
||||
};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::chunked::ChunkedDecoder;
|
||||
use crate::date::fmt_http_date;
|
||||
|
@ -63,18 +62,16 @@ where
|
|||
|
||||
let mut res = Response::new(StatusCode::try_from(code)?);
|
||||
for header in httparse_res.headers.iter() {
|
||||
let name = HeaderName::from_str(header.name)?;
|
||||
let value = HeaderValue::from_str(std::str::from_utf8(header.value)?)?;
|
||||
res.append_header(name, value)?;
|
||||
res.append_header(header.name, std::str::from_utf8(header.value)?)?;
|
||||
}
|
||||
|
||||
if res.header(&DATE).is_none() {
|
||||
if res.header(DATE).is_none() {
|
||||
let date = fmt_http_date(std::time::SystemTime::now());
|
||||
res.insert_header(DATE, &format!("date: {}\r\n", date)[..])?;
|
||||
res.insert_header(DATE, &format!("date: {}\r\n", date)[..]);
|
||||
}
|
||||
|
||||
let content_length = res.header(&CONTENT_LENGTH);
|
||||
let transfer_encoding = res.header(&TRANSFER_ENCODING);
|
||||
let content_length = res.header(CONTENT_LENGTH);
|
||||
let transfer_encoding = res.header(TRANSFER_ENCODING);
|
||||
|
||||
ensure!(
|
||||
content_length.is_none() || transfer_encoding.is_none(),
|
||||
|
@ -82,7 +79,7 @@ where
|
|||
);
|
||||
|
||||
if let Some(encoding) = transfer_encoding {
|
||||
if !encoding.is_empty() && encoding.last().unwrap().as_str() == "chunked" {
|
||||
if encoding.last().as_str() == "chunked" {
|
||||
let trailers_sender = res.send_trailers();
|
||||
let reader = BufReader::new(ChunkedDecoder::new(reader, trailers_sender));
|
||||
res.set_body(Body::from_reader(reader, None));
|
||||
|
@ -94,7 +91,7 @@ where
|
|||
|
||||
// Check for Content-Length.
|
||||
if let Some(len) = content_length {
|
||||
let len = len.last().unwrap().as_str().parse::<usize>()?;
|
||||
let len = len.last().as_str().parse::<usize>()?;
|
||||
res.set_body(Body::from_reader(reader.take(len as u64), Some(len)));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use async_std::io::{self, Read};
|
|||
use async_std::prelude::*;
|
||||
use async_std::task::{Context, Poll};
|
||||
use http_types::format_err;
|
||||
use http_types::{Method, Request};
|
||||
use http_types::{headers::HOST, Method, Request};
|
||||
|
||||
use std::pin::Pin;
|
||||
|
||||
|
@ -54,7 +54,7 @@ impl Encoder {
|
|||
log::trace!("> {}", &val);
|
||||
buf.write_all(val.as_bytes()).await?;
|
||||
|
||||
if req.header(&http_types::headers::HOST).is_none() {
|
||||
if req.header(HOST).is_none() {
|
||||
// Insert Host header
|
||||
// Insert host
|
||||
let host = req.url().host_str();
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
//! println!("starting new connection from {}", stream.peer_addr()?);
|
||||
//! async_h1::accept(stream.clone(), |_req| async move {
|
||||
//! let mut res = Response::new(StatusCode::Ok);
|
||||
//! res.insert_header("Content-Type", "text/plain")?;
|
||||
//! res.insert_header("Content-Type", "text/plain");
|
||||
//! res.set_body("Hello");
|
||||
//! Ok(res)
|
||||
//! })
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::str::FromStr;
|
|||
|
||||
use async_std::io::{BufReader, Read, Write};
|
||||
use async_std::prelude::*;
|
||||
use http_types::headers::{HeaderName, HeaderValue, CONTENT_LENGTH, HOST, TRANSFER_ENCODING};
|
||||
use http_types::headers::{CONTENT_LENGTH, HOST, TRANSFER_ENCODING};
|
||||
use http_types::{ensure, ensure_eq, format_err};
|
||||
use http_types::{Body, Method, Request};
|
||||
|
||||
|
@ -75,16 +75,14 @@ where
|
|||
);
|
||||
|
||||
for header in httparse_req.headers.iter() {
|
||||
let name = HeaderName::from_str(header.name)?;
|
||||
let value = HeaderValue::from_str(std::str::from_utf8(header.value)?)?;
|
||||
req.insert_header(name, value)?;
|
||||
req.insert_header(header.name, std::str::from_utf8(header.value)?);
|
||||
}
|
||||
|
||||
set_url_and_port_from_host_header(&mut req)?;
|
||||
handle_100_continue(&req, &mut io).await?;
|
||||
|
||||
let content_length = req.header(&CONTENT_LENGTH);
|
||||
let transfer_encoding = req.header(&TRANSFER_ENCODING);
|
||||
let content_length = req.header(CONTENT_LENGTH);
|
||||
let transfer_encoding = req.header(TRANSFER_ENCODING);
|
||||
|
||||
http_types::ensure!(
|
||||
content_length.is_none() || transfer_encoding.is_none(),
|
||||
|
@ -93,7 +91,7 @@ where
|
|||
|
||||
// Check for Transfer-Encoding
|
||||
if let Some(encoding) = transfer_encoding {
|
||||
if !encoding.is_empty() && encoding.last().unwrap().as_str() == "chunked" {
|
||||
if encoding.last().as_str() == "chunked" {
|
||||
let trailer_sender = req.send_trailers();
|
||||
let reader = BufReader::new(ChunkedDecoder::new(reader, trailer_sender));
|
||||
req.set_body(Body::from_reader(reader, None));
|
||||
|
@ -104,7 +102,7 @@ where
|
|||
|
||||
// Check for Content-Length.
|
||||
if let Some(len) = content_length {
|
||||
let len = len.last().unwrap().as_str().parse::<usize>()?;
|
||||
let len = len.last().as_str().parse::<usize>()?;
|
||||
req.set_body(Body::from_reader(reader.take(len as u64), Some(len)));
|
||||
}
|
||||
|
||||
|
@ -113,11 +111,11 @@ where
|
|||
|
||||
fn set_url_and_port_from_host_header(req: &mut Request) -> http_types::Result<()> {
|
||||
let host = req
|
||||
.header(&HOST)
|
||||
.and_then(|header| header.last()) // There must only exactly one Host header, so this is permissive
|
||||
.ok_or_else(|| format_err!("Mandatory Host header missing"))?; // https://tools.ietf.org/html/rfc7230#section-5.4
|
||||
.header(HOST)
|
||||
.map(|header| header.last()) // There must only exactly one Host header, so this is permissive
|
||||
.ok_or_else(|| format_err!("Mandatory Host header missing"))? // https://tools.ietf.org/html/rfc7230#section-5.4
|
||||
.to_string();
|
||||
|
||||
let host = host.to_string();
|
||||
if let Some(colon) = host.find(":") {
|
||||
req.url_mut().set_host(Some(&host[0..colon]))?;
|
||||
req.url_mut()
|
||||
|
@ -134,10 +132,7 @@ async fn handle_100_continue<IO: Write + Unpin>(
|
|||
req: &Request,
|
||||
io: &mut IO,
|
||||
) -> http_types::Result<()> {
|
||||
let expect_header_value = req
|
||||
.header(&HeaderName::from_str("expect").unwrap())
|
||||
.and_then(|v| v.last())
|
||||
.map(|v| v.as_str());
|
||||
let expect_header_value = req.header("expect").map(|v| v.as_str());
|
||||
|
||||
if let Some("100-continue") = expect_header_value {
|
||||
io.write_all("HTTP/1.1 100 Continue\r\n".as_bytes()).await?;
|
||||
|
@ -255,7 +250,7 @@ mod tests {
|
|||
.unwrap(),
|
||||
);
|
||||
|
||||
req.insert_header(HOST, host).unwrap();
|
||||
req.insert_header(HOST, host);
|
||||
|
||||
req
|
||||
}
|
||||
|
|
|
@ -5,7 +5,10 @@ use std::pin::Pin;
|
|||
use async_std::io;
|
||||
use async_std::io::prelude::*;
|
||||
use async_std::task::{Context, Poll};
|
||||
use http_types::Response;
|
||||
use http_types::{
|
||||
headers::{CONTENT_LENGTH, DATE, TRANSFER_ENCODING},
|
||||
Response,
|
||||
};
|
||||
|
||||
use crate::chunked::ChunkedEncoder;
|
||||
use crate::date::fmt_http_date;
|
||||
|
@ -138,7 +141,7 @@ impl Encoder {
|
|||
)?;
|
||||
}
|
||||
|
||||
if self.res.header(&http_types::headers::DATE).is_none() {
|
||||
if self.res.header(DATE).is_none() {
|
||||
let date = fmt_http_date(std::time::SystemTime::now());
|
||||
std::io::Write::write_fmt(&mut self.head, format_args!("date: {}\r\n", date))?;
|
||||
}
|
||||
|
@ -146,8 +149,8 @@ impl Encoder {
|
|||
let iter = self
|
||||
.res
|
||||
.iter()
|
||||
.filter(|(h, _)| h != &&http_types::headers::CONTENT_LENGTH)
|
||||
.filter(|(h, _)| h != &&http_types::headers::TRANSFER_ENCODING);
|
||||
.filter(|(h, _)| h != &&CONTENT_LENGTH)
|
||||
.filter(|(h, _)| h != &&TRANSFER_ENCODING);
|
||||
for (header, values) in iter {
|
||||
for value in values.iter() {
|
||||
std::io::Write::write_fmt(
|
||||
|
|
|
@ -45,7 +45,7 @@ async fn test_multiple_header_values_for_same_header_name() {
|
|||
|
||||
let res = client::decode(response_fixture).await.unwrap();
|
||||
|
||||
pretty_assertions::assert_eq!(res.header(&headers::SET_COOKIE).unwrap().len(), 2);
|
||||
pretty_assertions::assert_eq!(res.header(&headers::SET_COOKIE).unwrap().iter().count(), 2);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
|
@ -60,7 +60,6 @@ async fn test_response_newlines() {
|
|||
res.header(&headers::CONTENT_LENGTH)
|
||||
.unwrap()
|
||||
.last()
|
||||
.unwrap()
|
||||
.as_str()
|
||||
.parse::<usize>()
|
||||
.unwrap(),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
POST / HTTP/1.1
|
||||
host: localhost:8080
|
||||
content-length: 5
|
||||
content-type: text/plain; charset=utf-8
|
||||
content-type: text/plain;charset=utf-8
|
||||
|
||||
hello
|
|
@ -1,5 +1,5 @@
|
|||
HTTP/1.1 200 OK
|
||||
content-length: 0
|
||||
date: {DATE}
|
||||
content-type: text/plain; charset=utf-8
|
||||
content-type: text/plain;charset=utf-8
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
HTTP/1.1 200 OK
|
||||
transfer-encoding: chunked
|
||||
date: {DATE}
|
||||
content-type: text/plain
|
||||
content-type: text/plain;charset=utf-8
|
||||
|
||||
7
|
||||
Mozilla
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
HTTP/1.1 200 OK
|
||||
content-length: 41
|
||||
date: {DATE}
|
||||
content-type: text/plain; charset=utf-8
|
||||
content-type: text/plain;charset=utf-8
|
||||
|
||||
http://www.w3.org/pub/WWW/TheProject.html
|
Loading…
Reference in New Issue