mirror of https://github.com/fafhrd91/actix-web
Merge branch 'master' into master
This commit is contained in:
commit
a18b272ea2
22
CHANGES.md
22
CHANGES.md
|
@ -1,6 +1,19 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
## not released yet
|
||||||
|
|
||||||
## [1.0.6] - 2019-xx-xx
|
### Added
|
||||||
|
|
||||||
|
* Add `middleware::Conditon` that conditionally enables another middleware
|
||||||
|
|
||||||
|
|
||||||
|
## [1.0.7] - 2019-08-29
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Request Extensions leak #1062
|
||||||
|
|
||||||
|
|
||||||
|
## [1.0.6] - 2019-08-28
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
@ -8,10 +21,17 @@
|
||||||
|
|
||||||
* Form immplements Responder, returning a `application/x-www-form-urlencoded` response
|
* Form immplements Responder, returning a `application/x-www-form-urlencoded` response
|
||||||
|
|
||||||
|
* Add `into_inner` to `Data`
|
||||||
|
|
||||||
|
* Add `test::TestRequest::set_form()` convenience method to automatically serialize data and set
|
||||||
|
the header in test requests.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
* `Query` payload made `pub`. Allows user to pattern-match the payload.
|
* `Query` payload made `pub`. Allows user to pattern-match the payload.
|
||||||
|
|
||||||
|
* Enable `rust-tls` feature for client #1045
|
||||||
|
|
||||||
* Update serde_urlencoded to 0.6.1
|
* Update serde_urlencoded to 0.6.1
|
||||||
|
|
||||||
* Update url to 2.1
|
* Update url to 2.1
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "actix-web"
|
name = "actix-web"
|
||||||
version = "1.0.5"
|
version = "1.0.7"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
|
description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -66,7 +66,7 @@ fail = ["actix-http/fail"]
|
||||||
ssl = ["openssl", "actix-server/ssl", "awc/ssl"]
|
ssl = ["openssl", "actix-server/ssl", "awc/ssl"]
|
||||||
|
|
||||||
# rustls
|
# rustls
|
||||||
rust-tls = ["rustls", "actix-server/rust-tls"]
|
rust-tls = ["rustls", "actix-server/rust-tls", "awc/rust-tls"]
|
||||||
|
|
||||||
# unix domain sockets support
|
# unix domain sockets support
|
||||||
uds = ["actix-server/uds"]
|
uds = ["actix-server/uds"]
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## [0.2.10] - 2019-09-xx
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* on_connect result isn't added to request extensions for http2 requests #1009
|
||||||
|
|
||||||
|
|
||||||
## [0.2.9] - 2019-08-13
|
## [0.2.9] - 2019-08-13
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -49,7 +49,7 @@ secure-cookies = ["ring"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-service = "0.4.1"
|
actix-service = "0.4.1"
|
||||||
actix-codec = "0.1.2"
|
actix-codec = "0.1.2"
|
||||||
actix-connect = "0.2.2"
|
actix-connect = "0.2.4"
|
||||||
actix-utils = "0.4.4"
|
actix-utils = "0.4.4"
|
||||||
actix-server-config = "0.1.2"
|
actix-server-config = "0.1.2"
|
||||||
actix-threadpool = "0.1.1"
|
actix-threadpool = "0.1.1"
|
||||||
|
|
|
@ -199,6 +199,7 @@ where
|
||||||
self.client_disconnect,
|
self.client_disconnect,
|
||||||
);
|
);
|
||||||
H2Service::with_config(cfg, service.into_new_service())
|
H2Service::with_config(cfg, service.into_new_service())
|
||||||
|
.on_connect(self.on_connect)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish service configuration and create `HttpService` instance.
|
/// Finish service configuration and create `HttpService` instance.
|
||||||
|
|
|
@ -502,7 +502,7 @@ where
|
||||||
let pl = self.codec.message_type();
|
let pl = self.codec.message_type();
|
||||||
req.head_mut().peer_addr = self.peer_addr;
|
req.head_mut().peer_addr = self.peer_addr;
|
||||||
|
|
||||||
// on_connect data
|
// set on_connect data
|
||||||
if let Some(ref on_connect) = self.on_connect {
|
if let Some(ref on_connect) = self.on_connect {
|
||||||
on_connect.set(&mut req.extensions_mut());
|
on_connect.set(&mut req.extensions_mut());
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ use crate::cloneable::CloneableService;
|
||||||
use crate::config::ServiceConfig;
|
use crate::config::ServiceConfig;
|
||||||
use crate::error::{DispatchError, Error, ParseError, PayloadError, ResponseError};
|
use crate::error::{DispatchError, Error, ParseError, PayloadError, ResponseError};
|
||||||
use crate::helpers::DataFactory;
|
use crate::helpers::DataFactory;
|
||||||
|
use crate::httpmessage::HttpMessage;
|
||||||
use crate::message::ResponseHead;
|
use crate::message::ResponseHead;
|
||||||
use crate::payload::Payload;
|
use crate::payload::Payload;
|
||||||
use crate::request::Request;
|
use crate::request::Request;
|
||||||
|
@ -122,6 +123,12 @@ where
|
||||||
head.version = parts.version;
|
head.version = parts.version;
|
||||||
head.headers = parts.headers.into();
|
head.headers = parts.headers.into();
|
||||||
head.peer_addr = self.peer_addr;
|
head.peer_addr = self.peer_addr;
|
||||||
|
|
||||||
|
// set on_connect data
|
||||||
|
if let Some(ref on_connect) = self.on_connect {
|
||||||
|
on_connect.set(&mut req.extensions_mut());
|
||||||
|
}
|
||||||
|
|
||||||
tokio_current_thread::spawn(ServiceResponse::<S::Future, B> {
|
tokio_current_thread::spawn(ServiceResponse::<S::Future, B> {
|
||||||
state: ServiceResponseState::ServiceCall(
|
state: ServiceResponseState::ServiceCall(
|
||||||
self.service.call(req),
|
self.service.call(req),
|
||||||
|
|
|
@ -11,6 +11,7 @@ use futures::stream::{once, Stream};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use tokio_timer::sleep;
|
use tokio_timer::sleep;
|
||||||
|
|
||||||
|
use actix_http::httpmessage::HttpMessage;
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
body, error, http, http::header, Error, HttpService, KeepAlive, Request, Response,
|
body, error, http, http::header, Error, HttpService, KeepAlive, Request, Response,
|
||||||
};
|
};
|
||||||
|
@ -602,3 +603,18 @@ fn test_h1_service_error() {
|
||||||
let bytes = srv.load_body(response).unwrap();
|
let bytes = srv.load_body(response).unwrap();
|
||||||
assert_eq!(bytes, Bytes::from_static(b"error"));
|
assert_eq!(bytes, Bytes::from_static(b"error"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h1_on_connect() {
|
||||||
|
let mut srv = TestServer::new(|| {
|
||||||
|
HttpService::build()
|
||||||
|
.on_connect(|_| 10usize)
|
||||||
|
.h1(|req: Request| {
|
||||||
|
assert!(req.extensions().contains::<usize>());
|
||||||
|
future::ok::<_, ()>(Response::Ok().finish())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.get("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
#![cfg(feature = "ssl")]
|
#![cfg(feature = "ssl")]
|
||||||
use actix_codec::{AsyncRead, AsyncWrite};
|
use actix_codec::{AsyncRead, AsyncWrite};
|
||||||
use actix_http::error::{ErrorBadRequest, PayloadError};
|
|
||||||
use actix_http::http::header::{self, HeaderName, HeaderValue};
|
|
||||||
use actix_http::http::{Method, StatusCode, Version};
|
|
||||||
use actix_http::{body, Error, HttpService, Request, Response};
|
|
||||||
use actix_http_test::TestServer;
|
use actix_http_test::TestServer;
|
||||||
use actix_server::ssl::OpensslAcceptor;
|
use actix_server::ssl::OpensslAcceptor;
|
||||||
use actix_server_config::ServerConfig;
|
use actix_server_config::ServerConfig;
|
||||||
|
@ -15,6 +11,12 @@ use futures::stream::{once, Stream};
|
||||||
use openssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod};
|
use openssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod};
|
||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
|
|
||||||
|
use actix_http::error::{ErrorBadRequest, PayloadError};
|
||||||
|
use actix_http::http::header::{self, HeaderName, HeaderValue};
|
||||||
|
use actix_http::http::{Method, StatusCode, Version};
|
||||||
|
use actix_http::httpmessage::HttpMessage;
|
||||||
|
use actix_http::{body, Error, HttpService, Request, Response};
|
||||||
|
|
||||||
fn load_body<S>(stream: S) -> impl Future<Item = BytesMut, Error = PayloadError>
|
fn load_body<S>(stream: S) -> impl Future<Item = BytesMut, Error = PayloadError>
|
||||||
where
|
where
|
||||||
S: Stream<Item = Bytes, Error = PayloadError>,
|
S: Stream<Item = Bytes, Error = PayloadError>,
|
||||||
|
@ -453,3 +455,26 @@ fn test_h2_service_error() {
|
||||||
let bytes = srv.load_body(response).unwrap();
|
let bytes = srv.load_body(response).unwrap();
|
||||||
assert!(bytes.is_empty());
|
assert!(bytes.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_h2_on_connect() {
|
||||||
|
let openssl = ssl_acceptor().unwrap();
|
||||||
|
|
||||||
|
let mut srv = TestServer::new(move || {
|
||||||
|
openssl
|
||||||
|
.clone()
|
||||||
|
.map_err(|e| println!("Openssl error: {}", e))
|
||||||
|
.and_then(
|
||||||
|
HttpService::build()
|
||||||
|
.on_connect(|_| 10usize)
|
||||||
|
.h2(|req: Request| {
|
||||||
|
assert!(req.extensions().contains::<usize>());
|
||||||
|
ok::<_, ()>(Response::Ok().finish())
|
||||||
|
})
|
||||||
|
.map_err(|_| ()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let response = srv.block_on(srv.sget("/").send()).unwrap();
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## [0.2.5] - 2019-09-06
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* Ensure that the `Host` header is set when initiating a WebSocket client connection.
|
||||||
|
|
||||||
## [0.2.4] - 2019-08-13
|
## [0.2.4] - 2019-08-13
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -233,6 +233,10 @@ impl WebsocketsRequest {
|
||||||
return Either::A(err(InvalidUrl::UnknownScheme.into()));
|
return Either::A(err(InvalidUrl::UnknownScheme.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.head.headers.contains_key(header::HOST) {
|
||||||
|
self.head.headers.insert(header::HOST, HeaderValue::from_str(uri.host().unwrap()).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
// set cookies
|
// set cookies
|
||||||
if let Some(ref mut jar) = self.cookies {
|
if let Some(ref mut jar) = self.cookies {
|
||||||
let mut cookie = String::new();
|
let mut cookie = String::new();
|
||||||
|
|
|
@ -77,6 +77,11 @@ impl<T> Data<T> {
|
||||||
pub fn get_ref(&self) -> &T {
|
pub fn get_ref(&self) -> &T {
|
||||||
self.0.as_ref()
|
self.0.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert to the internal Arc<T>
|
||||||
|
pub fn into_inner(self) -> Arc<T> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Deref for Data<T> {
|
impl<T> Deref for Data<T> {
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
//! `Middleware` for conditionally enables another middleware.
|
||||||
|
use actix_service::{Service, Transform};
|
||||||
|
use futures::future::{ok, Either, FutureResult, Map};
|
||||||
|
use futures::{Future, Poll};
|
||||||
|
|
||||||
|
/// `Middleware` for conditionally enables another middleware.
|
||||||
|
/// The controled middleware must not change the `Service` interfaces.
|
||||||
|
/// This means you cannot control such middlewares like `Logger` or `Compress`.
|
||||||
|
///
|
||||||
|
/// ## Usage
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use actix_web::middleware::{Condition, NormalizePath};
|
||||||
|
/// use actix_web::App;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let enable_normalize = std::env::var("NORMALIZE_PATH") == Ok("true".into());
|
||||||
|
/// let app = App::new()
|
||||||
|
/// .wrap(Condition::new(enable_normalize, NormalizePath));
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub struct Condition<T> {
|
||||||
|
trans: T,
|
||||||
|
enable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Condition<T> {
|
||||||
|
pub fn new(enable: bool, trans: T) -> Self {
|
||||||
|
Self { trans, enable }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, T> Transform<S> for Condition<T>
|
||||||
|
where
|
||||||
|
S: Service,
|
||||||
|
T: Transform<S, Request = S::Request, Response = S::Response, Error = S::Error>,
|
||||||
|
{
|
||||||
|
type Request = S::Request;
|
||||||
|
type Response = S::Response;
|
||||||
|
type Error = S::Error;
|
||||||
|
type InitError = T::InitError;
|
||||||
|
type Transform = ConditionMiddleware<T::Transform, S>;
|
||||||
|
type Future = Either<
|
||||||
|
Map<T::Future, fn(T::Transform) -> Self::Transform>,
|
||||||
|
FutureResult<Self::Transform, Self::InitError>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
fn new_transform(&self, service: S) -> Self::Future {
|
||||||
|
if self.enable {
|
||||||
|
let f = self
|
||||||
|
.trans
|
||||||
|
.new_transform(service)
|
||||||
|
.map(ConditionMiddleware::Enable as fn(T::Transform) -> Self::Transform);
|
||||||
|
Either::A(f)
|
||||||
|
} else {
|
||||||
|
Either::B(ok(ConditionMiddleware::Disable(service)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ConditionMiddleware<E, D> {
|
||||||
|
Enable(E),
|
||||||
|
Disable(D),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E, D> Service for ConditionMiddleware<E, D>
|
||||||
|
where
|
||||||
|
E: Service,
|
||||||
|
D: Service<Request = E::Request, Response = E::Response, Error = E::Error>,
|
||||||
|
{
|
||||||
|
type Request = E::Request;
|
||||||
|
type Response = E::Response;
|
||||||
|
type Error = E::Error;
|
||||||
|
type Future = Either<E::Future, D::Future>;
|
||||||
|
|
||||||
|
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||||
|
use ConditionMiddleware::*;
|
||||||
|
match self {
|
||||||
|
Enable(service) => service.poll_ready(),
|
||||||
|
Disable(service) => service.poll_ready(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, req: E::Request) -> Self::Future {
|
||||||
|
use ConditionMiddleware::*;
|
||||||
|
match self {
|
||||||
|
Enable(service) => Either::A(service.call(req)),
|
||||||
|
Disable(service) => Either::B(service.call(req)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use actix_service::IntoService;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::dev::{ServiceRequest, ServiceResponse};
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::http::{header::CONTENT_TYPE, HeaderValue, StatusCode};
|
||||||
|
use crate::middleware::errhandlers::*;
|
||||||
|
use crate::test::{self, TestRequest};
|
||||||
|
use crate::HttpResponse;
|
||||||
|
|
||||||
|
fn render_500<B>(mut res: ServiceResponse<B>) -> Result<ErrorHandlerResponse<B>> {
|
||||||
|
res.response_mut()
|
||||||
|
.headers_mut()
|
||||||
|
.insert(CONTENT_TYPE, HeaderValue::from_static("0001"));
|
||||||
|
Ok(ErrorHandlerResponse::Response(res))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handler_enabled() {
|
||||||
|
let srv = |req: ServiceRequest| {
|
||||||
|
req.into_response(HttpResponse::InternalServerError().finish())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mw =
|
||||||
|
ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, render_500);
|
||||||
|
|
||||||
|
let mut mw =
|
||||||
|
test::block_on(Condition::new(true, mw).new_transform(srv.into_service()))
|
||||||
|
.unwrap();
|
||||||
|
let resp = test::call_service(&mut mw, TestRequest::default().to_srv_request());
|
||||||
|
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_handler_disabled() {
|
||||||
|
let srv = |req: ServiceRequest| {
|
||||||
|
req.into_response(HttpResponse::InternalServerError().finish())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mw =
|
||||||
|
ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, render_500);
|
||||||
|
|
||||||
|
let mut mw =
|
||||||
|
test::block_on(Condition::new(false, mw).new_transform(srv.into_service()))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let resp = test::call_service(&mut mw, TestRequest::default().to_srv_request());
|
||||||
|
assert_eq!(resp.headers().get(CONTENT_TYPE), None);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,9 @@ mod defaultheaders;
|
||||||
pub mod errhandlers;
|
pub mod errhandlers;
|
||||||
mod logger;
|
mod logger;
|
||||||
mod normalize;
|
mod normalize;
|
||||||
|
mod condition;
|
||||||
|
|
||||||
pub use self::defaultheaders::DefaultHeaders;
|
pub use self::defaultheaders::DefaultHeaders;
|
||||||
pub use self::logger::Logger;
|
pub use self::logger::Logger;
|
||||||
pub use self::normalize::NormalizePath;
|
pub use self::normalize::NormalizePath;
|
||||||
|
pub use self::condition::Condition;
|
||||||
|
|
|
@ -259,6 +259,7 @@ impl Drop for HttpRequest {
|
||||||
if Rc::strong_count(&self.0) == 1 {
|
if Rc::strong_count(&self.0) == 1 {
|
||||||
let v = &mut self.0.pool.0.borrow_mut();
|
let v = &mut self.0.pool.0.borrow_mut();
|
||||||
if v.len() < 128 {
|
if v.len() < 128 {
|
||||||
|
self.extensions_mut().clear();
|
||||||
v.push(self.0.clone());
|
v.push(self.0.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,4 +495,38 @@ mod tests {
|
||||||
let resp = call_service(&mut srv, req);
|
let resp = call_service(&mut srv, req);
|
||||||
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extensions_dropped() {
|
||||||
|
struct Tracker {
|
||||||
|
pub dropped: bool,
|
||||||
|
}
|
||||||
|
struct Foo {
|
||||||
|
tracker: Rc<RefCell<Tracker>>,
|
||||||
|
}
|
||||||
|
impl Drop for Foo {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.tracker.borrow_mut().dropped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tracker = Rc::new(RefCell::new(Tracker { dropped: false }));
|
||||||
|
{
|
||||||
|
let tracker2 = Rc::clone(&tracker);
|
||||||
|
let mut srv = init_service(App::new().data(10u32).service(
|
||||||
|
web::resource("/").to(move |req: HttpRequest| {
|
||||||
|
req.extensions_mut().insert(Foo {
|
||||||
|
tracker: Rc::clone(&tracker2),
|
||||||
|
});
|
||||||
|
HttpResponse::Ok()
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
|
let req = TestRequest::default().to_request();
|
||||||
|
let resp = call_service(&mut srv, req);
|
||||||
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(tracker.borrow().dropped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
35
src/test.rs
35
src/test.rs
|
@ -478,6 +478,16 @@ impl TestRequest {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serialize `data` to a URL encoded form and set it as the request payload. The `Content-Type`
|
||||||
|
/// header is set to `application/x-www-form-urlencoded`.
|
||||||
|
pub fn set_form<T: Serialize>(mut self, data: &T) -> Self {
|
||||||
|
let bytes = serde_urlencoded::to_string(data)
|
||||||
|
.expect("Failed to serialize test data as a urlencoded form");
|
||||||
|
self.req.set_payload(bytes);
|
||||||
|
self.req.set(ContentType::form_url_encoded());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// 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 {
|
||||||
|
@ -670,6 +680,31 @@ mod tests {
|
||||||
assert_eq!(&result.id, "12345");
|
assert_eq!(&result.id, "12345");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_request_response_form() {
|
||||||
|
let mut app = init_service(App::new().service(web::resource("/people").route(
|
||||||
|
web::post().to(|person: web::Form<Person>| {
|
||||||
|
HttpResponse::Ok().json(person.into_inner())
|
||||||
|
}),
|
||||||
|
)));
|
||||||
|
|
||||||
|
let payload = Person {
|
||||||
|
id: "12345".to_string(),
|
||||||
|
name: "User name".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let req = TestRequest::post()
|
||||||
|
.uri("/people")
|
||||||
|
.set_form(&payload)
|
||||||
|
.to_request();
|
||||||
|
|
||||||
|
assert_eq!(req.content_type(), "application/x-www-form-urlencoded");
|
||||||
|
|
||||||
|
let result: Person = read_response_json(&mut app, req);
|
||||||
|
assert_eq!(&result.id, "12345");
|
||||||
|
assert_eq!(&result.name, "User name");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_request_response_json() {
|
fn test_request_response_json() {
|
||||||
let mut app = init_service(App::new().service(web::resource("/people").route(
|
let mut app = init_service(App::new().service(web::resource("/people").route(
|
||||||
|
|
Loading…
Reference in New Issue