diff --git a/CHANGES.md b/CHANGES.md index 954410b30..743f5066b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,10 @@ # Changes ## Unreleased - 2021-xx-xx +### Changed +* 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 diff --git a/Cargo.toml b/Cargo.toml index b0302b352..64b447e14 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 +# support for cookies +cookies = ["actix-http/cookies", "awc/cookies"] + +# secure cookies feature secure-cookies = ["actix-http/secure-cookies"] # openssl @@ -95,17 +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 } -smallvec = "1.6" +url = "2.1" [target.'cfg(windows)'.dependencies.tls-openssl] version = "0.10.9" @@ -122,9 +126,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 b781fe50e..54f7357f1 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -1,6 +1,10 @@ # Changes ## Unreleased - 2021-xx-xx +### Changed +* 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 diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 2c4775898..0e6916a0b 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" @@ -30,11 +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/secure"] +secure-cookies = ["cookies", "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" -sha-1 = "0.9" -smallvec = "1.6" -slab = "0.4" serde_urlencoded = "0.7" +sha-1 = "0.9" +slab = "0.4" +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 5eb3c157a..6a9de2d3e 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/h1/encoder.rs b/actix-http/src/h1/encoder.rs index 69e69de42..97916e7db 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 2610b8784..b1f04e50d 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,7 +106,7 @@ pub trait HttpMessage: Sized { } /// Load request cookies. - #[inline] + #[cfg(feature = "cookies")] fn cookies(&self) -> Result>>, CookieParseError> { if self.extensions().get::().is_none() { let mut cookies = Vec::new(); @@ -119,12 +121,14 @@ pub trait HttpMessage: Sized { } self.extensions_mut().insert(Cookies(cookies)); } + Ok(Ref::map(self.extensions(), |ext| { &ext.get::().unwrap().0 })) } /// 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 a55aaadbf..574d4ef68 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -1,4 +1,19 @@ //! HTTP primitives for the Actix ecosystem. +//! +//! ## Crate Features +//! | Feature | Functionality | +//! | ---------------- | ----------------------------------------------------- | +//! | `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` | 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 #![deny(rust_2018_idioms, nonstandard_style)] #![allow( @@ -34,13 +49,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 +78,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 763243a63..471dacd28 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 8f0a7d21a..870a656df 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("; "); + #[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()); + 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 20e8af6df..9224f414d 100644 --- a/awc/CHANGES.md +++ b/awc/CHANGES.md @@ -1,6 +1,10 @@ # Changes ## Unreleased - 2021-xx-xx +### Changed +* 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 diff --git a/awc/Cargo.toml b/awc/Cargo.toml index 615a76e09..9beecc6d4 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 bd52f7ab1..e50c19c8c 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 db8196c5b..812c0e805 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 1c887ee4e..cf687329d 100644 --- a/awc/src/response.rs +++ b/awc/src/response.rs @@ -1,20 +1,25 @@ -use std::cell::{Ref, RefMut}; 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}; -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}; 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 @@ -39,17 +44,17 @@ 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. - #[inline] + #[cfg(feature = "cookies")] 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 +166,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 +261,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 84646b9f7..97bbb9c3d 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 8db002836..d5528595d 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 1d7c781d8..0865257d3 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), diff --git a/src/lib.rs b/src/lib.rs index 39cfaf197..73390a55e 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 diff --git a/tests/test_server.rs b/tests/test_server.rs index c2caa9eb2..c2e627a3f 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -806,15 +806,15 @@ async fn test_server_cookies() { })) }); + let req = srv.get("/"); + let res = req.send().await.unwrap(); + assert!(res.status().is_success()); + 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()); - let cookies = res.cookies().expect("To have cookies"); assert_eq!(cookies.len(), 2); if cookies[0] == first_cookie {