diff --git a/Cargo.toml b/Cargo.toml index b47ba4627d8..d40e68e1af4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,10 +18,6 @@ edition = "2018" # features that docs.rs will build with features = ["openssl", "rustls", "compress", "secure-cookies"] -[badges] -travis-ci = { repository = "actix/actix-web", branch = "master" } -codecov = { repository = "actix/actix-web", branch = "master", service = "github" } - [lib] name = "actix_web" path = "src/lib.rs" @@ -46,10 +42,10 @@ default = ["compress", "cookies"] compress = ["actix-http/compress"] # support for cookies -cookies = ["actix-http/cookies"] +cookies = ["cookie"] # secure cookies feature -secure-cookies = ["actix-http/secure-cookies"] +secure-cookies = ["cookie/secure"] # openssl openssl = ["actix-http/openssl", "actix-tls/accept", "actix-tls/openssl"] @@ -88,7 +84,7 @@ actix-http = "3.0.0-beta.5" ahash = "0.7" bytes = "1" -cookie = "0.15" +cookie = { version = "0.15", features = ["percent-encode"], optional = true } derive_more = "0.99.5" either = "1.5.3" encoding_rs = "0.8" diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 840304966a3..573376b0744 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -16,7 +16,7 @@ edition = "2018" [package.metadata.docs.rs] # features that docs.rs will build with -features = ["openssl", "rustls", "compress", "cookies", "secure-cookies"] +features = ["openssl", "rustls", "compress"] [lib] name = "actix_http" @@ -34,12 +34,6 @@ rustls = ["actix-tls/rustls"] # enable compression support compress = ["flate2", "brotli2"] -# support for cookies -cookies = ["cookie"] - -# support for secure cookies -secure-cookies = ["cookies", "cookie/secure"] - # trust-dns as client dns resolver trust-dns = ["trust-dns-resolver"] @@ -55,7 +49,6 @@ base64 = "0.13" bitflags = "1.2" bytes = "1" bytestring = "1" -cookie = { version = "0.15", features = ["percent-encode"], optional = true } derive_more = "0.99.5" encoding_rs = "0.8" futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] } @@ -95,7 +88,7 @@ actix-tls = { version = "3.0.0-beta.5", features = ["openssl"] } criterion = "0.3" env_logger = "0.8" rcgen = "0.8" -serde_derive = "1.0" +serde = { version = "1.0", features = ["derive"] } tls-openssl = { version = "0.10", package = "openssl" } tls-rustls = { version = "0.19", package = "rustls" } diff --git a/actix-http/src/lib.rs b/actix-http/src/lib.rs index c94ebbd4af7..5dd23249155 100644 --- a/actix-http/src/lib.rs +++ b/actix-http/src/lib.rs @@ -53,9 +53,6 @@ pub mod h2; pub mod test; pub mod ws; -#[cfg(feature = "cookies")] -use cookie; - pub use self::builder::HttpServiceBuilder; pub use self::config::{KeepAlive, ServiceConfig}; pub use self::error::{Error, ResponseError, Result}; @@ -76,8 +73,6 @@ 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; /// A collection of HTTP headers and helpers. diff --git a/actix-http/src/request.rs b/actix-http/src/request.rs index 9209de10809..09c6dd29603 100644 --- a/actix-http/src/request.rs +++ b/actix-http/src/request.rs @@ -5,8 +5,6 @@ use std::{ fmt, net, str, }; -#[cfg(feature = "cookies")] -use cookie::{Cookie, ParseError as CookieParseError}; use http::{header, Method, Uri, Version}; use crate::{ @@ -17,9 +15,6 @@ use crate::{ HttpMessage, }; -#[cfg(feature = "cookies")] -struct Cookies(Vec>); - /// Request pub struct Request

{ pub(crate) payload: Payload

, @@ -175,42 +170,6 @@ impl

Request

{ pub fn peer_addr(&self) -> Option { self.head().peer_addr } - - /// Load request cookies. - #[cfg(feature = "cookies")] - pub fn cookies(&self) -> Result>>, CookieParseError> { - if self.extensions().get::().is_none() { - let mut cookies = Vec::new(); - for hdr in self.headers().get_all(header::COOKIE) { - let s = - str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?; - for cookie_str in s.split(';').map(|s| s.trim()) { - if !cookie_str.is_empty() { - cookies.push(Cookie::parse_encoded(cookie_str)?.into_owned()); - } - } - } - self.extensions_mut().insert(Cookies(cookies)); - } - - Ok(Ref::map(self.extensions(), |ext| { - &ext.get::().unwrap().0 - })) - } - - /// Return request cookie. - #[cfg(feature = "cookies")] - pub fn cookie(&self, name: &str) -> Option> { - if let Ok(cookies) = self.cookies() { - for cookie in cookies.iter() { - if cookie.name() == name { - return Some(cookie.to_owned()); - } - } - } - - None - } } impl

fmt::Debug for Request

{ diff --git a/actix-http/src/response.rs b/actix-http/src/response.rs index 5767e224748..288928c88b5 100644 --- a/actix-http/src/response.rs +++ b/actix-http/src/response.rs @@ -25,11 +25,6 @@ use crate::{ }, message::{BoxedResponseHead, ConnectionType, ResponseHead}, }; -#[cfg(feature = "cookies")] -use crate::{ - cookie::{Cookie, CookieJar}, - http::header::HeaderValue, -}; /// An HTTP Response pub struct Response { @@ -248,34 +243,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>; - - #[inline] - fn next(&mut self) -> Option> { - for v in self.iter.by_ref() { - if let Ok(c) = Cookie::parse_encoded(v.to_str().ok()?) { - return Some(c); - } - } - None - } -} - /// An HTTP response builder. /// /// 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, } impl ResponseBuilder { @@ -285,8 +258,6 @@ impl ResponseBuilder { ResponseBuilder { head: Some(BoxedResponseHead::new(status)), err: None, - #[cfg(feature = "cookies")] - cookies: None, } } @@ -353,7 +324,10 @@ impl ResponseBuilder { } /// Replaced with [`Self::insert_header()`]. - #[deprecated = "Replaced with `insert_header((key, value))`."] + #[deprecated( + since = "4.0.0", + note = "Replaced with `insert_header((key, value))`. Will be removed in v5." + )] pub fn set_header(&mut self, key: K, value: V) -> &mut Self where K: TryInto, @@ -374,7 +348,10 @@ impl ResponseBuilder { } /// Replaced with [`Self::append_header()`]. - #[deprecated = "Replaced with `append_header((key, value))`."] + #[deprecated( + since = "4.0.0", + note = "Replaced with `append_header((key, value))`. Will be removed in v5." + )] pub fn header(&mut self, key: K, value: V) -> &mut Self where K: TryInto, @@ -467,89 +444,6 @@ impl ResponseBuilder { self } - /// Set a cookie - /// - /// ``` - /// use actix_http::{http, Request, Response}; - /// - /// fn index(req: Request) -> Response { - /// Response::Ok() - /// .cookie( - /// http::Cookie::build("name", "value") - /// .domain("www.rust-lang.org") - /// .path("/") - /// .secure(true) - /// .http_only(true) - /// .finish(), - /// ) - /// .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(); - jar.add(cookie.into_owned()); - self.cookies = Some(jar) - } else { - self.cookies.as_mut().unwrap().add(cookie.into_owned()); - } - self - } - - /// Remove cookie - /// - /// ``` - /// use actix_http::{http, Request, Response, HttpMessage}; - /// - /// fn index(req: Request) -> Response { - /// let mut builder = Response::Ok(); - /// - /// if let Some(ref cookie) = req.cookie("name") { - /// builder.del_cookie(cookie); - /// } - /// - /// 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()) - } - let jar = self.cookies.as_mut().unwrap(); - let cookie = cookie.clone().into_owned(); - jar.add_original(cookie.clone()); - jar.remove(cookie); - self - } - - /// This method calls provided closure with builder reference if value is `true`. - #[doc(hidden)] - #[deprecated = "Use an if statement."] - pub fn if_true(&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(&mut self, value: Option, f: F) -> &mut Self - where - F: FnOnce(T, &mut ResponseBuilder), - { - if let Some(val) = value { - f(val, self); - } - self - } - /// Responses extensions #[inline] pub fn extensions(&self) -> Ref<'_, Extensions> { @@ -580,19 +474,7 @@ 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()) { - Ok(val) => response.headers.append(header::SET_COOKIE, val), - Err(e) => return Response::from(Error::from(e)).into_body(), - }; - } - } + let response = self.head.take().expect("cannot reuse response builder"); Response { head: response, @@ -648,8 +530,6 @@ impl ResponseBuilder { ResponseBuilder { head: self.head.take(), err: self.err.take(), - #[cfg(feature = "cookies")] - cookies: self.cookies.take(), } } } @@ -671,8 +551,6 @@ impl From> for ResponseBuilder { ResponseBuilder { head: Some(res.head), err: None, - #[cfg(feature = "cookies")] - cookies: None, } } } @@ -693,8 +571,6 @@ impl<'a> From<&'a ResponseHead> for ResponseBuilder { ResponseBuilder { head: Some(msg), err: None, - #[cfg(feature = "cookies")] - cookies: None, } } } @@ -866,6 +742,7 @@ mod tests { #[test] fn test_serde_json_in_body() { use serde_json::json; + let resp = ResponseBuilder::new(StatusCode::OK).body(json!({"test-key":"test-value"})); assert_eq!(resp.body().get_ref(), br#"{"test-key":"test-value"}"#); diff --git a/actix-test/Cargo.toml b/actix-test/Cargo.toml index aa82fd046f0..db7a50c5e58 100644 --- a/actix-test/Cargo.toml +++ b/actix-test/Cargo.toml @@ -20,7 +20,7 @@ openssl = ["tls-openssl", "actix-http/openssl"] [dependencies] actix-codec = "0.4.0-beta.1" -actix-http = { version = "3.0.0-beta.5", features = ["cookies"] } +actix-http = "3.0.0-beta.5" actix-http-test = { version = "3.0.0-beta.4", features = [] } actix-service = "2.0.0-beta.4" actix-utils = "3.0.0-beta.2" diff --git a/awc/Cargo.toml b/awc/Cargo.toml index c793972dd2b..27d8bdfbcc1 100644 --- a/awc/Cargo.toml +++ b/awc/Cargo.toml @@ -41,7 +41,7 @@ rustls = ["tls-rustls", "actix-http/rustls"] compress = ["actix-http/compress"] # cookie parsing and cookie jar -cookies = ["actix-http/cookies"] +cookies = ["cookie"] # trust-dns as dns resolver trust-dns = ["actix-http/trust-dns"] @@ -54,7 +54,7 @@ actix-rt = { version = "2.1", default-features = false } base64 = "0.13" bytes = "1" -cookie = "0.15" +cookie = { version = "0.15", features = ["percent-encode"], optional = true } derive_more = "0.99.5" futures-core = { version = "0.3.7", default-features = false } itoa = "0.4" diff --git a/awc/src/request.rs b/awc/src/request.rs index fe0f6bfc5a1..3f783445b4a 100644 --- a/awc/src/request.rs +++ b/awc/src/request.rs @@ -494,7 +494,7 @@ impl ClientRequest { let cookie: String = jar .delta() // ensure only name=value is written to cookie header - .map(|c| Cookie::new(c.name(), c.value()).encoded().to_string()) + .map(|c| c.stripped().encoded().to_string()) .collect::>() .join("; "); diff --git a/awc/src/ws.rs b/awc/src/ws.rs index cfc572d3f20..34b71f05288 100644 --- a/awc/src/ws.rs +++ b/awc/src/ws.rs @@ -280,7 +280,7 @@ impl WebsocketsRequest { let cookie: String = jar .delta() // ensure only name=value is written to cookie header - .map(|c| Cookie::new(c.name(), c.value()).encoded().to_string()) + .map(|c| c.stripped().encoded().to_string()) .collect::>() .join("; "); diff --git a/src/response.rs b/src/response.rs index 267064d60e4..37e1528fc11 100644 --- a/src/response.rs +++ b/src/response.rs @@ -340,7 +340,7 @@ impl HttpResponseBuilder { /// Set HTTP status code of this response. #[inline] pub fn status(&mut self, status: StatusCode) -> &mut Self { - if let Some(parts) = self.parts() { + if let Some(parts) = self.inner() { parts.status = status; } self @@ -361,7 +361,7 @@ impl HttpResponseBuilder { where H: IntoHeaderPair, { - if let Some(parts) = self.parts() { + if let Some(parts) = self.inner() { match header.try_into_header_pair() { Ok((key, value)) => { parts.headers.insert(key, value); @@ -389,7 +389,7 @@ impl HttpResponseBuilder { where H: IntoHeaderPair, { - if let Some(parts) = self.parts() { + if let Some(parts) = self.inner() { match header.try_into_header_pair() { Ok((key, value)) => parts.headers.append(key, value), Err(e) => self.err = Some(e.into()), @@ -444,7 +444,7 @@ impl HttpResponseBuilder { /// Set the custom reason for the response. #[inline] pub fn reason(&mut self, reason: &'static str) -> &mut Self { - if let Some(parts) = self.parts() { + if let Some(parts) = self.inner() { parts.reason = Some(reason); } self @@ -453,7 +453,7 @@ impl HttpResponseBuilder { /// Set connection type to KeepAlive #[inline] pub fn keep_alive(&mut self) -> &mut Self { - if let Some(parts) = self.parts() { + if let Some(parts) = self.inner() { parts.set_connection_type(ConnectionType::KeepAlive); } self @@ -465,7 +465,7 @@ impl HttpResponseBuilder { where V: IntoHeaderValue, { - if let Some(parts) = self.parts() { + if let Some(parts) = self.inner() { parts.set_connection_type(ConnectionType::Upgrade); } @@ -479,7 +479,7 @@ impl HttpResponseBuilder { /// Force close connection, even if it is marked as keep-alive #[inline] pub fn force_close(&mut self) -> &mut Self { - if let Some(parts) = self.parts() { + if let Some(parts) = self.inner() { parts.set_connection_type(ConnectionType::Close); } self @@ -491,7 +491,7 @@ impl HttpResponseBuilder { let mut buf = itoa::Buffer::new(); self.insert_header((header::CONTENT_LENGTH, buf.format(len))); - if let Some(parts) = self.parts() { + if let Some(parts) = self.inner() { parts.no_chunking(true); } self @@ -503,7 +503,7 @@ impl HttpResponseBuilder { where V: IntoHeaderValue, { - if let Some(parts) = self.parts() { + if let Some(parts) = self.inner() { match value.try_into_value() { Ok(value) => { parts.headers.insert(header::CONTENT_TYPE, value); @@ -560,7 +560,7 @@ impl HttpResponseBuilder { /// } /// ``` #[cfg(feature = "cookies")] - pub fn del_cookie<'a>(&mut self, cookie: &Cookie<'a>) -> &mut Self { + pub fn del_cookie(&mut self, cookie: &Cookie<'_>) -> &mut Self { if self.cookies.is_none() { self.cookies = Some(CookieJar::new()) } @@ -639,7 +639,7 @@ impl HttpResponseBuilder { pub fn json(&mut self, value: impl Serialize) -> HttpResponse { match serde_json::to_string(&value) { Ok(body) => { - let contains = if let Some(parts) = self.parts() { + let contains = if let Some(parts) = self.inner() { parts.headers.contains_key(header::CONTENT_TYPE) } else { true @@ -674,7 +674,7 @@ impl HttpResponseBuilder { } #[inline] - fn parts(&mut self) -> Option<&mut ResponseHead> { + fn inner(&mut self) -> Option<&mut ResponseHead> { if self.err.is_some() { return None; } diff --git a/src/test.rs b/src/test.rs index b6fd8d2c974..cf0ef80857a 100644 --- a/src/test.rs +++ b/src/test.rs @@ -520,7 +520,7 @@ impl TestRequest { .cookies .delta() // ensure only name=value is written to cookie header - .map(|c| Cookie::new(c.name(), c.value()).encoded().to_string()) + .map(|c| c.stripped().encoded().to_string()) .collect::>() .join("; ");