mirror of
https://github.com/fafhrd91/actix-web
synced 2024-11-27 17:52:56 +01:00
change rustfmt line width to 96
This commit is contained in:
parent
c1af5089b9
commit
31d9ed81c5
@ -49,10 +49,7 @@ impl fmt::Debug for ChunkedReadFile {
|
|||||||
impl Stream for ChunkedReadFile {
|
impl Stream for ChunkedReadFile {
|
||||||
type Item = Result<Bytes, Error>;
|
type Item = Result<Bytes, Error>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
mut self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
let this = self.as_mut().get_mut();
|
let this = self.as_mut().get_mut();
|
||||||
match this.state {
|
match this.state {
|
||||||
ChunkedReadFileState::File(ref mut file) => {
|
ChunkedReadFileState::File(ref mut file) => {
|
||||||
@ -68,16 +65,13 @@ impl Stream for ChunkedReadFile {
|
|||||||
.expect("ChunkedReadFile polled after completion");
|
.expect("ChunkedReadFile polled after completion");
|
||||||
|
|
||||||
let fut = spawn_blocking(move || {
|
let fut = spawn_blocking(move || {
|
||||||
let max_bytes =
|
let max_bytes = cmp::min(size.saturating_sub(counter), 65_536) as usize;
|
||||||
cmp::min(size.saturating_sub(counter), 65_536) as usize;
|
|
||||||
|
|
||||||
let mut buf = Vec::with_capacity(max_bytes);
|
let mut buf = Vec::with_capacity(max_bytes);
|
||||||
file.seek(io::SeekFrom::Start(offset))?;
|
file.seek(io::SeekFrom::Start(offset))?;
|
||||||
|
|
||||||
let n_bytes = file
|
let n_bytes =
|
||||||
.by_ref()
|
file.by_ref().take(max_bytes as u64).read_to_end(&mut buf)?;
|
||||||
.take(max_bytes as u64)
|
|
||||||
.read_to_end(&mut buf)?;
|
|
||||||
|
|
||||||
if n_bytes == 0 {
|
if n_bytes == 0 {
|
||||||
return Err(io::ErrorKind::UnexpectedEof.into());
|
return Err(io::ErrorKind::UnexpectedEof.into());
|
||||||
|
@ -66,9 +66,7 @@ pub(crate) fn directory_listing(
|
|||||||
if dir.is_visible(&entry) {
|
if dir.is_visible(&entry) {
|
||||||
let entry = entry.unwrap();
|
let entry = entry.unwrap();
|
||||||
let p = match entry.path().strip_prefix(&dir.path) {
|
let p = match entry.path().strip_prefix(&dir.path) {
|
||||||
Ok(p) if cfg!(windows) => {
|
Ok(p) if cfg!(windows) => base.join(p).to_string_lossy().replace("\\", "/"),
|
||||||
base.join(p).to_string_lossy().replace("\\", "/")
|
|
||||||
}
|
|
||||||
Ok(p) => base.join(p).to_string_lossy().into_owned(),
|
Ok(p) => base.join(p).to_string_lossy().into_owned(),
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
};
|
};
|
||||||
|
@ -2,9 +2,7 @@ use std::{cell::RefCell, fmt, io, path::PathBuf, rc::Rc};
|
|||||||
|
|
||||||
use actix_service::{boxed, IntoServiceFactory, ServiceFactory, ServiceFactoryExt};
|
use actix_service::{boxed, IntoServiceFactory, ServiceFactory, ServiceFactoryExt};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::{
|
dev::{AppService, HttpServiceFactory, ResourceDef, ServiceRequest, ServiceResponse},
|
||||||
AppService, HttpServiceFactory, ResourceDef, ServiceRequest, ServiceResponse,
|
|
||||||
},
|
|
||||||
error::Error,
|
error::Error,
|
||||||
guard::Guard,
|
guard::Guard,
|
||||||
http::header::DispositionType,
|
http::header::DispositionType,
|
||||||
@ -13,8 +11,8 @@ use actix_web::{
|
|||||||
use futures_util::future::{ok, FutureExt, LocalBoxFuture};
|
use futures_util::future::{ok, FutureExt, LocalBoxFuture};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
directory_listing, named, Directory, DirectoryRenderer, FilesService,
|
directory_listing, named, Directory, DirectoryRenderer, FilesService, HttpNewService,
|
||||||
HttpNewService, MimeOverride,
|
MimeOverride,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Static files handling service.
|
/// Static files handling service.
|
||||||
@ -129,8 +127,8 @@ impl Files {
|
|||||||
/// Set custom directory renderer
|
/// Set custom directory renderer
|
||||||
pub fn files_listing_renderer<F>(mut self, f: F) -> Self
|
pub fn files_listing_renderer<F>(mut self, f: F) -> Self
|
||||||
where
|
where
|
||||||
for<'r, 's> F: Fn(&'r Directory, &'s HttpRequest) -> Result<ServiceResponse, io::Error>
|
for<'r, 's> F:
|
||||||
+ 'static,
|
Fn(&'r Directory, &'s HttpRequest) -> Result<ServiceResponse, io::Error> + 'static,
|
||||||
{
|
{
|
||||||
self.renderer = Rc::new(f);
|
self.renderer = Rc::new(f);
|
||||||
self
|
self
|
||||||
|
@ -98,8 +98,7 @@ mod tests {
|
|||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_if_modified_since_without_if_none_match() {
|
async fn test_if_modified_since_without_if_none_match() {
|
||||||
let file = NamedFile::open("Cargo.toml").unwrap();
|
let file = NamedFile::open("Cargo.toml").unwrap();
|
||||||
let since =
|
let since = header::HttpDate::from(SystemTime::now().add(Duration::from_secs(60)));
|
||||||
header::HttpDate::from(SystemTime::now().add(Duration::from_secs(60)));
|
|
||||||
|
|
||||||
let req = TestRequest::default()
|
let req = TestRequest::default()
|
||||||
.insert_header((header::IF_MODIFIED_SINCE, since))
|
.insert_header((header::IF_MODIFIED_SINCE, since))
|
||||||
@ -123,8 +122,7 @@ mod tests {
|
|||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_if_modified_since_with_if_none_match() {
|
async fn test_if_modified_since_with_if_none_match() {
|
||||||
let file = NamedFile::open("Cargo.toml").unwrap();
|
let file = NamedFile::open("Cargo.toml").unwrap();
|
||||||
let since =
|
let since = header::HttpDate::from(SystemTime::now().add(Duration::from_secs(60)));
|
||||||
header::HttpDate::from(SystemTime::now().add(Duration::from_secs(60)));
|
|
||||||
|
|
||||||
let req = TestRequest::default()
|
let req = TestRequest::default()
|
||||||
.insert_header((header::IF_NONE_MATCH, "miss_etag"))
|
.insert_header((header::IF_NONE_MATCH, "miss_etag"))
|
||||||
@ -212,8 +210,7 @@ mod tests {
|
|||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_named_file_non_ascii_file_name() {
|
async fn test_named_file_non_ascii_file_name() {
|
||||||
let mut file =
|
let mut file =
|
||||||
NamedFile::from_file(File::open("Cargo.toml").unwrap(), "貨物.toml")
|
NamedFile::from_file(File::open("Cargo.toml").unwrap(), "貨物.toml").unwrap();
|
||||||
.unwrap();
|
|
||||||
{
|
{
|
||||||
file.file();
|
file.file();
|
||||||
let _f: &File = &file;
|
let _f: &File = &file;
|
||||||
@ -605,10 +602,9 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_static_files() {
|
async fn test_static_files() {
|
||||||
let srv = test::init_service(
|
let srv =
|
||||||
App::new().service(Files::new("/", ".").show_files_listing()),
|
test::init_service(App::new().service(Files::new("/", ".").show_files_listing()))
|
||||||
)
|
.await;
|
||||||
.await;
|
|
||||||
let req = TestRequest::with_uri("/missing").to_request();
|
let req = TestRequest::with_uri("/missing").to_request();
|
||||||
|
|
||||||
let resp = test::call_service(&srv, req).await;
|
let resp = test::call_service(&srv, req).await;
|
||||||
@ -620,10 +616,9 @@ mod tests {
|
|||||||
let resp = test::call_service(&srv, req).await;
|
let resp = test::call_service(&srv, req).await;
|
||||||
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
|
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
|
||||||
|
|
||||||
let srv = test::init_service(
|
let srv =
|
||||||
App::new().service(Files::new("/", ".").show_files_listing()),
|
test::init_service(App::new().service(Files::new("/", ".").show_files_listing()))
|
||||||
)
|
.await;
|
||||||
.await;
|
|
||||||
let req = TestRequest::with_uri("/tests").to_request();
|
let req = TestRequest::with_uri("/tests").to_request();
|
||||||
let resp = test::call_service(&srv, req).await;
|
let resp = test::call_service(&srv, req).await;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -11,8 +11,7 @@ use actix_web::{
|
|||||||
dev::{BodyEncoding, SizedStream},
|
dev::{BodyEncoding, SizedStream},
|
||||||
http::{
|
http::{
|
||||||
header::{
|
header::{
|
||||||
self, Charset, ContentDisposition, DispositionParam, DispositionType,
|
self, Charset, ContentDisposition, DispositionParam, DispositionType, ExtendedValue,
|
||||||
ExtendedValue,
|
|
||||||
},
|
},
|
||||||
ContentEncoding, StatusCode,
|
ContentEncoding, StatusCode,
|
||||||
},
|
},
|
||||||
@ -395,18 +394,10 @@ impl NamedFile {
|
|||||||
resp.encoding(ContentEncoding::Identity);
|
resp.encoding(ContentEncoding::Identity);
|
||||||
resp.insert_header((
|
resp.insert_header((
|
||||||
header::CONTENT_RANGE,
|
header::CONTENT_RANGE,
|
||||||
format!(
|
format!("bytes {}-{}/{}", offset, offset + length - 1, self.md.len()),
|
||||||
"bytes {}-{}/{}",
|
|
||||||
offset,
|
|
||||||
offset + length - 1,
|
|
||||||
self.md.len()
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
resp.insert_header((
|
resp.insert_header((header::CONTENT_RANGE, format!("bytes */{}", length)));
|
||||||
header::CONTENT_RANGE,
|
|
||||||
format!("bytes */{}", length),
|
|
||||||
));
|
|
||||||
return resp.status(StatusCode::RANGE_NOT_SATISFIABLE).finish();
|
return resp.status(StatusCode::RANGE_NOT_SATISFIABLE).finish();
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -46,8 +46,7 @@ impl HttpRange {
|
|||||||
if start_str.is_empty() {
|
if start_str.is_empty() {
|
||||||
// If no start is specified, end specifies the
|
// If no start is specified, end specifies the
|
||||||
// range start relative to the end of the file.
|
// range start relative to the end of the file.
|
||||||
let mut length: i64 =
|
let mut length: i64 = end_str.parse().map_err(|_| ParseRangeErr(()))?;
|
||||||
end_str.parse().map_err(|_| ParseRangeErr(()))?;
|
|
||||||
|
|
||||||
if length > size_sig {
|
if length > size_sig {
|
||||||
length = size_sig;
|
length = size_sig;
|
||||||
@ -72,8 +71,7 @@ impl HttpRange {
|
|||||||
// If no end is specified, range extends to end of the file.
|
// If no end is specified, range extends to end of the file.
|
||||||
size_sig - start
|
size_sig - start
|
||||||
} else {
|
} else {
|
||||||
let mut end: i64 =
|
let mut end: i64 = end_str.parse().map_err(|_| ParseRangeErr(()))?;
|
||||||
end_str.parse().map_err(|_| ParseRangeErr(()))?;
|
|
||||||
|
|
||||||
if start > end {
|
if start > end {
|
||||||
return Err(ParseRangeErr(()));
|
return Err(ParseRangeErr(()));
|
||||||
|
@ -11,8 +11,8 @@ use actix_web::{
|
|||||||
use futures_util::future::{ok, Either, LocalBoxFuture, Ready};
|
use futures_util::future::{ok, Either, LocalBoxFuture, Ready};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
named, Directory, DirectoryRenderer, FilesError, HttpService, MimeOverride,
|
named, Directory, DirectoryRenderer, FilesError, HttpService, MimeOverride, NamedFile,
|
||||||
NamedFile, PathBufWrap,
|
PathBufWrap,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Assembled file serving service.
|
/// Assembled file serving service.
|
||||||
@ -138,8 +138,7 @@ impl Service<ServiceRequest> for FilesService {
|
|||||||
match NamedFile::open(path) {
|
match NamedFile::open(path) {
|
||||||
Ok(mut named_file) => {
|
Ok(mut named_file) => {
|
||||||
if let Some(ref mime_override) = self.mime_override {
|
if let Some(ref mime_override) = self.mime_override {
|
||||||
let new_disposition =
|
let new_disposition = mime_override(&named_file.content_type.type_());
|
||||||
mime_override(&named_file.content_type.type_());
|
|
||||||
named_file.content_disposition.disposition = new_disposition;
|
named_file.content_disposition.disposition = new_disposition;
|
||||||
}
|
}
|
||||||
named_file.flags = self.file_flags;
|
named_file.flags = self.file_flags;
|
||||||
|
@ -23,10 +23,9 @@ async fn test_utf8_file_contents() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// prefer UTF-8 encoding
|
// prefer UTF-8 encoding
|
||||||
let srv = test::init_service(
|
let srv =
|
||||||
App::new().service(Files::new("/", "./tests").prefer_utf8(true)),
|
test::init_service(App::new().service(Files::new("/", "./tests").prefer_utf8(true)))
|
||||||
)
|
.await;
|
||||||
.await;
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/utf8.txt").to_request();
|
let req = TestRequest::with_uri("/utf8.txt").to_request();
|
||||||
let res = test::call_service(&srv, req).await;
|
let res = test::call_service(&srv, req).await;
|
||||||
|
@ -120,8 +120,7 @@ pub async fn test_server_with_addr<F: ServiceFactory<TcpStream>>(
|
|||||||
/// Get first available unused address
|
/// Get first available unused address
|
||||||
pub fn unused_addr() -> net::SocketAddr {
|
pub fn unused_addr() -> net::SocketAddr {
|
||||||
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
|
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
|
||||||
let socket =
|
let socket = Socket::new(Domain::ipv4(), Type::stream(), Some(Protocol::tcp())).unwrap();
|
||||||
Socket::new(Domain::ipv4(), Type::stream(), Some(Protocol::tcp())).unwrap();
|
|
||||||
socket.bind(&addr.into()).unwrap();
|
socket.bind(&addr.into()).unwrap();
|
||||||
socket.set_reuse_address(true).unwrap();
|
socket.set_reuse_address(true).unwrap();
|
||||||
let tcp = socket.into_tcp_listener();
|
let tcp = socket.into_tcp_listener();
|
||||||
@ -248,8 +247,7 @@ impl TestServer {
|
|||||||
pub async fn ws_at(
|
pub async fn ws_at(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &str,
|
path: &str,
|
||||||
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError>
|
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError> {
|
||||||
{
|
|
||||||
let url = self.url(path);
|
let url = self.url(path);
|
||||||
let connect = self.client.ws(url).connect();
|
let connect = self.client.ws(url).connect();
|
||||||
connect.await.map(|(_, framed)| framed)
|
connect.await.map(|(_, framed)| framed)
|
||||||
@ -258,8 +256,7 @@ impl TestServer {
|
|||||||
/// Connect to a websocket server
|
/// Connect to a websocket server
|
||||||
pub async fn ws(
|
pub async fn ws(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError>
|
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError> {
|
||||||
{
|
|
||||||
self.ws_at("/").await
|
self.ws_at("/").await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,9 +9,9 @@ use http::{header, Method, Uri, Version};
|
|||||||
|
|
||||||
use crate::extensions::Extensions;
|
use crate::extensions::Extensions;
|
||||||
use crate::header::HeaderMap;
|
use crate::header::HeaderMap;
|
||||||
use crate::HttpMessage;
|
|
||||||
use crate::message::{Message, RequestHead};
|
use crate::message::{Message, RequestHead};
|
||||||
use crate::payload::{Payload, PayloadStream};
|
use crate::payload::{Payload, PayloadStream};
|
||||||
|
use crate::HttpMessage;
|
||||||
|
|
||||||
/// Request
|
/// Request
|
||||||
pub struct Request<P = PayloadStream> {
|
pub struct Request<P = PayloadStream> {
|
||||||
|
@ -13,9 +13,7 @@ use futures_util::stream::{LocalBoxStream, Stream, StreamExt};
|
|||||||
|
|
||||||
use actix_utils::task::LocalWaker;
|
use actix_utils::task::LocalWaker;
|
||||||
use actix_web::error::{ParseError, PayloadError};
|
use actix_web::error::{ParseError, PayloadError};
|
||||||
use actix_web::http::header::{
|
use actix_web::http::header::{self, ContentDisposition, HeaderMap, HeaderName, HeaderValue};
|
||||||
self, ContentDisposition, HeaderMap, HeaderName, HeaderValue,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::error::MultipartError;
|
use crate::error::MultipartError;
|
||||||
|
|
||||||
@ -120,10 +118,7 @@ impl Multipart {
|
|||||||
impl Stream for Multipart {
|
impl Stream for Multipart {
|
||||||
type Item = Result<Field, MultipartError>;
|
type Item = Result<Field, MultipartError>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
mut self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
if let Some(err) = self.error.take() {
|
if let Some(err) = self.error.take() {
|
||||||
Poll::Ready(Some(Err(err)))
|
Poll::Ready(Some(Err(err)))
|
||||||
} else if self.safety.current() {
|
} else if self.safety.current() {
|
||||||
@ -142,9 +137,7 @@ impl Stream for Multipart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl InnerMultipart {
|
impl InnerMultipart {
|
||||||
fn read_headers(
|
fn read_headers(payload: &mut PayloadBuffer) -> Result<Option<HeaderMap>, MultipartError> {
|
||||||
payload: &mut PayloadBuffer,
|
|
||||||
) -> Result<Option<HeaderMap>, MultipartError> {
|
|
||||||
match payload.read_until(b"\r\n\r\n")? {
|
match payload.read_until(b"\r\n\r\n")? {
|
||||||
None => {
|
None => {
|
||||||
if payload.eof {
|
if payload.eof {
|
||||||
@ -226,8 +219,7 @@ impl InnerMultipart {
|
|||||||
if chunk.len() < boundary.len() {
|
if chunk.len() < boundary.len() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if &chunk[..2] == b"--"
|
if &chunk[..2] == b"--" && &chunk[2..chunk.len() - 2] == boundary.as_bytes()
|
||||||
&& &chunk[2..chunk.len() - 2] == boundary.as_bytes()
|
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
@ -273,9 +265,7 @@ impl InnerMultipart {
|
|||||||
match field.borrow_mut().poll(safety) {
|
match field.borrow_mut().poll(safety) {
|
||||||
Poll::Pending => return Poll::Pending,
|
Poll::Pending => return Poll::Pending,
|
||||||
Poll::Ready(Some(Ok(_))) => continue,
|
Poll::Ready(Some(Ok(_))) => continue,
|
||||||
Poll::Ready(Some(Err(e))) => {
|
Poll::Ready(Some(Err(e))) => return Poll::Ready(Some(Err(e))),
|
||||||
return Poll::Ready(Some(Err(e)))
|
|
||||||
}
|
|
||||||
Poll::Ready(None) => true,
|
Poll::Ready(None) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -311,10 +301,7 @@ impl InnerMultipart {
|
|||||||
}
|
}
|
||||||
// read boundary
|
// read boundary
|
||||||
InnerState::Boundary => {
|
InnerState::Boundary => {
|
||||||
match InnerMultipart::read_boundary(
|
match InnerMultipart::read_boundary(&mut *payload, &self.boundary)? {
|
||||||
&mut *payload,
|
|
||||||
&self.boundary,
|
|
||||||
)? {
|
|
||||||
None => return Poll::Pending,
|
None => return Poll::Pending,
|
||||||
Some(eof) => {
|
Some(eof) => {
|
||||||
if eof {
|
if eof {
|
||||||
@ -418,8 +405,7 @@ impl Field {
|
|||||||
pub fn content_disposition(&self) -> Option<ContentDisposition> {
|
pub fn content_disposition(&self) -> Option<ContentDisposition> {
|
||||||
// RFC 7578: 'Each part MUST contain a Content-Disposition header field
|
// RFC 7578: 'Each part MUST contain a Content-Disposition header field
|
||||||
// where the disposition type is "form-data".'
|
// where the disposition type is "form-data".'
|
||||||
if let Some(content_disposition) = self.headers.get(&header::CONTENT_DISPOSITION)
|
if let Some(content_disposition) = self.headers.get(&header::CONTENT_DISPOSITION) {
|
||||||
{
|
|
||||||
ContentDisposition::from_raw(content_disposition).ok()
|
ContentDisposition::from_raw(content_disposition).ok()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -430,15 +416,10 @@ impl Field {
|
|||||||
impl Stream for Field {
|
impl Stream for Field {
|
||||||
type Item = Result<Bytes, MultipartError>;
|
type Item = Result<Bytes, MultipartError>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
if self.safety.current() {
|
if self.safety.current() {
|
||||||
let mut inner = self.inner.borrow_mut();
|
let mut inner = self.inner.borrow_mut();
|
||||||
if let Some(mut payload) =
|
if let Some(mut payload) = inner.payload.as_ref().unwrap().get_mut(&self.safety) {
|
||||||
inner.payload.as_ref().unwrap().get_mut(&self.safety)
|
|
||||||
{
|
|
||||||
payload.poll_stream(cx)?;
|
payload.poll_stream(cx)?;
|
||||||
}
|
}
|
||||||
inner.poll(&self.safety)
|
inner.poll(&self.safety)
|
||||||
@ -607,8 +588,7 @@ impl InnerField {
|
|||||||
return Poll::Ready(None);
|
return Poll::Ready(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s)
|
let result = if let Some(mut payload) = self.payload.as_ref().unwrap().get_mut(s) {
|
||||||
{
|
|
||||||
if !self.eof {
|
if !self.eof {
|
||||||
let res = if let Some(ref mut len) = self.length {
|
let res = if let Some(ref mut len) = self.length {
|
||||||
InnerField::read_len(&mut *payload, len)
|
InnerField::read_len(&mut *payload, len)
|
||||||
@ -628,7 +608,9 @@ impl InnerField {
|
|||||||
Ok(None) => Poll::Pending,
|
Ok(None) => Poll::Pending,
|
||||||
Ok(Some(line)) => {
|
Ok(Some(line)) => {
|
||||||
if line.as_ref() != b"\r\n" {
|
if line.as_ref() != b"\r\n" {
|
||||||
log::warn!("multipart field did not read all the data or it is malformed");
|
log::warn!(
|
||||||
|
"multipart field did not read all the data or it is malformed"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Poll::Ready(None)
|
Poll::Ready(None)
|
||||||
}
|
}
|
||||||
@ -804,9 +786,7 @@ impl PayloadBuffer {
|
|||||||
/// Read bytes until new line delimiter or eof
|
/// Read bytes until new line delimiter or eof
|
||||||
pub fn readline_or_eof(&mut self) -> Result<Option<Bytes>, MultipartError> {
|
pub fn readline_or_eof(&mut self) -> Result<Option<Bytes>, MultipartError> {
|
||||||
match self.readline() {
|
match self.readline() {
|
||||||
Err(MultipartError::Incomplete) if self.eof => {
|
Err(MultipartError::Incomplete) if self.eof => Ok(Some(self.buf.split().freeze())),
|
||||||
Ok(Some(self.buf.split().freeze()))
|
|
||||||
}
|
|
||||||
line => line,
|
line => line,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -902,10 +882,7 @@ mod tests {
|
|||||||
impl Stream for SlowStream {
|
impl Stream for SlowStream {
|
||||||
type Item = Result<Bytes, PayloadError>;
|
type Item = Result<Bytes, PayloadError>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
let this = self.get_mut();
|
let this = self.get_mut();
|
||||||
if !this.ready {
|
if !this.ready {
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
|
@ -3,9 +3,7 @@ use std::future::Future;
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
use actix::dev::{
|
use actix::dev::{AsyncContextParts, ContextFut, ContextParts, Envelope, Mailbox, ToEnvelope};
|
||||||
AsyncContextParts, ContextFut, ContextParts, Envelope, Mailbox, ToEnvelope,
|
|
||||||
};
|
|
||||||
use actix::fut::ActorFuture;
|
use actix::fut::ActorFuture;
|
||||||
use actix::{
|
use actix::{
|
||||||
Actor, ActorContext, ActorState, Addr, AsyncContext, Handler, Message, SpawnHandle,
|
Actor, ActorContext, ActorState, Addr, AsyncContext, Handler, Message, SpawnHandle,
|
||||||
@ -165,10 +163,7 @@ where
|
|||||||
{
|
{
|
||||||
type Item = Result<Bytes, Error>;
|
type Item = Result<Bytes, Error>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
mut self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
if self.fut.alive() {
|
if self.fut.alive() {
|
||||||
let _ = Pin::new(&mut self.fut).poll(cx);
|
let _ = Pin::new(&mut self.fut).poll(cx);
|
||||||
}
|
}
|
||||||
@ -233,10 +228,11 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_default_resource() {
|
async fn test_default_resource() {
|
||||||
let srv = init_service(App::new().service(web::resource("/test").to(|| {
|
let srv =
|
||||||
HttpResponse::Ok().streaming(HttpContext::create(MyActor { count: 0 }))
|
init_service(App::new().service(web::resource("/test").to(|| {
|
||||||
})))
|
HttpResponse::Ok().streaming(HttpContext::create(MyActor { count: 0 }))
|
||||||
.await;
|
})))
|
||||||
|
.await;
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/test").to_request();
|
let req = TestRequest::with_uri("/test").to_request();
|
||||||
let resp = call_service(&srv, req).await;
|
let resp = call_service(&srv, req).await;
|
||||||
|
@ -7,13 +7,12 @@ use std::task::{Context, Poll};
|
|||||||
use std::{collections::VecDeque, convert::TryFrom};
|
use std::{collections::VecDeque, convert::TryFrom};
|
||||||
|
|
||||||
use actix::dev::{
|
use actix::dev::{
|
||||||
AsyncContextParts, ContextFut, ContextParts, Envelope, Mailbox, StreamHandler,
|
AsyncContextParts, ContextFut, ContextParts, Envelope, Mailbox, StreamHandler, ToEnvelope,
|
||||||
ToEnvelope,
|
|
||||||
};
|
};
|
||||||
use actix::fut::ActorFuture;
|
use actix::fut::ActorFuture;
|
||||||
use actix::{
|
use actix::{
|
||||||
Actor, ActorContext, ActorState, Addr, AsyncContext, Handler,
|
Actor, ActorContext, ActorState, Addr, AsyncContext, Handler, Message as ActixMessage,
|
||||||
Message as ActixMessage, SpawnHandle,
|
SpawnHandle,
|
||||||
};
|
};
|
||||||
use actix_codec::{Decoder, Encoder};
|
use actix_codec::{Decoder, Encoder};
|
||||||
use actix_http::ws::{hash_key, Codec};
|
use actix_http::ws::{hash_key, Codec};
|
||||||
@ -32,8 +31,7 @@ use tokio::sync::oneshot::Sender;
|
|||||||
/// Perform WebSocket handshake and start actor.
|
/// Perform WebSocket handshake and start actor.
|
||||||
pub fn start<A, T>(actor: A, req: &HttpRequest, stream: T) -> Result<HttpResponse, Error>
|
pub fn start<A, T>(actor: A, req: &HttpRequest, stream: T) -> Result<HttpResponse, Error>
|
||||||
where
|
where
|
||||||
A: Actor<Context = WebsocketContext<A>>
|
A: Actor<Context = WebsocketContext<A>> + StreamHandler<Result<Message, ProtocolError>>,
|
||||||
+ StreamHandler<Result<Message, ProtocolError>>,
|
|
||||||
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
|
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
|
||||||
{
|
{
|
||||||
let mut res = handshake(req)?;
|
let mut res = handshake(req)?;
|
||||||
@ -57,8 +55,7 @@ pub fn start_with_addr<A, T>(
|
|||||||
stream: T,
|
stream: T,
|
||||||
) -> Result<(Addr<A>, HttpResponse), Error>
|
) -> Result<(Addr<A>, HttpResponse), Error>
|
||||||
where
|
where
|
||||||
A: Actor<Context = WebsocketContext<A>>
|
A: Actor<Context = WebsocketContext<A>> + StreamHandler<Result<Message, ProtocolError>>,
|
||||||
+ StreamHandler<Result<Message, ProtocolError>>,
|
|
||||||
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
|
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
|
||||||
{
|
{
|
||||||
let mut res = handshake(req)?;
|
let mut res = handshake(req)?;
|
||||||
@ -76,8 +73,7 @@ pub fn start_with_protocols<A, T>(
|
|||||||
stream: T,
|
stream: T,
|
||||||
) -> Result<HttpResponse, Error>
|
) -> Result<HttpResponse, Error>
|
||||||
where
|
where
|
||||||
A: Actor<Context = WebsocketContext<A>>
|
A: Actor<Context = WebsocketContext<A>> + StreamHandler<Result<Message, ProtocolError>>,
|
||||||
+ StreamHandler<Result<Message, ProtocolError>>,
|
|
||||||
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
|
T: Stream<Item = Result<Bytes, PayloadError>> + 'static,
|
||||||
{
|
{
|
||||||
let mut res = handshake_with_protocols(req, protocols)?;
|
let mut res = handshake_with_protocols(req, protocols)?;
|
||||||
@ -301,10 +297,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Websocket context
|
/// Create a new Websocket context
|
||||||
pub fn with_factory<S, F>(
|
pub fn with_factory<S, F>(stream: S, f: F) -> impl Stream<Item = Result<Bytes, Error>>
|
||||||
stream: S,
|
|
||||||
f: F,
|
|
||||||
) -> impl Stream<Item = Result<Bytes, Error>>
|
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self) -> A + 'static,
|
F: FnOnce(&mut Self) -> A + 'static,
|
||||||
A: StreamHandler<Result<Message, ProtocolError>>,
|
A: StreamHandler<Result<Message, ProtocolError>>,
|
||||||
@ -423,10 +416,7 @@ where
|
|||||||
{
|
{
|
||||||
type Item = Result<Bytes, Error>;
|
type Item = Result<Bytes, Error>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
let this = self.get_mut();
|
let this = self.get_mut();
|
||||||
|
|
||||||
if this.fut.alive() {
|
if this.fut.alive() {
|
||||||
@ -493,10 +483,7 @@ where
|
|||||||
{
|
{
|
||||||
type Item = Result<Message, ProtocolError>;
|
type Item = Result<Message, ProtocolError>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
mut self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
let mut this = self.as_mut().project();
|
let mut this = self.as_mut().project();
|
||||||
|
|
||||||
if !*this.closed {
|
if !*this.closed {
|
||||||
@ -512,9 +499,10 @@ where
|
|||||||
}
|
}
|
||||||
Poll::Pending => break,
|
Poll::Pending => break,
|
||||||
Poll::Ready(Some(Err(e))) => {
|
Poll::Ready(Some(Err(e))) => {
|
||||||
return Poll::Ready(Some(Err(ProtocolError::Io(
|
return Poll::Ready(Some(Err(ProtocolError::Io(io::Error::new(
|
||||||
io::Error::new(io::ErrorKind::Other, format!("{}", e)),
|
io::ErrorKind::Other,
|
||||||
))));
|
format!("{}", e),
|
||||||
|
)))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,7 @@ impl Actor for Ws {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for Ws {
|
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for Ws {
|
||||||
fn handle(
|
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
|
||||||
&mut self,
|
|
||||||
msg: Result<ws::Message, ws::ProtocolError>,
|
|
||||||
ctx: &mut Self::Context,
|
|
||||||
) {
|
|
||||||
match msg.unwrap() {
|
match msg.unwrap() {
|
||||||
ws::Message::Ping(msg) => ctx.pong(&msg),
|
ws::Message::Ping(msg) => ctx.pong(&msg),
|
||||||
ws::Message::Text(text) => ctx.text(text),
|
ws::Message::Text(text) => ctx.text(text),
|
||||||
@ -30,9 +26,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for Ws {
|
|||||||
async fn test_simple() {
|
async fn test_simple() {
|
||||||
let mut srv = test::start(|| {
|
let mut srv = test::start(|| {
|
||||||
App::new().service(web::resource("/").to(
|
App::new().service(web::resource("/").to(
|
||||||
|req: HttpRequest, stream: web::Payload| async move {
|
|req: HttpRequest, stream: web::Payload| async move { ws::start(Ws, &req, stream) },
|
||||||
ws::start(Ws, &req, stream)
|
|
||||||
},
|
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,9 +4,7 @@ use std::task::{Context, Poll};
|
|||||||
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
|
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
|
||||||
use actix_web::http::header::{HeaderName, HeaderValue};
|
use actix_web::http::header::{HeaderName, HeaderValue};
|
||||||
use actix_web::{http, test, web::Path, App, Error, HttpResponse, Responder};
|
use actix_web::{http, test, web::Path, App, Error, HttpResponse, Responder};
|
||||||
use actix_web_codegen::{
|
use actix_web_codegen::{connect, delete, get, head, options, patch, post, put, route, trace};
|
||||||
connect, delete, get, head, options, patch, post, put, route, trace,
|
|
||||||
};
|
|
||||||
use futures_util::future::{self, LocalBoxFuture};
|
use futures_util::future::{self, LocalBoxFuture};
|
||||||
|
|
||||||
// Make sure that we can name function as 'config'
|
// Make sure that we can name function as 'config'
|
||||||
|
@ -82,8 +82,7 @@ where
|
|||||||
let connection = fut.await?;
|
let connection = fut.await?;
|
||||||
|
|
||||||
// send request
|
// send request
|
||||||
let (head, framed) =
|
let (head, framed) = connection.open_tunnel(RequestHeadType::from(head)).await?;
|
||||||
connection.open_tunnel(RequestHeadType::from(head)).await?;
|
|
||||||
|
|
||||||
let framed = framed.into_map_io(|io| BoxedSocket(Box::new(Socket(io))));
|
let framed = framed.into_map_io(|io| BoxedSocket(Box::new(Socket(io))));
|
||||||
Ok((head, framed))
|
Ok((head, framed))
|
||||||
@ -142,10 +141,7 @@ impl AsyncWrite for BoxedSocket {
|
|||||||
Pin::new(self.get_mut().0.as_write()).poll_flush(cx)
|
Pin::new(self.get_mut().0.as_write()).poll_flush(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_shutdown(
|
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<io::Result<()>> {
|
|
||||||
Pin::new(self.get_mut().0.as_write()).poll_shutdown(cx)
|
Pin::new(self.get_mut().0.as_write()).poll_shutdown(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
//! Http client errors
|
//! Http client errors
|
||||||
pub use actix_http::client::{
|
pub use actix_http::client::{ConnectError, FreezeRequestError, InvalidUrl, SendRequestError};
|
||||||
ConnectError, FreezeRequestError, InvalidUrl, SendRequestError,
|
|
||||||
};
|
|
||||||
pub use actix_http::error::PayloadError;
|
pub use actix_http::error::PayloadError;
|
||||||
pub use actix_http::http::Error as HttpError;
|
pub use actix_http::http::Error as HttpError;
|
||||||
pub use actix_http::ws::HandshakeError as WsHandshakeError;
|
pub use actix_http::ws::HandshakeError as WsHandshakeError;
|
||||||
|
@ -11,8 +11,7 @@ use actix_http::body::Body;
|
|||||||
use actix_http::cookie::{Cookie, CookieJar};
|
use actix_http::cookie::{Cookie, CookieJar};
|
||||||
use actix_http::http::header::{self, IntoHeaderPair};
|
use actix_http::http::header::{self, IntoHeaderPair};
|
||||||
use actix_http::http::{
|
use actix_http::http::{
|
||||||
uri, ConnectionType, Error as HttpError, HeaderMap, HeaderValue, Method, Uri,
|
uri, ConnectionType, Error as HttpError, HeaderMap, HeaderValue, Method, Uri, Version,
|
||||||
Version,
|
|
||||||
};
|
};
|
||||||
use actix_http::{Error, RequestHead};
|
use actix_http::{Error, RequestHead};
|
||||||
|
|
||||||
@ -520,15 +519,11 @@ impl ClientRequest {
|
|||||||
.unwrap_or(true);
|
.unwrap_or(true);
|
||||||
|
|
||||||
if https {
|
if https {
|
||||||
slf =
|
slf = slf.insert_header_if_none((header::ACCEPT_ENCODING, HTTPS_ENCODING))
|
||||||
slf.insert_header_if_none((header::ACCEPT_ENCODING, HTTPS_ENCODING))
|
|
||||||
} else {
|
} else {
|
||||||
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
|
#[cfg(any(feature = "flate2-zlib", feature = "flate2-rust"))]
|
||||||
{
|
{
|
||||||
slf = slf.insert_header_if_none((
|
slf = slf.insert_header_if_none((header::ACCEPT_ENCODING, "gzip, deflate"))
|
||||||
header::ACCEPT_ENCODING,
|
|
||||||
"gzip, deflate",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -50,8 +50,7 @@ impl<S> HttpMessage for ClientResponse<S> {
|
|||||||
if self.extensions().get::<Cookies>().is_none() {
|
if self.extensions().get::<Cookies>().is_none() {
|
||||||
let mut cookies = Vec::new();
|
let mut cookies = Vec::new();
|
||||||
for hdr in self.headers().get_all(&SET_COOKIE) {
|
for hdr in self.headers().get_all(&SET_COOKIE) {
|
||||||
let s = std::str::from_utf8(hdr.as_bytes())
|
let s = std::str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?;
|
||||||
.map_err(CookieParseError::from)?;
|
|
||||||
cookies.push(Cookie::parse_encoded(s)?.into_owned());
|
cookies.push(Cookie::parse_encoded(s)?.into_owned());
|
||||||
}
|
}
|
||||||
self.extensions_mut().insert(Cookies(cookies));
|
self.extensions_mut().insert(Cookies(cookies));
|
||||||
@ -132,10 +131,7 @@ where
|
|||||||
{
|
{
|
||||||
type Item = Result<Bytes, PayloadError>;
|
type Item = Result<Bytes, PayloadError>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
Pin::new(&mut self.get_mut().payload).poll_next(cx)
|
Pin::new(&mut self.get_mut().payload).poll_next(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -306,9 +302,7 @@ where
|
|||||||
|
|
||||||
if let Some(len) = self.length.take() {
|
if let Some(len) = self.length.take() {
|
||||||
if len > self.fut.as_ref().unwrap().limit {
|
if len > self.fut.as_ref().unwrap().limit {
|
||||||
return Poll::Ready(Err(JsonPayloadError::Payload(
|
return Poll::Ready(Err(JsonPayloadError::Payload(PayloadError::Overflow)));
|
||||||
PayloadError::Overflow,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,8 +368,7 @@ mod tests {
|
|||||||
_ => unreachable!("error"),
|
_ => unreachable!("error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut req =
|
let mut req = TestResponse::with_header(header::CONTENT_LENGTH, "1000000").finish();
|
||||||
TestResponse::with_header(header::CONTENT_LENGTH, "1000000").finish();
|
|
||||||
match req.body().await.err().unwrap() {
|
match req.body().await.err().unwrap() {
|
||||||
PayloadError::Overflow => {}
|
PayloadError::Overflow => {}
|
||||||
_ => unreachable!("error"),
|
_ => unreachable!("error"),
|
||||||
|
@ -81,8 +81,7 @@ impl SendClientRequest {
|
|||||||
|
|
||||||
#[cfg(feature = "compress")]
|
#[cfg(feature = "compress")]
|
||||||
impl Future for SendClientRequest {
|
impl Future for SendClientRequest {
|
||||||
type Output =
|
type Output = Result<ClientResponse<Decoder<Payload<PayloadStream>>>, SendRequestError>;
|
||||||
Result<ClientResponse<Decoder<Payload<PayloadStream>>>, SendRequestError>;
|
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||||
let this = self.get_mut();
|
let this = self.get_mut();
|
||||||
@ -99,15 +98,9 @@ impl Future for SendClientRequest {
|
|||||||
let res = futures_core::ready!(Pin::new(send).poll(cx)).map(|res| {
|
let res = futures_core::ready!(Pin::new(send).poll(cx)).map(|res| {
|
||||||
res.map_body(|head, payload| {
|
res.map_body(|head, payload| {
|
||||||
if *response_decompress {
|
if *response_decompress {
|
||||||
Payload::Stream(Decoder::from_headers(
|
Payload::Stream(Decoder::from_headers(payload, &head.headers))
|
||||||
payload,
|
|
||||||
&head.headers,
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
Payload::Stream(Decoder::new(
|
Payload::Stream(Decoder::new(payload, ContentEncoding::Identity))
|
||||||
payload,
|
|
||||||
ContentEncoding::Identity,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
@ -189,11 +182,11 @@ impl RequestSender {
|
|||||||
B: Into<Body>,
|
B: Into<Body>,
|
||||||
{
|
{
|
||||||
let fut = match self {
|
let fut = match self {
|
||||||
RequestSender::Owned(head) => config.connector.send_request(
|
RequestSender::Owned(head) => {
|
||||||
RequestHeadType::Owned(head),
|
config
|
||||||
body.into(),
|
.connector
|
||||||
addr,
|
.send_request(RequestHeadType::Owned(head), body.into(), addr)
|
||||||
),
|
}
|
||||||
RequestSender::Rc(head, extra_headers) => config.connector.send_request(
|
RequestSender::Rc(head, extra_headers) => config.connector.send_request(
|
||||||
RequestHeadType::Rc(head, extra_headers),
|
RequestHeadType::Rc(head, extra_headers),
|
||||||
body.into(),
|
body.into(),
|
||||||
@ -217,8 +210,7 @@ impl RequestSender {
|
|||||||
Err(e) => return Error::from(e).into(),
|
Err(e) => return Error::from(e).into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = self.set_header_if_none(header::CONTENT_TYPE, "application/json")
|
if let Err(e) = self.set_header_if_none(header::CONTENT_TYPE, "application/json") {
|
||||||
{
|
|
||||||
return e.into();
|
return e.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,10 +237,9 @@ impl RequestSender {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// set content-type
|
// set content-type
|
||||||
if let Err(e) = self.set_header_if_none(
|
if let Err(e) =
|
||||||
header::CONTENT_TYPE,
|
self.set_header_if_none(header::CONTENT_TYPE, "application/x-www-form-urlencoded")
|
||||||
"application/x-www-form-urlencoded",
|
{
|
||||||
) {
|
|
||||||
return e.into();
|
return e.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,11 +283,7 @@ impl RequestSender {
|
|||||||
self.send_body(addr, response_decompress, timeout, config, Body::Empty)
|
self.send_body(addr, response_decompress, timeout, config, Body::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_header_if_none<V>(
|
fn set_header_if_none<V>(&mut self, key: HeaderName, value: V) -> Result<(), HttpError>
|
||||||
&mut self,
|
|
||||||
key: HeaderName,
|
|
||||||
value: V,
|
|
||||||
) -> Result<(), HttpError>
|
|
||||||
where
|
where
|
||||||
V: IntoHeaderValue,
|
V: IntoHeaderValue,
|
||||||
{
|
{
|
||||||
|
@ -40,12 +40,8 @@ pub use actix_http::ws::{CloseCode, CloseReason, Codec, Frame, Message};
|
|||||||
|
|
||||||
use crate::connect::BoxedSocket;
|
use crate::connect::BoxedSocket;
|
||||||
use crate::error::{InvalidUrl, SendRequestError, WsClientError};
|
use crate::error::{InvalidUrl, SendRequestError, WsClientError};
|
||||||
use crate::http::header::{
|
use crate::http::header::{self, HeaderName, HeaderValue, IntoHeaderValue, AUTHORIZATION};
|
||||||
self, HeaderName, HeaderValue, IntoHeaderValue, AUTHORIZATION,
|
use crate::http::{ConnectionType, Error as HttpError, Method, StatusCode, Uri, Version};
|
||||||
};
|
|
||||||
use crate::http::{
|
|
||||||
ConnectionType, Error as HttpError, Method, StatusCode, Uri, Version,
|
|
||||||
};
|
|
||||||
use crate::response::ClientResponse;
|
use crate::response::ClientResponse;
|
||||||
use crate::ClientConfig;
|
use crate::ClientConfig;
|
||||||
|
|
||||||
|
@ -51,8 +51,7 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
|
|||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_simple() {
|
async fn test_simple() {
|
||||||
let srv = test::start(|| {
|
let srv = test::start(|| {
|
||||||
App::new()
|
App::new().service(web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))))
|
||||||
.service(web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let request = srv.get("/").insert_header(("x-test", "111")).send();
|
let request = srv.get("/").insert_header(("x-test", "111")).send();
|
||||||
@ -612,9 +611,8 @@ async fn test_client_streaming_explicit() {
|
|||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
|
||||||
let body = stream::once(async {
|
let body =
|
||||||
Ok::<_, actix_http::Error>(Bytes::from_static(STR.as_bytes()))
|
stream::once(async { Ok::<_, actix_http::Error>(Bytes::from_static(STR.as_bytes())) });
|
||||||
});
|
|
||||||
let req = srv.post("/").send_stream(Box::pin(body));
|
let req = srv.post("/").send_stream(Box::pin(body));
|
||||||
|
|
||||||
let mut res = req.await.unwrap();
|
let mut res = req.await.unwrap();
|
||||||
|
@ -64,8 +64,7 @@ async fn test_connection_reuse_h2() {
|
|||||||
.and_then(
|
.and_then(
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.h2(map_config(
|
.h2(map_config(
|
||||||
App::new()
|
App::new().service(web::resource("/").route(web::to(HttpResponse::Ok))),
|
||||||
.service(web::resource("/").route(web::to(HttpResponse::Ok))),
|
|
||||||
|_| AppConfig::default(),
|
|_| AppConfig::default(),
|
||||||
))
|
))
|
||||||
.rustls(tls_config())
|
.rustls(tls_config())
|
||||||
|
@ -48,8 +48,7 @@ async fn test_connection_reuse_h2() {
|
|||||||
.and_then(
|
.and_then(
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.h2(map_config(
|
.h2(map_config(
|
||||||
App::new()
|
App::new().service(web::resource("/").route(web::to(HttpResponse::Ok))),
|
||||||
.service(web::resource("/").route(web::to(HttpResponse::Ok))),
|
|
||||||
|_| AppConfig::default(),
|
|_| AppConfig::default(),
|
||||||
))
|
))
|
||||||
.openssl(ssl_acceptor())
|
.openssl(ssl_acceptor())
|
||||||
|
@ -33,9 +33,8 @@ fn bench_async_burst(c: &mut Criterion) {
|
|||||||
|
|
||||||
let srv = rt.block_on(async {
|
let srv = rt.block_on(async {
|
||||||
test::start(|| {
|
test::start(|| {
|
||||||
App::new().service(
|
App::new()
|
||||||
web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))),
|
.service(web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))))
|
||||||
)
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -29,12 +29,8 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.service(no_params)
|
.service(no_params)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/resource2/index.html")
|
web::resource("/resource2/index.html")
|
||||||
.wrap(
|
.wrap(middleware::DefaultHeaders::new().header("X-Version-R2", "0.3"))
|
||||||
middleware::DefaultHeaders::new().header("X-Version-R2", "0.3"),
|
.default_service(web::route().to(|| HttpResponse::MethodNotAllowed()))
|
||||||
)
|
|
||||||
.default_service(
|
|
||||||
web::route().to(|| HttpResponse::MethodNotAllowed()),
|
|
||||||
)
|
|
||||||
.route(web::get().to(index_async)),
|
.route(web::get().to(index_async)),
|
||||||
)
|
)
|
||||||
.service(web::resource("/test1.html").to(|| async { "Test\r\n" }))
|
.service(web::resource("/test1.html").to(|| async { "Test\r\n" }))
|
||||||
|
@ -33,12 +33,8 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.service(no_params)
|
.service(no_params)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/resource2/index.html")
|
web::resource("/resource2/index.html")
|
||||||
.wrap(
|
.wrap(middleware::DefaultHeaders::new().header("X-Version-R2", "0.3"))
|
||||||
middleware::DefaultHeaders::new().header("X-Version-R2", "0.3"),
|
.default_service(web::route().to(|| HttpResponse::MethodNotAllowed()))
|
||||||
)
|
|
||||||
.default_service(
|
|
||||||
web::route().to(|| HttpResponse::MethodNotAllowed()),
|
|
||||||
)
|
|
||||||
.route(web::get().to(index_async)),
|
.route(web::get().to(index_async)),
|
||||||
)
|
)
|
||||||
.service(web::resource("/test1.html").to(|| async { "Test\r\n" }))
|
.service(web::resource("/test1.html").to(|| async { "Test\r\n" }))
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
max_width = 89
|
max_width = 96
|
||||||
reorder_imports = true
|
reorder_imports = true
|
||||||
|
71
src/app.rs
71
src/app.rs
@ -8,8 +8,7 @@ use actix_http::body::{Body, MessageBody};
|
|||||||
use actix_http::{Extensions, Request};
|
use actix_http::{Extensions, Request};
|
||||||
use actix_service::boxed::{self, BoxServiceFactory};
|
use actix_service::boxed::{self, BoxServiceFactory};
|
||||||
use actix_service::{
|
use actix_service::{
|
||||||
apply, apply_fn_factory, IntoServiceFactory, ServiceFactory, ServiceFactoryExt,
|
apply, apply_fn_factory, IntoServiceFactory, ServiceFactory, ServiceFactoryExt, Transform,
|
||||||
Transform,
|
|
||||||
};
|
};
|
||||||
use futures_util::future::FutureExt;
|
use futures_util::future::FutureExt;
|
||||||
|
|
||||||
@ -473,17 +472,13 @@ mod tests {
|
|||||||
use crate::http::{header, HeaderValue, Method, StatusCode};
|
use crate::http::{header, HeaderValue, Method, StatusCode};
|
||||||
use crate::middleware::DefaultHeaders;
|
use crate::middleware::DefaultHeaders;
|
||||||
use crate::service::ServiceRequest;
|
use crate::service::ServiceRequest;
|
||||||
use crate::test::{
|
use crate::test::{call_service, init_service, read_body, try_init_service, TestRequest};
|
||||||
call_service, init_service, read_body, try_init_service, TestRequest,
|
|
||||||
};
|
|
||||||
use crate::{web, HttpRequest, HttpResponse};
|
use crate::{web, HttpRequest, HttpResponse};
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_default_resource() {
|
async fn test_default_resource() {
|
||||||
let srv = init_service(
|
let srv =
|
||||||
App::new().service(web::resource("/test").to(HttpResponse::Ok)),
|
init_service(App::new().service(web::resource("/test").to(HttpResponse::Ok))).await;
|
||||||
)
|
|
||||||
.await;
|
|
||||||
let req = TestRequest::with_uri("/test").to_request();
|
let req = TestRequest::with_uri("/test").to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
@ -525,20 +520,22 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_data_factory() {
|
async fn test_data_factory() {
|
||||||
let srv =
|
let srv = init_service(
|
||||||
init_service(App::new().data_factory(|| ok::<_, ()>(10usize)).service(
|
App::new()
|
||||||
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
|
.data_factory(|| ok::<_, ()>(10usize))
|
||||||
))
|
.service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
|
||||||
.await;
|
)
|
||||||
|
.await;
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
let srv =
|
let srv = init_service(
|
||||||
init_service(App::new().data_factory(|| ok::<_, ()>(10u32)).service(
|
App::new()
|
||||||
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
|
.data_factory(|| ok::<_, ()>(10u32))
|
||||||
))
|
.service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
|
||||||
.await;
|
)
|
||||||
|
.await;
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
@ -546,23 +543,24 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_data_factory_errors() {
|
async fn test_data_factory_errors() {
|
||||||
let srv =
|
let srv = try_init_service(
|
||||||
try_init_service(App::new().data_factory(|| err::<u32, _>(())).service(
|
App::new()
|
||||||
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
|
.data_factory(|| err::<u32, _>(()))
|
||||||
))
|
.service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
|
||||||
.await;
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
assert!(srv.is_err());
|
assert!(srv.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_extension() {
|
async fn test_extension() {
|
||||||
let srv = init_service(App::new().app_data(10usize).service(
|
let srv = init_service(App::new().app_data(10usize).service(web::resource("/").to(
|
||||||
web::resource("/").to(|req: HttpRequest| {
|
|req: HttpRequest| {
|
||||||
assert_eq!(*req.app_data::<usize>().unwrap(), 10);
|
assert_eq!(*req.app_data::<usize>().unwrap(), 10);
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
}),
|
},
|
||||||
))
|
)))
|
||||||
.await;
|
.await;
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
@ -617,10 +615,8 @@ mod tests {
|
|||||||
let fut = srv.call(req);
|
let fut = srv.call(req);
|
||||||
async move {
|
async move {
|
||||||
let mut res = fut.await?;
|
let mut res = fut.await?;
|
||||||
res.headers_mut().insert(
|
res.headers_mut()
|
||||||
header::CONTENT_TYPE,
|
.insert(header::CONTENT_TYPE, HeaderValue::from_static("0001"));
|
||||||
HeaderValue::from_static("0001"),
|
|
||||||
);
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -645,10 +641,8 @@ mod tests {
|
|||||||
let fut = srv.call(req);
|
let fut = srv.call(req);
|
||||||
async {
|
async {
|
||||||
let mut res = fut.await?;
|
let mut res = fut.await?;
|
||||||
res.headers_mut().insert(
|
res.headers_mut()
|
||||||
header::CONTENT_TYPE,
|
.insert(header::CONTENT_TYPE, HeaderValue::from_static("0001"));
|
||||||
HeaderValue::from_static("0001"),
|
|
||||||
);
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@ -671,9 +665,8 @@ mod tests {
|
|||||||
.route(
|
.route(
|
||||||
"/test",
|
"/test",
|
||||||
web::get().to(|req: HttpRequest| {
|
web::get().to(|req: HttpRequest| {
|
||||||
HttpResponse::Ok().body(
|
HttpResponse::Ok()
|
||||||
req.url_for("youtube", &["12345"]).unwrap().to_string(),
|
.body(req.url_for("youtube", &["12345"]).unwrap().to_string())
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -241,16 +241,15 @@ impl ServiceFactory<ServiceRequest> for AppRoutingFactory {
|
|||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
// construct all services factory future with it's resource def and guards.
|
// construct all services factory future with it's resource def and guards.
|
||||||
let factory_fut =
|
let factory_fut = join_all(self.services.iter().map(|(path, factory, guards)| {
|
||||||
join_all(self.services.iter().map(|(path, factory, guards)| {
|
let path = path.clone();
|
||||||
let path = path.clone();
|
let guards = guards.borrow_mut().take();
|
||||||
let guards = guards.borrow_mut().take();
|
let factory_fut = factory.new_service(());
|
||||||
let factory_fut = factory.new_service(());
|
async move {
|
||||||
async move {
|
let service = factory_fut.await?;
|
||||||
let service = factory_fut.await?;
|
Ok((path, guards, service))
|
||||||
Ok((path, guards, service))
|
}
|
||||||
}
|
}));
|
||||||
}));
|
|
||||||
|
|
||||||
// construct default service factory future
|
// construct default service factory future
|
||||||
let default_fut = self.default.new_service(());
|
let default_fut = self.default.new_service(());
|
||||||
|
@ -17,8 +17,7 @@ use crate::service::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
type Guards = Vec<Box<dyn Guard>>;
|
type Guards = Vec<Box<dyn Guard>>;
|
||||||
type HttpNewService =
|
type HttpNewService = boxed::BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>;
|
||||||
boxed::BoxServiceFactory<(), ServiceRequest, ServiceResponse, Error, ()>;
|
|
||||||
|
|
||||||
/// Application configuration
|
/// Application configuration
|
||||||
pub struct AppService {
|
pub struct AppService {
|
||||||
@ -99,12 +98,8 @@ impl AppService {
|
|||||||
InitError = (),
|
InitError = (),
|
||||||
> + 'static,
|
> + 'static,
|
||||||
{
|
{
|
||||||
self.services.push((
|
self.services
|
||||||
rdef,
|
.push((rdef, boxed::factory(factory.into_factory()), guards, nested));
|
||||||
boxed::factory(factory.into_factory()),
|
|
||||||
guards,
|
|
||||||
nested,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,12 +258,12 @@ mod tests {
|
|||||||
cfg.app_data(15u8);
|
cfg.app_data(15u8);
|
||||||
};
|
};
|
||||||
|
|
||||||
let srv = init_service(App::new().configure(cfg).service(
|
let srv = init_service(App::new().configure(cfg).service(web::resource("/").to(
|
||||||
web::resource("/").to(|_: web::Data<usize>, req: HttpRequest| {
|
|_: web::Data<usize>, req: HttpRequest| {
|
||||||
assert_eq!(*req.app_data::<u8>().unwrap(), 15u8);
|
assert_eq!(*req.app_data::<u8>().unwrap(), 15u8);
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
}),
|
},
|
||||||
))
|
)))
|
||||||
.await;
|
.await;
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
@ -312,17 +307,13 @@ mod tests {
|
|||||||
let srv = init_service(
|
let srv = init_service(
|
||||||
App::new()
|
App::new()
|
||||||
.configure(|cfg| {
|
.configure(|cfg| {
|
||||||
cfg.external_resource(
|
cfg.external_resource("youtube", "https://youtube.com/watch/{video_id}");
|
||||||
"youtube",
|
|
||||||
"https://youtube.com/watch/{video_id}",
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
.route(
|
.route(
|
||||||
"/test",
|
"/test",
|
||||||
web::get().to(|req: HttpRequest| {
|
web::get().to(|req: HttpRequest| {
|
||||||
HttpResponse::Ok().body(
|
HttpResponse::Ok()
|
||||||
req.url_for("youtube", &["12345"]).unwrap().to_string(),
|
.body(req.url_for("youtube", &["12345"]).unwrap().to_string())
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -337,10 +328,8 @@ mod tests {
|
|||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_service() {
|
async fn test_service() {
|
||||||
let srv = init_service(App::new().configure(|cfg| {
|
let srv = init_service(App::new().configure(|cfg| {
|
||||||
cfg.service(
|
cfg.service(web::resource("/test").route(web::get().to(HttpResponse::Created)))
|
||||||
web::resource("/test").route(web::get().to(HttpResponse::Created)),
|
.route("/index.html", web::get().to(HttpResponse::Ok));
|
||||||
)
|
|
||||||
.route("/index.html", web::get().to(HttpResponse::Ok));
|
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
52
src/data.rs
52
src/data.rs
@ -156,11 +156,12 @@ mod tests {
|
|||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
let srv =
|
let srv = init_service(
|
||||||
init_service(App::new().data(10u32).service(
|
App::new()
|
||||||
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
|
.data(10u32)
|
||||||
))
|
.service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
|
||||||
.await;
|
)
|
||||||
|
.await;
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
@ -186,21 +187,23 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_app_data_extractor() {
|
async fn test_app_data_extractor() {
|
||||||
let srv =
|
let srv = init_service(
|
||||||
init_service(App::new().app_data(Data::new(10usize)).service(
|
App::new()
|
||||||
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
|
.app_data(Data::new(10usize))
|
||||||
))
|
.service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
|
||||||
.await;
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
let srv =
|
let srv = init_service(
|
||||||
init_service(App::new().app_data(Data::new(10u32)).service(
|
App::new()
|
||||||
web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok()),
|
.app_data(Data::new(10u32))
|
||||||
))
|
.service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
|
||||||
.await;
|
)
|
||||||
|
.await;
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
@ -237,15 +240,16 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_override_data() {
|
async fn test_override_data() {
|
||||||
let srv = init_service(App::new().data(1usize).service(
|
let srv =
|
||||||
web::resource("/").data(10usize).route(web::get().to(
|
init_service(App::new().data(1usize).service(
|
||||||
|data: web::Data<usize>| {
|
web::resource("/").data(10usize).route(web::get().to(
|
||||||
assert_eq!(**data, 10);
|
|data: web::Data<usize>| {
|
||||||
HttpResponse::Ok()
|
assert_eq!(**data, 10);
|
||||||
},
|
HttpResponse::Ok()
|
||||||
)),
|
},
|
||||||
))
|
)),
|
||||||
.await;
|
))
|
||||||
|
.await;
|
||||||
|
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
|
@ -92,9 +92,7 @@ impl std::error::Error for JsonPayloadError {}
|
|||||||
impl ResponseError for JsonPayloadError {
|
impl ResponseError for JsonPayloadError {
|
||||||
fn error_response(&self) -> HttpResponse {
|
fn error_response(&self) -> HttpResponse {
|
||||||
match *self {
|
match *self {
|
||||||
JsonPayloadError::Overflow => {
|
JsonPayloadError::Overflow => HttpResponse::new(StatusCode::PAYLOAD_TOO_LARGE),
|
||||||
HttpResponse::new(StatusCode::PAYLOAD_TOO_LARGE)
|
|
||||||
}
|
|
||||||
_ => HttpResponse::new(StatusCode::BAD_REQUEST),
|
_ => HttpResponse::new(StatusCode::BAD_REQUEST),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,9 +130,7 @@ pub mod dev {
|
|||||||
pub use crate::handler::Handler;
|
pub use crate::handler::Handler;
|
||||||
pub use crate::info::ConnectionInfo;
|
pub use crate::info::ConnectionInfo;
|
||||||
pub use crate::rmap::ResourceMap;
|
pub use crate::rmap::ResourceMap;
|
||||||
pub use crate::service::{
|
pub use crate::service::{HttpServiceFactory, ServiceRequest, ServiceResponse, WebService};
|
||||||
HttpServiceFactory, ServiceRequest, ServiceResponse, WebService,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub use crate::types::form::UrlEncoded;
|
pub use crate::types::form::UrlEncoded;
|
||||||
pub use crate::types::json::JsonBody;
|
pub use crate::types::json::JsonBody;
|
||||||
@ -142,9 +140,7 @@ pub mod dev {
|
|||||||
#[cfg(feature = "compress")]
|
#[cfg(feature = "compress")]
|
||||||
pub use actix_http::encoding::Decoder as Decompress;
|
pub use actix_http::encoding::Decoder as Decompress;
|
||||||
pub use actix_http::ResponseBuilder as HttpResponseBuilder;
|
pub use actix_http::ResponseBuilder as HttpResponseBuilder;
|
||||||
pub use actix_http::{
|
pub use actix_http::{Extensions, Payload, PayloadStream, RequestHead, ResponseHead};
|
||||||
Extensions, Payload, PayloadStream, RequestHead, ResponseHead,
|
|
||||||
};
|
|
||||||
pub use actix_router::{Path, ResourceDef, ResourcePath, Url};
|
pub use actix_router::{Path, ResourceDef, ResourcePath, Url};
|
||||||
pub use actix_server::Server;
|
pub use actix_server::Server;
|
||||||
pub use actix_service::{Service, Transform};
|
pub use actix_service::{Service, Transform};
|
||||||
|
@ -143,9 +143,7 @@ mod tests {
|
|||||||
web::scope("app")
|
web::scope("app")
|
||||||
.wrap(Compat::new(logger))
|
.wrap(Compat::new(logger))
|
||||||
.wrap(Compat::new(compress))
|
.wrap(Compat::new(compress))
|
||||||
.service(
|
.service(web::resource("/test").route(web::get().to(HttpResponse::Ok))),
|
||||||
web::resource("/test").route(web::get().to(HttpResponse::Ok)),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -119,15 +119,13 @@ mod tests {
|
|||||||
ok(req.into_response(HttpResponse::InternalServerError().finish()))
|
ok(req.into_response(HttpResponse::InternalServerError().finish()))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mw =
|
let mw = ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, render_500);
|
||||||
ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, render_500);
|
|
||||||
|
|
||||||
let mw = Condition::new(true, mw)
|
let mw = Condition::new(true, mw)
|
||||||
.new_transform(srv.into_service())
|
.new_transform(srv.into_service())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let resp =
|
let resp = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
|
||||||
test::call_service(&mw, TestRequest::default().to_srv_request()).await;
|
|
||||||
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
|
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,16 +135,14 @@ mod tests {
|
|||||||
ok(req.into_response(HttpResponse::InternalServerError().finish()))
|
ok(req.into_response(HttpResponse::InternalServerError().finish()))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mw =
|
let mw = ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, render_500);
|
||||||
ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, render_500);
|
|
||||||
|
|
||||||
let mw = Condition::new(false, mw)
|
let mw = Condition::new(false, mw)
|
||||||
.new_transform(srv.into_service())
|
.new_transform(srv.into_service())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let resp =
|
let resp = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
|
||||||
test::call_service(&mw, TestRequest::default().to_srv_request()).await;
|
|
||||||
assert_eq!(resp.headers().get(CONTENT_TYPE), None);
|
assert_eq!(resp.headers().get(CONTENT_TYPE), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,8 +229,7 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_content_type() {
|
async fn test_content_type() {
|
||||||
let srv =
|
let srv = |req: ServiceRequest| ok(req.into_response(HttpResponse::Ok().finish()));
|
||||||
|req: ServiceRequest| ok(req.into_response(HttpResponse::Ok().finish()));
|
|
||||||
let mw = DefaultHeaders::new()
|
let mw = DefaultHeaders::new()
|
||||||
.add_content_type()
|
.add_content_type()
|
||||||
.new_transform(srv.into_service())
|
.new_transform(srv.into_service())
|
||||||
|
@ -201,8 +201,7 @@ mod tests {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let resp =
|
let resp = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
|
||||||
test::call_service(&mw, TestRequest::default().to_srv_request()).await;
|
|
||||||
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
|
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,8 +226,7 @@ mod tests {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let resp =
|
let resp = test::call_service(&mw, TestRequest::default().to_srv_request()).await;
|
||||||
test::call_service(&mw, TestRequest::default().to_srv_request()).await;
|
|
||||||
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
|
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,9 +137,9 @@ impl Logger {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let inner = Rc::get_mut(&mut self.0).unwrap();
|
let inner = Rc::get_mut(&mut self.0).unwrap();
|
||||||
|
|
||||||
let ft = inner.format.0.iter_mut().find(|ft| {
|
let ft = inner.format.0.iter_mut().find(
|
||||||
matches!(ft, FormatText::CustomRequest(unit_label, _) if label == unit_label)
|
|ft| matches!(ft, FormatText::CustomRequest(unit_label, _) if label == unit_label),
|
||||||
});
|
);
|
||||||
|
|
||||||
if let Some(FormatText::CustomRequest(_, request_fn)) = ft {
|
if let Some(FormatText::CustomRequest(_, request_fn)) = ft {
|
||||||
// replace into None or previously registered fn using same label
|
// replace into None or previously registered fn using same label
|
||||||
@ -363,8 +363,7 @@ impl Format {
|
|||||||
/// Returns `None` if the format string syntax is incorrect.
|
/// Returns `None` if the format string syntax is incorrect.
|
||||||
pub fn new(s: &str) -> Format {
|
pub fn new(s: &str) -> Format {
|
||||||
log::trace!("Access log format: {}", s);
|
log::trace!("Access log format: {}", s);
|
||||||
let fmt =
|
let fmt = Regex::new(r"%(\{([A-Za-z0-9\-_]+)\}([aioe]|xi)|[atPrUsbTD]?)").unwrap();
|
||||||
Regex::new(r"%(\{([A-Za-z0-9\-_]+)\}([aioe]|xi)|[atPrUsbTD]?)").unwrap();
|
|
||||||
|
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
@ -385,12 +384,12 @@ impl Format {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"i" => FormatText::RequestHeader(
|
"i" => {
|
||||||
HeaderName::try_from(key.as_str()).unwrap(),
|
FormatText::RequestHeader(HeaderName::try_from(key.as_str()).unwrap())
|
||||||
),
|
}
|
||||||
"o" => FormatText::ResponseHeader(
|
"o" => {
|
||||||
HeaderName::try_from(key.as_str()).unwrap(),
|
FormatText::ResponseHeader(HeaderName::try_from(key.as_str()).unwrap())
|
||||||
),
|
}
|
||||||
"e" => FormatText::EnvironHeader(key.as_str().to_owned()),
|
"e" => FormatText::EnvironHeader(key.as_str().to_owned()),
|
||||||
"xi" => FormatText::CustomRequest(key.as_str().to_owned(), None),
|
"xi" => FormatText::CustomRequest(key.as_str().to_owned(), None),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -533,9 +532,7 @@ impl FormatText {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
FormatText::UrlPath => *self = FormatText::Str(req.path().to_string()),
|
FormatText::UrlPath => *self = FormatText::Str(req.path().to_string()),
|
||||||
FormatText::RequestTime => {
|
FormatText::RequestTime => *self = FormatText::Str(now.format("%Y-%m-%dT%H:%M:%S")),
|
||||||
*self = FormatText::Str(now.format("%Y-%m-%dT%H:%M:%S"))
|
|
||||||
}
|
|
||||||
FormatText::RequestHeader(ref name) => {
|
FormatText::RequestHeader(ref name) => {
|
||||||
let s = if let Some(val) = req.headers().get(name) {
|
let s = if let Some(val) = req.headers().get(name) {
|
||||||
if let Ok(s) = val.to_str() {
|
if let Ok(s) = val.to_str() {
|
||||||
@ -557,8 +554,7 @@ impl FormatText {
|
|||||||
*self = s;
|
*self = s;
|
||||||
}
|
}
|
||||||
FormatText::RealIPRemoteAddr => {
|
FormatText::RealIPRemoteAddr => {
|
||||||
let s = if let Some(remote) = req.connection_info().realip_remote_addr()
|
let s = if let Some(remote) = req.connection_info().realip_remote_addr() {
|
||||||
{
|
|
||||||
FormatText::Str(remote.to_string())
|
FormatText::Str(remote.to_string())
|
||||||
} else {
|
} else {
|
||||||
FormatText::Str("-".to_string())
|
FormatText::Str("-".to_string())
|
||||||
@ -629,8 +625,8 @@ mod tests {
|
|||||||
.finish(),
|
.finish(),
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test")
|
let logger =
|
||||||
.exclude_regex("\\w");
|
Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test").exclude_regex("\\w");
|
||||||
|
|
||||||
let srv = logger.new_transform(srv.into_service()).await.unwrap();
|
let srv = logger.new_transform(srv.into_service()).await.unwrap();
|
||||||
|
|
||||||
@ -743,9 +739,7 @@ mod tests {
|
|||||||
let req = TestRequest::default()
|
let req = TestRequest::default()
|
||||||
.insert_header((
|
.insert_header((
|
||||||
header::FORWARDED,
|
header::FORWARDED,
|
||||||
header::HeaderValue::from_static(
|
header::HeaderValue::from_static("for=192.0.2.60;proto=http;by=203.0.113.43"),
|
||||||
"for=192.0.2.60;proto=http;by=203.0.113.43",
|
|
||||||
),
|
|
||||||
))
|
))
|
||||||
.to_srv_request();
|
.to_srv_request();
|
||||||
|
|
||||||
|
@ -175,11 +175,7 @@ impl HttpRequest {
|
|||||||
/// );
|
/// );
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn url_for<U, I>(
|
pub fn url_for<U, I>(&self, name: &str, elements: U) -> Result<url::Url, UrlGenerationError>
|
||||||
&self,
|
|
||||||
name: &str,
|
|
||||||
elements: U,
|
|
||||||
) -> Result<url::Url, UrlGenerationError>
|
|
||||||
where
|
where
|
||||||
U: IntoIterator<Item = I>,
|
U: IntoIterator<Item = I>,
|
||||||
I: AsRef<str>,
|
I: AsRef<str>,
|
||||||
@ -577,30 +573,30 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_data() {
|
async fn test_data() {
|
||||||
let srv = init_service(App::new().app_data(10usize).service(
|
let srv = init_service(App::new().app_data(10usize).service(web::resource("/").to(
|
||||||
web::resource("/").to(|req: HttpRequest| {
|
|req: HttpRequest| {
|
||||||
if req.app_data::<usize>().is_some() {
|
if req.app_data::<usize>().is_some() {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
} else {
|
} else {
|
||||||
HttpResponse::BadRequest()
|
HttpResponse::BadRequest()
|
||||||
}
|
}
|
||||||
}),
|
},
|
||||||
))
|
)))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
let resp = call_service(&srv, req).await;
|
let resp = call_service(&srv, req).await;
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
let srv = init_service(App::new().app_data(10u32).service(
|
let srv = init_service(App::new().app_data(10u32).service(web::resource("/").to(
|
||||||
web::resource("/").to(|req: HttpRequest| {
|
|req: HttpRequest| {
|
||||||
if req.app_data::<usize>().is_some() {
|
if req.app_data::<usize>().is_some() {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
} else {
|
} else {
|
||||||
HttpResponse::BadRequest()
|
HttpResponse::BadRequest()
|
||||||
}
|
}
|
||||||
}),
|
},
|
||||||
))
|
)))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
@ -687,14 +683,14 @@ mod tests {
|
|||||||
let tracker = Rc::new(RefCell::new(Tracker { dropped: false }));
|
let tracker = Rc::new(RefCell::new(Tracker { dropped: false }));
|
||||||
{
|
{
|
||||||
let tracker2 = Rc::clone(&tracker);
|
let tracker2 = Rc::clone(&tracker);
|
||||||
let srv = init_service(App::new().data(10u32).service(
|
let srv = init_service(App::new().data(10u32).service(web::resource("/").to(
|
||||||
web::resource("/").to(move |req: HttpRequest| {
|
move |req: HttpRequest| {
|
||||||
req.extensions_mut().insert(Foo {
|
req.extensions_mut().insert(Foo {
|
||||||
tracker: Rc::clone(&tracker2),
|
tracker: Rc::clone(&tracker2),
|
||||||
});
|
});
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
}),
|
},
|
||||||
))
|
)))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let req = TestRequest::default().to_request();
|
let req = TestRequest::default().to_request();
|
||||||
|
@ -358,9 +358,10 @@ where
|
|||||||
U::InitError: fmt::Debug,
|
U::InitError: fmt::Debug,
|
||||||
{
|
{
|
||||||
// create and configure default resource
|
// create and configure default resource
|
||||||
self.default = boxed::factory(f.into_factory().map_init_err(|e| {
|
self.default = boxed::factory(
|
||||||
log::error!("Can not construct default service: {:?}", e)
|
f.into_factory()
|
||||||
}));
|
.map_init_err(|e| log::error!("Can not construct default service: {:?}", e)),
|
||||||
|
);
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -437,8 +438,7 @@ impl ServiceFactory<ServiceRequest> for ResourceFactory {
|
|||||||
let default_fut = self.default.new_service(());
|
let default_fut = self.default.new_service(());
|
||||||
|
|
||||||
// construct route service factory futures
|
// construct route service factory futures
|
||||||
let factory_fut =
|
let factory_fut = join_all(self.routes.iter().map(|route| route.new_service(())));
|
||||||
join_all(self.routes.iter().map(|route| route.new_service(())));
|
|
||||||
|
|
||||||
let app_data = self.app_data.clone();
|
let app_data = self.app_data.clone();
|
||||||
|
|
||||||
@ -530,19 +530,18 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_middleware() {
|
async fn test_middleware() {
|
||||||
let srv =
|
let srv = init_service(
|
||||||
init_service(
|
App::new().service(
|
||||||
App::new().service(
|
web::resource("/test")
|
||||||
web::resource("/test")
|
.name("test")
|
||||||
.name("test")
|
.wrap(
|
||||||
.wrap(DefaultHeaders::new().header(
|
DefaultHeaders::new()
|
||||||
header::CONTENT_TYPE,
|
.header(header::CONTENT_TYPE, HeaderValue::from_static("0001")),
|
||||||
HeaderValue::from_static("0001"),
|
)
|
||||||
))
|
.route(web::get().to(HttpResponse::Ok)),
|
||||||
.route(web::get().to(HttpResponse::Ok)),
|
),
|
||||||
),
|
)
|
||||||
)
|
.await;
|
||||||
.await;
|
|
||||||
let req = TestRequest::with_uri("/test").to_request();
|
let req = TestRequest::with_uri("/test").to_request();
|
||||||
let resp = call_service(&srv, req).await;
|
let resp = call_service(&srv, req).await;
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
@ -584,12 +583,11 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_to() {
|
async fn test_to() {
|
||||||
let srv =
|
let srv = init_service(App::new().service(web::resource("/test").to(|| async {
|
||||||
init_service(App::new().service(web::resource("/test").to(|| async {
|
sleep(Duration::from_millis(100)).await;
|
||||||
sleep(Duration::from_millis(100)).await;
|
Ok::<_, Error>(HttpResponse::Ok())
|
||||||
Ok::<_, Error>(HttpResponse::Ok())
|
})))
|
||||||
})))
|
.await;
|
||||||
.await;
|
|
||||||
let req = TestRequest::with_uri("/test").to_request();
|
let req = TestRequest::with_uri("/test").to_request();
|
||||||
let resp = call_service(&srv, req).await;
|
let resp = call_service(&srv, req).await;
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
@ -262,9 +262,7 @@ pub(crate) mod tests {
|
|||||||
async fn test_option_responder() {
|
async fn test_option_responder() {
|
||||||
let srv = init_service(
|
let srv = init_service(
|
||||||
App::new()
|
App::new()
|
||||||
.service(
|
.service(web::resource("/none").to(|| async { Option::<&'static str>::None }))
|
||||||
web::resource("/none").to(|| async { Option::<&'static str>::None }),
|
|
||||||
)
|
|
||||||
.service(web::resource("/some").to(|| async { Some("some") })),
|
.service(web::resource("/some").to(|| async { Some("some") })),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@ -364,8 +362,7 @@ pub(crate) mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// InternalError
|
// InternalError
|
||||||
let resp =
|
let resp = error::InternalError::new("err", StatusCode::BAD_REQUEST).respond_to(&req);
|
||||||
error::InternalError::new("err", StatusCode::BAD_REQUEST).respond_to(&req);
|
|
||||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,9 +379,8 @@ pub(crate) mod tests {
|
|||||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||||
);
|
);
|
||||||
|
|
||||||
let res =
|
let res = Err::<String, _>(error::InternalError::new("err", StatusCode::BAD_REQUEST))
|
||||||
Err::<String, _>(error::InternalError::new("err", StatusCode::BAD_REQUEST))
|
.respond_to(&req);
|
||||||
.respond_to(&req);
|
|
||||||
|
|
||||||
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
|
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
14
src/route.rs
14
src/route.rs
@ -238,12 +238,7 @@ where
|
|||||||
|
|
||||||
impl<T> RouteNewService<T>
|
impl<T> RouteNewService<T>
|
||||||
where
|
where
|
||||||
T: ServiceFactory<
|
T: ServiceFactory<ServiceRequest, Config = (), Response = ServiceResponse, Error = Error>,
|
||||||
ServiceRequest,
|
|
||||||
Config = (),
|
|
||||||
Response = ServiceResponse,
|
|
||||||
Error = Error,
|
|
||||||
>,
|
|
||||||
T::Future: 'static,
|
T::Future: 'static,
|
||||||
T::Service: 'static,
|
T::Service: 'static,
|
||||||
<T::Service as Service<ServiceRequest>>::Future: 'static,
|
<T::Service as Service<ServiceRequest>>::Future: 'static,
|
||||||
@ -255,12 +250,7 @@ where
|
|||||||
|
|
||||||
impl<T> ServiceFactory<ServiceRequest> for RouteNewService<T>
|
impl<T> ServiceFactory<ServiceRequest> for RouteNewService<T>
|
||||||
where
|
where
|
||||||
T: ServiceFactory<
|
T: ServiceFactory<ServiceRequest, Config = (), Response = ServiceResponse, Error = Error>,
|
||||||
ServiceRequest,
|
|
||||||
Config = (),
|
|
||||||
Response = ServiceResponse,
|
|
||||||
Error = Error,
|
|
||||||
>,
|
|
||||||
T::Future: 'static,
|
T::Future: 'static,
|
||||||
T::Service: 'static,
|
T::Service: 'static,
|
||||||
<T::Service as Service<ServiceRequest>>::Future: 'static,
|
<T::Service as Service<ServiceRequest>>::Future: 'static,
|
||||||
|
70
src/scope.rs
70
src/scope.rs
@ -8,8 +8,8 @@ use actix_http::Extensions;
|
|||||||
use actix_router::{ResourceDef, Router};
|
use actix_router::{ResourceDef, Router};
|
||||||
use actix_service::boxed::{self, BoxService, BoxServiceFactory};
|
use actix_service::boxed::{self, BoxService, BoxServiceFactory};
|
||||||
use actix_service::{
|
use actix_service::{
|
||||||
apply, apply_fn_factory, IntoServiceFactory, Service, ServiceFactory,
|
apply, apply_fn_factory, IntoServiceFactory, Service, ServiceFactory, ServiceFactoryExt,
|
||||||
ServiceFactoryExt, Transform,
|
Transform,
|
||||||
};
|
};
|
||||||
use futures_core::future::LocalBoxFuture;
|
use futures_core::future::LocalBoxFuture;
|
||||||
use futures_util::future::join_all;
|
use futures_util::future::join_all;
|
||||||
@ -476,16 +476,15 @@ impl ServiceFactory<ServiceRequest> for ScopeFactory {
|
|||||||
let default_fut = self.default.new_service(());
|
let default_fut = self.default.new_service(());
|
||||||
|
|
||||||
// construct all services factory future with it's resource def and guards.
|
// construct all services factory future with it's resource def and guards.
|
||||||
let factory_fut =
|
let factory_fut = join_all(self.services.iter().map(|(path, factory, guards)| {
|
||||||
join_all(self.services.iter().map(|(path, factory, guards)| {
|
let path = path.clone();
|
||||||
let path = path.clone();
|
let guards = guards.borrow_mut().take();
|
||||||
let guards = guards.borrow_mut().take();
|
let factory_fut = factory.new_service(());
|
||||||
let factory_fut = factory.new_service(());
|
async move {
|
||||||
async move {
|
let service = factory_fut.await?;
|
||||||
let service = factory_fut.await?;
|
Ok((path, guards, service))
|
||||||
Ok((path, guards, service))
|
}
|
||||||
}
|
}));
|
||||||
}));
|
|
||||||
|
|
||||||
let app_data = self.app_data.clone();
|
let app_data = self.app_data.clone();
|
||||||
|
|
||||||
@ -589,10 +588,11 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope() {
|
async fn test_scope() {
|
||||||
let srv = init_service(App::new().service(
|
let srv =
|
||||||
web::scope("/app").service(web::resource("/path1").to(HttpResponse::Ok)),
|
init_service(App::new().service(
|
||||||
))
|
web::scope("/app").service(web::resource("/path1").to(HttpResponse::Ok)),
|
||||||
.await;
|
))
|
||||||
|
.await;
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/app/path1").to_request();
|
let req = TestRequest::with_uri("/app/path1").to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
@ -621,9 +621,10 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_root2() {
|
async fn test_scope_root2() {
|
||||||
let srv = init_service(App::new().service(
|
let srv = init_service(
|
||||||
web::scope("/app/").service(web::resource("").to(HttpResponse::Ok)),
|
App::new()
|
||||||
))
|
.service(web::scope("/app/").service(web::resource("").to(HttpResponse::Ok))),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/app").to_request();
|
let req = TestRequest::with_uri("/app").to_request();
|
||||||
@ -637,9 +638,10 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_scope_root3() {
|
async fn test_scope_root3() {
|
||||||
let srv = init_service(App::new().service(
|
let srv = init_service(
|
||||||
web::scope("/app/").service(web::resource("/").to(HttpResponse::Ok)),
|
App::new()
|
||||||
))
|
.service(web::scope("/app/").service(web::resource("/").to(HttpResponse::Ok))),
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/app").to_request();
|
let req = TestRequest::with_uri("/app").to_request();
|
||||||
@ -737,8 +739,7 @@ mod tests {
|
|||||||
async fn test_scope_variable_segment() {
|
async fn test_scope_variable_segment() {
|
||||||
let srv = init_service(App::new().service(web::scope("/ab-{project}").service(
|
let srv = init_service(App::new().service(web::scope("/ab-{project}").service(
|
||||||
web::resource("/path1").to(|r: HttpRequest| {
|
web::resource("/path1").to(|r: HttpRequest| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().body(format!("project: {}", &r.match_info()["project"]))
|
||||||
.body(format!("project: {}", &r.match_info()["project"]))
|
|
||||||
}),
|
}),
|
||||||
)))
|
)))
|
||||||
.await;
|
.await;
|
||||||
@ -945,14 +946,10 @@ mod tests {
|
|||||||
App::new().service(
|
App::new().service(
|
||||||
web::scope("app")
|
web::scope("app")
|
||||||
.wrap(
|
.wrap(
|
||||||
DefaultHeaders::new().header(
|
DefaultHeaders::new()
|
||||||
header::CONTENT_TYPE,
|
.header(header::CONTENT_TYPE, HeaderValue::from_static("0001")),
|
||||||
HeaderValue::from_static("0001"),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.service(
|
.service(web::resource("/test").route(web::get().to(HttpResponse::Ok))),
|
||||||
web::resource("/test").route(web::get().to(HttpResponse::Ok)),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@ -975,10 +972,8 @@ mod tests {
|
|||||||
let fut = srv.call(req);
|
let fut = srv.call(req);
|
||||||
async move {
|
async move {
|
||||||
let mut res = fut.await?;
|
let mut res = fut.await?;
|
||||||
res.headers_mut().insert(
|
res.headers_mut()
|
||||||
header::CONTENT_TYPE,
|
.insert(header::CONTENT_TYPE, HeaderValue::from_static("0001"));
|
||||||
HeaderValue::from_static("0001"),
|
|
||||||
);
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -1083,9 +1078,8 @@ mod tests {
|
|||||||
s.route(
|
s.route(
|
||||||
"/",
|
"/",
|
||||||
web::get().to(|req: HttpRequest| {
|
web::get().to(|req: HttpRequest| {
|
||||||
HttpResponse::Ok().body(
|
HttpResponse::Ok()
|
||||||
req.url_for("youtube", &["xxxxxx"]).unwrap().to_string(),
|
.body(req.url_for("youtube", &["xxxxxx"]).unwrap().to_string())
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
|
200
src/server.rs
200
src/server.rs
@ -277,32 +277,28 @@ where
|
|||||||
});
|
});
|
||||||
let on_connect_fn = self.on_connect_fn.clone();
|
let on_connect_fn = self.on_connect_fn.clone();
|
||||||
|
|
||||||
self.builder = self.builder.listen(
|
self.builder =
|
||||||
format!("actix-web-service-{}", addr),
|
self.builder
|
||||||
lst,
|
.listen(format!("actix-web-service-{}", addr), lst, move || {
|
||||||
move || {
|
let c = cfg.lock().unwrap();
|
||||||
let c = cfg.lock().unwrap();
|
let host = c.host.clone().unwrap_or_else(|| format!("{}", addr));
|
||||||
let host = c.host.clone().unwrap_or_else(|| format!("{}", addr));
|
|
||||||
|
|
||||||
let svc = HttpService::build()
|
let svc = HttpService::build()
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_timeout(c.client_timeout)
|
.client_timeout(c.client_timeout)
|
||||||
.local_addr(addr);
|
.local_addr(addr);
|
||||||
|
|
||||||
let svc = if let Some(handler) = on_connect_fn.clone() {
|
let svc = if let Some(handler) = on_connect_fn.clone() {
|
||||||
svc.on_connect_ext(move |io: &_, ext: _| {
|
svc.on_connect_ext(move |io: &_, ext: _| (handler)(io as &dyn Any, ext))
|
||||||
(handler)(io as &dyn Any, ext)
|
} else {
|
||||||
})
|
svc
|
||||||
} else {
|
};
|
||||||
svc
|
|
||||||
};
|
|
||||||
|
|
||||||
svc.finish(map_config(factory(), move |_| {
|
svc.finish(map_config(factory(), move |_| {
|
||||||
AppConfig::new(false, addr, host.clone())
|
AppConfig::new(false, addr, host.clone())
|
||||||
}))
|
}))
|
||||||
.tcp()
|
.tcp()
|
||||||
},
|
})?;
|
||||||
)?;
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,32 +330,30 @@ where
|
|||||||
|
|
||||||
let on_connect_fn = self.on_connect_fn.clone();
|
let on_connect_fn = self.on_connect_fn.clone();
|
||||||
|
|
||||||
self.builder = self.builder.listen(
|
self.builder =
|
||||||
format!("actix-web-service-{}", addr),
|
self.builder
|
||||||
lst,
|
.listen(format!("actix-web-service-{}", addr), lst, move || {
|
||||||
move || {
|
let c = cfg.lock().unwrap();
|
||||||
let c = cfg.lock().unwrap();
|
let host = c.host.clone().unwrap_or_else(|| format!("{}", addr));
|
||||||
let host = c.host.clone().unwrap_or_else(|| format!("{}", addr));
|
|
||||||
|
|
||||||
let svc = HttpService::build()
|
let svc = HttpService::build()
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_timeout(c.client_timeout)
|
.client_timeout(c.client_timeout)
|
||||||
.client_disconnect(c.client_shutdown);
|
.client_disconnect(c.client_shutdown);
|
||||||
|
|
||||||
let svc = if let Some(handler) = on_connect_fn.clone() {
|
let svc = if let Some(handler) = on_connect_fn.clone() {
|
||||||
svc.on_connect_ext(move |io: &_, ext: _| {
|
svc.on_connect_ext(move |io: &_, ext: _| {
|
||||||
(&*handler)(io as &dyn Any, ext)
|
(&*handler)(io as &dyn Any, ext)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
svc
|
svc
|
||||||
};
|
};
|
||||||
|
|
||||||
svc.finish(map_config(factory(), move |_| {
|
svc.finish(map_config(factory(), move |_| {
|
||||||
AppConfig::new(true, addr, host.clone())
|
AppConfig::new(true, addr, host.clone())
|
||||||
}))
|
}))
|
||||||
.openssl(acceptor.clone())
|
.openssl(acceptor.clone())
|
||||||
},
|
})?;
|
||||||
)?;
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,32 +385,28 @@ where
|
|||||||
|
|
||||||
let on_connect_fn = self.on_connect_fn.clone();
|
let on_connect_fn = self.on_connect_fn.clone();
|
||||||
|
|
||||||
self.builder = self.builder.listen(
|
self.builder =
|
||||||
format!("actix-web-service-{}", addr),
|
self.builder
|
||||||
lst,
|
.listen(format!("actix-web-service-{}", addr), lst, move || {
|
||||||
move || {
|
let c = cfg.lock().unwrap();
|
||||||
let c = cfg.lock().unwrap();
|
let host = c.host.clone().unwrap_or_else(|| format!("{}", addr));
|
||||||
let host = c.host.clone().unwrap_or_else(|| format!("{}", addr));
|
|
||||||
|
|
||||||
let svc = HttpService::build()
|
let svc = HttpService::build()
|
||||||
.keep_alive(c.keep_alive)
|
.keep_alive(c.keep_alive)
|
||||||
.client_timeout(c.client_timeout)
|
.client_timeout(c.client_timeout)
|
||||||
.client_disconnect(c.client_shutdown);
|
.client_disconnect(c.client_shutdown);
|
||||||
|
|
||||||
let svc = if let Some(handler) = on_connect_fn.clone() {
|
let svc = if let Some(handler) = on_connect_fn.clone() {
|
||||||
svc.on_connect_ext(move |io: &_, ext: _| {
|
svc.on_connect_ext(move |io: &_, ext: _| (handler)(io as &dyn Any, ext))
|
||||||
(handler)(io as &dyn Any, ext)
|
} else {
|
||||||
})
|
svc
|
||||||
} else {
|
};
|
||||||
svc
|
|
||||||
};
|
|
||||||
|
|
||||||
svc.finish(map_config(factory(), move |_| {
|
svc.finish(map_config(factory(), move |_| {
|
||||||
AppConfig::new(true, addr, host.clone())
|
AppConfig::new(true, addr, host.clone())
|
||||||
}))
|
}))
|
||||||
.rustls(config.clone())
|
.rustls(config.clone())
|
||||||
},
|
})?;
|
||||||
)?;
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,10 +423,7 @@ where
|
|||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bind2<A: net::ToSocketAddrs>(
|
fn bind2<A: net::ToSocketAddrs>(&self, addr: A) -> io::Result<Vec<net::TcpListener>> {
|
||||||
&self,
|
|
||||||
addr: A,
|
|
||||||
) -> io::Result<Vec<net::TcpListener>> {
|
|
||||||
let mut err = None;
|
let mut err = None;
|
||||||
let mut success = false;
|
let mut success = false;
|
||||||
let mut sockets = Vec::new();
|
let mut sockets = Vec::new();
|
||||||
@ -469,11 +456,7 @@ where
|
|||||||
/// Start listening for incoming tls connections.
|
/// Start listening for incoming tls connections.
|
||||||
///
|
///
|
||||||
/// This method sets alpn protocols to "h2" and "http/1.1"
|
/// This method sets alpn protocols to "h2" and "http/1.1"
|
||||||
pub fn bind_openssl<A>(
|
pub fn bind_openssl<A>(mut self, addr: A, builder: SslAcceptorBuilder) -> io::Result<Self>
|
||||||
mut self,
|
|
||||||
addr: A,
|
|
||||||
builder: SslAcceptorBuilder,
|
|
||||||
) -> io::Result<Self>
|
|
||||||
where
|
where
|
||||||
A: net::ToSocketAddrs,
|
A: net::ToSocketAddrs,
|
||||||
{
|
{
|
||||||
@ -505,18 +488,13 @@ where
|
|||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
/// Start listening for unix domain (UDS) connections on existing listener.
|
/// Start listening for unix domain (UDS) connections on existing listener.
|
||||||
pub fn listen_uds(
|
pub fn listen_uds(mut self, lst: std::os::unix::net::UnixListener) -> io::Result<Self> {
|
||||||
mut self,
|
|
||||||
lst: std::os::unix::net::UnixListener,
|
|
||||||
) -> io::Result<Self> {
|
|
||||||
use actix_rt::net::UnixStream;
|
use actix_rt::net::UnixStream;
|
||||||
|
|
||||||
let cfg = self.config.clone();
|
let cfg = self.config.clone();
|
||||||
let factory = self.factory.clone();
|
let factory = self.factory.clone();
|
||||||
let socket_addr = net::SocketAddr::new(
|
let socket_addr =
|
||||||
net::IpAddr::V4(net::Ipv4Addr::new(127, 0, 0, 1)),
|
net::SocketAddr::new(net::IpAddr::V4(net::Ipv4Addr::new(127, 0, 0, 1)), 8080);
|
||||||
8080,
|
|
||||||
);
|
|
||||||
self.sockets.push(Socket {
|
self.sockets.push(Socket {
|
||||||
scheme: "http",
|
scheme: "http",
|
||||||
addr: socket_addr,
|
addr: socket_addr,
|
||||||
@ -533,23 +511,19 @@ where
|
|||||||
c.host.clone().unwrap_or_else(|| format!("{}", socket_addr)),
|
c.host.clone().unwrap_or_else(|| format!("{}", socket_addr)),
|
||||||
);
|
);
|
||||||
|
|
||||||
pipeline_factory(|io: UnixStream| ok((io, Protocol::Http1, None))).and_then(
|
pipeline_factory(|io: UnixStream| ok((io, Protocol::Http1, None))).and_then({
|
||||||
{
|
let svc = HttpService::build()
|
||||||
let svc = HttpService::build()
|
.keep_alive(c.keep_alive)
|
||||||
.keep_alive(c.keep_alive)
|
.client_timeout(c.client_timeout);
|
||||||
.client_timeout(c.client_timeout);
|
|
||||||
|
|
||||||
let svc = if let Some(handler) = on_connect_fn.clone() {
|
let svc = if let Some(handler) = on_connect_fn.clone() {
|
||||||
svc.on_connect_ext(move |io: &_, ext: _| {
|
svc.on_connect_ext(move |io: &_, ext: _| (&*handler)(io as &dyn Any, ext))
|
||||||
(&*handler)(io as &dyn Any, ext)
|
} else {
|
||||||
})
|
svc
|
||||||
} else {
|
};
|
||||||
svc
|
|
||||||
};
|
|
||||||
|
|
||||||
svc.finish(map_config(factory(), move |_| config.clone()))
|
svc.finish(map_config(factory(), move |_| config.clone()))
|
||||||
},
|
})
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
@ -564,10 +538,8 @@ where
|
|||||||
|
|
||||||
let cfg = self.config.clone();
|
let cfg = self.config.clone();
|
||||||
let factory = self.factory.clone();
|
let factory = self.factory.clone();
|
||||||
let socket_addr = net::SocketAddr::new(
|
let socket_addr =
|
||||||
net::IpAddr::V4(net::Ipv4Addr::new(127, 0, 0, 1)),
|
net::SocketAddr::new(net::IpAddr::V4(net::Ipv4Addr::new(127, 0, 0, 1)), 8080);
|
||||||
8080,
|
|
||||||
);
|
|
||||||
self.sockets.push(Socket {
|
self.sockets.push(Socket {
|
||||||
scheme: "http",
|
scheme: "http",
|
||||||
addr: socket_addr,
|
addr: socket_addr,
|
||||||
@ -583,13 +555,12 @@ where
|
|||||||
socket_addr,
|
socket_addr,
|
||||||
c.host.clone().unwrap_or_else(|| format!("{}", socket_addr)),
|
c.host.clone().unwrap_or_else(|| format!("{}", socket_addr)),
|
||||||
);
|
);
|
||||||
pipeline_factory(|io: UnixStream| ok((io, Protocol::Http1, None)))
|
pipeline_factory(|io: UnixStream| ok((io, Protocol::Http1, None))).and_then(
|
||||||
.and_then(
|
HttpService::build()
|
||||||
HttpService::build()
|
.keep_alive(c.keep_alive)
|
||||||
.keep_alive(c.keep_alive)
|
.client_timeout(c.client_timeout)
|
||||||
.client_timeout(c.client_timeout)
|
.finish(map_config(factory(), move |_| config.clone())),
|
||||||
.finish(map_config(factory(), move |_| config.clone())),
|
)
|
||||||
)
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
@ -633,10 +604,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_tcp_listener(
|
fn create_tcp_listener(addr: net::SocketAddr, backlog: u32) -> io::Result<net::TcpListener> {
|
||||||
addr: net::SocketAddr,
|
|
||||||
backlog: u32,
|
|
||||||
) -> io::Result<net::TcpListener> {
|
|
||||||
use socket2::{Domain, Protocol, Socket, Type};
|
use socket2::{Domain, Protocol, Socket, Type};
|
||||||
let domain = match addr {
|
let domain = match addr {
|
||||||
net::SocketAddr::V4(_) => Domain::ipv4(),
|
net::SocketAddr::V4(_) => Domain::ipv4(),
|
||||||
|
@ -5,8 +5,7 @@ use std::{fmt, net};
|
|||||||
use actix_http::body::{Body, MessageBody, ResponseBody};
|
use actix_http::body::{Body, MessageBody, ResponseBody};
|
||||||
use actix_http::http::{HeaderMap, Method, StatusCode, Uri, Version};
|
use actix_http::http::{HeaderMap, Method, StatusCode, Uri, Version};
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
Error, Extensions, HttpMessage, Payload, PayloadStream, RequestHead, Response,
|
Error, Extensions, HttpMessage, Payload, PayloadStream, RequestHead, Response, ResponseHead,
|
||||||
ResponseHead,
|
|
||||||
};
|
};
|
||||||
use actix_router::{IntoPattern, Path, Resource, ResourceDef, Url};
|
use actix_router::{IntoPattern, Path, Resource, ResourceDef, Url};
|
||||||
use actix_service::{IntoServiceFactory, ServiceFactory};
|
use actix_service::{IntoServiceFactory, ServiceFactory};
|
||||||
@ -635,20 +634,18 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_service_data() {
|
async fn test_service_data() {
|
||||||
let srv = init_service(
|
let srv =
|
||||||
App::new()
|
init_service(
|
||||||
.data(42u32)
|
App::new()
|
||||||
.service(web::service("/test").name("test").finish(
|
.data(42u32)
|
||||||
|req: ServiceRequest| {
|
.service(web::service("/test").name("test").finish(
|
||||||
assert_eq!(
|
|req: ServiceRequest| {
|
||||||
req.app_data::<web::Data<u32>>().unwrap().as_ref(),
|
assert_eq!(req.app_data::<web::Data<u32>>().unwrap().as_ref(), &42);
|
||||||
&42
|
ok(req.into_response(HttpResponse::Ok().finish()))
|
||||||
);
|
},
|
||||||
ok(req.into_response(HttpResponse::Ok().finish()))
|
)),
|
||||||
},
|
)
|
||||||
)),
|
.await;
|
||||||
)
|
|
||||||
.await;
|
|
||||||
let req = TestRequest::with_uri("/test").to_request();
|
let req = TestRequest::with_uri("/test").to_request();
|
||||||
let resp = srv.call(req).await.unwrap();
|
let resp = srv.call(req).await.unwrap();
|
||||||
assert_eq!(resp.status(), http::StatusCode::OK);
|
assert_eq!(resp.status(), http::StatusCode::OK);
|
||||||
|
78
src/test.rs
78
src/test.rs
@ -12,9 +12,7 @@ use actix_http::test::TestRequest as HttpTestRequest;
|
|||||||
use actix_http::{cookie::Cookie, ws, Extensions, HttpService, Request};
|
use actix_http::{cookie::Cookie, ws, Extensions, HttpService, Request};
|
||||||
use actix_router::{Path, ResourceDef, Url};
|
use actix_router::{Path, ResourceDef, Url};
|
||||||
use actix_rt::{time::sleep, System};
|
use actix_rt::{time::sleep, System};
|
||||||
use actix_service::{
|
use actix_service::{map_config, IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||||
map_config, IntoService, IntoServiceFactory, Service, ServiceFactory,
|
|
||||||
};
|
|
||||||
use awc::error::PayloadError;
|
use awc::error::PayloadError;
|
||||||
use awc::{Client, ClientRequest, ClientResponse, Connector};
|
use awc::{Client, ClientRequest, ClientResponse, Connector};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
@ -78,12 +76,7 @@ pub async fn init_service<R, S, B, E>(
|
|||||||
) -> impl Service<Request, Response = ServiceResponse<B>, Error = E>
|
) -> impl Service<Request, Response = ServiceResponse<B>, Error = E>
|
||||||
where
|
where
|
||||||
R: IntoServiceFactory<S, Request>,
|
R: IntoServiceFactory<S, Request>,
|
||||||
S: ServiceFactory<
|
S: ServiceFactory<Request, Config = AppConfig, Response = ServiceResponse<B>, Error = E>,
|
||||||
Request,
|
|
||||||
Config = AppConfig,
|
|
||||||
Response = ServiceResponse<B>,
|
|
||||||
Error = E,
|
|
||||||
>,
|
|
||||||
S::InitError: std::fmt::Debug,
|
S::InitError: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
try_init_service(app)
|
try_init_service(app)
|
||||||
@ -97,12 +90,7 @@ pub(crate) async fn try_init_service<R, S, B, E>(
|
|||||||
) -> Result<impl Service<Request, Response = ServiceResponse<B>, Error = E>, S::InitError>
|
) -> Result<impl Service<Request, Response = ServiceResponse<B>, Error = E>, S::InitError>
|
||||||
where
|
where
|
||||||
R: IntoServiceFactory<S, Request>,
|
R: IntoServiceFactory<S, Request>,
|
||||||
S: ServiceFactory<
|
S: ServiceFactory<Request, Config = AppConfig, Response = ServiceResponse<B>, Error = E>,
|
||||||
Request,
|
|
||||||
Config = AppConfig,
|
|
||||||
Response = ServiceResponse<B>,
|
|
||||||
Error = E,
|
|
||||||
>,
|
|
||||||
S::InitError: std::fmt::Debug,
|
S::InitError: std::fmt::Debug,
|
||||||
{
|
{
|
||||||
let srv = app.into_factory();
|
let srv = app.into_factory();
|
||||||
@ -264,9 +252,8 @@ where
|
|||||||
{
|
{
|
||||||
let body = read_body(res).await;
|
let body = read_body(res).await;
|
||||||
|
|
||||||
serde_json::from_slice(&body).unwrap_or_else(|e| {
|
serde_json::from_slice(&body)
|
||||||
panic!("read_response_json failed during deserialization: {}", e)
|
.unwrap_or_else(|e| panic!("read_response_json failed during deserialization: {}", e))
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn load_stream<S>(mut stream: S) -> Result<Bytes, Error>
|
pub async fn load_stream<S>(mut stream: S) -> Result<Bytes, Error>
|
||||||
@ -487,8 +474,7 @@ impl TestRequest {
|
|||||||
/// Serialize `data` to JSON and set it as the request payload. The `Content-Type` header is
|
/// Serialize `data` to JSON and set it as the request payload. The `Content-Type` header is
|
||||||
/// set to `application/json`.
|
/// set to `application/json`.
|
||||||
pub fn set_json<T: Serialize>(mut self, data: &T) -> Self {
|
pub fn set_json<T: Serialize>(mut self, data: &T) -> Self {
|
||||||
let bytes =
|
let bytes = serde_json::to_string(data).expect("Failed to serialize test data to json");
|
||||||
serde_json::to_string(data).expect("Failed to serialize test data to json");
|
|
||||||
self.req.set_payload(bytes);
|
self.req.set_payload(bytes);
|
||||||
self.req.insert_header(ContentType::json());
|
self.req.insert_header(ContentType::json());
|
||||||
self
|
self
|
||||||
@ -528,8 +514,7 @@ impl TestRequest {
|
|||||||
head.peer_addr = self.peer_addr;
|
head.peer_addr = self.peer_addr;
|
||||||
self.path.get_mut().update(&head.uri);
|
self.path.get_mut().update(&head.uri);
|
||||||
|
|
||||||
let app_state =
|
let app_state = AppInitServiceState::new(Rc::new(self.rmap), self.config.clone());
|
||||||
AppInitServiceState::new(Rc::new(self.rmap), self.config.clone());
|
|
||||||
|
|
||||||
ServiceRequest::new(
|
ServiceRequest::new(
|
||||||
HttpRequest::new(self.path, head, app_state, Rc::new(self.app_data)),
|
HttpRequest::new(self.path, head, app_state, Rc::new(self.app_data)),
|
||||||
@ -548,8 +533,7 @@ impl TestRequest {
|
|||||||
head.peer_addr = self.peer_addr;
|
head.peer_addr = self.peer_addr;
|
||||||
self.path.get_mut().update(&head.uri);
|
self.path.get_mut().update(&head.uri);
|
||||||
|
|
||||||
let app_state =
|
let app_state = AppInitServiceState::new(Rc::new(self.rmap), self.config.clone());
|
||||||
AppInitServiceState::new(Rc::new(self.rmap), self.config.clone());
|
|
||||||
|
|
||||||
HttpRequest::new(self.path, head, app_state, Rc::new(self.app_data))
|
HttpRequest::new(self.path, head, app_state, Rc::new(self.app_data))
|
||||||
}
|
}
|
||||||
@ -560,8 +544,7 @@ impl TestRequest {
|
|||||||
head.peer_addr = self.peer_addr;
|
head.peer_addr = self.peer_addr;
|
||||||
self.path.get_mut().update(&head.uri);
|
self.path.get_mut().update(&head.uri);
|
||||||
|
|
||||||
let app_state =
|
let app_state = AppInitServiceState::new(Rc::new(self.rmap), self.config.clone());
|
||||||
AppInitServiceState::new(Rc::new(self.rmap), self.config.clone());
|
|
||||||
|
|
||||||
let req = HttpRequest::new(self.path, head, app_state, Rc::new(self.app_data));
|
let req = HttpRequest::new(self.path, head, app_state, Rc::new(self.app_data));
|
||||||
|
|
||||||
@ -678,24 +661,21 @@ where
|
|||||||
let srv = match cfg.stream {
|
let srv = match cfg.stream {
|
||||||
StreamType::Tcp => match cfg.tp {
|
StreamType::Tcp => match cfg.tp {
|
||||||
HttpVer::Http1 => builder.listen("test", tcp, move || {
|
HttpVer::Http1 => builder.listen("test", tcp, move || {
|
||||||
let cfg =
|
let cfg = AppConfig::new(false, local_addr, format!("{}", local_addr));
|
||||||
AppConfig::new(false, local_addr, format!("{}", local_addr));
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(ctimeout)
|
.client_timeout(ctimeout)
|
||||||
.h1(map_config(factory(), move |_| cfg.clone()))
|
.h1(map_config(factory(), move |_| cfg.clone()))
|
||||||
.tcp()
|
.tcp()
|
||||||
}),
|
}),
|
||||||
HttpVer::Http2 => builder.listen("test", tcp, move || {
|
HttpVer::Http2 => builder.listen("test", tcp, move || {
|
||||||
let cfg =
|
let cfg = AppConfig::new(false, local_addr, format!("{}", local_addr));
|
||||||
AppConfig::new(false, local_addr, format!("{}", local_addr));
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(ctimeout)
|
.client_timeout(ctimeout)
|
||||||
.h2(map_config(factory(), move |_| cfg.clone()))
|
.h2(map_config(factory(), move |_| cfg.clone()))
|
||||||
.tcp()
|
.tcp()
|
||||||
}),
|
}),
|
||||||
HttpVer::Both => builder.listen("test", tcp, move || {
|
HttpVer::Both => builder.listen("test", tcp, move || {
|
||||||
let cfg =
|
let cfg = AppConfig::new(false, local_addr, format!("{}", local_addr));
|
||||||
AppConfig::new(false, local_addr, format!("{}", local_addr));
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(ctimeout)
|
.client_timeout(ctimeout)
|
||||||
.finish(map_config(factory(), move |_| cfg.clone()))
|
.finish(map_config(factory(), move |_| cfg.clone()))
|
||||||
@ -705,24 +685,21 @@ where
|
|||||||
#[cfg(feature = "openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
StreamType::Openssl(acceptor) => match cfg.tp {
|
StreamType::Openssl(acceptor) => match cfg.tp {
|
||||||
HttpVer::Http1 => builder.listen("test", tcp, move || {
|
HttpVer::Http1 => builder.listen("test", tcp, move || {
|
||||||
let cfg =
|
let cfg = AppConfig::new(true, local_addr, format!("{}", local_addr));
|
||||||
AppConfig::new(true, local_addr, format!("{}", local_addr));
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(ctimeout)
|
.client_timeout(ctimeout)
|
||||||
.h1(map_config(factory(), move |_| cfg.clone()))
|
.h1(map_config(factory(), move |_| cfg.clone()))
|
||||||
.openssl(acceptor.clone())
|
.openssl(acceptor.clone())
|
||||||
}),
|
}),
|
||||||
HttpVer::Http2 => builder.listen("test", tcp, move || {
|
HttpVer::Http2 => builder.listen("test", tcp, move || {
|
||||||
let cfg =
|
let cfg = AppConfig::new(true, local_addr, format!("{}", local_addr));
|
||||||
AppConfig::new(true, local_addr, format!("{}", local_addr));
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(ctimeout)
|
.client_timeout(ctimeout)
|
||||||
.h2(map_config(factory(), move |_| cfg.clone()))
|
.h2(map_config(factory(), move |_| cfg.clone()))
|
||||||
.openssl(acceptor.clone())
|
.openssl(acceptor.clone())
|
||||||
}),
|
}),
|
||||||
HttpVer::Both => builder.listen("test", tcp, move || {
|
HttpVer::Both => builder.listen("test", tcp, move || {
|
||||||
let cfg =
|
let cfg = AppConfig::new(true, local_addr, format!("{}", local_addr));
|
||||||
AppConfig::new(true, local_addr, format!("{}", local_addr));
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(ctimeout)
|
.client_timeout(ctimeout)
|
||||||
.finish(map_config(factory(), move |_| cfg.clone()))
|
.finish(map_config(factory(), move |_| cfg.clone()))
|
||||||
@ -732,24 +709,21 @@ where
|
|||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
StreamType::Rustls(config) => match cfg.tp {
|
StreamType::Rustls(config) => match cfg.tp {
|
||||||
HttpVer::Http1 => builder.listen("test", tcp, move || {
|
HttpVer::Http1 => builder.listen("test", tcp, move || {
|
||||||
let cfg =
|
let cfg = AppConfig::new(true, local_addr, format!("{}", local_addr));
|
||||||
AppConfig::new(true, local_addr, format!("{}", local_addr));
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(ctimeout)
|
.client_timeout(ctimeout)
|
||||||
.h1(map_config(factory(), move |_| cfg.clone()))
|
.h1(map_config(factory(), move |_| cfg.clone()))
|
||||||
.rustls(config.clone())
|
.rustls(config.clone())
|
||||||
}),
|
}),
|
||||||
HttpVer::Http2 => builder.listen("test", tcp, move || {
|
HttpVer::Http2 => builder.listen("test", tcp, move || {
|
||||||
let cfg =
|
let cfg = AppConfig::new(true, local_addr, format!("{}", local_addr));
|
||||||
AppConfig::new(true, local_addr, format!("{}", local_addr));
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(ctimeout)
|
.client_timeout(ctimeout)
|
||||||
.h2(map_config(factory(), move |_| cfg.clone()))
|
.h2(map_config(factory(), move |_| cfg.clone()))
|
||||||
.rustls(config.clone())
|
.rustls(config.clone())
|
||||||
}),
|
}),
|
||||||
HttpVer::Both => builder.listen("test", tcp, move || {
|
HttpVer::Both => builder.listen("test", tcp, move || {
|
||||||
let cfg =
|
let cfg = AppConfig::new(true, local_addr, format!("{}", local_addr));
|
||||||
AppConfig::new(true, local_addr, format!("{}", local_addr));
|
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.client_timeout(ctimeout)
|
.client_timeout(ctimeout)
|
||||||
.finish(map_config(factory(), move |_| cfg.clone()))
|
.finish(map_config(factory(), move |_| cfg.clone()))
|
||||||
@ -887,8 +861,7 @@ impl TestServerConfig {
|
|||||||
/// Get first available unused address
|
/// Get first available unused address
|
||||||
pub fn unused_addr() -> net::SocketAddr {
|
pub fn unused_addr() -> net::SocketAddr {
|
||||||
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
|
let addr: net::SocketAddr = "127.0.0.1:0".parse().unwrap();
|
||||||
let socket =
|
let socket = Socket::new(Domain::ipv4(), Type::stream(), Some(Protocol::tcp())).unwrap();
|
||||||
Socket::new(Domain::ipv4(), Type::stream(), Some(Protocol::tcp())).unwrap();
|
|
||||||
socket.bind(&addr.into()).unwrap();
|
socket.bind(&addr.into()).unwrap();
|
||||||
socket.set_reuse_address(true).unwrap();
|
socket.set_reuse_address(true).unwrap();
|
||||||
let tcp = socket.into_tcp_listener();
|
let tcp = socket.into_tcp_listener();
|
||||||
@ -975,8 +948,7 @@ impl TestServer {
|
|||||||
pub async fn ws_at(
|
pub async fn ws_at(
|
||||||
&mut self,
|
&mut self,
|
||||||
path: &str,
|
path: &str,
|
||||||
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError>
|
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError> {
|
||||||
{
|
|
||||||
let url = self.url(path);
|
let url = self.url(path);
|
||||||
let connect = self.client.ws(url).connect();
|
let connect = self.client.ws(url).connect();
|
||||||
connect.await.map(|(_, framed)| framed)
|
connect.await.map(|(_, framed)| framed)
|
||||||
@ -985,8 +957,7 @@ impl TestServer {
|
|||||||
/// Connect to a websocket server
|
/// Connect to a websocket server
|
||||||
pub async fn ws(
|
pub async fn ws(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError>
|
) -> Result<Framed<impl AsyncRead + AsyncWrite, ws::Codec>, awc::error::WsClientError> {
|
||||||
{
|
|
||||||
self.ws_at("/").await
|
self.ws_at("/").await
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1218,10 +1189,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = init_service(
|
let app =
|
||||||
App::new().service(web::resource("/index.html").to(async_with_block)),
|
init_service(App::new().service(web::resource("/index.html").to(async_with_block)))
|
||||||
)
|
.await;
|
||||||
.await;
|
|
||||||
|
|
||||||
let req = TestRequest::post().uri("/index.html").to_request();
|
let req = TestRequest::post().uri("/index.html").to_request();
|
||||||
let res = app.call(req).await.unwrap();
|
let res = app.call(req).await.unwrap();
|
||||||
|
@ -276,13 +276,12 @@ mod tests {
|
|||||||
.set_payload(Bytes::from_static(b"!@$%^&*()"))
|
.set_payload(Bytes::from_static(b"!@$%^&*()"))
|
||||||
.to_http_parts();
|
.to_http_parts();
|
||||||
|
|
||||||
let payload =
|
let payload = Either::<Either<Form<TestForm>, Json<TestForm>>, Bytes>::from_request(
|
||||||
Either::<Either<Form<TestForm>, Json<TestForm>>, Bytes>::from_request(
|
&req, &mut pl,
|
||||||
&req, &mut pl,
|
)
|
||||||
)
|
.await
|
||||||
.await
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap_right();
|
||||||
.unwrap_right();
|
|
||||||
assert_eq!(&payload.as_ref(), &b"!@$%^&*()");
|
assert_eq!(&payload.as_ref(), &b"!@$%^&*()");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,15 +293,14 @@ mod tests {
|
|||||||
})
|
})
|
||||||
.to_http_parts();
|
.to_http_parts();
|
||||||
|
|
||||||
let form =
|
let form = Either::<Either<Form<TestForm>, Json<TestForm>>, Bytes>::from_request(
|
||||||
Either::<Either<Form<TestForm>, Json<TestForm>>, Bytes>::from_request(
|
&req, &mut pl,
|
||||||
&req, &mut pl,
|
)
|
||||||
)
|
.await
|
||||||
.await
|
.unwrap()
|
||||||
.unwrap()
|
.unwrap_left()
|
||||||
.unwrap_left()
|
.unwrap_right()
|
||||||
.unwrap_right()
|
.into_inner();
|
||||||
.into_inner();
|
|
||||||
assert_eq!(&form.hello, "world");
|
assert_eq!(&form.hello, "world");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ use serde::{de::DeserializeOwned, Serialize};
|
|||||||
#[cfg(feature = "compress")]
|
#[cfg(feature = "compress")]
|
||||||
use crate::dev::Decompress;
|
use crate::dev::Decompress;
|
||||||
use crate::{
|
use crate::{
|
||||||
error::UrlencodedError, extract::FromRequest, http::header::CONTENT_LENGTH, web,
|
error::UrlencodedError, extract::FromRequest, http::header::CONTENT_LENGTH, web, Error,
|
||||||
Error, HttpMessage, HttpRequest, HttpResponse, Responder,
|
HttpMessage, HttpRequest, HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// URL encoded payload extractor and responder.
|
/// URL encoded payload extractor and responder.
|
||||||
@ -342,16 +342,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
if encoding == UTF_8 {
|
if encoding == UTF_8 {
|
||||||
serde_urlencoded::from_bytes::<T>(&body)
|
serde_urlencoded::from_bytes::<T>(&body).map_err(|_| UrlencodedError::Parse)
|
||||||
.map_err(|_| UrlencodedError::Parse)
|
|
||||||
} else {
|
} else {
|
||||||
let body = encoding
|
let body = encoding
|
||||||
.decode_without_bom_handling_and_without_replacement(&body)
|
.decode_without_bom_handling_and_without_replacement(&body)
|
||||||
.map(|s| s.into_owned())
|
.map(|s| s.into_owned())
|
||||||
.ok_or(UrlencodedError::Parse)?;
|
.ok_or(UrlencodedError::Parse)?;
|
||||||
|
|
||||||
serde_urlencoded::from_str::<T>(&body)
|
serde_urlencoded::from_str::<T>(&body).map_err(|_| UrlencodedError::Parse)
|
||||||
.map_err(|_| UrlencodedError::Parse)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.boxed_local(),
|
.boxed_local(),
|
||||||
|
@ -482,8 +482,8 @@ mod tests {
|
|||||||
let msg = MyObject {
|
let msg = MyObject {
|
||||||
name: "invalid request".to_string(),
|
name: "invalid request".to_string(),
|
||||||
};
|
};
|
||||||
let resp = HttpResponse::BadRequest()
|
let resp =
|
||||||
.body(serde_json::to_string(&msg).unwrap());
|
HttpResponse::BadRequest().body(serde_json::to_string(&msg).unwrap());
|
||||||
InternalError::from_response(err, resp).into()
|
InternalError::from_response(err, resp).into()
|
||||||
}))
|
}))
|
||||||
.to_http_parts();
|
.to_http_parts();
|
||||||
|
@ -235,11 +235,9 @@ mod tests {
|
|||||||
assert_eq!(res.1, "user1");
|
assert_eq!(res.1, "user1");
|
||||||
|
|
||||||
let (Path(a), Path(b)) =
|
let (Path(a), Path(b)) =
|
||||||
<(Path<(String, String)>, Path<(String, String)>)>::from_request(
|
<(Path<(String, String)>, Path<(String, String)>)>::from_request(&req, &mut pl)
|
||||||
&req, &mut pl,
|
.await
|
||||||
)
|
.unwrap();
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(a.0, "name");
|
assert_eq!(a.0, "name");
|
||||||
assert_eq!(a.1, "user1");
|
assert_eq!(a.1, "user1");
|
||||||
assert_eq!(b.0, "name");
|
assert_eq!(b.0, "name");
|
||||||
@ -300,11 +298,8 @@ mod tests {
|
|||||||
async fn test_custom_err_handler() {
|
async fn test_custom_err_handler() {
|
||||||
let (req, mut pl) = TestRequest::with_uri("/name/user1/")
|
let (req, mut pl) = TestRequest::with_uri("/name/user1/")
|
||||||
.app_data(PathConfig::default().error_handler(|err, _| {
|
.app_data(PathConfig::default().error_handler(|err, _| {
|
||||||
error::InternalError::from_response(
|
error::InternalError::from_response(err, HttpResponse::Conflict().finish())
|
||||||
err,
|
.into()
|
||||||
HttpResponse::Conflict().finish(),
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
}))
|
}))
|
||||||
.to_http_parts();
|
.to_http_parts();
|
||||||
|
|
||||||
|
@ -55,10 +55,7 @@ impl Stream for Payload {
|
|||||||
type Item = Result<Bytes, PayloadError>;
|
type Item = Result<Bytes, PayloadError>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn poll_next(
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
mut self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
Pin::new(&mut self.0).poll_next(cx)
|
Pin::new(&mut self.0).poll_next(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -396,9 +393,7 @@ mod tests {
|
|||||||
App::new()
|
App::new()
|
||||||
.service(
|
.service(
|
||||||
web::resource("/bytes-app-data")
|
web::resource("/bytes-app-data")
|
||||||
.app_data(
|
.app_data(PayloadConfig::default().mimetype(mime::APPLICATION_JSON))
|
||||||
PayloadConfig::default().mimetype(mime::APPLICATION_JSON),
|
|
||||||
)
|
|
||||||
.route(web::get().to(bytes_handler)),
|
.route(web::get().to(bytes_handler)),
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
@ -408,9 +403,7 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
web::resource("/string-app-data")
|
web::resource("/string-app-data")
|
||||||
.app_data(
|
.app_data(PayloadConfig::default().mimetype(mime::APPLICATION_JSON))
|
||||||
PayloadConfig::default().mimetype(mime::APPLICATION_JSON),
|
|
||||||
)
|
|
||||||
.route(web::get().to(string_handler)),
|
.route(web::get().to(string_handler)),
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
|
@ -167,8 +167,7 @@ where
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct QueryConfig {
|
pub struct QueryConfig {
|
||||||
err_handler:
|
err_handler: Option<Arc<dyn Fn(QueryPayloadError, &HttpRequest) -> Error + Send + Sync>>,
|
||||||
Option<Arc<dyn Fn(QueryPayloadError, &HttpRequest) -> Error + Send + Sync>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QueryConfig {
|
impl QueryConfig {
|
||||||
|
@ -74,10 +74,7 @@ where
|
|||||||
{
|
{
|
||||||
type Item = Result<String, ReadlinesError>;
|
type Item = Result<String, ReadlinesError>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
let this = self.get_mut();
|
let this = self.get_mut();
|
||||||
|
|
||||||
if let Some(err) = this.err.take() {
|
if let Some(err) = this.err.take() {
|
||||||
|
@ -23,8 +23,7 @@ async fn test_start() {
|
|||||||
sys.block_on(async {
|
sys.block_on(async {
|
||||||
let srv = HttpServer::new(|| {
|
let srv = HttpServer::new(|| {
|
||||||
App::new().service(
|
App::new().service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::to(|| HttpResponse::Ok().body("test"))),
|
||||||
.route(web::to(|| HttpResponse::Ok().body("test"))),
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.workers(1)
|
.workers(1)
|
||||||
|
@ -11,8 +11,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::http::header::{
|
use actix_http::http::header::{
|
||||||
ContentEncoding, ACCEPT_ENCODING, CONTENT_ENCODING, CONTENT_LENGTH,
|
ContentEncoding, ACCEPT_ENCODING, CONTENT_ENCODING, CONTENT_LENGTH, TRANSFER_ENCODING,
|
||||||
TRANSFER_ENCODING,
|
|
||||||
};
|
};
|
||||||
use brotli2::write::{BrotliDecoder, BrotliEncoder};
|
use brotli2::write::{BrotliDecoder, BrotliEncoder};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
@ -69,14 +68,10 @@ impl TestBody {
|
|||||||
impl futures_core::stream::Stream for TestBody {
|
impl futures_core::stream::Stream for TestBody {
|
||||||
type Item = Result<Bytes, Error>;
|
type Item = Result<Bytes, Error>;
|
||||||
|
|
||||||
fn poll_next(
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
mut self: Pin<&mut Self>,
|
|
||||||
cx: &mut Context<'_>,
|
|
||||||
) -> Poll<Option<Self::Item>> {
|
|
||||||
ready!(Pin::new(&mut self.delay).poll(cx));
|
ready!(Pin::new(&mut self.delay).poll(cx));
|
||||||
|
|
||||||
self.delay =
|
self.delay = Box::pin(actix_rt::time::sleep(std::time::Duration::from_millis(10)));
|
||||||
Box::pin(actix_rt::time::sleep(std::time::Duration::from_millis(10)));
|
|
||||||
let chunk_size = std::cmp::min(self.chunk_size, self.data.len());
|
let chunk_size = std::cmp::min(self.chunk_size, self.data.len());
|
||||||
let chunk = self.data.split_to(chunk_size);
|
let chunk = self.data.split_to(chunk_size);
|
||||||
if chunk.is_empty() {
|
if chunk.is_empty() {
|
||||||
@ -90,8 +85,7 @@ impl futures_core::stream::Stream for TestBody {
|
|||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_body() {
|
async fn test_body() {
|
||||||
let srv = test::start(|| {
|
let srv = test::start(|| {
|
||||||
App::new()
|
App::new().service(web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))))
|
||||||
.service(web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut response = srv.get("/").send().await.unwrap();
|
let mut response = srv.get("/").send().await.unwrap();
|
||||||
@ -328,12 +322,12 @@ async fn test_body_chunked_implicit() {
|
|||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_body_br_streaming() {
|
async fn test_body_br_streaming() {
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().wrap(Compress::new(ContentEncoding::Br)).service(
|
App::new()
|
||||||
web::resource("/").route(web::to(move || {
|
.wrap(Compress::new(ContentEncoding::Br))
|
||||||
|
.service(web::resource("/").route(web::to(move || {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.streaming(TestBody::new(Bytes::from_static(STR.as_ref()), 24))
|
.streaming(TestBody::new(Bytes::from_static(STR.as_ref()), 24))
|
||||||
})),
|
})))
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut response = srv
|
let mut response = srv
|
||||||
@ -361,8 +355,7 @@ async fn test_body_br_streaming() {
|
|||||||
async fn test_head_binary() {
|
async fn test_head_binary() {
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().service(
|
App::new().service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::head().to(move || HttpResponse::Ok().body(STR))),
|
||||||
.route(web::head().to(move || HttpResponse::Ok().body(STR))),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -403,9 +396,7 @@ async fn test_body_deflate() {
|
|||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new()
|
App::new()
|
||||||
.wrap(Compress::new(ContentEncoding::Deflate))
|
.wrap(Compress::new(ContentEncoding::Deflate))
|
||||||
.service(
|
.service(web::resource("/").route(web::to(move || HttpResponse::Ok().body(STR))))
|
||||||
web::resource("/").route(web::to(move || HttpResponse::Ok().body(STR))),
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
@ -430,9 +421,9 @@ async fn test_body_deflate() {
|
|||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_body_brotli() {
|
async fn test_body_brotli() {
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().wrap(Compress::new(ContentEncoding::Br)).service(
|
App::new()
|
||||||
web::resource("/").route(web::to(move || HttpResponse::Ok().body(STR))),
|
.wrap(Compress::new(ContentEncoding::Br))
|
||||||
)
|
.service(web::resource("/").route(web::to(move || HttpResponse::Ok().body(STR))))
|
||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
@ -459,8 +450,7 @@ async fn test_body_brotli() {
|
|||||||
async fn test_encoding() {
|
async fn test_encoding() {
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().wrap(Compress::default()).service(
|
App::new().wrap(Compress::default()).service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
||||||
.route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -485,8 +475,7 @@ async fn test_encoding() {
|
|||||||
async fn test_gzip_encoding() {
|
async fn test_gzip_encoding() {
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().service(
|
App::new().service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
||||||
.route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -512,8 +501,7 @@ async fn test_gzip_encoding_large() {
|
|||||||
let data = STR.repeat(10);
|
let data = STR.repeat(10);
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().service(
|
App::new().service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
||||||
.route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -544,8 +532,7 @@ async fn test_reading_gzip_encoding_large_random() {
|
|||||||
|
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().service(
|
App::new().service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
||||||
.route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -571,8 +558,7 @@ async fn test_reading_gzip_encoding_large_random() {
|
|||||||
async fn test_reading_deflate_encoding() {
|
async fn test_reading_deflate_encoding() {
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().service(
|
App::new().service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
||||||
.route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -598,8 +584,7 @@ async fn test_reading_deflate_encoding_large() {
|
|||||||
let data = STR.repeat(10);
|
let data = STR.repeat(10);
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().service(
|
App::new().service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
||||||
.route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -630,8 +615,7 @@ async fn test_reading_deflate_encoding_large_random() {
|
|||||||
|
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().service(
|
App::new().service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
||||||
.route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -657,8 +641,7 @@ async fn test_reading_deflate_encoding_large_random() {
|
|||||||
async fn test_brotli_encoding() {
|
async fn test_brotli_encoding() {
|
||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new().service(
|
App::new().service(
|
||||||
web::resource("/")
|
web::resource("/").route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
||||||
.route(web::to(move |body: Bytes| HttpResponse::Ok().body(body))),
|
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -883,9 +866,7 @@ async fn test_normalize() {
|
|||||||
let srv = test::start_with(test::config().h1(), || {
|
let srv = test::start_with(test::config().h1(), || {
|
||||||
App::new()
|
App::new()
|
||||||
.wrap(NormalizePath::new(TrailingSlash::Trim))
|
.wrap(NormalizePath::new(TrailingSlash::Trim))
|
||||||
.service(
|
.service(web::resource("/one").route(web::to(|| HttpResponse::Ok().finish())))
|
||||||
web::resource("/one").route(web::to(|| HttpResponse::Ok().finish())),
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let response = srv.get("/one/").send().await.unwrap();
|
let response = srv.get("/one/").send().await.unwrap();
|
||||||
|
Loading…
Reference in New Issue
Block a user