Skip to content

Commit 7ff68fd

Browse files
authored
Merge pull request #58 from yoshuawuyts/update-errors
Update errors
2 parents 48aae50 + 8f07641 commit 7ff68fd

File tree

3 files changed

+72
-129
lines changed

3 files changed

+72
-129
lines changed

src/client.rs

Lines changed: 24 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ use async_std::io::{self, BufReader, Read, Write};
44
use async_std::prelude::*;
55
use async_std::task::{Context, Poll};
66
use futures_core::ready;
7+
use http_types::{ensure, ensure_eq, format_err};
78
use http_types::{
89
headers::{HeaderName, HeaderValue, CONTENT_LENGTH, DATE, TRANSFER_ENCODING},
910
Body, Request, Response, StatusCode,
1011
};
11-
use http_types::{Error, ErrorKind};
1212

13+
use std::convert::TryFrom;
1314
use std::pin::Pin;
1415
use std::str::FromStr;
1516

@@ -50,7 +51,7 @@ impl Encoder {
5051
}
5152

5253
/// Opens an HTTP/1.1 connection to a remote host.
53-
pub async fn connect<RW>(mut stream: RW, req: Request) -> Result<Response, Error>
54+
pub async fn connect<RW>(mut stream: RW, req: Request) -> http_types::Result<Response>
5455
where
5556
RW: Read + Write + Send + Sync + Unpin + 'static,
5657
{
@@ -67,7 +68,7 @@ where
6768

6869
/// Encode an HTTP request on the client.
6970
#[doc(hidden)]
70-
async fn encode(req: Request) -> Result<Encoder, Error> {
71+
async fn encode(req: Request) -> http_types::Result<Encoder> {
7172
let mut buf: Vec<u8> = vec![];
7273

7374
let mut url = req.url().path().to_owned();
@@ -86,13 +87,8 @@ async fn encode(req: Request) -> Result<Encoder, Error> {
8687

8788
// Insert Host header
8889
// Insert host
89-
let host = req.url().host_str().ok_or_else(|| {
90-
Error::from_str(
91-
ErrorKind::InvalidInput,
92-
"missing hostname",
93-
StatusCode::BadRequest,
94-
)
95-
})?;
90+
let host = req.url().host_str();
91+
let host = host.ok_or_else(|| format_err!("Missing hostname"))?;
9692
let val = if let Some(port) = req.url().port() {
9793
format!("host: {}:{}\r\n", host, port)
9894
} else {
@@ -135,7 +131,7 @@ async fn encode(req: Request) -> Result<Encoder, Error> {
135131

136132
/// Decode an HTTP response on the client.
137133
#[doc(hidden)]
138-
pub async fn decode<R>(reader: R) -> Result<Response, Error>
134+
pub async fn decode<R>(reader: R) -> http_types::Result<Response>
139135
where
140136
R: Read + Unpin + Send + Sync + 'static,
141137
{
@@ -148,9 +144,7 @@ where
148144
loop {
149145
let bytes_read = reader.read_until(b'\n', &mut buf).await?;
150146
// No more bytes are yielded from the stream.
151-
if bytes_read == 0 {
152-
panic!("empty response");
153-
}
147+
assert!(bytes_read != 0, "Empty response"); // TODO: ensure?
154148

155149
// We've hit the end delimiter of the stream.
156150
let idx = buf.len() - 1;
@@ -161,37 +155,16 @@ where
161155

162156
// Convert our header buf into an httparse instance, and validate.
163157
let status = httparse_res.parse(&buf)?;
164-
if status.is_partial() {
165-
return Err(Error::from_str(
166-
ErrorKind::InvalidData,
167-
"Malformed HTTP head",
168-
StatusCode::BadRequest,
169-
));
170-
}
171-
let code = httparse_res.code.ok_or_else(|| {
172-
Error::from_str(
173-
ErrorKind::InvalidData,
174-
"No status code found",
175-
StatusCode::BadRequest,
176-
)
177-
})?;
178-
179-
// Convert httparse headers + body into a `http::Response` type.
180-
let version = httparse_res.version.ok_or_else(|| {
181-
Error::from_str(
182-
ErrorKind::InvalidData,
183-
"No version found",
184-
StatusCode::BadRequest,
185-
)
186-
})?;
187-
if version != 1 {
188-
return Err(Error::from_str(
189-
ErrorKind::InvalidData,
190-
"Unsupported HTTP version",
191-
StatusCode::BadRequest,
192-
));
193-
}
194-
use std::convert::TryFrom;
158+
ensure!(!status.is_partial(), "Malformed HTTP head");
159+
160+
let code = httparse_res.code;
161+
let code = code.ok_or_else(|| format_err!("No status code found"))?;
162+
163+
// Convert httparse headers + body into a `http_types::Response` type.
164+
let version = httparse_res.version;
165+
let version = version.ok_or_else(|| format_err!("No version found"))?;
166+
ensure_eq!(version, 1, "Unsupported HTTP version");
167+
195168
let mut res = Response::new(StatusCode::try_from(code)?);
196169
for header in httparse_res.headers.iter() {
197170
let name = HeaderName::from_str(header.name)?;
@@ -207,24 +180,18 @@ where
207180
let content_length = res.header(&CONTENT_LENGTH);
208181
let transfer_encoding = res.header(&TRANSFER_ENCODING);
209182

210-
if content_length.is_some() && transfer_encoding.is_some() {
211-
// This is always an error.
212-
return Err(Error::from_str(
213-
ErrorKind::InvalidData,
214-
"Unexpected Content-Length header",
215-
StatusCode::BadRequest,
216-
));
217-
}
183+
ensure!(
184+
content_length.is_none() || transfer_encoding.is_none(),
185+
"Unexpected Content-Length header"
186+
);
218187

219188
// Check for Transfer-Encoding
220189
match transfer_encoding {
221190
Some(encoding) if !encoding.is_empty() => {
222191
if encoding.last().unwrap().as_str() == "chunked" {
223192
let trailers_sender = res.send_trailers();
224-
res.set_body(Body::from_reader(
225-
BufReader::new(ChunkedDecoder::new(reader, trailers_sender)),
226-
None,
227-
));
193+
let reader = BufReader::new(ChunkedDecoder::new(reader, trailers_sender));
194+
res.set_body(Body::from_reader(reader, None));
228195
return Ok(res);
229196
}
230197
// Fall through to Content-Length

src/date.rs

Lines changed: 21 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
22
use std::str::{from_utf8, FromStr};
33
use std::time::{Duration, SystemTime, UNIX_EPOCH};
44

5-
use http_types::{Error, ErrorKind, StatusCode};
5+
use http_types::{bail, ensure, format_err};
66

77
const IMF_FIXDATE_LENGTH: usize = 29;
88
const RFC850_MAX_LENGTH: usize = 23;
@@ -39,7 +39,7 @@ pub struct HttpDate {
3939
/// ascdate formats. Two digit years are mapped to dates between
4040
/// 1970 and 2069.
4141
#[allow(dead_code)]
42-
pub(crate) fn parse_http_date(s: &str) -> Result<SystemTime, Error> {
42+
pub(crate) fn parse_http_date(s: &str) -> http_types::Result<SystemTime> {
4343
s.parse::<HttpDate>().map(|d| d.into())
4444
}
4545

@@ -66,19 +66,15 @@ impl HttpDate {
6666
}
6767
}
6868

69-
fn err(msg: &'static str) -> Error {
70-
Error::from_str(ErrorKind::InvalidData, msg, StatusCode::BadRequest)
71-
}
72-
73-
fn parse_imf_fixdate(s: &[u8]) -> Result<HttpDate, Error> {
69+
fn parse_imf_fixdate(s: &[u8]) -> http_types::Result<HttpDate> {
7470
// Example: `Sun, 06 Nov 1994 08:49:37 GMT`
7571
if s.len() != IMF_FIXDATE_LENGTH
7672
|| &s[25..] != b" GMT"
7773
|| s[16] != b' '
7874
|| s[19] != b':'
7975
|| s[22] != b':'
8076
{
81-
return Err(err("Date time not in imf fixdate format"));
77+
bail!("Date time not in imf fixdate format");
8278
}
8379
Ok(HttpDate {
8480
second: from_utf8(&s[23..25])?.parse()?,
@@ -98,7 +94,7 @@ fn parse_imf_fixdate(s: &[u8]) -> Result<HttpDate, Error> {
9894
b" Oct " => 10,
9995
b" Nov " => 11,
10096
b" Dec " => 12,
101-
_ => return Err(err("Invalid Month")),
97+
_ => bail!("Invalid Month"),
10298
},
10399
year: from_utf8(&s[12..16])?.parse()?,
104100
week_day: match &s[..5] {
@@ -109,16 +105,17 @@ fn parse_imf_fixdate(s: &[u8]) -> Result<HttpDate, Error> {
109105
b"Fri, " => 5,
110106
b"Sat, " => 6,
111107
b"Sun, " => 7,
112-
_ => return Err(err("Invalid Day")),
108+
_ => bail!("Invalid Day"),
113109
},
114110
})
115111
}
116112

117-
fn parse_rfc850_date(s: &[u8]) -> Result<HttpDate, Error> {
113+
fn parse_rfc850_date(s: &[u8]) -> http_types::Result<HttpDate> {
118114
// Example: `Sunday, 06-Nov-94 08:49:37 GMT`
119-
if s.len() < RFC850_MAX_LENGTH {
120-
return Err(err("Date time not in rfc850 format"));
121-
}
115+
ensure!(
116+
s.len() >= RFC850_MAX_LENGTH,
117+
"Date time not in rfc850 format"
118+
);
122119

123120
fn week_day<'a>(s: &'a [u8], week_day: u8, name: &'static [u8]) -> Option<(u8, &'a [u8])> {
124121
if &s[0..name.len()] == name {
@@ -133,9 +130,9 @@ fn parse_rfc850_date(s: &[u8]) -> Result<HttpDate, Error> {
133130
.or_else(|| week_day(s, 5, b"Friday, "))
134131
.or_else(|| week_day(s, 6, b"Saturday, "))
135132
.or_else(|| week_day(s, 7, b"Sunday, "))
136-
.ok_or_else(|| err("Invalid day"))?;
133+
.ok_or_else(|| format_err!("Invalid day"))?;
137134
if s.len() != 22 || s[12] != b':' || s[15] != b':' || &s[18..22] != b" GMT" {
138-
return Err(err("Date time not in rfc850 format"));
135+
bail!("Date time not in rfc950 fmt");
139136
}
140137
let mut year = from_utf8(&s[7..9])?.parse::<u16>()?;
141138
if year < 70 {
@@ -161,18 +158,18 @@ fn parse_rfc850_date(s: &[u8]) -> Result<HttpDate, Error> {
161158
b"-Oct-" => 10,
162159
b"-Nov-" => 11,
163160
b"-Dec-" => 12,
164-
_ => return Err(err("Invalid month")),
161+
_ => bail!("Invalid month"),
165162
},
166163
year: year,
167164
week_day: week_day,
168165
})
169166
}
170167

171-
fn parse_asctime(s: &[u8]) -> Result<HttpDate, Error> {
168+
fn parse_asctime(s: &[u8]) -> http_types::Result<HttpDate> {
172169
// Example: `Sun Nov 6 08:49:37 1994`
173170
if s.len() != ASCTIME_LENGTH || s[10] != b' ' || s[13] != b':' || s[16] != b':' || s[19] != b' '
174171
{
175-
return Err(err("Date time not in asctime format"));
172+
bail!("Date time not in asctime format");
176173
}
177174
Ok(HttpDate {
178175
second: from_utf8(&s[17..19])?.parse()?,
@@ -195,7 +192,7 @@ fn parse_asctime(s: &[u8]) -> Result<HttpDate, Error> {
195192
b"Oct " => 10,
196193
b"Nov " => 11,
197194
b"Dec " => 12,
198-
_ => return Err(err("Invalid month")),
195+
_ => bail!("Invalid month"),
199196
},
200197
year: from_utf8(&s[20..24])?.parse()?,
201198
week_day: match &s[0..4] {
@@ -206,7 +203,7 @@ fn parse_asctime(s: &[u8]) -> Result<HttpDate, Error> {
206203
b"Fri " => 5,
207204
b"Sat " => 6,
208205
b"Sun " => 7,
209-
_ => return Err(err("Invalid day")),
206+
_ => bail!("Invalid day"),
210207
},
211208
})
212209
}
@@ -329,19 +326,15 @@ impl From<HttpDate> for SystemTime {
329326
}
330327

331328
impl FromStr for HttpDate {
332-
type Err = Error;
329+
type Err = http_types::Error;
333330

334331
fn from_str(s: &str) -> Result<Self, Self::Err> {
335-
if !s.is_ascii() {
336-
return Err(err("Not ascii"));
337-
}
332+
ensure!(s.is_ascii(), "String slice is not valid ASCII");
338333
let x = s.trim().as_bytes();
339334
let date = parse_imf_fixdate(x)
340335
.or_else(|_| parse_rfc850_date(x))
341336
.or_else(|_| parse_asctime(x))?;
342-
if !date.is_valid() {
343-
return Err(err("Invalid date time"));
344-
}
337+
ensure!(date.is_valid(), "Invalid date time");
345338
Ok(date)
346339
}
347340
}

0 commit comments

Comments
 (0)