1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-25 00:12:59 +01:00
actix-extras/src/client/response.rs

140 lines
3.7 KiB
Rust
Raw Normal View History

use std::{fmt, str};
use std::rc::Rc;
use std::cell::UnsafeCell;
2018-01-28 07:03:03 +01:00
use bytes::Bytes;
use cookie::Cookie;
use futures::{Async, Poll, Stream};
use http::{HeaderMap, StatusCode, Version};
use http::header::{self, HeaderValue};
2018-01-28 07:03:03 +01:00
use httpmessage::HttpMessage;
use error::{CookieParseError, PayloadError};
2018-02-19 12:11:11 +01:00
use super::pipeline::Pipeline;
2018-01-28 07:03:03 +01:00
pub(crate) struct ClientMessage {
pub status: StatusCode,
pub version: Version,
pub headers: HeaderMap<HeaderValue>,
pub cookies: Option<Vec<Cookie<'static>>>,
}
2018-01-28 07:03:03 +01:00
impl Default for ClientMessage {
2018-01-28 07:03:03 +01:00
fn default() -> ClientMessage {
ClientMessage {
status: StatusCode::OK,
version: Version::HTTP_11,
headers: HeaderMap::with_capacity(16),
cookies: None,
}
}
2018-01-28 07:03:03 +01:00
}
/// An HTTP Client response
2018-02-19 12:11:11 +01:00
pub struct ClientResponse(Rc<UnsafeCell<ClientMessage>>, Option<Box<Pipeline>>);
impl HttpMessage for ClientResponse {
/// Get the headers from the response.
#[inline]
fn headers(&self) -> &HeaderMap {
&self.as_ref().headers
}
}
2018-01-28 07:03:03 +01:00
impl ClientResponse {
pub(crate) fn new(msg: ClientMessage) -> ClientResponse {
2018-02-19 12:11:11 +01:00
ClientResponse(Rc::new(UnsafeCell::new(msg)), None)
}
pub(crate) fn set_pipeline(&mut self, pl: Box<Pipeline>) {
self.1 = Some(pl);
}
#[inline]
fn as_ref(&self) -> &ClientMessage {
unsafe{ &*self.0.get() }
}
#[inline]
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
fn as_mut(&self) -> &mut ClientMessage {
unsafe{ &mut *self.0.get() }
2018-01-28 07:03:03 +01:00
}
/// Get the HTTP version of this response.
2018-01-28 07:03:03 +01:00
#[inline]
pub fn version(&self) -> Version {
self.as_ref().version
2018-01-28 07:03:03 +01:00
}
/// Get the status from the server.
#[inline]
pub fn status(&self) -> StatusCode {
self.as_ref().status
2018-01-28 07:03:03 +01:00
}
2018-03-07 07:36:34 +01:00
/// Load response cookies.
pub fn cookies(&self) -> Result<&Vec<Cookie<'static>>, CookieParseError> {
if self.as_ref().cookies.is_none() {
let msg = self.as_mut();
let mut cookies = Vec::new();
2018-03-07 07:36:34 +01:00
if let Some(val) = msg.headers.get(header::SET_COOKIE) {
let s = str::from_utf8(val.as_bytes())
.map_err(CookieParseError::from)?;
for cookie in s.split("; ") {
cookies.push(Cookie::parse_encoded(cookie)?.into_owned());
}
}
msg.cookies = Some(cookies)
}
Ok(self.as_ref().cookies.as_ref().unwrap())
}
/// Return request cookie.
pub fn cookie(&self, name: &str) -> Option<&Cookie> {
if let Ok(cookies) = self.cookies() {
for cookie in cookies {
if cookie.name() == name {
return Some(cookie)
}
}
}
None
}
2018-01-28 07:03:03 +01:00
}
impl fmt::Debug for ClientResponse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let res = write!(
f, "\nClientResponse {:?} {}\n", self.version(), self.status());
2018-01-28 07:03:03 +01:00
let _ = write!(f, " headers:\n");
for key in self.headers().keys() {
let vals: Vec<_> = self.headers().get_all(key).iter().collect();
2018-01-28 07:03:03 +01:00
if vals.len() > 1 {
let _ = write!(f, " {:?}: {:?}\n", key, vals);
} else {
let _ = write!(f, " {:?}: {:?}\n", key, vals[0]);
}
}
res
}
}
/// Future that resolves to a complete request body.
2018-02-19 12:11:11 +01:00
impl Stream for ClientResponse {
type Item = Bytes;
type Error = PayloadError;
2018-02-19 12:11:11 +01:00
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
if let Some(ref mut pl) = self.1 {
pl.poll()
} else {
Ok(Async::Ready(None))
}
}
}