From afd14d2dedc548f189e1b71e88e91779332b82c4 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 12 Feb 2021 01:24:38 +0000 Subject: [PATCH 1/7] optional cookies features --- CHANGES.md | 3 +- Cargo.toml | 16 +++--- actix-http/CHANGES.md | 3 +- actix-http/Cargo.toml | 19 ++++--- actix-http/src/error.rs | 5 +- actix-http/src/http_message.rs | 8 ++- actix-http/src/lib.rs | 5 +- actix-http/src/response.rs | 92 ++++++++++++++++++++++------------ actix-http/src/test.rs | 37 ++++++++------ awc/CHANGES.md | 3 +- awc/Cargo.toml | 8 ++- awc/src/lib.rs | 4 +- awc/src/request.rs | 11 +++- awc/src/response.rs | 14 +++--- awc/src/test.rs | 14 +++++- awc/src/ws.rs | 8 ++- src/error.rs | 2 + 17 files changed, 171 insertions(+), 81 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 954410b302e..eebc770f59f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,8 @@ # Changes ## Unreleased - 2021-xx-xx - +### Changed +* Feature `cookies` is now optional and enabled by default. ## 4.0.0-beta.3 - 2021-02-10 * Update `actix-web-codegen` to `0.5.0-beta.1`. diff --git a/Cargo.toml b/Cargo.toml index b0302b35239..a935666b19e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ license = "MIT OR Apache-2.0" edition = "2018" [package.metadata.docs.rs] +# features that docs.rs will build with features = ["openssl", "rustls", "compress", "secure-cookies"] [badges] @@ -38,12 +39,15 @@ members = [ ] [features] -default = ["compress"] +default = ["compress", "cookies"] # content-encoding support compress = ["actix-http/compress", "awc/compress"] -# sessions feature +# cookies feature +cookies = ["actix-http/cookies"] + +# secure cookies feature secure-cookies = ["actix-http/secure-cookies"] # openssl @@ -95,16 +99,17 @@ futures-core = { version = "0.3.7", default-features = false } futures-util = { version = "0.3.7", default-features = false } log = "0.4" mime = "0.3" -socket2 = "0.3.16" pin-project = "1.0.0" regex = "1.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_urlencoded = "0.7" +smallvec = "1.6" +socket2 = "0.3.16" time = { version = "0.2.23", default-features = false, features = ["std"] } -url = "2.1" tls-openssl = { package = "openssl", version = "0.10.9", optional = true } tls-rustls = { package = "rustls", version = "0.19.0", optional = true } +url = "2.1" smallvec = "1.6" [target.'cfg(windows)'.dependencies.tls-openssl] @@ -122,9 +127,6 @@ brotli2 = "0.3.2" flate2 = "1.0.13" criterion = "0.3" -[profile.dev] -debug = false - [profile.release] lto = true opt-level = 3 diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index b781fe50e72..94a76e19cbc 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -1,7 +1,8 @@ # Changes ## Unreleased - 2021-xx-xx - +### Changed +* Feature `cookies` is now optional and disabled by default. ## 3.0.0-beta.3 - 2021-02-10 * No notable changes. diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 2c4775898b2..850ca014dfe 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -15,7 +15,8 @@ license = "MIT OR Apache-2.0" edition = "2018" [package.metadata.docs.rs] -features = ["openssl", "rustls", "compress", "secure-cookies"] +# features that docs.rs will build with +features = ["openssl", "rustls", "compress", "cookies", "secure-cookies"] [lib] name = "actix_http" @@ -33,8 +34,11 @@ rustls = ["actix-tls/rustls"] # enable compressison support compress = ["flate2", "brotli2"] +# support for cookies +cookies = ["cookie"] + # support for secure cookies -secure-cookies = ["cookie/secure"] +secure-cookies = ["cookie", "cookie/secure"] # trust-dns as client dns resolver trust-dns = ["trust-dns-resolver"] @@ -46,24 +50,25 @@ actix-utils = "3.0.0-beta.2" actix-rt = "2" actix-tls = "3.0.0-beta.2" +ahash = "0.7" base64 = "0.13" bitflags = "1.2" bytes = "1" bytestring = "1" -cookie = { version = "0.14.1", features = ["percent-encode"] } +cfg-if = "1" +cookie = { version = "0.14.1", features = ["percent-encode"], optional = true } derive_more = "0.99.5" encoding_rs = "0.8" futures-channel = { version = "0.3.7", default-features = false, features = ["alloc"] } futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] } futures-util = { version = "0.3.7", default-features = false, features = ["alloc", "sink"] } -ahash = "0.7" h2 = "0.3.0" http = "0.2.2" httparse = "1.3" indexmap = "1.3" itoa = "0.4" -lazy_static = "1.4" language-tags = "0.2" +lazy_static = "1.4" log = "0.4" mime = "0.3" percent-encoding = "2.1" @@ -72,10 +77,10 @@ rand = "0.8" regex = "1.3" serde = "1.0" serde_json = "1.0" +serde_urlencoded = "0.7" sha-1 = "0.9" -smallvec = "1.6" slab = "0.4" -serde_urlencoded = "0.7" +smallvec = "1.6" time = { version = "0.2.23", default-features = false, features = ["std"] } # compression diff --git a/actix-http/src/error.rs b/actix-http/src/error.rs index 5eb3c157a14..6a9de2d3e02 100644 --- a/actix-http/src/error.rs +++ b/actix-http/src/error.rs @@ -19,10 +19,12 @@ use serde_json::error::Error as JsonError; use serde_urlencoded::ser::Error as FormError; use crate::body::Body; -pub use crate::cookie::ParseError as CookieParseError; use crate::helpers::Writer; use crate::response::{Response, ResponseBuilder}; +#[cfg(feature = "cookies")] +pub use crate::cookie::ParseError as CookieParseError; + /// A specialized [`std::result::Result`] /// for actix web operations /// @@ -397,6 +399,7 @@ impl ResponseError for PayloadError { } /// Return `BadRequest` for `cookie::ParseError` +#[cfg(feature = "cookies")] impl ResponseError for crate::cookie::ParseError { fn status_code(&self) -> StatusCode { StatusCode::BAD_REQUEST diff --git a/actix-http/src/http_message.rs b/actix-http/src/http_message.rs index 2610b878469..1a0983df8e1 100644 --- a/actix-http/src/http_message.rs +++ b/actix-http/src/http_message.rs @@ -5,12 +5,14 @@ use encoding_rs::{Encoding, UTF_8}; use http::header; use mime::Mime; -use crate::cookie::Cookie; -use crate::error::{ContentTypeError, CookieParseError, ParseError}; +use crate::error::{ContentTypeError, ParseError}; use crate::extensions::Extensions; use crate::header::{Header, HeaderMap}; use crate::payload::Payload; +#[cfg(feature = "cookies")] +use crate::{cookie::Cookie, error::CookieParseError}; +#[cfg(feature = "cookies")] struct Cookies(Vec>); /// Trait that implements general purpose operations on HTTP messages. @@ -104,6 +106,7 @@ pub trait HttpMessage: Sized { } /// Load request cookies. + #[cfg(feature = "cookies")] #[inline] fn cookies(&self) -> Result>>, CookieParseError> { if self.extensions().get::().is_none() { @@ -125,6 +128,7 @@ pub trait HttpMessage: Sized { } /// Return request cookie. + #[cfg(feature = "cookies")] fn cookie(&self, name: &str) -> Option> { if let Ok(cookies) = self.cookies() { for cookie in cookies.iter() { diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index a55aaadbf13..a1cb2d846eb 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -34,13 +34,15 @@ mod response; mod service; mod time_parser; -pub use cookie; pub mod error; pub mod h1; pub mod h2; pub mod test; pub mod ws; +#[cfg(feature = "cookies")] +pub use cookie; + pub use self::builder::HttpServiceBuilder; pub use self::config::{KeepAlive, ServiceConfig}; pub use self::error::{Error, ResponseError, Result}; @@ -61,6 +63,7 @@ pub mod http { pub use http::{uri, Error, Uri}; pub use http::{Method, StatusCode, Version}; + #[cfg(feature = "cookies")] pub use crate::cookie::{Cookie, CookieBuilder}; pub use crate::header::HeaderMap; diff --git a/actix-http/src/response.rs b/actix-http/src/response.rs index 763243a63ef..471dacd2841 100644 --- a/actix-http/src/response.rs +++ b/actix-http/src/response.rs @@ -16,13 +16,17 @@ use futures_core::Stream; use serde::Serialize; use crate::body::{Body, BodyStream, MessageBody, ResponseBody}; -use crate::cookie::{Cookie, CookieJar}; use crate::error::Error; use crate::extensions::Extensions; use crate::header::{IntoHeaderPair, IntoHeaderValue}; -use crate::http::header::{self, HeaderName, HeaderValue}; +use crate::http::header::{self, HeaderName}; use crate::http::{Error as HttpError, HeaderMap, StatusCode}; use crate::message::{BoxedResponseHead, ConnectionType, ResponseHead}; +#[cfg(feature = "cookies")] +use crate::{ + cookie::{Cookie, CookieJar}, + http::header::HeaderValue, +}; /// An HTTP Response pub struct Response { @@ -133,6 +137,7 @@ impl Response { } /// Get an iterator for the cookies set by this response + #[cfg(feature = "cookies")] #[inline] pub fn cookies(&self) -> CookieIter<'_> { CookieIter { @@ -141,6 +146,7 @@ impl Response { } /// Add a cookie to this response + #[cfg(feature = "cookies")] #[inline] pub fn add_cookie(&mut self, cookie: &Cookie<'_>) -> Result<(), HttpError> { let h = &mut self.head.headers; @@ -153,6 +159,7 @@ impl Response { /// Remove all cookies with the given name from this response. Returns /// the number of cookies removed. + #[cfg(feature = "cookies")] #[inline] pub fn del_cookie(&mut self, name: &str) -> usize { let h = &mut self.head.headers; @@ -298,10 +305,12 @@ impl Future for Response { } } +#[cfg(feature = "cookies")] pub struct CookieIter<'a> { iter: header::GetAll<'a>, } +#[cfg(feature = "cookies")] impl<'a> Iterator for CookieIter<'a> { type Item = Cookie<'a>; @@ -316,13 +325,13 @@ impl<'a> Iterator for CookieIter<'a> { } } -/// An HTTP response builder +/// An HTTP response builder. /// -/// This type can be used to construct an instance of `Response` through a -/// builder-like pattern. +/// This type can be used to construct an instance of `Response` through a builder-like pattern. pub struct ResponseBuilder { head: Option, err: Option, + #[cfg(feature = "cookies")] cookies: Option, } @@ -333,6 +342,7 @@ impl ResponseBuilder { ResponseBuilder { head: Some(BoxedResponseHead::new(status)), err: None, + #[cfg(feature = "cookies")] cookies: None, } } @@ -531,6 +541,7 @@ impl ResponseBuilder { /// .finish() /// } /// ``` + #[cfg(feature = "cookies")] pub fn cookie<'c>(&mut self, cookie: Cookie<'c>) -> &mut Self { if self.cookies.is_none() { let mut jar = CookieJar::new(); @@ -557,6 +568,7 @@ impl ResponseBuilder { /// builder.finish() /// } /// ``` + #[cfg(feature = "cookies")] pub fn del_cookie<'a>(&mut self, cookie: &Cookie<'a>) -> &mut Self { if self.cookies.is_none() { self.cookies = Some(CookieJar::new()) @@ -624,8 +636,11 @@ impl ResponseBuilder { return Response::from(Error::from(e)).into_body(); } + // allow unused mut when cookies feature is disabled + #[allow(unused_mut)] let mut response = self.head.take().expect("cannot reuse response builder"); + #[cfg(feature = "cookies")] if let Some(ref jar) = self.cookies { for cookie in jar.delta() { match HeaderValue::from_str(&cookie.to_string()) { @@ -693,6 +708,7 @@ impl ResponseBuilder { ResponseBuilder { head: self.head.take(), err: self.err.take(), + #[cfg(feature = "cookies")] cookies: self.cookies.take(), } } @@ -712,21 +728,28 @@ fn parts<'a>( /// Convert `Response` to a `ResponseBuilder`. Body get dropped. impl From> for ResponseBuilder { fn from(res: Response) -> ResponseBuilder { - // If this response has cookies, load them into a jar - let mut jar: Option = None; - for c in res.cookies() { - if let Some(ref mut j) = jar { - j.add_original(c.into_owned()); - } else { - let mut j = CookieJar::new(); - j.add_original(c.into_owned()); - jar = Some(j); + #[cfg(feature = "cookies")] + let jar = { + // If this response has cookies, load them into a jar + let mut jar: Option = None; + + for c in res.cookies() { + if let Some(ref mut j) = jar { + j.add_original(c.into_owned()); + } else { + let mut j = CookieJar::new(); + j.add_original(c.into_owned()); + jar = Some(j); + } } - } + + jar + }; ResponseBuilder { head: Some(res.head), err: None, + #[cfg(feature = "cookies")] cookies: jar, } } @@ -735,22 +758,6 @@ impl From> for ResponseBuilder { /// Convert `ResponseHead` to a `ResponseBuilder` impl<'a> From<&'a ResponseHead> for ResponseBuilder { fn from(head: &'a ResponseHead) -> ResponseBuilder { - // If this response has cookies, load them into a jar - let mut jar: Option = None; - - let cookies = CookieIter { - iter: head.headers.get_all(header::SET_COOKIE), - }; - for c in cookies { - if let Some(ref mut j) = jar { - j.add_original(c.into_owned()); - } else { - let mut j = CookieJar::new(); - j.add_original(c.into_owned()); - jar = Some(j); - } - } - let mut msg = BoxedResponseHead::new(head.status); msg.version = head.version; msg.reason = head.reason; @@ -761,9 +768,32 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder { msg.no_chunking(!head.chunked()); + #[cfg(feature = "cookies")] + let jar = { + // If this response has cookies, load them into a jar + let mut jar: Option = None; + + let cookies = CookieIter { + iter: head.headers.get_all(header::SET_COOKIE), + }; + + for c in cookies { + if let Some(ref mut j) = jar { + j.add_original(c.into_owned()); + } else { + let mut j = CookieJar::new(); + j.add_original(c.into_owned()); + jar = Some(j); + } + } + + jar + }; + ResponseBuilder { head: Some(msg), err: None, + #[cfg(feature = "cookies")] cookies: jar, } } diff --git a/actix-http/src/test.rs b/actix-http/src/test.rs index 8f0a7d21afb..870a656dfc6 100644 --- a/actix-http/src/test.rs +++ b/actix-http/src/test.rs @@ -11,13 +11,14 @@ use std::{ use actix_codec::{AsyncRead, AsyncWrite, ReadBuf}; use bytes::{Bytes, BytesMut}; -use http::{ - header::{self, HeaderValue}, - Method, Uri, Version, -}; +use http::{Method, Uri, Version}; +#[cfg(feature = "cookies")] use crate::{ cookie::{Cookie, CookieJar}, + header::{self, HeaderValue}, +}; +use crate::{ header::{HeaderMap, IntoHeaderPair}, payload::Payload, Request, @@ -53,6 +54,7 @@ struct Inner { method: Method, uri: Uri, headers: HeaderMap, + #[cfg(feature = "cookies")] cookies: CookieJar, payload: Option, } @@ -64,6 +66,7 @@ impl Default for TestRequest { uri: Uri::from_str("/").unwrap(), version: Version::HTTP_11, headers: HeaderMap::new(), + #[cfg(feature = "cookies")] cookies: CookieJar::new(), payload: None, })) @@ -132,6 +135,7 @@ impl TestRequest { } /// Set cookie for this request. + #[cfg(feature = "cookies")] pub fn cookie<'a>(&mut self, cookie: Cookie<'a>) -> &mut Self { parts(&mut self.0).cookies.add(cookie.into_owned()); self @@ -165,17 +169,20 @@ impl TestRequest { head.version = inner.version; head.headers = inner.headers; - let cookie: String = inner - .cookies - .delta() - // ensure only name=value is written to cookie header - .map(|c| Cookie::new(c.name(), c.value()).encoded().to_string()) - .collect::>() - .join("; "); - - if !cookie.is_empty() { - head.headers - .insert(header::COOKIE, HeaderValue::from_str(&cookie).unwrap()); + #[cfg(feature = "cookies")] + { + let cookie: String = inner + .cookies + .delta() + // ensure only name=value is written to cookie header + .map(|c| Cookie::new(c.name(), c.value()).encoded().to_string()) + .collect::>() + .join("; "); + + if !cookie.is_empty() { + head.headers + .insert(header::COOKIE, HeaderValue::from_str(&cookie).unwrap()); + } } req diff --git a/awc/CHANGES.md b/awc/CHANGES.md index 20e8af6df2a..b33bdcf81eb 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -1,7 +1,8 @@ # Changes ## Unreleased - 2021-xx-xx - +### Changed +* Feature `cookies` is now optional and enabled by default. ## 3.0.0-beta.2 - 2021-02-10 ### Added diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 615a76e098e..9beecc6d4d3 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -22,10 +22,11 @@ name = "awc" path = "src/lib.rs" [package.metadata.docs.rs] -features = ["openssl", "rustls", "compress"] +# features that docs.rs will build with +features = ["openssl", "rustls", "compress", "cookies"] [features] -default = ["compress"] +default = ["compress", "cookies"] # openssl openssl = ["tls-openssl", "actix-http/openssl"] @@ -36,6 +37,9 @@ rustls = ["tls-rustls", "actix-http/rustls"] # content-encoding support compress = ["actix-http/compress"] +# cookie parsing and cookie jar +cookies = ["actix-http/cookies"] + # trust-dns as dns resolver trust-dns = ["actix-http/trust-dns"] diff --git a/awc/src/lib.rs b/awc/src/lib.rs index bd52f7ab131..e50c19c8cae 100644 --- a/awc/src/lib.rs +++ b/awc/src/lib.rs @@ -97,7 +97,9 @@ use std::convert::TryFrom; use std::rc::Rc; use std::time::Duration; -pub use actix_http::{client::Connector, cookie, http}; +#[cfg(feature = "cookies")] +pub use actix_http::cookie; +pub use actix_http::{client::Connector, http}; use actix_http::http::{Error as HttpError, HeaderMap, Method, Uri}; use actix_http::RequestHead; diff --git a/awc/src/request.rs b/awc/src/request.rs index db8196c5b0f..812c0e8056e 100644 --- a/awc/src/request.rs +++ b/awc/src/request.rs @@ -8,6 +8,7 @@ use futures_core::Stream; use serde::Serialize; use actix_http::body::Body; +#[cfg(feature = "cookies")] use actix_http::cookie::{Cookie, CookieJar}; use actix_http::http::header::{self, IntoHeaderPair}; use actix_http::http::{ @@ -54,10 +55,12 @@ pub struct ClientRequest { pub(crate) head: RequestHead, err: Option, addr: Option, - cookies: Option, response_decompress: bool, timeout: Option, config: Rc, + + #[cfg(feature = "cookies")] + cookies: Option, } impl ClientRequest { @@ -72,6 +75,7 @@ impl ClientRequest { head: RequestHead::default(), err: None, addr: None, + #[cfg(feature = "cookies")] cookies: None, timeout: None, response_decompress: true, @@ -290,6 +294,7 @@ impl ClientRequest { /// println!("Response: {:?}", resp); /// } /// ``` + #[cfg(feature = "cookies")] pub fn cookie(mut self, cookie: Cookie<'_>) -> Self { if self.cookies.is_none() { let mut jar = CookieJar::new(); @@ -472,7 +477,8 @@ impl ClientRequest { ) } - fn prep_for_sending(mut self) -> Result { + // allow unused mut when cookies feature is disabled + fn prep_for_sending(#[allow(unused_mut)] mut self) -> Result { if let Some(e) = self.err { return Err(e.into()); } @@ -493,6 +499,7 @@ impl ClientRequest { } // set cookies + #[cfg(feature = "cookies")] if let Some(ref mut jar) = self.cookies { let cookie: String = jar .delta() diff --git a/awc/src/response.rs b/awc/src/response.rs index 1c887ee4ea7..faf89192ec8 100644 --- a/awc/src/response.rs +++ b/awc/src/response.rs @@ -8,10 +8,11 @@ use std::task::{Context, Poll}; use bytes::{Bytes, BytesMut}; use futures_core::{ready, Stream}; -use actix_http::cookie::Cookie; -use actix_http::error::{CookieParseError, PayloadError}; -use actix_http::http::header::{CONTENT_LENGTH, SET_COOKIE}; +use actix_http::error::PayloadError; +use actix_http::http::header; use actix_http::http::{HeaderMap, StatusCode, Version}; +#[cfg(feature = "cookies")] +use actix_http::{cookie::Cookie, error::CookieParseError}; use actix_http::{Extensions, HttpMessage, Payload, PayloadStream, ResponseHead}; use serde::de::DeserializeOwned; @@ -43,13 +44,14 @@ impl HttpMessage for ClientResponse { } /// Load request cookies. + #[cfg(feature = "cookies")] #[inline] fn cookies(&self) -> Result>>, CookieParseError> { struct Cookies(Vec>); if self.extensions().get::().is_none() { let mut cookies = Vec::new(); - for hdr in self.headers().get_all(&SET_COOKIE) { + for hdr in self.headers().get_all(&header::SET_COOKIE) { let s = std::str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?; cookies.push(Cookie::parse_encoded(s)?.into_owned()); } @@ -161,7 +163,7 @@ where /// Create `MessageBody` for request. pub fn new(res: &mut ClientResponse) -> MessageBody { let mut len = None; - if let Some(l) = res.headers().get(&CONTENT_LENGTH) { + if let Some(l) = res.headers().get(&header::CONTENT_LENGTH) { if let Ok(s) = l.to_str() { if let Ok(l) = s.parse::() { len = Some(l) @@ -256,7 +258,7 @@ where } let mut len = None; - if let Some(l) = req.headers().get(&CONTENT_LENGTH) { + if let Some(l) = req.headers().get(&header::CONTENT_LENGTH) { if let Ok(s) = l.to_str() { if let Ok(l) = s.parse::() { len = Some(l) diff --git a/awc/src/test.rs b/awc/src/test.rs index 84646b9f717..97bbb9c3da5 100644 --- a/awc/src/test.rs +++ b/awc/src/test.rs @@ -1,9 +1,13 @@ //! Test helpers for actix http client to use during testing. use std::convert::TryFrom; -use actix_http::cookie::{Cookie, CookieJar}; -use actix_http::http::header::{self, Header, HeaderValue, IntoHeaderValue}; +use actix_http::http::header::{Header, IntoHeaderValue}; use actix_http::http::{Error as HttpError, HeaderName, StatusCode, Version}; +#[cfg(feature = "cookies")] +use actix_http::{ + cookie::{Cookie, CookieJar}, + http::header::{self, HeaderValue}, +}; use actix_http::{h1, Payload, ResponseHead}; use bytes::Bytes; @@ -12,6 +16,7 @@ use crate::ClientResponse; /// Test `ClientResponse` builder pub struct TestResponse { head: ResponseHead, + #[cfg(feature = "cookies")] cookies: CookieJar, payload: Option, } @@ -20,6 +25,7 @@ impl Default for TestResponse { fn default() -> TestResponse { TestResponse { head: ResponseHead::new(StatusCode::OK), + #[cfg(feature = "cookies")] cookies: CookieJar::new(), payload: None, } @@ -69,6 +75,7 @@ impl TestResponse { } /// Set cookie for this response + #[cfg(feature = "cookies")] pub fn cookie(mut self, cookie: Cookie<'_>) -> Self { self.cookies.add(cookie.into_owned()); self @@ -84,8 +91,11 @@ impl TestResponse { /// Complete response creation and generate `ClientResponse` instance pub fn finish(self) -> ClientResponse { + // allow unused mut when cookies feature is disabled + #[allow(unused_mut)] let mut head = self.head; + #[cfg(feature = "cookies")] for cookie in self.cookies.delta() { head.headers.insert( header::SET_COOKIE, diff --git a/awc/src/ws.rs b/awc/src/ws.rs index 8db0028364f..d5528595d88 100644 --- a/awc/src/ws.rs +++ b/awc/src/ws.rs @@ -32,6 +32,7 @@ use std::rc::Rc; use std::{fmt, str}; use actix_codec::Framed; +#[cfg(feature = "cookies")] use actix_http::cookie::{Cookie, CookieJar}; use actix_http::{ws, Payload, RequestHead}; use actix_rt::time::timeout; @@ -54,8 +55,10 @@ pub struct WebsocketsRequest { addr: Option, max_size: usize, server_mode: bool, - cookies: Option, config: Rc, + + #[cfg(feature = "cookies")] + cookies: Option, } impl WebsocketsRequest { @@ -89,6 +92,7 @@ impl WebsocketsRequest { protocols: None, max_size: 65_536, server_mode: false, + #[cfg(feature = "cookies")] cookies: None, } } @@ -117,6 +121,7 @@ impl WebsocketsRequest { } /// Set a cookie + #[cfg(feature = "cookies")] pub fn cookie(mut self, cookie: Cookie<'_>) -> Self { if self.cookies.is_none() { let mut jar = CookieJar::new(); @@ -270,6 +275,7 @@ impl WebsocketsRequest { } // set cookies + #[cfg(feature = "cookies")] if let Some(ref mut jar) = self.cookies { let cookie: String = jar .delta() diff --git a/src/error.rs b/src/error.rs index 1d7c781d872..0865257d3c3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,9 +13,11 @@ pub enum UrlGenerationError { /// Resource not found #[display(fmt = "Resource not found")] ResourceNotFound, + /// Not all path pattern covered #[display(fmt = "Not all path pattern covered")] NotEnoughElements, + /// URL parse error #[display(fmt = "{}", _0)] ParseError(UrlParseError), From 685ba0eea2a337f799e4111327347c14ee041791 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 12 Feb 2021 01:55:25 +0000 Subject: [PATCH 2/7] update changelogs --- CHANGES.md | 5 ++++- actix-http/CHANGES.md | 5 ++++- actix-http/Cargo.toml | 4 ++-- actix-http/src/lib.rs | 17 +++++++++++++++++ awc/CHANGES.md | 5 ++++- src/lib.rs | 1 + 6 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index eebc770f59f..743f5066b88 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,10 @@ ## Unreleased - 2021-xx-xx ### Changed -* Feature `cookies` is now optional and enabled by default. +* Feature `cookies` is now optional and enabled by default. [#1981] + +[#1981]: https://github.com/actix/actix-web/pull/1981 + ## 4.0.0-beta.3 - 2021-02-10 * Update `actix-web-codegen` to `0.5.0-beta.1`. diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index 94a76e19cbc..54f7357f1a4 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -2,7 +2,10 @@ ## Unreleased - 2021-xx-xx ### Changed -* Feature `cookies` is now optional and disabled by default. +* Feature `cookies` is now optional and disabled by default. [#1981] + +[#1981]: https://github.com/actix/actix-web/pull/1981 + ## 3.0.0-beta.3 - 2021-02-10 * No notable changes. diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 850ca014dfe..0e6916a0b83 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -31,14 +31,14 @@ openssl = ["actix-tls/openssl"] # rustls support rustls = ["actix-tls/rustls"] -# enable compressison support +# enable compression support compress = ["flate2", "brotli2"] # support for cookies cookies = ["cookie"] # support for secure cookies -secure-cookies = ["cookie", "cookie/secure"] +secure-cookies = ["cookies", "cookie/secure"] # trust-dns as client dns resolver trust-dns = ["trust-dns-resolver"] diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index a1cb2d846eb..5fac02fa482 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -1,4 +1,21 @@ //! HTTP primitives for the Actix ecosystem. +//! +//! # Crate Features +//! | Feature | Functionality | +//! | ---------------- | ----------------------------------------------------- | +//! | `openssl` | TLS support via [OpenSSL](openssl). | +//! | `rustls` | TLS support via [rustls](rustls). | +//! | `compress` | Payload compression support. (Deflate, Gzip & Brotli) | +//! | `cookies` | Support for cookies backed by the [cookie] crate. | +//! | `secure-cookies` | Adds for secure cookies. Enables `cookies` feature. | +//! | `trust-dns` | Uses [`trust-dns`] as the client DNS resolver. | +//! +//! [openssl]: https://crates.io/crates/openssl +//! [rustls]: https://crates.io/crates/rustls +//! [cookie]: https://crates.io/crates/cookie +//! [trust-dns]: https://crates.io/crates/trust-dns +//! [trust-dns]: https://crates.io/crates/trust-dns + #![deny(rust_2018_idioms, nonstandard_style)] #![allow( diff --git a/awc/CHANGES.md b/awc/CHANGES.md index b33bdcf81eb..9224f414d5f 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -2,7 +2,10 @@ ## Unreleased - 2021-xx-xx ### Changed -* Feature `cookies` is now optional and enabled by default. +* Feature `cookies` is now optional and enabled by default. [#1981] + +[#1981]: https://github.com/actix/actix-web/pull/1981 + ## 3.0.0-beta.2 - 2021-02-10 ### Added diff --git a/src/lib.rs b/src/lib.rs index 39cfaf1978a..73390a55e8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,6 +61,7 @@ //! ## Crate Features //! //! * `compress` - content encoding compression support (enabled by default) +//! * `cookies` - cookies support (enabled by default) //! * `openssl` - HTTPS support via `openssl` crate, supports `HTTP/2` //! * `rustls` - HTTPS support via `rustls` crate, supports `HTTP/2` //! * `secure-cookies` - secure cookies support From 156462fdc1feaa17c40b74dd0c95428df70ff6aa Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 12 Feb 2021 02:00:45 +0000 Subject: [PATCH 3/7] update feature docs --- actix-http/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index 5fac02fa482..574d4ef68b7 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -1,21 +1,19 @@ //! HTTP primitives for the Actix ecosystem. //! -//! # Crate Features +//! ## Crate Features //! | Feature | Functionality | //! | ---------------- | ----------------------------------------------------- | -//! | `openssl` | TLS support via [OpenSSL](openssl). | -//! | `rustls` | TLS support via [rustls](rustls). | +//! | `openssl` | TLS support via [OpenSSL]. | +//! | `rustls` | TLS support via [rustls]. | //! | `compress` | Payload compression support. (Deflate, Gzip & Brotli) | //! | `cookies` | Support for cookies backed by the [cookie] crate. | //! | `secure-cookies` | Adds for secure cookies. Enables `cookies` feature. | -//! | `trust-dns` | Uses [`trust-dns`] as the client DNS resolver. | -//! -//! [openssl]: https://crates.io/crates/openssl +//! | `trust-dns` | Use [trust-dns] as the client DNS resolver. | +//! +//! [OpenSSL]: https://crates.io/crates/openssl //! [rustls]: https://crates.io/crates/rustls //! [cookie]: https://crates.io/crates/cookie //! [trust-dns]: https://crates.io/crates/trust-dns -//! [trust-dns]: https://crates.io/crates/trust-dns - #![deny(rust_2018_idioms, nonstandard_style)] #![allow( From 0dbd16511b6903b021e0860218516b2ec2a7ab22 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Fri, 12 Feb 2021 03:58:21 +0000 Subject: [PATCH 4/7] wat --- actix-http/src/http_message.rs | 4 +++- awc/src/response.rs | 13 ++++++++----- tests/test_server.rs | 11 +++++++---- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/actix-http/src/http_message.rs b/actix-http/src/http_message.rs index 1a0983df8e1..577de8d59db 100644 --- a/actix-http/src/http_message.rs +++ b/actix-http/src/http_message.rs @@ -107,8 +107,9 @@ pub trait HttpMessage: Sized { /// Load request cookies. #[cfg(feature = "cookies")] - #[inline] fn cookies(&self) -> Result>>, CookieParseError> { + eprintln!("default impl cookies?"); + if self.extensions().get::().is_none() { let mut cookies = Vec::new(); for hdr in self.headers().get_all(header::COOKIE) { @@ -122,6 +123,7 @@ pub trait HttpMessage: Sized { } self.extensions_mut().insert(Cookies(cookies)); } + Ok(Ref::map(self.extensions(), |ext| { &ext.get::().unwrap().0 })) diff --git a/awc/src/response.rs b/awc/src/response.rs index faf89192ec8..242bdb6235c 100644 --- a/awc/src/response.rs +++ b/awc/src/response.rs @@ -1,4 +1,4 @@ -use std::cell::{Ref, RefMut}; +use std::{cell::{Ref, RefMut}, mem}; use std::fmt; use std::future::Future; use std::marker::PhantomData; @@ -11,11 +11,12 @@ use futures_core::{ready, Stream}; use actix_http::error::PayloadError; use actix_http::http::header; use actix_http::http::{HeaderMap, StatusCode, Version}; -#[cfg(feature = "cookies")] -use actix_http::{cookie::Cookie, error::CookieParseError}; use actix_http::{Extensions, HttpMessage, Payload, PayloadStream, ResponseHead}; use serde::de::DeserializeOwned; +#[cfg(feature = "cookies")] +use actix_http::{cookie::Cookie, error::CookieParseError}; + use crate::error::JsonPayloadError; /// Client Response @@ -40,16 +41,18 @@ impl HttpMessage for ClientResponse { } fn take_payload(&mut self) -> Payload { - std::mem::replace(&mut self.payload, Payload::None) + mem::replace(&mut self.payload, Payload::None) } /// Load request cookies. #[cfg(feature = "cookies")] - #[inline] fn cookies(&self) -> Result>>, CookieParseError> { + eprintln!("awc fn cookies"); + struct Cookies(Vec>); if self.extensions().get::().is_none() { + eprintln!("no cookies, inserting"); let mut cookies = Vec::new(); for hdr in self.headers().get_all(&header::SET_COOKIE) { let s = std::str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?; diff --git a/tests/test_server.rs b/tests/test_server.rs index c2caa9eb2c8..6bf8dbcb602 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -806,15 +806,18 @@ async fn test_server_cookies() { })) }); + let req = srv.get("/"); + let res = req.send().await.unwrap(); + assert!(res.status().is_success()); + + eprintln!("{:?}", &res); + let first_cookie = http::CookieBuilder::new("first", "first_value") .http_only(true) .finish(); let second_cookie = http::Cookie::new("second", "second_value"); - let req = srv.get("/"); - let res = req.send().await.unwrap(); - assert!(res.status().is_success()); - + eprintln!("gimme cookie"); let cookies = res.cookies().expect("To have cookies"); assert_eq!(cookies.len(), 2); if cookies[0] == first_cookie { From ac81a6825f075ee774d7e0eee4c572b3f783c67b Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sat, 13 Feb 2021 04:53:45 +0000 Subject: [PATCH 5/7] revert printlns --- Cargo.toml | 4 ++-- actix-http/src/h1/encoder.rs | 1 - actix-http/src/http_message.rs | 2 -- awc/src/response.rs | 2 -- tests/test_server.rs | 3 --- 5 files changed, 2 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a935666b19e..6f13efac26f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,8 +44,8 @@ default = ["compress", "cookies"] # content-encoding support compress = ["actix-http/compress", "awc/compress"] -# cookies feature -cookies = ["actix-http/cookies"] +# support for cookies +cookies = ["actix-http/cookies", "awc/cookies"] # secure cookies feature secure-cookies = ["actix-http/secure-cookies"] diff --git a/actix-http/src/h1/encoder.rs b/actix-http/src/h1/encoder.rs index 69e69de4212..97916e7dbb7 100644 --- a/actix-http/src/h1/encoder.rs +++ b/actix-http/src/h1/encoder.rs @@ -549,7 +549,6 @@ mod tests { ); let data = String::from_utf8(Vec::from(bytes.split().freeze().as_ref())).unwrap(); - eprintln!("{}", &data); assert!(data.contains("Content-Length: 0\r\n")); assert!(data.contains("Connection: close\r\n")); diff --git a/actix-http/src/http_message.rs b/actix-http/src/http_message.rs index 577de8d59db..b1f04e50d82 100644 --- a/actix-http/src/http_message.rs +++ b/actix-http/src/http_message.rs @@ -108,8 +108,6 @@ pub trait HttpMessage: Sized { /// Load request cookies. #[cfg(feature = "cookies")] fn cookies(&self) -> Result>>, CookieParseError> { - eprintln!("default impl cookies?"); - if self.extensions().get::().is_none() { let mut cookies = Vec::new(); for hdr in self.headers().get_all(header::COOKIE) { diff --git a/awc/src/response.rs b/awc/src/response.rs index 242bdb6235c..a9284963196 100644 --- a/awc/src/response.rs +++ b/awc/src/response.rs @@ -47,12 +47,10 @@ impl HttpMessage for ClientResponse { /// Load request cookies. #[cfg(feature = "cookies")] fn cookies(&self) -> Result>>, CookieParseError> { - eprintln!("awc fn cookies"); struct Cookies(Vec>); if self.extensions().get::().is_none() { - eprintln!("no cookies, inserting"); let mut cookies = Vec::new(); for hdr in self.headers().get_all(&header::SET_COOKIE) { let s = std::str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?; diff --git a/tests/test_server.rs b/tests/test_server.rs index 6bf8dbcb602..c2e627a3faa 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -810,14 +810,11 @@ async fn test_server_cookies() { let res = req.send().await.unwrap(); assert!(res.status().is_success()); - eprintln!("{:?}", &res); - let first_cookie = http::CookieBuilder::new("first", "first_value") .http_only(true) .finish(); let second_cookie = http::Cookie::new("second", "second_value"); - eprintln!("gimme cookie"); let cookies = res.cookies().expect("To have cookies"); assert_eq!(cookies.len(), 2); if cookies[0] == first_cookie { From 1e85b0fdc455e919f5019b221665dcc59d264b4c Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sat, 13 Feb 2021 04:58:25 +0000 Subject: [PATCH 6/7] fix cargo --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6f13efac26f..64b447e149e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,7 +110,6 @@ time = { version = "0.2.23", default-features = false, features = ["std"] } tls-openssl = { package = "openssl", version = "0.10.9", optional = true } tls-rustls = { package = "rustls", version = "0.19.0", optional = true } url = "2.1" -smallvec = "1.6" [target.'cfg(windows)'.dependencies.tls-openssl] version = "0.10.9" From 65072fdb3ceb427e08a1b8f54882aeca0c09ebfb Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sat, 13 Feb 2021 05:00:55 +0000 Subject: [PATCH 7/7] fmt --- awc/src/response.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/awc/src/response.rs b/awc/src/response.rs index a9284963196..cf687329d3a 100644 --- a/awc/src/response.rs +++ b/awc/src/response.rs @@ -1,9 +1,12 @@ -use std::{cell::{Ref, RefMut}, mem}; use std::fmt; use std::future::Future; use std::marker::PhantomData; use std::pin::Pin; use std::task::{Context, Poll}; +use std::{ + cell::{Ref, RefMut}, + mem, +}; use bytes::{Bytes, BytesMut}; use futures_core::{ready, Stream}; @@ -47,7 +50,6 @@ impl HttpMessage for ClientResponse { /// Load request cookies. #[cfg(feature = "cookies")] fn cookies(&self) -> Result>>, CookieParseError> { - struct Cookies(Vec>); if self.extensions().get::().is_none() {