1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 09:42:40 +01:00
actix-extras/src/httpmessage.rs

836 lines
26 KiB
Rust
Raw Normal View History

use bytes::{Bytes, BytesMut};
2018-04-14 01:02:01 +02:00
use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label;
2018-04-14 01:02:01 +02:00
use encoding::types::{DecoderTrap, Encoding};
2018-04-29 07:55:47 +02:00
use encoding::EncodingRef;
2018-06-16 23:26:34 +02:00
use futures::{Async, Future, Poll, Stream};
use http::{header, HeaderMap};
2018-04-14 01:02:01 +02:00
use mime::Mime;
use serde::de::DeserializeOwned;
use serde_urlencoded;
use std::str;
2018-12-06 23:32:52 +01:00
use crate::error::{
2018-06-17 04:48:50 +02:00
ContentTypeError, ParseError, PayloadError, ReadlinesError, UrlencodedError,
2018-05-17 21:20:20 +02:00
};
2018-12-06 23:32:52 +01:00
use crate::header::Header;
use crate::json::JsonBody;
2018-02-28 08:30:26 +01:00
/// Trait that implements general purpose operations on http messages
2018-06-25 06:58:04 +02:00
pub trait HttpMessage: Sized {
/// Type of message payload stream
type Stream: Stream<Item = Bytes, Error = PayloadError> + Sized;
2018-02-28 08:30:26 +01:00
/// Read the message headers.
fn headers(&self) -> &HeaderMap;
2018-06-25 06:58:04 +02:00
/// Message payload stream
fn payload(&mut self) -> Option<Self::Stream>;
2018-06-25 06:58:04 +02:00
2018-03-06 04:28:42 +01:00
#[doc(hidden)]
/// Get a header
2018-04-14 01:02:01 +02:00
fn get_header<H: Header>(&self) -> Option<H>
where
Self: Sized,
{
2018-03-08 02:40:13 +01:00
if self.headers().contains_key(H::name()) {
H::parse(self).ok()
} else {
None
}
2018-03-06 04:28:42 +01:00
}
2018-04-14 01:02:01 +02:00
/// Read the request content type. If request does not contain
/// *Content-Type* header, empty str get returned.
fn content_type(&self) -> &str {
if let Some(content_type) = self.headers().get(header::CONTENT_TYPE) {
if let Ok(content_type) = content_type.to_str() {
2018-04-14 01:02:01 +02:00
return content_type.split(';').next().unwrap().trim();
}
}
""
}
/// Get content type encoding
///
/// UTF-8 is used by default, If request charset is not set.
fn encoding(&self) -> Result<EncodingRef, ContentTypeError> {
if let Some(mime_type) = self.mime_type()? {
if let Some(charset) = mime_type.get_param("charset") {
if let Some(enc) = encoding_from_whatwg_label(charset.as_str()) {
Ok(enc)
} else {
Err(ContentTypeError::UnknownEncoding)
}
} else {
Ok(UTF_8)
}
} else {
Ok(UTF_8)
}
}
/// Convert the request content type to a known mime type.
fn mime_type(&self) -> Result<Option<Mime>, ContentTypeError> {
if let Some(content_type) = self.headers().get(header::CONTENT_TYPE) {
if let Ok(content_type) = content_type.to_str() {
return match content_type.parse() {
Ok(mt) => Ok(Some(mt)),
Err(_) => Err(ContentTypeError::ParseError),
};
} else {
2018-04-14 01:02:01 +02:00
return Err(ContentTypeError::ParseError);
}
}
Ok(None)
}
/// Check if request has chunked transfer encoding
fn chunked(&self) -> Result<bool, ParseError> {
if let Some(encodings) = self.headers().get(header::TRANSFER_ENCODING) {
if let Ok(s) = encodings.to_str() {
Ok(s.to_lowercase().contains("chunked"))
} else {
Err(ParseError::Header)
}
} else {
Ok(false)
}
}
/// Load http message body.
///
2018-04-14 01:02:01 +02:00
/// By default only 256Kb payload reads to a memory, then
/// `PayloadError::Overflow` get returned. Use `MessageBody::limit()`
/// method to change upper limit.
///
/// ## Server example
///
2018-10-05 06:14:18 +02:00
/// ```rust,ignore
/// # extern crate bytes;
/// # extern crate actix_web;
/// # extern crate futures;
/// # #[macro_use] extern crate serde_derive;
2018-06-01 18:36:16 +02:00
/// use actix_web::{
2018-10-05 20:04:59 +02:00
/// AsyncResponder, FutureResponse, HttpMessage, HttpRequest, Response,
2018-06-01 18:36:16 +02:00
/// };
/// use bytes::Bytes;
/// use futures::future::Future;
///
2018-10-05 20:04:59 +02:00
/// fn index(mut req: HttpRequest) -> FutureResponse<Response> {
/// req.body() // <- get Body future
/// .limit(1024) // <- change max size of the body to a 1kb
/// .from_err()
/// .and_then(|bytes: Bytes| { // <- complete body
/// println!("==== BODY ==== {:?}", bytes);
2018-10-05 20:04:59 +02:00
/// Ok(Response::Ok().into())
/// }).responder()
/// }
/// # fn main() {}
/// ```
fn body(&mut self) -> MessageBody<Self> {
MessageBody::new(self)
}
2018-03-28 05:33:24 +02:00
/// Parse `application/x-www-form-urlencoded` encoded request's body.
2018-04-14 01:02:01 +02:00
/// Return `UrlEncoded` future. Form can be deserialized to any type that
/// implements `Deserialize` trait from *serde*.
///
/// Returns error:
///
/// * content type is not `application/x-www-form-urlencoded`
/// * content-length is greater than 256k
///
/// ## Server example
///
2018-10-05 06:14:18 +02:00
/// ```rust,ignore
/// # extern crate actix_web;
/// # extern crate futures;
2018-03-28 05:33:24 +02:00
/// # use futures::Future;
2018-04-02 23:00:18 +02:00
/// # use std::collections::HashMap;
2018-10-05 20:04:59 +02:00
/// use actix_web::{FutureResponse, HttpMessage, HttpRequest, Response};
///
2018-10-05 20:04:59 +02:00
/// fn index(mut req: HttpRequest) -> FutureResponse<Response> {
2018-04-02 23:00:18 +02:00
/// Box::new(
/// req.urlencoded::<HashMap<String, String>>() // <- get UrlEncoded future
/// .from_err()
/// .and_then(|params| { // <- url encoded parameters
/// println!("==== BODY ==== {:?}", params);
2018-10-05 20:04:59 +02:00
/// Ok(Response::Ok().into())
2018-06-01 18:36:16 +02:00
/// }),
/// )
/// }
/// # fn main() {}
/// ```
fn urlencoded<T: DeserializeOwned>(&mut self) -> UrlEncoded<Self, T> {
UrlEncoded::new(self)
}
/// Parse `application/json` encoded body.
/// Return `JsonBody<T>` future. It resolves to a `T` value.
///
/// Returns error:
///
/// * content type is not `application/json`
/// * content length is greater than 256k
///
/// ## Server example
///
2018-10-05 06:14:18 +02:00
/// ```rust,ignore
/// # extern crate actix_web;
/// # extern crate futures;
/// # #[macro_use] extern crate serde_derive;
/// use actix_web::*;
2018-06-01 18:36:16 +02:00
/// use futures::future::{ok, Future};
///
/// #[derive(Deserialize, Debug)]
/// struct MyObj {
/// name: String,
/// }
///
2018-10-05 20:04:59 +02:00
/// fn index(mut req: HttpRequest) -> Box<Future<Item = Response, Error = Error>> {
/// req.json() // <- get JsonBody future
/// .from_err()
/// .and_then(|val: MyObj| { // <- deserialized value
/// println!("==== BODY ==== {:?}", val);
2018-10-05 20:04:59 +02:00
/// Ok(Response::Ok().into())
/// }).responder()
/// }
/// # fn main() {}
/// ```
fn json<T: DeserializeOwned>(&mut self) -> JsonBody<Self, T> {
JsonBody::new(self)
}
2018-06-13 19:43:03 +02:00
/// Return stream of lines.
fn readlines(&mut self) -> Readlines<Self> {
2018-06-13 19:43:03 +02:00
Readlines::new(self)
}
}
/// Stream to read request line by line.
2018-06-25 06:58:04 +02:00
pub struct Readlines<T: HttpMessage> {
stream: Option<T::Stream>,
2018-06-13 21:41:35 +02:00
buff: BytesMut,
2018-06-13 19:43:03 +02:00
limit: usize,
2018-06-13 23:19:48 +02:00
checked_buff: bool,
2018-06-25 06:58:04 +02:00
encoding: EncodingRef,
err: Option<ReadlinesError>,
2018-06-13 19:43:03 +02:00
}
2018-06-25 06:58:04 +02:00
impl<T: HttpMessage> Readlines<T> {
2018-06-13 19:43:03 +02:00
/// Create a new stream to read request line by line.
fn new(req: &mut T) -> Self {
2018-06-25 06:58:04 +02:00
let encoding = match req.encoding() {
Ok(enc) => enc,
Err(err) => return Self::err(req, err.into()),
};
2018-06-13 19:43:03 +02:00
Readlines {
2018-06-25 06:58:04 +02:00
stream: req.payload(),
2018-06-13 21:41:35 +02:00
buff: BytesMut::with_capacity(262_144),
2018-06-13 19:43:03 +02:00
limit: 262_144,
2018-06-13 23:19:48 +02:00
checked_buff: true,
2018-06-25 06:58:04 +02:00
err: None,
encoding,
2018-06-13 19:43:03 +02:00
}
}
2018-06-16 23:26:34 +02:00
2018-06-13 21:41:35 +02:00
/// Change max line size. By default max size is 256Kb
2018-06-13 19:43:03 +02:00
pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit;
self
}
2018-06-25 06:58:04 +02:00
fn err(req: &mut T, err: ReadlinesError) -> Self {
2018-06-25 06:58:04 +02:00
Readlines {
stream: req.payload(),
buff: BytesMut::new(),
2018-06-25 06:58:04 +02:00
limit: 262_144,
checked_buff: true,
encoding: UTF_8,
err: Some(err),
}
}
2018-06-13 19:43:03 +02:00
}
2018-06-25 06:58:04 +02:00
impl<T: HttpMessage + 'static> Stream for Readlines<T> {
2018-06-13 19:43:03 +02:00
type Item = String;
type Error = ReadlinesError;
2018-06-16 23:26:34 +02:00
2018-06-13 19:43:03 +02:00
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
2018-06-25 06:58:04 +02:00
if let Some(err) = self.err.take() {
return Err(err);
}
2018-06-13 21:41:35 +02:00
// check if there is a newline in the buffer
2018-06-13 23:19:48 +02:00
if !self.checked_buff {
let mut found: Option<usize> = None;
for (ind, b) in self.buff.iter().enumerate() {
2018-06-16 23:26:34 +02:00
if *b == b'\n' {
2018-06-13 23:19:48 +02:00
found = Some(ind);
break;
}
2018-06-13 21:41:35 +02:00
}
2018-06-13 23:19:48 +02:00
if let Some(ind) = found {
// check if line is longer than limit
2018-06-16 23:26:34 +02:00
if ind + 1 > self.limit {
2018-06-13 23:19:48 +02:00
return Err(ReadlinesError::LimitOverflow);
}
2018-06-25 06:58:04 +02:00
let enc: *const Encoding = self.encoding as *const Encoding;
2018-06-13 23:19:48 +02:00
let line = if enc == UTF_8 {
2018-06-16 23:26:34 +02:00
str::from_utf8(&self.buff.split_to(ind + 1))
2018-06-13 23:19:48 +02:00
.map_err(|_| ReadlinesError::EncodingError)?
.to_owned()
} else {
2018-06-25 06:58:04 +02:00
self.encoding
2018-06-16 23:26:34 +02:00
.decode(&self.buff.split_to(ind + 1), DecoderTrap::Strict)
2018-06-13 23:19:48 +02:00
.map_err(|_| ReadlinesError::EncodingError)?
};
return Ok(Async::Ready(Some(line)));
2018-06-13 21:41:35 +02:00
}
2018-06-13 23:19:48 +02:00
self.checked_buff = true;
2018-06-13 21:41:35 +02:00
}
// poll req for more bytes
if let Some(ref mut stream) = self.stream {
match stream.poll() {
Ok(Async::Ready(Some(mut bytes))) => {
// check if there is a newline in bytes
let mut found: Option<usize> = None;
for (ind, b) in bytes.iter().enumerate() {
if *b == b'\n' {
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);
}
let enc: *const Encoding = self.encoding as *const Encoding;
let line = if enc == UTF_8 {
str::from_utf8(&bytes.split_to(ind + 1))
.map_err(|_| ReadlinesError::EncodingError)?
.to_owned()
} else {
self.encoding
.decode(&bytes.split_to(ind + 1), DecoderTrap::Strict)
.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)));
2018-06-13 19:43:03 +02:00
}
self.buff.extend_from_slice(&bytes);
Ok(Async::NotReady)
2018-06-13 21:41:35 +02:00
}
Ok(Async::NotReady) => Ok(Async::NotReady),
Ok(Async::Ready(None)) => {
if self.buff.is_empty() {
return Ok(Async::Ready(None));
}
if self.buff.len() > self.limit {
2018-06-13 19:43:03 +02:00
return Err(ReadlinesError::LimitOverflow);
}
2018-06-25 06:58:04 +02:00
let enc: *const Encoding = self.encoding as *const Encoding;
2018-06-13 21:41:35 +02:00
let line = if enc == UTF_8 {
str::from_utf8(&self.buff)
2018-06-13 23:19:48 +02:00
.map_err(|_| ReadlinesError::EncodingError)?
2018-06-13 21:41:35 +02:00
.to_owned()
} else {
2018-06-25 06:58:04 +02:00
self.encoding
.decode(&self.buff, DecoderTrap::Strict)
2018-06-13 23:19:48 +02:00
.map_err(|_| ReadlinesError::EncodingError)?
2018-06-13 21:41:35 +02:00
};
self.buff.clear();
Ok(Async::Ready(Some(line)))
2018-06-13 19:43:03 +02:00
}
Err(e) => Err(ReadlinesError::from(e)),
2018-06-16 23:26:34 +02:00
}
} else {
Ok(Async::Ready(None))
2018-06-13 19:43:03 +02:00
}
}
}
/// Future that resolves to a complete http message body.
2018-06-25 06:58:04 +02:00
pub struct MessageBody<T: HttpMessage> {
limit: usize,
2018-06-25 06:58:04 +02:00
length: Option<usize>,
stream: Option<T::Stream>,
err: Option<PayloadError>,
2018-04-14 01:02:01 +02:00
fut: Option<Box<Future<Item = Bytes, Error = PayloadError>>>,
}
2018-06-25 06:58:04 +02:00
impl<T: HttpMessage> MessageBody<T> {
/// Create `MessageBody` for request.
pub fn new(req: &mut T) -> MessageBody<T> {
2018-06-25 06:58:04 +02:00
let mut len = None;
if let Some(l) = req.headers().get(header::CONTENT_LENGTH) {
if let Ok(s) = l.to_str() {
if let Ok(l) = s.parse::<usize>() {
len = Some(l)
} else {
return Self::err(PayloadError::UnknownLength);
}
} else {
return Self::err(PayloadError::UnknownLength);
}
}
MessageBody {
limit: 262_144,
2018-06-25 06:58:04 +02:00
length: len,
stream: req.payload(),
fut: None,
2018-06-25 06:58:04 +02:00
err: None,
}
}
/// Change max size of payload. By default max size is 256Kb
pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit;
self
}
2018-06-25 06:58:04 +02:00
fn err(e: PayloadError) -> Self {
MessageBody {
stream: None,
limit: 262_144,
fut: None,
err: Some(e),
length: None,
}
}
}
impl<T> Future for MessageBody<T>
2018-04-14 01:02:01 +02:00
where
2018-06-25 06:58:04 +02:00
T: HttpMessage + 'static,
{
type Item = Bytes;
type Error = PayloadError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
2018-06-25 06:58:04 +02:00
if let Some(ref mut fut) = self.fut {
return fut.poll();
}
2018-06-25 06:58:04 +02:00
if let Some(err) = self.err.take() {
return Err(err);
}
2018-06-25 06:58:04 +02:00
if let Some(len) = self.length.take() {
if len > self.limit {
return Err(PayloadError::Overflow);
}
}
if self.stream.is_none() {
return Ok(Async::Ready(Bytes::new()));
}
2018-06-25 06:58:04 +02:00
// future
let limit = self.limit;
self.fut = Some(Box::new(
self.stream
.take()
.expect("Can not be used second time")
.from_err()
.fold(BytesMut::with_capacity(8192), move |mut body, chunk| {
2018-06-25 06:58:04 +02:00
if (body.len() + chunk.len()) > limit {
Err(PayloadError::Overflow)
} else {
body.extend_from_slice(&chunk);
Ok(body)
}
2018-12-06 23:32:52 +01:00
})
.map(|body| body.freeze()),
2018-06-25 06:58:04 +02:00
));
self.poll()
}
}
/// Future that resolves to a parsed urlencoded values.
2018-06-25 06:58:04 +02:00
pub struct UrlEncoded<T: HttpMessage, U> {
stream: Option<T::Stream>,
limit: usize,
2018-06-25 06:58:04 +02:00
length: Option<usize>,
encoding: EncodingRef,
err: Option<UrlencodedError>,
2018-04-14 01:02:01 +02:00
fut: Option<Box<Future<Item = U, Error = UrlencodedError>>>,
}
2018-06-25 06:58:04 +02:00
impl<T: HttpMessage, U> UrlEncoded<T, U> {
/// Create a new future to URL encode a request
pub fn new(req: &mut T) -> UrlEncoded<T, U> {
2018-06-25 06:58:04 +02:00
// check content type
if req.content_type().to_lowercase() != "application/x-www-form-urlencoded" {
return Self::err(UrlencodedError::ContentType);
}
let encoding = match req.encoding() {
Ok(enc) => enc,
Err(_) => return Self::err(UrlencodedError::ContentType),
};
let mut len = None;
if let Some(l) = req.headers().get(header::CONTENT_LENGTH) {
if let Ok(s) = l.to_str() {
if let Ok(l) = s.parse::<usize>() {
len = Some(l)
} else {
return Self::err(UrlencodedError::UnknownLength);
}
} else {
return Self::err(UrlencodedError::UnknownLength);
}
};
UrlEncoded {
2018-06-25 06:58:04 +02:00
encoding,
stream: req.payload(),
limit: 262_144,
2018-06-25 06:58:04 +02:00
length: len,
fut: None,
2018-06-25 06:58:04 +02:00
err: None,
}
}
fn err(e: UrlencodedError) -> Self {
UrlEncoded {
stream: None,
limit: 262_144,
fut: None,
err: Some(e),
length: None,
encoding: UTF_8,
}
}
/// Change max size of payload. By default max size is 256Kb
pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit;
self
}
}
2018-04-02 23:00:18 +02:00
impl<T, U> Future for UrlEncoded<T, U>
2018-04-14 01:02:01 +02:00
where
2018-06-25 06:58:04 +02:00
T: HttpMessage + 'static,
2018-04-14 01:02:01 +02:00
U: DeserializeOwned + 'static,
{
2018-04-02 23:00:18 +02:00
type Item = U;
type Error = UrlencodedError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
2018-06-25 06:58:04 +02:00
if let Some(ref mut fut) = self.fut {
return fut.poll();
}
2018-06-25 06:58:04 +02:00
if let Some(err) = self.err.take() {
return Err(err);
}
2018-06-25 06:58:04 +02:00
// payload size
let limit = self.limit;
if let Some(len) = self.length.take() {
if len > limit {
return Err(UrlencodedError::Overflow);
}
}
2018-06-25 06:58:04 +02:00
// future
let encoding = self.encoding;
let fut = self
.stream
.take()
2018-04-29 18:09:08 +02:00
.expect("UrlEncoded could not be used second time")
2018-06-25 06:58:04 +02:00
.from_err()
.fold(BytesMut::with_capacity(8192), move |mut body, chunk| {
2018-06-25 06:58:04 +02:00
if (body.len() + chunk.len()) > limit {
Err(UrlencodedError::Overflow)
} else {
body.extend_from_slice(&chunk);
Ok(body)
}
2018-12-06 23:32:52 +01:00
})
.and_then(move |body| {
2018-06-25 06:58:04 +02:00
if (encoding as *const Encoding) == UTF_8 {
serde_urlencoded::from_bytes::<U>(&body)
.map_err(|_| UrlencodedError::Parse)
} else {
let body = encoding
.decode(&body, DecoderTrap::Strict)
.map_err(|_| UrlencodedError::Parse)?;
serde_urlencoded::from_str::<U>(&body)
.map_err(|_| UrlencodedError::Parse)
}
});
self.fut = Some(Box::new(fut));
self.poll()
}
}
#[cfg(test)]
mod tests {
use encoding::all::ISO_8859_2;
2018-04-29 07:55:47 +02:00
use encoding::Encoding;
use futures::Async;
2018-04-14 01:02:01 +02:00
use mime;
2018-12-07 00:03:01 +01:00
use serde_derive::Deserialize;
2019-01-27 19:59:07 +01:00
use super::*;
use crate::test::TestRequest;
#[test]
fn test_content_type() {
let req = TestRequest::with_header("content-type", "text/plain").finish();
assert_eq!(req.content_type(), "text/plain");
2018-04-14 01:02:01 +02:00
let req =
TestRequest::with_header("content-type", "application/json; charset=utf=8")
.finish();
assert_eq!(req.content_type(), "application/json");
2018-06-25 06:58:04 +02:00
let req = TestRequest::default().finish();
assert_eq!(req.content_type(), "");
}
#[test]
fn test_mime_type() {
let req = TestRequest::with_header("content-type", "application/json").finish();
assert_eq!(req.mime_type().unwrap(), Some(mime::APPLICATION_JSON));
2018-06-25 06:58:04 +02:00
let req = TestRequest::default().finish();
assert_eq!(req.mime_type().unwrap(), None);
2018-04-14 01:02:01 +02:00
let req =
TestRequest::with_header("content-type", "application/json; charset=utf-8")
.finish();
let mt = req.mime_type().unwrap().unwrap();
assert_eq!(mt.get_param(mime::CHARSET), Some(mime::UTF_8));
assert_eq!(mt.type_(), mime::APPLICATION);
assert_eq!(mt.subtype(), mime::JSON);
}
#[test]
fn test_mime_type_error() {
let req = TestRequest::with_header(
2018-04-14 01:02:01 +02:00
"content-type",
"applicationadfadsfasdflknadsfklnadsfjson",
2018-12-06 23:32:52 +01:00
)
.finish();
assert_eq!(Err(ContentTypeError::ParseError), req.mime_type());
}
#[test]
fn test_encoding() {
2018-06-25 06:58:04 +02:00
let req = TestRequest::default().finish();
assert_eq!(UTF_8.name(), req.encoding().unwrap().name());
2018-04-14 01:02:01 +02:00
let req = TestRequest::with_header("content-type", "application/json").finish();
assert_eq!(UTF_8.name(), req.encoding().unwrap().name());
let req = TestRequest::with_header(
2018-04-14 01:02:01 +02:00
"content-type",
"application/json; charset=ISO-8859-2",
2018-12-06 23:32:52 +01:00
)
.finish();
assert_eq!(ISO_8859_2.name(), req.encoding().unwrap().name());
}
#[test]
fn test_encoding_error() {
2018-04-14 01:02:01 +02:00
let req = TestRequest::with_header("content-type", "applicatjson").finish();
2018-05-17 21:20:20 +02:00
assert_eq!(Some(ContentTypeError::ParseError), req.encoding().err());
let req = TestRequest::with_header(
2018-04-14 01:02:01 +02:00
"content-type",
"application/json; charset=kkkttktk",
2018-12-06 23:32:52 +01:00
)
.finish();
2018-04-29 18:09:08 +02:00
assert_eq!(
Some(ContentTypeError::UnknownEncoding),
req.encoding().err()
);
}
#[test]
fn test_chunked() {
2018-06-25 06:58:04 +02:00
let req = TestRequest::default().finish();
assert!(!req.chunked().unwrap());
2018-04-14 01:02:01 +02:00
let req =
TestRequest::with_header(header::TRANSFER_ENCODING, "chunked").finish();
assert!(req.chunked().unwrap());
2018-06-25 06:58:04 +02:00
let req = TestRequest::default()
.header(
header::TRANSFER_ENCODING,
Bytes::from_static(b"some va\xadscc\xacas0xsdasdlue"),
2018-12-06 23:32:52 +01:00
)
.finish();
assert!(req.chunked().is_err());
}
impl PartialEq for UrlencodedError {
fn eq(&self, other: &UrlencodedError) -> bool {
match *self {
UrlencodedError::Chunked => match *other {
UrlencodedError::Chunked => true,
_ => false,
},
UrlencodedError::Overflow => match *other {
UrlencodedError::Overflow => true,
_ => false,
},
UrlencodedError::UnknownLength => match *other {
UrlencodedError::UnknownLength => true,
_ => false,
},
UrlencodedError::ContentType => match *other {
UrlencodedError::ContentType => true,
_ => false,
},
_ => false,
}
}
}
2018-04-02 23:00:18 +02:00
#[derive(Deserialize, Debug, PartialEq)]
struct Info {
hello: String,
}
#[test]
fn test_urlencoded_error() {
let mut req = TestRequest::with_header(
2018-04-14 01:02:01 +02:00
header::CONTENT_TYPE,
"application/x-www-form-urlencoded",
2018-12-06 23:32:52 +01:00
)
.header(header::CONTENT_LENGTH, "xxxx")
2018-08-23 18:48:01 +02:00
.finish();
2018-04-14 01:02:01 +02:00
assert_eq!(
req.urlencoded::<Info>().poll().err().unwrap(),
UrlencodedError::UnknownLength
);
let mut req = TestRequest::with_header(
2018-04-14 01:02:01 +02:00
header::CONTENT_TYPE,
"application/x-www-form-urlencoded",
2018-12-06 23:32:52 +01:00
)
.header(header::CONTENT_LENGTH, "1000000")
2018-08-23 18:48:01 +02:00
.finish();
2018-04-14 01:02:01 +02:00
assert_eq!(
req.urlencoded::<Info>().poll().err().unwrap(),
UrlencodedError::Overflow
);
let mut req = TestRequest::with_header(header::CONTENT_TYPE, "text/plain")
.header(header::CONTENT_LENGTH, "10")
.finish();
2018-04-14 01:02:01 +02:00
assert_eq!(
req.urlencoded::<Info>().poll().err().unwrap(),
UrlencodedError::ContentType
);
}
#[test]
fn test_urlencoded() {
let mut req = TestRequest::with_header(
2018-04-14 01:02:01 +02:00
header::CONTENT_TYPE,
"application/x-www-form-urlencoded",
2018-12-06 23:32:52 +01:00
)
.header(header::CONTENT_LENGTH, "11")
2018-08-23 18:48:01 +02:00
.set_payload(Bytes::from_static(b"hello=world"))
.finish();
2018-04-02 23:00:18 +02:00
let result = req.urlencoded::<Info>().poll().ok().unwrap();
2018-04-14 01:02:01 +02:00
assert_eq!(
result,
Async::Ready(Info {
hello: "world".to_owned()
})
);
let mut req = TestRequest::with_header(
2018-04-14 01:02:01 +02:00
header::CONTENT_TYPE,
"application/x-www-form-urlencoded; charset=utf-8",
2018-12-06 23:32:52 +01:00
)
.header(header::CONTENT_LENGTH, "11")
2018-08-23 18:48:01 +02:00
.set_payload(Bytes::from_static(b"hello=world"))
.finish();
let result = req.urlencoded().poll().ok().unwrap();
2018-04-14 01:02:01 +02:00
assert_eq!(
result,
Async::Ready(Info {
hello: "world".to_owned()
})
);
2018-04-02 23:00:18 +02:00
}
#[test]
fn test_message_body() {
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "xxxx").finish();
match req.body().poll().err().unwrap() {
PayloadError::UnknownLength => (),
2018-03-30 00:55:27 +02:00
_ => unreachable!("error"),
}
let mut req =
TestRequest::with_header(header::CONTENT_LENGTH, "1000000").finish();
match req.body().poll().err().unwrap() {
PayloadError::Overflow => (),
2018-03-30 00:55:27 +02:00
_ => unreachable!("error"),
}
let mut req = TestRequest::default()
2018-06-25 06:58:04 +02:00
.set_payload(Bytes::from_static(b"test"))
.finish();
match req.body().poll().ok().unwrap() {
Async::Ready(bytes) => assert_eq!(bytes, Bytes::from_static(b"test")),
2018-03-30 00:55:27 +02:00
_ => unreachable!("error"),
}
let mut req = TestRequest::default()
2018-06-25 06:58:04 +02:00
.set_payload(Bytes::from_static(b"11111111111111"))
.finish();
match req.body().limit(5).poll().err().unwrap() {
PayloadError::Overflow => (),
2018-03-30 00:55:27 +02:00
_ => unreachable!("error"),
}
}
2018-06-16 23:26:34 +02:00
2018-06-13 23:19:48 +02:00
#[test]
fn test_readlines() {
let mut req = TestRequest::default()
2018-06-25 06:58:04 +02:00
.set_payload(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.",
2018-12-06 23:32:52 +01:00
))
.finish();
let mut r = Readlines::new(&mut req);
2018-06-13 23:19:48 +02:00
match r.poll().ok().unwrap() {
2018-06-16 23:26:34 +02:00
Async::Ready(Some(s)) => assert_eq!(
s,
"Lorem Ipsum is simply dummy text of the printing and typesetting\n"
),
2018-06-13 23:19:48 +02:00
_ => unreachable!("error"),
}
match r.poll().ok().unwrap() {
2018-06-16 23:26:34 +02:00
Async::Ready(Some(s)) => assert_eq!(
s,
"industry. Lorem Ipsum has been the industry's standard dummy\n"
),
2018-06-13 23:19:48 +02:00
_ => unreachable!("error"),
}
match r.poll().ok().unwrap() {
2018-06-16 23:26:34 +02:00
Async::Ready(Some(s)) => assert_eq!(
s,
"Contrary to popular belief, Lorem Ipsum is not simply random text."
),
2018-06-13 23:19:48 +02:00
_ => unreachable!("error"),
}
}
}