1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-11-22 17:41:11 +00:00

Add HttpMessage::readlines()

This commit is contained in:
Dursun Akkurt 2018-06-14 00:19:48 +03:00
parent 1bee528018
commit cb77f7e688
3 changed files with 64 additions and 32 deletions

View file

@ -4,6 +4,8 @@
### Added
* Add `HttpMessage::readlines()` for reading line by line.
* Add `ClientRequestBuilder::form()` for sending `application/x-www-form-urlencoded` requests.
* Add method to configure custom error handler to Form extractor.

View file

@ -592,9 +592,13 @@ impl From<JsonError> for JsonPayloadError {
/// Error type returned when reading body as lines.
pub enum ReadlinesError {
/// Error when decoding a line.
EncodingError,
/// Payload error.
PayloadError(PayloadError),
/// Line limit exceeded.
LimitOverflow,
/// ContentType error.
ContentTypeError(ContentTypeError),
}
@ -604,12 +608,6 @@ impl From<PayloadError> for ReadlinesError {
}
}
impl From<Error> for ReadlinesError {
fn from(_: Error) -> Self {
ReadlinesError::EncodingError
}
}
impl From<ContentTypeError> for ReadlinesError {
fn from(err: ContentTypeError) -> Self {
ReadlinesError::ContentTypeError(err)

View file

@ -13,7 +13,7 @@ use std::str;
use error::{
ContentTypeError, HttpRangeError, ParseError, PayloadError, UrlencodedError,
Error, ErrorBadRequest, ReadlinesError
ReadlinesError
};
use header::Header;
use json::JsonBody;
@ -279,6 +279,7 @@ where
req: T,
buff: BytesMut,
limit: usize,
checked_buff: bool,
}
impl<T> Readlines<T>
@ -291,6 +292,7 @@ where
req,
buff: BytesMut::with_capacity(262_144),
limit: 262_144,
checked_buff: true,
}
}
@ -311,29 +313,32 @@ where
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
let encoding = self.req.encoding()?;
// check if there is a newline in the buffer
let mut found: Option<usize> = None;
for (ind, b) in self.buff.iter().enumerate() {
if *b == '\n' as u8 {
found = Some(ind);
break;
if !self.checked_buff {
let mut found: Option<usize> = None;
for (ind, b) in self.buff.iter().enumerate() {
if *b == '\n' as u8 {
found = Some(ind);
break;
}
}
}
if let Some(ind) = found {
// check if line is longer than limit
if ind+1 > self.limit {
return Err(ReadlinesError::LimitOverflow);
if let Some(ind) = found {
// check if line is longer than limit
if ind+1 > self.limit {
return Err(ReadlinesError::LimitOverflow);
}
let enc: *const Encoding = encoding as *const Encoding;
let line = if enc == UTF_8 {
str::from_utf8(&self.buff.split_to(ind+1))
.map_err(|_| ReadlinesError::EncodingError)?
.to_owned()
} else {
encoding
.decode(&self.buff.split_to(ind+1), DecoderTrap::Strict)
.map_err(|_| ReadlinesError::EncodingError)?
};
return Ok(Async::Ready(Some(line)));
}
let enc: *const Encoding = encoding as *const Encoding;
let line = if enc == UTF_8 {
str::from_utf8(&self.buff.split_to(ind+1))
.map_err(|_| ErrorBadRequest("Can not decode body"))?
.to_owned()
} else {
encoding
.decode(&self.buff.split_to(ind+1), DecoderTrap::Strict)
.map_err(|_| ErrorBadRequest("Can not decode body"))?
};
return Ok(Async::Ready(Some(line)));
self.checked_buff = true;
}
// poll req for more bytes
match self.req.poll() {
@ -354,15 +359,16 @@ where
let enc: *const Encoding = encoding as *const Encoding;
let line = if enc == UTF_8 {
str::from_utf8(&bytes.split_to(ind+1))
.map_err(|_| ErrorBadRequest("Can not decode body"))?
.map_err(|_| ReadlinesError::EncodingError)?
.to_owned()
} else {
encoding
.decode(&bytes.split_to(ind+1), DecoderTrap::Strict)
.map_err(|_| ErrorBadRequest("Can not decode body"))?
.map_err(|_| ReadlinesError::EncodingError)?
};
// extend buffer with rest of the bytes;
self.buff.extend_from_slice(&bytes);
self.checked_buff = false;
return Ok(Async::Ready(Some(line)));
}
self.buff.extend_from_slice(&bytes);
@ -379,12 +385,12 @@ where
let enc: *const Encoding = encoding as *const Encoding;
let line = if enc == UTF_8 {
str::from_utf8(&self.buff)
.map_err(|_| ErrorBadRequest("Can not decode body"))?
.map_err(|_| ReadlinesError::EncodingError)?
.to_owned()
} else {
encoding
.decode(&self.buff, DecoderTrap::Strict)
.map_err(|_| ErrorBadRequest("Can not decode body"))?
.map_err(|_| ReadlinesError::EncodingError)?
};
self.buff.clear();
return Ok(Async::Ready(Some(line)))
@ -799,4 +805,30 @@ mod tests {
_ => unreachable!("error"),
}
}
#[test]
fn test_readlines() {
let mut req = HttpRequest::default();
req.payload_mut().unread_data(Bytes::from_static(
b"Lorem Ipsum is simply dummy text of the printing and typesetting\n\
industry. Lorem Ipsum has been the industry's standard dummy\n\
Contrary to popular belief, Lorem Ipsum is not simply random text."
));
let mut r = Readlines::new(req);
match r.poll().ok().unwrap() {
Async::Ready(Some(s)) => assert_eq!(s,
"Lorem Ipsum is simply dummy text of the printing and typesetting\n"),
_ => unreachable!("error"),
}
match r.poll().ok().unwrap() {
Async::Ready(Some(s)) => assert_eq!(s,
"industry. Lorem Ipsum has been the industry's standard dummy\n"),
_ => unreachable!("error"),
}
match r.poll().ok().unwrap() {
Async::Ready(Some(s)) => assert_eq!(s,
"Contrary to popular belief, Lorem Ipsum is not simply random text."),
_ => unreachable!("error"),
}
}
}