mirror of https://github.com/fafhrd91/actix-web
fix feature resolving
This commit is contained in:
parent
adc94f505d
commit
3f6350a4b6
|
@ -1,3 +1,7 @@
|
||||||
[alias]
|
[alias]
|
||||||
chk = "hack check --workspace --all-features --tests --examples"
|
chk = "hack check --workspace --all-features --tests --examples"
|
||||||
lint = "hack --clean-per-run clippy --workspace --tests --examples"
|
lint = "hack --clean-per-run clippy --workspace --tests --examples"
|
||||||
|
ci-min = "hack check --workspace --no-default-features"
|
||||||
|
ci-min-test = "hack check --workspace --no-default-features --tests --examples"
|
||||||
|
ci-default = "hack check --workspace"
|
||||||
|
ci-full = "check --workspace --bins --examples --tests"
|
||||||
|
|
35
Cargo.toml
35
Cargo.toml
|
@ -16,7 +16,7 @@ edition = "2018"
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
# features that docs.rs will build with
|
# features that docs.rs will build with
|
||||||
features = ["openssl", "rustls", "compress", "secure-cookies"]
|
features = ["openssl", "rustls", "compress", "cookies", "secure-cookies"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "actix_web"
|
name = "actix_web"
|
||||||
|
@ -34,6 +34,7 @@ members = [
|
||||||
"actix-http-test",
|
"actix-http-test",
|
||||||
"actix-test",
|
"actix-test",
|
||||||
]
|
]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["compress", "cookies"]
|
default = ["compress", "cookies"]
|
||||||
|
@ -53,22 +54,6 @@ openssl = ["actix-http/openssl", "actix-tls/accept", "actix-tls/openssl"]
|
||||||
# rustls
|
# rustls
|
||||||
rustls = ["actix-http/rustls", "actix-tls/accept", "actix-tls/rustls"]
|
rustls = ["actix-http/rustls", "actix-tls/accept", "actix-tls/rustls"]
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "basic"
|
|
||||||
required-features = ["compress"]
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "uds"
|
|
||||||
required-features = ["compress"]
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "test_server"
|
|
||||||
required-features = ["compress", "cookies"]
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "on_connect"
|
|
||||||
required-features = []
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-codec = "0.4.0-beta.1"
|
actix-codec = "0.4.0-beta.1"
|
||||||
actix-macros = "0.2.0"
|
actix-macros = "0.2.0"
|
||||||
|
@ -135,6 +120,22 @@ actix-web-actors = { path = "actix-web-actors" }
|
||||||
actix-web-codegen = { path = "actix-web-codegen" }
|
actix-web-codegen = { path = "actix-web-codegen" }
|
||||||
awc = { path = "awc" }
|
awc = { path = "awc" }
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "test_server"
|
||||||
|
required-features = ["compress", "cookies"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "basic"
|
||||||
|
required-features = ["compress"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "uds"
|
||||||
|
required-features = ["compress"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "on_connect"
|
||||||
|
required-features = []
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "server"
|
name = "server"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
|
@ -2,8 +2,13 @@
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
### Removed
|
### Removed
|
||||||
* `HttpMessage::cookies` and `HttpMessage::cookie`. [#????]
|
* `cookies` feature flag. [#2065]
|
||||||
* `impl ResponseError for CookieParseError`. [#????]
|
* Top-level `cookies` mod (re-export). [#2065]
|
||||||
|
* `HttpMessage` trait loses the `cookies` and `cookie` methods. [#2065]
|
||||||
|
* `impl ResponseError for CookieParseError`. [#2065]
|
||||||
|
|
||||||
|
[#2065]: https://github.com/actix/actix-web/pull/2065
|
||||||
|
|
||||||
|
|
||||||
## 3.0.0-beta.5 - 2021-04-02
|
## 3.0.0-beta.5 - 2021-04-02
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -36,12 +36,12 @@ async fn main() -> io::Result<()> {
|
||||||
|
|
||||||
async fn handler(req: Request) -> Result<Response<BodyStream<Heartbeat>>, Error> {
|
async fn handler(req: Request) -> Result<Response<BodyStream<Heartbeat>>, Error> {
|
||||||
log::info!("handshaking");
|
log::info!("handshaking");
|
||||||
let res = ws::handshake(req.head())?;
|
let mut res = ws::handshake(req.head())?;
|
||||||
|
|
||||||
// handshake will always fail under HTTP/2
|
// handshake will always fail under HTTP/2
|
||||||
|
|
||||||
log::info!("responding");
|
log::info!("responding");
|
||||||
Ok(res.set_body(BodyStream::new(Heartbeat::new(ws::Codec::new()))))
|
Ok(res.message_body(BodyStream::new(Heartbeat::new(ws::Codec::new()))))
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Heartbeat {
|
struct Heartbeat {
|
||||||
|
|
|
@ -14,9 +14,7 @@ use serde::de::value::Error as DeError;
|
||||||
use serde_json::error::Error as JsonError;
|
use serde_json::error::Error as JsonError;
|
||||||
use serde_urlencoded::ser::Error as FormError;
|
use serde_urlencoded::ser::Error as FormError;
|
||||||
|
|
||||||
use crate::body::Body;
|
use crate::{body::Body, helpers::Writer, Response, ResponseBuilder};
|
||||||
use crate::helpers::Writer;
|
|
||||||
use crate::response::Response;
|
|
||||||
|
|
||||||
/// A specialized [`std::result::Result`]
|
/// A specialized [`std::result::Result`]
|
||||||
/// for actix web operations
|
/// for actix web operations
|
||||||
|
@ -135,12 +133,12 @@ impl From<Response> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// Convert ResponseBuilder to a Error
|
/// Convert ResponseBuilder to a Error
|
||||||
// impl From<ResponseBuilder> for Error {
|
impl From<ResponseBuilder> for Error {
|
||||||
// fn from(mut res: ResponseBuilder) -> Error {
|
fn from(mut res: ResponseBuilder) -> Error {
|
||||||
// InternalError::from_response("", res.finish()).into()
|
InternalError::from_response("", res.finish()).into()
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
#[derive(Debug, Display)]
|
#[derive(Debug, Display)]
|
||||||
#[display(fmt = "UnknownError")]
|
#[display(fmt = "UnknownError")]
|
||||||
|
|
|
@ -340,14 +340,12 @@ where
|
||||||
StateProj::ServiceCall(fut) => match fut.poll(cx) {
|
StateProj::ServiceCall(fut) => match fut.poll(cx) {
|
||||||
// service call resolved. send response.
|
// service call resolved. send response.
|
||||||
Poll::Ready(Ok(res)) => {
|
Poll::Ready(Ok(res)) => {
|
||||||
eprintln!("dispatcher ok!");
|
|
||||||
let (res, body) = res.into().replace_body(());
|
let (res, body) = res.into().replace_body(());
|
||||||
self.as_mut().send_response(res, body)?;
|
self.as_mut().send_response(res, body)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send service call error as response
|
// send service call error as response
|
||||||
Poll::Ready(Err(err)) => {
|
Poll::Ready(Err(err)) => {
|
||||||
eprintln!("dispatcher err");
|
|
||||||
let res = Response::from_error(err.into());
|
let res = Response::from_error(err.into());
|
||||||
let (res, body) = res.replace_body(());
|
let (res, body) = res.replace_body(());
|
||||||
self.as_mut().send_response(res, body.into_body())?;
|
self.as_mut().send_response(res, body.into_body())?;
|
||||||
|
|
|
@ -34,6 +34,18 @@ pub struct Response<B = Body> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response<Body> {
|
impl Response<Body> {
|
||||||
|
/// Create HTTP response builder with specific status.
|
||||||
|
#[inline]
|
||||||
|
pub fn build(status: StatusCode) -> ResponseBuilder {
|
||||||
|
ResponseBuilder::new(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create HTTP response builder
|
||||||
|
#[inline]
|
||||||
|
pub fn build_from<T: Into<ResponseBuilder>>(source: T) -> ResponseBuilder {
|
||||||
|
source.into()
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a response
|
/// Constructs a response
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(status: StatusCode) -> Response {
|
pub fn new(status: StatusCode) -> Response {
|
||||||
|
@ -444,6 +456,32 @@ impl ResponseBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This method calls provided closure with builder reference if value is `true`.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated = "Use an if statement."]
|
||||||
|
pub fn if_true<F>(&mut self, value: bool, f: F) -> &mut Self
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut ResponseBuilder),
|
||||||
|
{
|
||||||
|
if value {
|
||||||
|
f(self);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method calls provided closure with builder reference if value is `Some`.
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[deprecated = "Use an if-let construction."]
|
||||||
|
pub fn if_some<T, F>(&mut self, value: Option<T>, f: F) -> &mut Self
|
||||||
|
where
|
||||||
|
F: FnOnce(T, &mut ResponseBuilder),
|
||||||
|
{
|
||||||
|
if let Some(val) = value {
|
||||||
|
f(val, self);
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Responses extensions
|
/// Responses extensions
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
pub fn extensions(&self) -> Ref<'_, Extensions> {
|
||||||
|
@ -692,7 +730,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_upgrade() {
|
fn test_upgrade() {
|
||||||
let resp = ResponseBuilder::new(StatusCode::OK)
|
let resp = Response::build(StatusCode::OK)
|
||||||
.upgrade("websocket")
|
.upgrade("websocket")
|
||||||
.finish();
|
.finish();
|
||||||
assert!(resp.upgrade());
|
assert!(resp.upgrade());
|
||||||
|
@ -704,13 +742,13 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_force_close() {
|
fn test_force_close() {
|
||||||
let resp = ResponseBuilder::new(StatusCode::OK).force_close().finish();
|
let resp = Response::build(StatusCode::OK).force_close().finish();
|
||||||
assert!(!resp.keep_alive())
|
assert!(!resp.keep_alive())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_content_type() {
|
fn test_content_type() {
|
||||||
let resp = ResponseBuilder::new(StatusCode::OK)
|
let resp = Response::build(StatusCode::OK)
|
||||||
.content_type("text/plain")
|
.content_type("text/plain")
|
||||||
.body(Body::Empty);
|
.body(Body::Empty);
|
||||||
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
|
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
|
||||||
|
@ -731,7 +769,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_json_ct() {
|
fn test_json_ct() {
|
||||||
let resp = ResponseBuilder::new(StatusCode::OK)
|
let resp = Response::build(StatusCode::OK)
|
||||||
.insert_header((CONTENT_TYPE, "text/json"))
|
.insert_header((CONTENT_TYPE, "text/json"))
|
||||||
.json(&vec!["v1", "v2", "v3"]);
|
.json(&vec!["v1", "v2", "v3"]);
|
||||||
let ct = resp.headers().get(CONTENT_TYPE).unwrap();
|
let ct = resp.headers().get(CONTENT_TYPE).unwrap();
|
||||||
|
@ -744,7 +782,7 @@ mod tests {
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
let resp =
|
let resp =
|
||||||
ResponseBuilder::new(StatusCode::OK).body(json!({"test-key":"test-value"}));
|
Response::build(StatusCode::OK).body(json!({"test-key":"test-value"}));
|
||||||
assert_eq!(resp.body().get_ref(), br#"{"test-key":"test-value"}"#);
|
assert_eq!(resp.body().get_ref(), br#"{"test-key":"test-value"}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -818,6 +856,24 @@ mod tests {
|
||||||
assert_eq!(resp.body().get_ref(), b"test");
|
assert_eq!(resp.body().get_ref(), b"test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_into_builder() {
|
||||||
|
let mut resp: Response = "test".into();
|
||||||
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
|
|
||||||
|
resp.headers_mut().insert(
|
||||||
|
HeaderName::from_static("cookie"),
|
||||||
|
HeaderValue::from_static("cookie1=val100"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut builder: ResponseBuilder = resp.into();
|
||||||
|
let resp = builder.status(StatusCode::BAD_REQUEST).finish();
|
||||||
|
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
|
||||||
|
|
||||||
|
let cookie = resp.headers().get_all("Cookie").next().unwrap();
|
||||||
|
assert_eq!(cookie.to_str().unwrap(), "cookie1=val100");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn response_builder_header_insert_kv() {
|
fn response_builder_header_insert_kv() {
|
||||||
let mut res = Response::Ok();
|
let mut res = Response::Ok();
|
||||||
|
|
|
@ -9,10 +9,8 @@ use derive_more::{Display, Error, From};
|
||||||
use http::{header, Method, StatusCode};
|
use http::{header, Method, StatusCode};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::ResponseError,
|
error::ResponseError, header::HeaderValue, message::RequestHead, response::Response,
|
||||||
header::HeaderValue,
|
ResponseBuilder,
|
||||||
message::{ConnectionType, RequestHead},
|
|
||||||
response::Response,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod codec;
|
mod codec;
|
||||||
|
@ -131,7 +129,7 @@ impl ResponseError for HandshakeError {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify WebSocket handshake request and create handshake response.
|
/// Verify WebSocket handshake request and create handshake response.
|
||||||
pub fn handshake(req: &RequestHead) -> Result<Response, HandshakeError> {
|
pub fn handshake(req: &RequestHead) -> Result<ResponseBuilder, HandshakeError> {
|
||||||
verify_handshake(req)?;
|
verify_handshake(req)?;
|
||||||
Ok(handshake_response(req))
|
Ok(handshake_response(req))
|
||||||
}
|
}
|
||||||
|
@ -187,39 +185,21 @@ pub fn verify_handshake(req: &RequestHead) -> Result<(), HandshakeError> {
|
||||||
/// Create WebSocket handshake response.
|
/// Create WebSocket handshake response.
|
||||||
///
|
///
|
||||||
/// This function returns handshake `Response`, ready to send to peer.
|
/// This function returns handshake `Response`, ready to send to peer.
|
||||||
pub fn handshake_response(req: &RequestHead) -> Response {
|
pub fn handshake_response(req: &RequestHead) -> ResponseBuilder {
|
||||||
let key = {
|
let key = {
|
||||||
let key = req.headers().get(header::SEC_WEBSOCKET_KEY).unwrap();
|
let key = req.headers().get(header::SEC_WEBSOCKET_KEY).unwrap();
|
||||||
proto::hash_key(key.as_ref())
|
proto::hash_key(key.as_ref())
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = Response::new(StatusCode::SWITCHING_PROTOCOLS);
|
Response::build(StatusCode::SWITCHING_PROTOCOLS)
|
||||||
|
.upgrade("websocket")
|
||||||
res.head_mut().set_connection_type(ConnectionType::Upgrade);
|
.insert_header((header::TRANSFER_ENCODING, "chunked"))
|
||||||
let headers = res.headers_mut();
|
.insert_header((
|
||||||
|
header::SEC_WEBSOCKET_ACCEPT,
|
||||||
headers.insert(header::UPGRADE, HeaderValue::from_static("websocket"));
|
// key is known to be header value safe ascii
|
||||||
|
HeaderValue::from_bytes(&key).unwrap(),
|
||||||
headers.insert(
|
))
|
||||||
header::TRANSFER_ENCODING,
|
.take()
|
||||||
HeaderValue::from_static("chunked"),
|
|
||||||
);
|
|
||||||
headers.insert(
|
|
||||||
header::SEC_WEBSOCKET_ACCEPT,
|
|
||||||
// key is known to be header value safe ascii
|
|
||||||
HeaderValue::from_bytes(&key).unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
res
|
|
||||||
|
|
||||||
// Response::build(StatusCode::SWITCHING_PROTOCOLS)
|
|
||||||
// .upgrade("websocket")
|
|
||||||
// .insert_header((header::TRANSFER_ENCODING, "chunked"))
|
|
||||||
// .insert_header((
|
|
||||||
// header::SEC_WEBSOCKET_ACCEPT,
|
|
||||||
// // key is known to be header value safe ascii
|
|
||||||
// HeaderValue::from_bytes(&key).unwrap(),
|
|
||||||
// ))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -334,7 +314,7 @@ mod tests {
|
||||||
.finish();
|
.finish();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
StatusCode::SWITCHING_PROTOCOLS,
|
StatusCode::SWITCHING_PROTOCOLS,
|
||||||
handshake_response(req.head()).status()
|
handshake_response(req.head()).finish().status()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ where
|
||||||
|
|
||||||
fn call(&self, (req, mut framed): (Request, Framed<T, h1::Codec>)) -> Self::Future {
|
fn call(&self, (req, mut framed): (Request, Framed<T, h1::Codec>)) -> Self::Future {
|
||||||
let fut = async move {
|
let fut = async move {
|
||||||
let res = ws::handshake(req.head()).unwrap().set_body(());
|
let res = ws::handshake(req.head()).unwrap().message_body(());
|
||||||
|
|
||||||
framed
|
framed
|
||||||
.send((res, body::BodySize::None).into())
|
.send((res, body::BodySize::None).into())
|
||||||
|
|
|
@ -163,7 +163,7 @@ pub fn handshake_with_protocols(
|
||||||
.find(|req_p| protocols.iter().any(|p| p == req_p))
|
.find(|req_p| protocols.iter().any(|p| p == req_p))
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut response = HttpResponseBuilder::new(StatusCode::SWITCHING_PROTOCOLS)
|
let mut response = HttpResponse::build(StatusCode::SWITCHING_PROTOCOLS)
|
||||||
.upgrade("websocket")
|
.upgrade("websocket")
|
||||||
.insert_header((
|
.insert_header((
|
||||||
header::SEC_WEBSOCKET_ACCEPT,
|
header::SEC_WEBSOCKET_ACCEPT,
|
||||||
|
|
|
@ -8,13 +8,13 @@ use futures_core::Stream;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use actix_http::body::Body;
|
use actix_http::body::Body;
|
||||||
#[cfg(feature = "cookies")]
|
|
||||||
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, Version,
|
uri, ConnectionType, Error as HttpError, HeaderMap, HeaderValue, Method, Uri, Version,
|
||||||
};
|
};
|
||||||
use actix_http::{Error, RequestHead};
|
use actix_http::{Error, RequestHead};
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
use crate::cookie::{Cookie, CookieJar};
|
use crate::cookie::{Cookie, CookieJar};
|
||||||
use crate::error::{FreezeRequestError, InvalidUrl};
|
use crate::error::{FreezeRequestError, InvalidUrl};
|
||||||
use crate::frozen::FrozenClientRequest;
|
use crate::frozen::FrozenClientRequest;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
//! Test helpers for actix http client to use during testing.
|
//! Test helpers for actix http client to use during testing.
|
||||||
use actix_http::http::header::IntoHeaderPair;
|
use actix_http::http::header::IntoHeaderPair;
|
||||||
use actix_http::http::header::{self, HeaderValue};
|
|
||||||
use actix_http::http::{StatusCode, Version};
|
use actix_http::http::{StatusCode, Version};
|
||||||
use actix_http::{h1, Payload, ResponseHead};
|
use actix_http::{h1, Payload, ResponseHead};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
@ -90,6 +89,8 @@ impl TestResponse {
|
||||||
|
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
for cookie in self.cookies.delta() {
|
for cookie in self.cookies.delta() {
|
||||||
|
use actix_http::http::header::{self, HeaderValue};
|
||||||
|
|
||||||
head.headers.insert(
|
head.headers.insert(
|
||||||
header::SET_COOKIE,
|
header::SET_COOKIE,
|
||||||
HeaderValue::from_str(&cookie.encoded().to_string()).unwrap(),
|
HeaderValue::from_str(&cookie.encoded().to_string()).unwrap(),
|
||||||
|
|
|
@ -25,7 +25,7 @@ async fn test_simple() {
|
||||||
HttpService::build()
|
HttpService::build()
|
||||||
.upgrade(|(req, mut framed): (Request, Framed<_, _>)| {
|
.upgrade(|(req, mut framed): (Request, Framed<_, _>)| {
|
||||||
async move {
|
async move {
|
||||||
let res = ws::handshake_response(req.head());
|
let res = ws::handshake_response(req.head()).finish();
|
||||||
// send handshake response
|
// send handshake response
|
||||||
framed
|
framed
|
||||||
.send(h1::Message::Item((res.drop_body(), BodySize::None)))
|
.send(h1::Message::Item((res.drop_body(), BodySize::None)))
|
||||||
|
|
|
@ -17,7 +17,7 @@ use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_service::AppInitServiceState, config::AppConfig, error::UrlGenerationError,
|
app_service::AppInitServiceState, config::AppConfig, error::UrlGenerationError,
|
||||||
extract::FromRequest, http::header, info::ConnectionInfo, rmap::ResourceMap,
|
extract::FromRequest, info::ConnectionInfo, rmap::ResourceMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
|
@ -272,9 +272,11 @@ impl HttpRequest {
|
||||||
/// Load request cookies.
|
/// Load request cookies.
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
pub fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> {
|
pub fn cookies(&self) -> Result<Ref<'_, Vec<Cookie<'static>>>, CookieParseError> {
|
||||||
|
use actix_http::http::header::COOKIE;
|
||||||
|
|
||||||
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(header::COOKIE) {
|
for hdr in self.headers().get_all(COOKIE) {
|
||||||
let s = str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?;
|
let s = str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?;
|
||||||
for cookie_str in s.split(';').map(|s| s.trim()) {
|
for cookie_str in s.split(';').map(|s| s.trim()) {
|
||||||
if !cookie_str.is_empty() {
|
if !cookie_str.is_empty() {
|
||||||
|
|
|
@ -3,7 +3,6 @@ use std::fmt;
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
error::InternalError,
|
error::InternalError,
|
||||||
http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode},
|
http::{header::IntoHeaderPair, Error as HttpError, HeaderMap, StatusCode},
|
||||||
ResponseBuilder,
|
|
||||||
};
|
};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
|
|
||||||
|
@ -73,11 +72,25 @@ impl Responder for actix_http::Response {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Responder for HttpResponseBuilder {
|
||||||
|
#[inline]
|
||||||
|
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
||||||
|
self.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Responder for actix_http::ResponseBuilder {
|
||||||
|
#[inline]
|
||||||
|
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
||||||
|
HttpResponse::from(self.finish())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Responder> Responder for Option<T> {
|
impl<T: Responder> Responder for Option<T> {
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
||||||
match self {
|
match self {
|
||||||
Some(t) => t.respond_to(req),
|
Some(val) => val.respond_to(req),
|
||||||
None => HttpResponseBuilder::new(StatusCode::NOT_FOUND).finish(),
|
None => HttpResponse::new(StatusCode::NOT_FOUND),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,20 +108,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for HttpResponseBuilder {
|
|
||||||
#[inline]
|
|
||||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
|
||||||
self.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Responder for ResponseBuilder {
|
|
||||||
#[inline]
|
|
||||||
fn respond_to(mut self, _: &HttpRequest) -> HttpResponse {
|
|
||||||
HttpResponse::from(self.finish())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Responder> Responder for (T, StatusCode) {
|
impl<T: Responder> Responder for (T, StatusCode) {
|
||||||
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse {
|
||||||
let mut res = self.0.respond_to(req);
|
let mut res = self.0.respond_to(req);
|
||||||
|
|
16
src/test.rs
16
src/test.rs
|
@ -4,21 +4,19 @@ use std::{net::SocketAddr, rc::Rc};
|
||||||
|
|
||||||
pub use actix_http::test::TestBuffer;
|
pub use actix_http::test::TestBuffer;
|
||||||
use actix_http::{
|
use actix_http::{
|
||||||
http::{
|
http::{header::IntoHeaderPair, Method, StatusCode, Uri, Version},
|
||||||
header::{self, HeaderValue, IntoHeaderPair},
|
|
||||||
Method, StatusCode, Uri, Version,
|
|
||||||
},
|
|
||||||
test::TestRequest as HttpTestRequest,
|
test::TestRequest as HttpTestRequest,
|
||||||
Extensions, Request,
|
Extensions, Request,
|
||||||
};
|
};
|
||||||
use actix_router::{Path, ResourceDef, Url};
|
use actix_router::{Path, ResourceDef, Url};
|
||||||
use actix_service::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
use actix_service::{IntoService, IntoServiceFactory, Service, ServiceFactory};
|
||||||
use actix_utils::future::ok;
|
use actix_utils::future::ok;
|
||||||
use cookie::{Cookie, CookieJar};
|
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use futures_util::StreamExt as _;
|
use futures_util::StreamExt as _;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
|
use crate::cookie::{Cookie, CookieJar};
|
||||||
use crate::{
|
use crate::{
|
||||||
app_service::AppInitServiceState,
|
app_service::AppInitServiceState,
|
||||||
config::AppConfig,
|
config::AppConfig,
|
||||||
|
@ -361,6 +359,7 @@ pub struct TestRequest {
|
||||||
path: Path<Url>,
|
path: Path<Url>,
|
||||||
peer_addr: Option<SocketAddr>,
|
peer_addr: Option<SocketAddr>,
|
||||||
app_data: Extensions,
|
app_data: Extensions,
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: CookieJar,
|
cookies: CookieJar,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,6 +372,7 @@ impl Default for TestRequest {
|
||||||
path: Path::new(Url::new(Uri::default())),
|
path: Path::new(Url::new(Uri::default())),
|
||||||
peer_addr: None,
|
peer_addr: None,
|
||||||
app_data: Extensions::new(),
|
app_data: Extensions::new(),
|
||||||
|
#[cfg(feature = "cookies")]
|
||||||
cookies: CookieJar::new(),
|
cookies: CookieJar::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -512,10 +512,14 @@ impl TestRequest {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&mut self) -> Request {
|
fn finish(&mut self) -> Request {
|
||||||
|
// mut used when cookie feature is enabled
|
||||||
|
#[allow(unused_mut)]
|
||||||
let mut req = self.req.finish();
|
let mut req = self.req.finish();
|
||||||
|
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
{
|
{
|
||||||
|
use actix_http::http::header::{HeaderValue, COOKIE};
|
||||||
|
|
||||||
let cookie: String = self
|
let cookie: String = self
|
||||||
.cookies
|
.cookies
|
||||||
.delta()
|
.delta()
|
||||||
|
@ -526,7 +530,7 @@ impl TestRequest {
|
||||||
|
|
||||||
if !cookie.is_empty() {
|
if !cookie.is_empty() {
|
||||||
req.headers_mut()
|
req.headers_mut()
|
||||||
.insert(header::COOKIE, HeaderValue::from_str(&cookie).unwrap());
|
.insert(COOKIE, HeaderValue::from_str(&cookie).unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue