1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-28 01:52:57 +01:00
actix-web/awc/src/response.rs

459 lines
13 KiB
Rust
Raw Normal View History

use std::cell::{Ref, RefMut};
use std::fmt;
2019-04-02 19:53:44 +02:00
use std::marker::PhantomData;
2019-03-27 04:45:00 +01:00
use bytes::{Bytes, BytesMut};
2019-04-02 19:53:44 +02:00
use futures::{Async, Future, Poll, Stream};
2019-04-01 20:51:18 +02:00
use actix_http::cookie::Cookie;
use actix_http::error::{CookieParseError, PayloadError};
2019-03-27 05:31:18 +01:00
use actix_http::http::header::{CONTENT_LENGTH, SET_COOKIE};
use actix_http::http::{HeaderMap, StatusCode, Version};
2019-03-27 07:25:24 +01:00
use actix_http::{Extensions, HttpMessage, Payload, PayloadStream, ResponseHead};
2019-04-01 20:51:18 +02:00
use serde::de::DeserializeOwned;
2019-04-01 20:51:18 +02:00
use crate::error::JsonPayloadError;
2019-03-27 05:31:18 +01:00
/// Client Response
2019-03-27 04:45:00 +01:00
pub struct ClientResponse<S = PayloadStream> {
pub(crate) head: ResponseHead,
2019-03-27 04:45:00 +01:00
pub(crate) payload: Payload<S>,
}
2019-03-27 04:45:00 +01:00
impl<S> HttpMessage for ClientResponse<S> {
type Stream = S;
fn headers(&self) -> &HeaderMap {
&self.head.headers
}
fn extensions(&self) -> Ref<Extensions> {
self.head.extensions()
}
fn extensions_mut(&self) -> RefMut<Extensions> {
self.head.extensions_mut()
}
2019-03-27 04:45:00 +01:00
fn take_payload(&mut self) -> Payload<S> {
std::mem::replace(&mut self.payload, Payload::None)
}
2019-03-27 05:31:18 +01:00
/// Load request cookies.
#[inline]
fn cookies(&self) -> Result<Ref<Vec<Cookie<'static>>>, CookieParseError> {
struct Cookies(Vec<Cookie<'static>>);
if self.extensions().get::<Cookies>().is_none() {
let mut cookies = Vec::new();
for hdr in self.headers().get_all(SET_COOKIE) {
let s = std::str::from_utf8(hdr.as_bytes())
.map_err(CookieParseError::from)?;
cookies.push(Cookie::parse_encoded(s)?.into_owned());
}
self.extensions_mut().insert(Cookies(cookies));
}
Ok(Ref::map(self.extensions(), |ext| {
&ext.get::<Cookies>().unwrap().0
}))
}
}
2019-03-27 04:45:00 +01:00
impl<S> ClientResponse<S> {
/// Create new Request instance
2019-03-27 04:45:00 +01:00
pub(crate) fn new(head: ResponseHead, payload: Payload<S>) -> Self {
ClientResponse { head, payload }
}
#[inline]
pub(crate) fn head(&self) -> &ResponseHead {
&self.head
}
/// Read the Request Version.
#[inline]
pub fn version(&self) -> Version {
self.head().version
}
/// Get the status from the server.
#[inline]
pub fn status(&self) -> StatusCode {
self.head().status
}
#[inline]
2019-04-02 22:35:01 +02:00
/// Returns request's headers.
pub fn headers(&self) -> &HeaderMap {
&self.head().headers
}
2019-03-27 04:45:00 +01:00
/// Set a body and return previous body value
pub fn map_body<F, U>(mut self, f: F) -> ClientResponse<U>
where
F: FnOnce(&mut ResponseHead, Payload<S>) -> Payload<U>,
{
let payload = f(&mut self.head, self.payload);
ClientResponse {
payload,
head: self.head,
}
}
}
2019-03-27 04:45:00 +01:00
impl<S> ClientResponse<S>
where
2019-04-02 19:53:44 +02:00
S: Stream<Item = Bytes, Error = PayloadError>,
2019-03-27 04:45:00 +01:00
{
2019-04-01 20:51:18 +02:00
/// Loads http response's body.
2019-04-01 20:29:26 +02:00
pub fn body(&mut self) -> MessageBody<S> {
2019-03-27 04:45:00 +01:00
MessageBody::new(self)
}
2019-04-01 20:51:18 +02:00
/// Loads and 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
pub fn json<T: DeserializeOwned>(&mut self) -> JsonBody<S, T> {
JsonBody::new(self)
}
2019-03-27 04:45:00 +01:00
}
impl<S> Stream for ClientResponse<S>
where
S: Stream<Item = Bytes, Error = PayloadError>,
{
type Item = Bytes;
type Error = PayloadError;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
self.payload.poll()
}
}
2019-03-27 04:45:00 +01:00
impl<S> fmt::Debug for ClientResponse<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "\nClientResponse {:?} {}", self.version(), self.status(),)?;
writeln!(f, " headers:")?;
for (key, val) in self.headers().iter() {
writeln!(f, " {:?}: {:?}", key, val)?;
}
Ok(())
}
}
2019-03-27 04:45:00 +01:00
/// Future that resolves to a complete http message body.
pub struct MessageBody<S> {
length: Option<usize>,
err: Option<PayloadError>,
2019-04-02 19:53:44 +02:00
fut: Option<ReadBody<S>>,
2019-03-27 04:45:00 +01:00
}
impl<S> MessageBody<S>
where
2019-04-02 19:53:44 +02:00
S: Stream<Item = Bytes, Error = PayloadError>,
2019-03-27 04:45:00 +01:00
{
/// Create `MessageBody` for request.
2019-04-01 20:29:26 +02:00
pub fn new(res: &mut ClientResponse<S>) -> MessageBody<S> {
2019-03-27 04:45:00 +01:00
let mut len = None;
if let Some(l) = res.headers().get(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 {
length: len,
err: None,
2019-04-02 19:53:44 +02:00
fut: Some(ReadBody::new(res.take_payload(), 262_144)),
2019-03-27 04:45:00 +01:00
}
}
/// Change max size of payload. By default max size is 256Kb
pub fn limit(mut self, limit: usize) -> Self {
2019-04-02 19:53:44 +02:00
if let Some(ref mut fut) = self.fut {
fut.limit = limit;
}
2019-03-27 04:45:00 +01:00
self
}
fn err(e: PayloadError) -> Self {
MessageBody {
fut: None,
err: Some(e),
length: None,
}
}
}
impl<S> Future for MessageBody<S>
where
2019-04-02 19:53:44 +02:00
S: Stream<Item = Bytes, Error = PayloadError>,
2019-03-27 04:45:00 +01:00
{
type Item = Bytes;
type Error = PayloadError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if let Some(err) = self.err.take() {
return Err(err);
}
if let Some(len) = self.length.take() {
2019-04-02 19:53:44 +02:00
if len > self.fut.as_ref().unwrap().limit {
2019-03-27 04:45:00 +01:00
return Err(PayloadError::Overflow);
}
}
2019-04-02 19:53:44 +02:00
self.fut.as_mut().unwrap().poll()
2019-03-27 04:45:00 +01:00
}
}
2019-03-27 05:54:57 +01:00
2019-04-01 20:51:18 +02:00
/// Response's payload json parser, it resolves to a deserialized `T` value.
///
/// Returns error:
///
/// * content type is not `application/json`
/// * content length is greater than 64k
pub struct JsonBody<S, U> {
length: Option<usize>,
err: Option<JsonPayloadError>,
2019-04-02 19:53:44 +02:00
fut: Option<ReadBody<S>>,
_t: PhantomData<U>,
2019-04-01 20:51:18 +02:00
}
impl<S, U> JsonBody<S, U>
where
2019-04-02 19:53:44 +02:00
S: Stream<Item = Bytes, Error = PayloadError>,
2019-04-01 20:51:18 +02:00
U: DeserializeOwned,
{
/// Create `JsonBody` for request.
pub fn new(req: &mut ClientResponse<S>) -> Self {
// check content-type
let json = if let Ok(Some(mime)) = req.mime_type() {
mime.subtype() == mime::JSON || mime.suffix() == Some(mime::JSON)
} else {
false
};
if !json {
return JsonBody {
length: None,
fut: None,
err: Some(JsonPayloadError::ContentType),
2019-04-02 19:53:44 +02:00
_t: PhantomData,
2019-04-01 20:51:18 +02:00
};
}
let mut len = None;
if let Some(l) = req.headers().get(CONTENT_LENGTH) {
if let Ok(s) = l.to_str() {
if let Ok(l) = s.parse::<usize>() {
len = Some(l)
}
}
}
JsonBody {
length: len,
err: None,
2019-04-02 19:53:44 +02:00
fut: Some(ReadBody::new(req.take_payload(), 65536)),
_t: PhantomData,
2019-04-01 20:51:18 +02:00
}
}
/// Change max size of payload. By default max size is 64Kb
pub fn limit(mut self, limit: usize) -> Self {
2019-04-02 19:53:44 +02:00
if let Some(ref mut fut) = self.fut {
fut.limit = limit;
}
2019-04-01 20:51:18 +02:00
self
}
}
impl<T, U> Future for JsonBody<T, U>
where
2019-04-02 19:53:44 +02:00
T: Stream<Item = Bytes, Error = PayloadError>,
2019-04-04 19:59:34 +02:00
U: DeserializeOwned,
2019-04-01 20:51:18 +02:00
{
type Item = U;
type Error = JsonPayloadError;
fn poll(&mut self) -> Poll<U, JsonPayloadError> {
if let Some(err) = self.err.take() {
return Err(err);
}
if let Some(len) = self.length.take() {
2019-04-02 19:53:44 +02:00
if len > self.fut.as_ref().unwrap().limit {
return Err(JsonPayloadError::Payload(PayloadError::Overflow));
2019-04-01 20:51:18 +02:00
}
}
2019-04-02 19:53:44 +02:00
let body = futures::try_ready!(self.fut.as_mut().unwrap().poll());
Ok(Async::Ready(serde_json::from_slice::<U>(&body)?))
}
}
struct ReadBody<S> {
stream: Payload<S>,
buf: BytesMut,
limit: usize,
}
impl<S> ReadBody<S> {
fn new(stream: Payload<S>, limit: usize) -> Self {
Self {
stream,
buf: BytesMut::with_capacity(std::cmp::min(limit, 32768)),
limit,
}
}
}
impl<S> Future for ReadBody<S>
where
S: Stream<Item = Bytes, Error = PayloadError>,
{
type Item = Bytes;
type Error = PayloadError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
loop {
return match self.stream.poll()? {
Async::Ready(Some(chunk)) => {
if (self.buf.len() + chunk.len()) > self.limit {
Err(PayloadError::Overflow)
} else {
self.buf.extend_from_slice(&chunk);
continue;
}
2019-04-01 20:51:18 +02:00
}
2019-04-02 19:53:44 +02:00
Async::Ready(None) => Ok(Async::Ready(self.buf.take().freeze())),
Async::NotReady => Ok(Async::NotReady),
};
}
2019-04-01 20:51:18 +02:00
}
}
2019-03-27 05:54:57 +01:00
#[cfg(test)]
mod tests {
use super::*;
use futures::Async;
2019-04-01 20:51:18 +02:00
use serde::{Deserialize, Serialize};
2019-03-27 05:54:57 +01:00
2019-04-01 20:51:18 +02:00
use crate::{http::header, test::block_on, test::TestResponse};
2019-03-27 05:54:57 +01:00
#[test]
fn test_body() {
2019-04-01 20:29:26 +02:00
let mut req = TestResponse::with_header(header::CONTENT_LENGTH, "xxxx").finish();
2019-03-27 05:54:57 +01:00
match req.body().poll().err().unwrap() {
PayloadError::UnknownLength => (),
_ => unreachable!("error"),
}
2019-04-01 20:29:26 +02:00
let mut req =
TestResponse::with_header(header::CONTENT_LENGTH, "1000000").finish();
2019-03-27 05:54:57 +01:00
match req.body().poll().err().unwrap() {
PayloadError::Overflow => (),
_ => unreachable!("error"),
}
2019-04-01 20:29:26 +02:00
let mut req = TestResponse::default()
2019-03-27 05:54:57 +01: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")),
_ => unreachable!("error"),
}
2019-04-01 20:29:26 +02:00
let mut req = TestResponse::default()
2019-03-27 05:54:57 +01:00
.set_payload(Bytes::from_static(b"11111111111111"))
.finish();
match req.body().limit(5).poll().err().unwrap() {
PayloadError::Overflow => (),
_ => unreachable!("error"),
}
}
2019-04-01 20:51:18 +02:00
#[derive(Serialize, Deserialize, PartialEq, Debug)]
struct MyObject {
name: String,
}
fn json_eq(err: JsonPayloadError, other: JsonPayloadError) -> bool {
match err {
2019-04-02 19:53:44 +02:00
JsonPayloadError::Payload(PayloadError::Overflow) => match other {
JsonPayloadError::Payload(PayloadError::Overflow) => true,
2019-04-01 20:51:18 +02:00
_ => false,
},
JsonPayloadError::ContentType => match other {
JsonPayloadError::ContentType => true,
_ => false,
},
_ => false,
}
}
#[test]
fn test_json_body() {
let mut req = TestResponse::default().finish();
let json = block_on(JsonBody::<_, MyObject>::new(&mut req));
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
let mut req = TestResponse::default()
.header(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/text"),
)
.finish();
let json = block_on(JsonBody::<_, MyObject>::new(&mut req));
assert!(json_eq(json.err().unwrap(), JsonPayloadError::ContentType));
let mut req = TestResponse::default()
.header(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json"),
)
.header(
header::CONTENT_LENGTH,
header::HeaderValue::from_static("10000"),
)
.finish();
let json = block_on(JsonBody::<_, MyObject>::new(&mut req).limit(100));
2019-04-02 19:53:44 +02:00
assert!(json_eq(
json.err().unwrap(),
JsonPayloadError::Payload(PayloadError::Overflow)
));
2019-04-01 20:51:18 +02:00
let mut req = TestResponse::default()
.header(
header::CONTENT_TYPE,
header::HeaderValue::from_static("application/json"),
)
.header(
header::CONTENT_LENGTH,
header::HeaderValue::from_static("16"),
)
.set_payload(Bytes::from_static(b"{\"name\": \"test\"}"))
.finish();
let json = block_on(JsonBody::<_, MyObject>::new(&mut req));
assert_eq!(
json.ok().unwrap(),
MyObject {
name: "test".to_owned()
}
);
}
2019-03-27 05:54:57 +01:00
}