mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-24 07:53:00 +01:00
add client decompression support
This commit is contained in:
parent
2629699b62
commit
1cca25c276
@ -74,7 +74,7 @@ where
|
|||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
return Ok(Async::Ready(Some(chunk)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Async::Ready(None) => {
|
Async::Ready(None) => {
|
||||||
@ -150,7 +150,7 @@ impl ContentDecoder {
|
|||||||
#[allow(unreachable_patterns)]
|
#[allow(unreachable_patterns)]
|
||||||
fn feed_data(&mut self, data: Bytes) -> io::Result<Option<Bytes>> {
|
fn feed_data(&mut self, data: Bytes) -> io::Result<Option<Bytes>> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
|
#[cfg(feature = "brotli")]
|
||||||
ContentDecoder::Br(ref mut decoder) => match decoder.write_all(&data) {
|
ContentDecoder::Br(ref mut decoder) => match decoder.write_all(&data) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
decoder.flush()?;
|
decoder.flush()?;
|
||||||
|
@ -30,7 +30,7 @@ ssl = ["openssl", "actix-http/ssl"]
|
|||||||
cookies = ["cookie", "actix-http/cookies"]
|
cookies = ["cookie", "actix-http/cookies"]
|
||||||
|
|
||||||
# brotli encoding, requires c compiler
|
# brotli encoding, requires c compiler
|
||||||
brotli = ["actix-http/brotli2"]
|
brotli = ["actix-http/brotli"]
|
||||||
|
|
||||||
# miniz-sys backend for flate2 crate
|
# miniz-sys backend for flate2 crate
|
||||||
flate2-zlib = ["actix-http/flate2-zlib"]
|
flate2-zlib = ["actix-http/flate2-zlib"]
|
||||||
@ -53,8 +53,12 @@ cookie = { version="0.11", features=["percent-encode"], optional = true }
|
|||||||
openssl = { version="0.10", optional = true }
|
openssl = { version="0.10", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.6"
|
|
||||||
mime = "0.3"
|
|
||||||
actix-rt = "0.2.1"
|
actix-rt = "0.2.1"
|
||||||
|
actix-web = { path = "..", features=["ssl"] }
|
||||||
actix-http = { path = "../actix-http/", features=["ssl"] }
|
actix-http = { path = "../actix-http/", features=["ssl"] }
|
||||||
actix-http-test = { path = "../test-server/", features=["ssl"] }
|
actix-http-test = { path = "../test-server/", features=["ssl"] }
|
||||||
|
brotli2 = { version="^0.3.2" }
|
||||||
|
flate2 = { version="^1.0.2" }
|
||||||
|
env_logger = "0.6"
|
||||||
|
mime = "0.3"
|
||||||
|
rand = "0.6"
|
||||||
|
@ -2,6 +2,7 @@ use std::cell::RefCell;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub use actix_http::client::{ConnectError, InvalidUrl, SendRequestError};
|
pub use actix_http::client::{ConnectError, InvalidUrl, SendRequestError};
|
||||||
|
pub use actix_http::error::PayloadError;
|
||||||
pub use actix_http::http;
|
pub use actix_http::http;
|
||||||
|
|
||||||
use actix_http::client::Connector;
|
use actix_http::client::Connector;
|
||||||
|
@ -13,15 +13,24 @@ use serde_json;
|
|||||||
|
|
||||||
use actix_http::body::{Body, BodyStream};
|
use actix_http::body::{Body, BodyStream};
|
||||||
use actix_http::client::{InvalidUrl, SendRequestError};
|
use actix_http::client::{InvalidUrl, SendRequestError};
|
||||||
use actix_http::http::header::{self, Header, IntoHeaderValue};
|
use actix_http::encoding::Decoder;
|
||||||
|
use actix_http::http::header::{self, ContentEncoding, Header, IntoHeaderValue};
|
||||||
use actix_http::http::{
|
use actix_http::http::{
|
||||||
uri, ConnectionType, Error as HttpError, HeaderName, HeaderValue, HttpTryFrom,
|
uri, ConnectionType, Error as HttpError, HeaderName, HeaderValue, HttpTryFrom,
|
||||||
Method, Uri, Version,
|
Method, Uri, Version,
|
||||||
};
|
};
|
||||||
use actix_http::{Error, Head, RequestHead};
|
use actix_http::{Error, Head, Payload, RequestHead};
|
||||||
|
|
||||||
use crate::response::ClientResponse;
|
use crate::response::ClientResponse;
|
||||||
use crate::Connect;
|
use crate::{Connect, PayloadError};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "brotli", feature = "flate2-zlib", feature = "flate2-rust"))]
|
||||||
|
const HTTPS_ENCODING: &str = "br, gzip, deflate";
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "flate2-zlib", feature = "flate2-rust"),
|
||||||
|
not(feature = "brotli")
|
||||||
|
))]
|
||||||
|
const HTTPS_ENCODING: &str = "gzip, deflate";
|
||||||
|
|
||||||
/// An HTTP Client request builder
|
/// An HTTP Client request builder
|
||||||
///
|
///
|
||||||
@ -52,6 +61,7 @@ pub struct ClientRequest {
|
|||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
cookies: Option<CookieJar>,
|
cookies: Option<CookieJar>,
|
||||||
default_headers: bool,
|
default_headers: bool,
|
||||||
|
response_decompress: bool,
|
||||||
connector: Rc<RefCell<dyn Connect>>,
|
connector: Rc<RefCell<dyn Connect>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +91,7 @@ impl ClientRequest {
|
|||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
cookies: None,
|
cookies: None,
|
||||||
default_headers: true,
|
default_headers: true,
|
||||||
|
response_decompress: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +286,12 @@ impl ClientRequest {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Disable automatic decompress of response's body
|
||||||
|
pub fn no_decompress(mut self) -> Self {
|
||||||
|
self.response_decompress = false;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// This method calls provided closure with builder reference if
|
/// This method calls provided closure with builder reference if
|
||||||
/// value is `true`.
|
/// value is `true`.
|
||||||
pub fn if_true<F>(mut self, value: bool, f: F) -> Self
|
pub fn if_true<F>(mut self, value: bool, f: F) -> Self
|
||||||
@ -303,7 +320,10 @@ impl ClientRequest {
|
|||||||
pub fn send_body<B>(
|
pub fn send_body<B>(
|
||||||
mut self,
|
mut self,
|
||||||
body: B,
|
body: B,
|
||||||
) -> impl Future<Item = ClientResponse, Error = SendRequestError>
|
) -> impl Future<
|
||||||
|
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
|
||||||
|
Error = SendRequestError,
|
||||||
|
>
|
||||||
where
|
where
|
||||||
B: Into<Body>,
|
B: Into<Body>,
|
||||||
{
|
{
|
||||||
@ -311,42 +331,44 @@ impl ClientRequest {
|
|||||||
return Either::A(err(e.into()));
|
return Either::A(err(e.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut slf = if self.default_headers {
|
// validate uri
|
||||||
// enable br only for https
|
let uri = &self.head.uri;
|
||||||
let https = self
|
if uri.host().is_none() {
|
||||||
.head
|
return Either::A(err(InvalidUrl::MissingHost.into()));
|
||||||
.uri
|
} else if uri.scheme_part().is_none() {
|
||||||
.scheme_part()
|
return Either::A(err(InvalidUrl::MissingScheme.into()));
|
||||||
.map(|s| s == &uri::Scheme::HTTPS)
|
} else if let Some(scheme) = uri.scheme_part() {
|
||||||
.unwrap_or(true);
|
match scheme.as_str() {
|
||||||
|
"http" | "ws" | "https" | "wss" => (),
|
||||||
let mut slf = if https {
|
_ => return Either::A(err(InvalidUrl::UnknownScheme.into())),
|
||||||
self.set_header_if_none(header::ACCEPT_ENCODING, "br, gzip, deflate")
|
}
|
||||||
} else {
|
} else {
|
||||||
self.set_header_if_none(header::ACCEPT_ENCODING, "gzip, deflate")
|
return Either::A(err(InvalidUrl::UnknownScheme.into()));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
// set default headers
|
||||||
|
let slf = if self.default_headers {
|
||||||
// set request host header
|
// set request host header
|
||||||
if let Some(host) = slf.head.uri.host() {
|
if let Some(host) = self.head.uri.host() {
|
||||||
if !slf.head.headers.contains_key(header::HOST) {
|
if !self.head.headers.contains_key(header::HOST) {
|
||||||
let mut wrt = BytesMut::with_capacity(host.len() + 5).writer();
|
let mut wrt = BytesMut::with_capacity(host.len() + 5).writer();
|
||||||
|
|
||||||
let _ = match slf.head.uri.port_u16() {
|
let _ = match self.head.uri.port_u16() {
|
||||||
None | Some(80) | Some(443) => write!(wrt, "{}", host),
|
None | Some(80) | Some(443) => write!(wrt, "{}", host),
|
||||||
Some(port) => write!(wrt, "{}:{}", host, port),
|
Some(port) => write!(wrt, "{}:{}", host, port),
|
||||||
};
|
};
|
||||||
|
|
||||||
match wrt.get_mut().take().freeze().try_into() {
|
match wrt.get_mut().take().freeze().try_into() {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
slf.head.headers.insert(header::HOST, value);
|
self.head.headers.insert(header::HOST, value);
|
||||||
}
|
}
|
||||||
Err(e) => slf.err = Some(e.into()),
|
Err(e) => return Either::A(err(HttpError::from(e).into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// user agent
|
// user agent
|
||||||
slf.set_header_if_none(
|
self.set_header_if_none(
|
||||||
header::USER_AGENT,
|
header::USER_AGENT,
|
||||||
concat!("actix-http/", env!("CARGO_PKG_VERSION")),
|
concat!("actix-http/", env!("CARGO_PKG_VERSION")),
|
||||||
)
|
)
|
||||||
@ -354,6 +376,32 @@ impl ClientRequest {
|
|||||||
self
|
self
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// enable br only for https
|
||||||
|
let https = slf
|
||||||
|
.head
|
||||||
|
.uri
|
||||||
|
.scheme_part()
|
||||||
|
.map(|s| s == &uri::Scheme::HTTPS)
|
||||||
|
.unwrap_or(true);
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "brotli",
|
||||||
|
feature = "flate2-zlib",
|
||||||
|
feature = "flate2-rust"
|
||||||
|
))]
|
||||||
|
let mut slf = {
|
||||||
|
if https {
|
||||||
|
slf.set_header_if_none(header::ACCEPT_ENCODING, HTTPS_ENCODING)
|
||||||
|
} else {
|
||||||
|
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
|
||||||
|
{
|
||||||
|
slf.set_header_if_none(header::ACCEPT_ENCODING, "gzip, deflate")
|
||||||
|
}
|
||||||
|
#[cfg(not(any(feature = "flate2-zlib", feature = "flate2-rust")))]
|
||||||
|
slf
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut head = slf.head;
|
let mut head = slf.head;
|
||||||
|
|
||||||
@ -378,30 +426,32 @@ impl ClientRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let uri = head.uri.clone();
|
let response_decompress = slf.response_decompress;
|
||||||
|
|
||||||
// validate uri
|
let fut = slf
|
||||||
if uri.host().is_none() {
|
.connector
|
||||||
Either::A(err(InvalidUrl::MissingHost.into()))
|
.borrow_mut()
|
||||||
} else if uri.scheme_part().is_none() {
|
.send_request(head, body.into())
|
||||||
Either::A(err(InvalidUrl::MissingScheme.into()))
|
.map(move |res| {
|
||||||
} else if let Some(scheme) = uri.scheme_part() {
|
res.map_body(|head, payload| {
|
||||||
match scheme.as_str() {
|
if response_decompress {
|
||||||
"http" | "ws" | "https" | "wss" => {
|
Payload::Stream(Decoder::from_headers(&head.headers, payload))
|
||||||
Either::B(slf.connector.borrow_mut().send_request(head, body.into()))
|
|
||||||
}
|
|
||||||
_ => Either::A(err(InvalidUrl::UnknownScheme.into())),
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Either::A(err(InvalidUrl::UnknownScheme.into()))
|
Payload::Stream(Decoder::new(payload, ContentEncoding::Identity))
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
Either::B(fut)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a JSON body and generate `ClientRequest`
|
/// Set a JSON body and generate `ClientRequest`
|
||||||
pub fn send_json<T: Serialize>(
|
pub fn send_json<T: Serialize>(
|
||||||
self,
|
self,
|
||||||
value: T,
|
value: T,
|
||||||
) -> impl Future<Item = ClientResponse, Error = SendRequestError> {
|
) -> impl Future<
|
||||||
|
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
|
||||||
|
Error = SendRequestError,
|
||||||
|
> {
|
||||||
let body = match serde_json::to_string(&value) {
|
let body = match serde_json::to_string(&value) {
|
||||||
Ok(body) => body,
|
Ok(body) => body,
|
||||||
Err(e) => return Either::A(err(Error::from(e).into())),
|
Err(e) => return Either::A(err(Error::from(e).into())),
|
||||||
@ -422,7 +472,10 @@ impl ClientRequest {
|
|||||||
pub fn send_form<T: Serialize>(
|
pub fn send_form<T: Serialize>(
|
||||||
self,
|
self,
|
||||||
value: T,
|
value: T,
|
||||||
) -> impl Future<Item = ClientResponse, Error = SendRequestError> {
|
) -> impl Future<
|
||||||
|
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
|
||||||
|
Error = SendRequestError,
|
||||||
|
> {
|
||||||
let body = match serde_urlencoded::to_string(&value) {
|
let body = match serde_urlencoded::to_string(&value) {
|
||||||
Ok(body) => body,
|
Ok(body) => body,
|
||||||
Err(e) => return Either::A(err(Error::from(e).into())),
|
Err(e) => return Either::A(err(Error::from(e).into())),
|
||||||
@ -441,7 +494,10 @@ impl ClientRequest {
|
|||||||
pub fn send_stream<S, E>(
|
pub fn send_stream<S, E>(
|
||||||
self,
|
self,
|
||||||
stream: S,
|
stream: S,
|
||||||
) -> impl Future<Item = ClientResponse, Error = SendRequestError>
|
) -> impl Future<
|
||||||
|
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
|
||||||
|
Error = SendRequestError,
|
||||||
|
>
|
||||||
where
|
where
|
||||||
S: Stream<Item = Bytes, Error = E> + 'static,
|
S: Stream<Item = Bytes, Error = E> + 'static,
|
||||||
E: Into<Error> + 'static,
|
E: Into<Error> + 'static,
|
||||||
@ -450,7 +506,12 @@ impl ClientRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set an empty body and generate `ClientRequest`.
|
/// Set an empty body and generate `ClientRequest`.
|
||||||
pub fn send(self) -> impl Future<Item = ClientResponse, Error = SendRequestError> {
|
pub fn send(
|
||||||
|
self,
|
||||||
|
) -> impl Future<
|
||||||
|
Item = ClientResponse<impl Stream<Item = Bytes, Error = PayloadError>>,
|
||||||
|
Error = SendRequestError,
|
||||||
|
> {
|
||||||
self.send_body(Body::Empty)
|
self.send_body(Body::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
use std::cell::{Ref, RefMut};
|
use std::cell::{Ref, RefMut};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::{Bytes, BytesMut};
|
||||||
use futures::{Poll, Stream};
|
use futures::{Future, Poll, Stream};
|
||||||
|
|
||||||
use actix_http::error::PayloadError;
|
use actix_http::error::PayloadError;
|
||||||
|
use actix_http::http::header::CONTENT_LENGTH;
|
||||||
use actix_http::http::{HeaderMap, StatusCode, Version};
|
use actix_http::http::{HeaderMap, StatusCode, Version};
|
||||||
use actix_http::{Extensions, Head, HttpMessage, Payload, PayloadStream, ResponseHead};
|
use actix_http::{Extensions, Head, HttpMessage, Payload, PayloadStream, ResponseHead};
|
||||||
|
|
||||||
/// Client Response
|
/// Client Response
|
||||||
pub struct ClientResponse {
|
pub struct ClientResponse<S = PayloadStream> {
|
||||||
pub(crate) head: ResponseHead,
|
pub(crate) head: ResponseHead,
|
||||||
pub(crate) payload: Payload,
|
pub(crate) payload: Payload<S>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpMessage for ClientResponse {
|
impl<S> HttpMessage for ClientResponse<S> {
|
||||||
type Stream = PayloadStream;
|
type Stream = S;
|
||||||
|
|
||||||
fn headers(&self) -> &HeaderMap {
|
fn headers(&self) -> &HeaderMap {
|
||||||
&self.head.headers
|
&self.head.headers
|
||||||
@ -29,14 +30,14 @@ impl HttpMessage for ClientResponse {
|
|||||||
self.head.extensions_mut()
|
self.head.extensions_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take_payload(&mut self) -> Payload {
|
fn take_payload(&mut self) -> Payload<S> {
|
||||||
std::mem::replace(&mut self.payload, Payload::None)
|
std::mem::replace(&mut self.payload, Payload::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientResponse {
|
impl<S> ClientResponse<S> {
|
||||||
/// Create new Request instance
|
/// Create new Request instance
|
||||||
pub(crate) fn new(head: ResponseHead, payload: Payload) -> ClientResponse {
|
pub(crate) fn new(head: ResponseHead, payload: Payload<S>) -> Self {
|
||||||
ClientResponse { head, payload }
|
ClientResponse { head, payload }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,9 +80,35 @@ impl ClientResponse {
|
|||||||
pub fn keep_alive(&self) -> bool {
|
pub fn keep_alive(&self) -> bool {
|
||||||
self.head().keep_alive()
|
self.head().keep_alive()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Stream for ClientResponse {
|
impl<S> ClientResponse<S>
|
||||||
|
where
|
||||||
|
S: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
||||||
|
{
|
||||||
|
/// Load http response's body.
|
||||||
|
pub fn body(self) -> MessageBody<S> {
|
||||||
|
MessageBody::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> Stream for ClientResponse<S>
|
||||||
|
where
|
||||||
|
S: Stream<Item = Bytes, Error = PayloadError>,
|
||||||
|
{
|
||||||
type Item = Bytes;
|
type Item = Bytes;
|
||||||
type Error = PayloadError;
|
type Error = PayloadError;
|
||||||
|
|
||||||
@ -90,7 +117,7 @@ impl Stream for ClientResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ClientResponse {
|
impl<S> fmt::Debug for ClientResponse<S> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
writeln!(f, "\nClientResponse {:?} {}", self.version(), self.status(),)?;
|
writeln!(f, "\nClientResponse {:?} {}", self.version(), self.status(),)?;
|
||||||
writeln!(f, " headers:")?;
|
writeln!(f, " headers:")?;
|
||||||
@ -100,3 +127,100 @@ impl fmt::Debug for ClientResponse {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Future that resolves to a complete http message body.
|
||||||
|
pub struct MessageBody<S> {
|
||||||
|
limit: usize,
|
||||||
|
length: Option<usize>,
|
||||||
|
stream: Option<ClientResponse<S>>,
|
||||||
|
err: Option<PayloadError>,
|
||||||
|
fut: Option<Box<Future<Item = Bytes, Error = PayloadError>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> MessageBody<S>
|
||||||
|
where
|
||||||
|
S: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
||||||
|
{
|
||||||
|
/// Create `MessageBody` for request.
|
||||||
|
pub fn new(res: ClientResponse<S>) -> MessageBody<S> {
|
||||||
|
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 {
|
||||||
|
limit: 262_144,
|
||||||
|
length: len,
|
||||||
|
stream: Some(res),
|
||||||
|
fut: None,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
fn err(e: PayloadError) -> Self {
|
||||||
|
MessageBody {
|
||||||
|
stream: None,
|
||||||
|
limit: 262_144,
|
||||||
|
fut: None,
|
||||||
|
err: Some(e),
|
||||||
|
length: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> Future for MessageBody<S>
|
||||||
|
where
|
||||||
|
S: Stream<Item = Bytes, Error = PayloadError> + 'static,
|
||||||
|
{
|
||||||
|
type Item = Bytes;
|
||||||
|
type Error = PayloadError;
|
||||||
|
|
||||||
|
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||||
|
if let Some(ref mut fut) = self.fut {
|
||||||
|
return fut.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(err) = self.err.take() {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(len) = self.length.take() {
|
||||||
|
if len > self.limit {
|
||||||
|
return Err(PayloadError::Overflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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| {
|
||||||
|
if (body.len() + chunk.len()) > limit {
|
||||||
|
Err(PayloadError::Overflow)
|
||||||
|
} else {
|
||||||
|
body.extend_from_slice(&chunk);
|
||||||
|
Ok(body)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|body| body.freeze()),
|
||||||
|
));
|
||||||
|
self.poll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
508
awc/tests/test_client.rs
Normal file
508
awc/tests/test_client.rs
Normal file
@ -0,0 +1,508 @@
|
|||||||
|
use std::io::{Read, Write};
|
||||||
|
use std::{net, thread};
|
||||||
|
|
||||||
|
use brotli2::write::BrotliEncoder;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use flate2::write::{GzEncoder, ZlibEncoder};
|
||||||
|
use flate2::Compression;
|
||||||
|
use futures::stream::once;
|
||||||
|
use futures::Future;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
use actix_http::HttpService;
|
||||||
|
use actix_http_test::TestServer;
|
||||||
|
use actix_web::{middleware, web, App, HttpRequest, HttpResponse};
|
||||||
|
|
||||||
|
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World \
|
||||||
|
Hello World Hello World Hello World Hello World Hello World";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_simple() {
|
||||||
|
let mut srv =
|
||||||
|
TestServer::new(|| {
|
||||||
|
HttpService::new(App::new().service(
|
||||||
|
web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
|
||||||
|
let request = srv.get().header("x-test", "111").send();
|
||||||
|
let response = srv.block_on(request).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.block_on(response.body()).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.post().send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.block_on(response.body()).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_connection_close() {
|
||||||
|
// let mut srv =
|
||||||
|
// test::TestServer::new(|app| app.handler(|_| HttpResponse::Ok().body(STR)));
|
||||||
|
|
||||||
|
// let request = srv.get().header("Connection", "close").finish().unwrap();
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_with_query_parameter() {
|
||||||
|
// let mut srv = test::TestServer::new(|app| {
|
||||||
|
// app.handler(|req: &HttpRequest| match req.query().get("qp") {
|
||||||
|
// Some(_) => HttpResponse::Ok().finish(),
|
||||||
|
// None => HttpResponse::BadRequest().finish(),
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let request = srv.get().uri(srv.url("/?qp=5").as_str()).finish().unwrap();
|
||||||
|
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_no_decompress() {
|
||||||
|
// let mut srv =
|
||||||
|
// test::TestServer::new(|app| app.handler(|_| HttpResponse::Ok().body(STR)));
|
||||||
|
|
||||||
|
// let request = srv.get().disable_decompress().finish().unwrap();
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// // read response
|
||||||
|
// let bytes = srv.execute(response.body()).unwrap();
|
||||||
|
|
||||||
|
// let mut e = GzDecoder::new(&bytes[..]);
|
||||||
|
// let mut dec = Vec::new();
|
||||||
|
// e.read_to_end(&mut dec).unwrap();
|
||||||
|
// assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
|
||||||
|
|
||||||
|
// // POST
|
||||||
|
// let request = srv.post().disable_decompress().finish().unwrap();
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
|
||||||
|
// let bytes = srv.execute(response.body()).unwrap();
|
||||||
|
// let mut e = GzDecoder::new(&bytes[..]);
|
||||||
|
// let mut dec = Vec::new();
|
||||||
|
// e.read_to_end(&mut dec).unwrap();
|
||||||
|
// assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_client_gzip_encoding() {
|
||||||
|
let mut srv = TestServer::new(|| {
|
||||||
|
HttpService::new(App::new().service(web::resource("/").route(web::to(|| {
|
||||||
|
let mut e = GzEncoder::new(Vec::new(), Compression::default());
|
||||||
|
e.write_all(STR.as_ref()).unwrap();
|
||||||
|
let data = e.finish().unwrap();
|
||||||
|
|
||||||
|
HttpResponse::Ok()
|
||||||
|
.header("content-encoding", "gzip")
|
||||||
|
.body(data)
|
||||||
|
}))))
|
||||||
|
});
|
||||||
|
|
||||||
|
// client request
|
||||||
|
let response = srv.block_on(srv.post().send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.block_on(response.body()).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_client_gzip_encoding_large() {
|
||||||
|
let mut srv = TestServer::new(|| {
|
||||||
|
HttpService::new(App::new().service(web::resource("/").route(web::to(|| {
|
||||||
|
let mut e = GzEncoder::new(Vec::new(), Compression::default());
|
||||||
|
e.write_all(STR.repeat(10).as_ref()).unwrap();
|
||||||
|
let data = e.finish().unwrap();
|
||||||
|
|
||||||
|
HttpResponse::Ok()
|
||||||
|
.header("content-encoding", "gzip")
|
||||||
|
.body(data)
|
||||||
|
}))))
|
||||||
|
});
|
||||||
|
|
||||||
|
// client request
|
||||||
|
let response = srv.block_on(srv.post().send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.block_on(response.body()).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from(STR.repeat(10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_client_gzip_encoding_large_random() {
|
||||||
|
let data = rand::thread_rng()
|
||||||
|
.sample_iter(&rand::distributions::Alphanumeric)
|
||||||
|
.take(100_000)
|
||||||
|
.collect::<String>();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(|| {
|
||||||
|
HttpService::new(App::new().service(web::resource("/").route(web::to(
|
||||||
|
|data: Bytes| {
|
||||||
|
let mut e = GzEncoder::new(Vec::new(), Compression::default());
|
||||||
|
e.write_all(&data).unwrap();
|
||||||
|
let data = e.finish().unwrap();
|
||||||
|
HttpResponse::Ok()
|
||||||
|
.header("content-encoding", "gzip")
|
||||||
|
.body(data)
|
||||||
|
},
|
||||||
|
))))
|
||||||
|
});
|
||||||
|
|
||||||
|
// client request
|
||||||
|
let response = srv.block_on(srv.post().send_body(data.clone())).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.block_on(response.body()).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_client_brotli_encoding() {
|
||||||
|
let mut srv = TestServer::new(|| {
|
||||||
|
HttpService::new(App::new().service(web::resource("/").route(web::to(
|
||||||
|
|data: Bytes| {
|
||||||
|
let mut e = BrotliEncoder::new(Vec::new(), 5);
|
||||||
|
e.write_all(&data).unwrap();
|
||||||
|
let data = e.finish().unwrap();
|
||||||
|
HttpResponse::Ok()
|
||||||
|
.header("content-encoding", "br")
|
||||||
|
.body(data)
|
||||||
|
},
|
||||||
|
))))
|
||||||
|
});
|
||||||
|
|
||||||
|
// client request
|
||||||
|
let response = srv.block_on(srv.post().send_body(STR)).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// read response
|
||||||
|
let bytes = srv.block_on(response.body()).unwrap();
|
||||||
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_client_brotli_encoding_large_random() {
|
||||||
|
// let data = rand::thread_rng()
|
||||||
|
// .sample_iter(&rand::distributions::Alphanumeric)
|
||||||
|
// .take(70_000)
|
||||||
|
// .collect::<String>();
|
||||||
|
|
||||||
|
// let mut srv = test::TestServer::new(|app| {
|
||||||
|
// app.handler(|req: &HttpRequest| {
|
||||||
|
// req.body()
|
||||||
|
// .and_then(move |bytes: Bytes| {
|
||||||
|
// Ok(HttpResponse::Ok()
|
||||||
|
// .content_encoding(http::ContentEncoding::Gzip)
|
||||||
|
// .body(bytes))
|
||||||
|
// })
|
||||||
|
// .responder()
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // client request
|
||||||
|
// let request = srv
|
||||||
|
// .client(http::Method::POST, "/")
|
||||||
|
// .content_encoding(http::ContentEncoding::Br)
|
||||||
|
// .body(data.clone())
|
||||||
|
// .unwrap();
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// // read response
|
||||||
|
// let bytes = srv.execute(response.body()).unwrap();
|
||||||
|
// assert_eq!(bytes.len(), data.len());
|
||||||
|
// assert_eq!(bytes, Bytes::from(data));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[cfg(feature = "brotli")]
|
||||||
|
// #[test]
|
||||||
|
// fn test_client_deflate_encoding() {
|
||||||
|
// let mut srv = test::TestServer::new(|app| {
|
||||||
|
// app.handler(|req: &HttpRequest| {
|
||||||
|
// req.body()
|
||||||
|
// .and_then(|bytes: Bytes| {
|
||||||
|
// Ok(HttpResponse::Ok()
|
||||||
|
// .content_encoding(http::ContentEncoding::Br)
|
||||||
|
// .body(bytes))
|
||||||
|
// })
|
||||||
|
// .responder()
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // client request
|
||||||
|
// let request = srv
|
||||||
|
// .post()
|
||||||
|
// .content_encoding(http::ContentEncoding::Deflate)
|
||||||
|
// .body(STR)
|
||||||
|
// .unwrap();
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// // read response
|
||||||
|
// let bytes = srv.execute(response.body()).unwrap();
|
||||||
|
// assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_client_deflate_encoding_large_random() {
|
||||||
|
// let data = rand::thread_rng()
|
||||||
|
// .sample_iter(&rand::distributions::Alphanumeric)
|
||||||
|
// .take(70_000)
|
||||||
|
// .collect::<String>();
|
||||||
|
|
||||||
|
// let mut srv = test::TestServer::new(|app| {
|
||||||
|
// app.handler(|req: &HttpRequest| {
|
||||||
|
// req.body()
|
||||||
|
// .and_then(|bytes: Bytes| {
|
||||||
|
// Ok(HttpResponse::Ok()
|
||||||
|
// .content_encoding(http::ContentEncoding::Br)
|
||||||
|
// .body(bytes))
|
||||||
|
// })
|
||||||
|
// .responder()
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // client request
|
||||||
|
// let request = srv
|
||||||
|
// .post()
|
||||||
|
// .content_encoding(http::ContentEncoding::Deflate)
|
||||||
|
// .body(data.clone())
|
||||||
|
// .unwrap();
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// // read response
|
||||||
|
// let bytes = srv.execute(response.body()).unwrap();
|
||||||
|
// assert_eq!(bytes, Bytes::from(data));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_client_streaming_explicit() {
|
||||||
|
// let mut srv = test::TestServer::new(|app| {
|
||||||
|
// app.handler(|req: &HttpRequest| {
|
||||||
|
// req.body()
|
||||||
|
// .map_err(Error::from)
|
||||||
|
// .and_then(|body| {
|
||||||
|
// Ok(HttpResponse::Ok()
|
||||||
|
// .chunked()
|
||||||
|
// .content_encoding(http::ContentEncoding::Identity)
|
||||||
|
// .body(body))
|
||||||
|
// })
|
||||||
|
// .responder()
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let body = once(Ok(Bytes::from_static(STR.as_ref())));
|
||||||
|
|
||||||
|
// let request = srv.get().body(Body::Streaming(Box::new(body))).unwrap();
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// // read response
|
||||||
|
// let bytes = srv.execute(response.body()).unwrap();
|
||||||
|
// assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_body_streaming_implicit() {
|
||||||
|
// let mut srv = test::TestServer::new(|app| {
|
||||||
|
// app.handler(|_| {
|
||||||
|
// let body = once(Ok(Bytes::from_static(STR.as_ref())));
|
||||||
|
// HttpResponse::Ok()
|
||||||
|
// .content_encoding(http::ContentEncoding::Gzip)
|
||||||
|
// .body(Body::Streaming(Box::new(body)))
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let request = srv.get().finish().unwrap();
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// // read response
|
||||||
|
// let bytes = srv.execute(response.body()).unwrap();
|
||||||
|
// assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_client_cookie_handling() {
|
||||||
|
// use actix_web::http::Cookie;
|
||||||
|
// fn err() -> Error {
|
||||||
|
// use std::io::{Error as IoError, ErrorKind};
|
||||||
|
// // stub some generic error
|
||||||
|
// Error::from(IoError::from(ErrorKind::NotFound))
|
||||||
|
// }
|
||||||
|
// let cookie1 = Cookie::build("cookie1", "value1").finish();
|
||||||
|
// let cookie2 = Cookie::build("cookie2", "value2")
|
||||||
|
// .domain("www.example.org")
|
||||||
|
// .path("/")
|
||||||
|
// .secure(true)
|
||||||
|
// .http_only(true)
|
||||||
|
// .finish();
|
||||||
|
// // Q: are all these clones really necessary? A: Yes, possibly
|
||||||
|
// let cookie1b = cookie1.clone();
|
||||||
|
// let cookie2b = cookie2.clone();
|
||||||
|
// let mut srv = test::TestServer::new(move |app| {
|
||||||
|
// let cookie1 = cookie1b.clone();
|
||||||
|
// let cookie2 = cookie2b.clone();
|
||||||
|
// app.handler(move |req: &HttpRequest| {
|
||||||
|
// // Check cookies were sent correctly
|
||||||
|
// req.cookie("cookie1")
|
||||||
|
// .ok_or_else(err)
|
||||||
|
// .and_then(|c1| {
|
||||||
|
// if c1.value() == "value1" {
|
||||||
|
// Ok(())
|
||||||
|
// } else {
|
||||||
|
// Err(err())
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// .and_then(|()| req.cookie("cookie2").ok_or_else(err))
|
||||||
|
// .and_then(|c2| {
|
||||||
|
// if c2.value() == "value2" {
|
||||||
|
// Ok(())
|
||||||
|
// } else {
|
||||||
|
// Err(err())
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// // Send some cookies back
|
||||||
|
// .map(|_| {
|
||||||
|
// HttpResponse::Ok()
|
||||||
|
// .cookie(cookie1.clone())
|
||||||
|
// .cookie(cookie2.clone())
|
||||||
|
// .finish()
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let request = srv
|
||||||
|
// .get()
|
||||||
|
// .cookie(cookie1.clone())
|
||||||
|
// .cookie(cookie2.clone())
|
||||||
|
// .finish()
|
||||||
|
// .unwrap();
|
||||||
|
// let response = srv.execute(request.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
// let c1 = response.cookie("cookie1").expect("Missing cookie1");
|
||||||
|
// assert_eq!(c1, cookie1);
|
||||||
|
// let c2 = response.cookie("cookie2").expect("Missing cookie2");
|
||||||
|
// assert_eq!(c2, cookie2);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn test_default_headers() {
|
||||||
|
// let srv = test::TestServer::new(|app| app.handler(|_| HttpResponse::Ok().body(STR)));
|
||||||
|
|
||||||
|
// let request = srv.get().finish().unwrap();
|
||||||
|
// let repr = format!("{:?}", request);
|
||||||
|
// assert!(repr.contains("\"accept-encoding\": \"gzip, deflate\""));
|
||||||
|
// assert!(repr.contains(concat!(
|
||||||
|
// "\"user-agent\": \"actix-web/",
|
||||||
|
// env!("CARGO_PKG_VERSION"),
|
||||||
|
// "\""
|
||||||
|
// )));
|
||||||
|
|
||||||
|
// let request_override = srv
|
||||||
|
// .get()
|
||||||
|
// .header("User-Agent", "test")
|
||||||
|
// .header("Accept-Encoding", "over_test")
|
||||||
|
// .finish()
|
||||||
|
// .unwrap();
|
||||||
|
// let repr_override = format!("{:?}", request_override);
|
||||||
|
// assert!(repr_override.contains("\"user-agent\": \"test\""));
|
||||||
|
// assert!(repr_override.contains("\"accept-encoding\": \"over_test\""));
|
||||||
|
// assert!(!repr_override.contains("\"accept-encoding\": \"gzip, deflate\""));
|
||||||
|
// assert!(!repr_override.contains(concat!(
|
||||||
|
// "\"user-agent\": \"Actix-web/",
|
||||||
|
// env!("CARGO_PKG_VERSION"),
|
||||||
|
// "\""
|
||||||
|
// )));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn client_read_until_eof() {
|
||||||
|
// let addr = test::TestServer::unused_addr();
|
||||||
|
|
||||||
|
// thread::spawn(move || {
|
||||||
|
// let lst = net::TcpListener::bind(addr).unwrap();
|
||||||
|
|
||||||
|
// for stream in lst.incoming() {
|
||||||
|
// let mut stream = stream.unwrap();
|
||||||
|
// let mut b = [0; 1000];
|
||||||
|
// let _ = stream.read(&mut b).unwrap();
|
||||||
|
// let _ = stream
|
||||||
|
// .write_all(b"HTTP/1.1 200 OK\r\nconnection: close\r\n\r\nwelcome!");
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
// let mut sys = actix::System::new("test");
|
||||||
|
|
||||||
|
// // client request
|
||||||
|
// let req = client::ClientRequest::get(format!("http://{}/", addr).as_str())
|
||||||
|
// .finish()
|
||||||
|
// .unwrap();
|
||||||
|
// let response = sys.block_on(req.send()).unwrap();
|
||||||
|
// assert!(response.status().is_success());
|
||||||
|
|
||||||
|
// // read response
|
||||||
|
// let bytes = sys.block_on(response.body()).unwrap();
|
||||||
|
// assert_eq!(bytes, Bytes::from_static(b"welcome!"));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn client_basic_auth() {
|
||||||
|
// let mut srv =
|
||||||
|
// test::TestServer::new(|app| app.handler(|_| HttpResponse::Ok().body(STR)));
|
||||||
|
// /// set authorization header to Basic <base64 encoded username:password>
|
||||||
|
// let request = srv
|
||||||
|
// .get()
|
||||||
|
// .basic_auth("username", Some("password"))
|
||||||
|
// .finish()
|
||||||
|
// .unwrap();
|
||||||
|
// let repr = format!("{:?}", request);
|
||||||
|
// assert!(repr.contains("Basic dXNlcm5hbWU6cGFzc3dvcmQ="));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn client_bearer_auth() {
|
||||||
|
// let mut srv =
|
||||||
|
// test::TestServer::new(|app| app.handler(|_| HttpResponse::Ok().body(STR)));
|
||||||
|
// /// set authorization header to Bearer <token>
|
||||||
|
// let request = srv
|
||||||
|
// .get()
|
||||||
|
// .bearer_auth("someS3cr3tAutht0k3n")
|
||||||
|
// .finish()
|
||||||
|
// .unwrap();
|
||||||
|
// let repr = format!("{:?}", request);
|
||||||
|
// assert!(repr.contains("Bearer someS3cr3tAutht0k3n"));
|
||||||
|
// }
|
@ -65,7 +65,7 @@ fn test_body_gzip() {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut response = srv.block_on(srv.get().send()).unwrap();
|
let mut response = srv.block_on(srv.get().no_decompress().send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
@ -95,7 +95,7 @@ fn test_body_gzip_large() {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut response = srv.block_on(srv.get().send()).unwrap();
|
let mut response = srv.block_on(srv.get().no_decompress().send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
@ -128,7 +128,7 @@ fn test_body_gzip_large_random() {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut response = srv.block_on(srv.get().send()).unwrap();
|
let mut response = srv.block_on(srv.get().no_decompress().send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
@ -156,7 +156,7 @@ fn test_body_chunked_implicit() {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut response = srv.block_on(srv.get().send()).unwrap();
|
let mut response = srv.block_on(srv.get().no_decompress().send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
response.headers().get(TRANSFER_ENCODING).unwrap(),
|
response.headers().get(TRANSFER_ENCODING).unwrap(),
|
||||||
@ -188,7 +188,12 @@ fn test_body_br_streaming() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let mut response = srv
|
let mut response = srv
|
||||||
.block_on(srv.get().header(ACCEPT_ENCODING, "br").send())
|
.block_on(
|
||||||
|
srv.get()
|
||||||
|
.header(ACCEPT_ENCODING, "br")
|
||||||
|
.no_decompress()
|
||||||
|
.send(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -258,7 +263,7 @@ fn test_body_deflate() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let mut response = srv.block_on(srv.get().send()).unwrap();
|
let mut response = srv.block_on(srv.get().no_decompress().send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
@ -285,7 +290,12 @@ fn test_body_brotli() {
|
|||||||
|
|
||||||
// client request
|
// client request
|
||||||
let mut response = srv
|
let mut response = srv
|
||||||
.block_on(srv.get().header(ACCEPT_ENCODING, "br").send())
|
.block_on(
|
||||||
|
srv.get()
|
||||||
|
.header(ACCEPT_ENCODING, "br")
|
||||||
|
.no_decompress()
|
||||||
|
.send(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user