mirror of
https://github.com/actix/actix-web.git
synced 2024-11-22 17:41:11 +00:00
remove ambiguous HttpResponseBuilder::del_cookie
(#2591)
This commit is contained in:
parent
bc89f0bfc2
commit
ae7f71e317
4 changed files with 59 additions and 79 deletions
|
@ -6,9 +6,11 @@
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- `HttpRequest::req_data[_mut]()`; request-local data is still available through `.extensions()`. [#2585]
|
- `HttpRequest::req_data[_mut]()`; request-local data is still available through `.extensions()`. [#2585]
|
||||||
|
- `HttpRequestBuilder::del_cookie`. [#2591]
|
||||||
|
|
||||||
[#2585]: https://github.com/actix/actix-web/pull/2585
|
[#2585]: https://github.com/actix/actix-web/pull/2585
|
||||||
[#2586]: https://github.com/actix/actix-web/pull/2586
|
[#2586]: https://github.com/actix/actix-web/pull/2586
|
||||||
|
[#2591]: https://github.com/actix/actix-web/pull/2591
|
||||||
|
|
||||||
|
|
||||||
## 4.0.0-beta.20 - 2022-01-14
|
## 4.0.0-beta.20 - 2022-01-14
|
||||||
|
|
|
@ -157,6 +157,10 @@ awc = { path = "awc" }
|
||||||
name = "test_server"
|
name = "test_server"
|
||||||
required-features = ["compress-brotli", "compress-gzip", "compress-zstd", "cookies"]
|
required-features = ["compress-brotli", "compress-gzip", "compress-zstd", "cookies"]
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "compression"
|
||||||
|
required-features = ["compress-brotli", "compress-gzip", "compress-zstd"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "basic"
|
name = "basic"
|
||||||
required-features = ["compress-gzip"]
|
required-features = ["compress-gzip"]
|
||||||
|
|
|
@ -6,18 +6,17 @@ use std::{
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_http::{
|
use actix_http::{error::HttpError, Response, ResponseHead};
|
||||||
error::HttpError,
|
|
||||||
header::{self, HeaderName, TryIntoHeaderPair, TryIntoHeaderValue},
|
|
||||||
ConnectionType, Extensions, Response, ResponseHead, StatusCode,
|
|
||||||
};
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures_core::Stream;
|
use futures_core::Stream;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{BodyStream, BoxBody, MessageBody},
|
body::{BodyStream, BoxBody, MessageBody},
|
||||||
|
dev::Extensions,
|
||||||
error::{Error, JsonPayloadError},
|
error::{Error, JsonPayloadError},
|
||||||
|
http::header::{self, HeaderName, TryIntoHeaderPair, TryIntoHeaderValue},
|
||||||
|
http::{ConnectionType, StatusCode},
|
||||||
BoxError, HttpRequest, HttpResponse, Responder,
|
BoxError, HttpRequest, HttpResponse, Responder,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,9 +25,7 @@ use crate::{
|
||||||
/// 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 HttpResponseBuilder {
|
pub struct HttpResponseBuilder {
|
||||||
res: Option<Response<BoxBody>>,
|
res: Option<Response<BoxBody>>,
|
||||||
err: Option<HttpError>,
|
error: Option<HttpError>,
|
||||||
#[cfg(feature = "cookies")]
|
|
||||||
cookies: Option<cookie::CookieJar>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HttpResponseBuilder {
|
impl HttpResponseBuilder {
|
||||||
|
@ -37,9 +34,7 @@ impl HttpResponseBuilder {
|
||||||
pub fn new(status: StatusCode) -> Self {
|
pub fn new(status: StatusCode) -> Self {
|
||||||
Self {
|
Self {
|
||||||
res: Some(Response::with_body(status, BoxBody::new(()))),
|
res: Some(Response::with_body(status, BoxBody::new(()))),
|
||||||
err: None,
|
error: None,
|
||||||
#[cfg(feature = "cookies")]
|
|
||||||
cookies: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +63,7 @@ impl HttpResponseBuilder {
|
||||||
Ok((key, value)) => {
|
Ok((key, value)) => {
|
||||||
parts.headers.insert(key, value);
|
parts.headers.insert(key, value);
|
||||||
}
|
}
|
||||||
Err(e) => self.err = Some(e.into()),
|
Err(e) => self.error = Some(e.into()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +85,7 @@ impl HttpResponseBuilder {
|
||||||
if let Some(parts) = self.inner() {
|
if let Some(parts) = self.inner() {
|
||||||
match header.try_into_pair() {
|
match header.try_into_pair() {
|
||||||
Ok((key, value)) => parts.headers.append(key, value),
|
Ok((key, value)) => parts.headers.append(key, value),
|
||||||
Err(e) => self.err = Some(e.into()),
|
Err(e) => self.error = Some(e.into()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,14 +104,14 @@ impl HttpResponseBuilder {
|
||||||
K::Error: Into<HttpError>,
|
K::Error: Into<HttpError>,
|
||||||
V: TryIntoHeaderValue,
|
V: TryIntoHeaderValue,
|
||||||
{
|
{
|
||||||
if self.err.is_some() {
|
if self.error.is_some() {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
match (key.try_into(), value.try_into_value()) {
|
match (key.try_into(), value.try_into_value()) {
|
||||||
(Ok(name), Ok(value)) => return self.insert_header((name, value)),
|
(Ok(name), Ok(value)) => return self.insert_header((name, value)),
|
||||||
(Err(err), _) => self.err = Some(err.into()),
|
(Err(err), _) => self.error = Some(err.into()),
|
||||||
(_, Err(err)) => self.err = Some(err.into()),
|
(_, Err(err)) => self.error = Some(err.into()),
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
@ -134,14 +129,14 @@ impl HttpResponseBuilder {
|
||||||
K::Error: Into<HttpError>,
|
K::Error: Into<HttpError>,
|
||||||
V: TryIntoHeaderValue,
|
V: TryIntoHeaderValue,
|
||||||
{
|
{
|
||||||
if self.err.is_some() {
|
if self.error.is_some() {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
match (key.try_into(), value.try_into_value()) {
|
match (key.try_into(), value.try_into_value()) {
|
||||||
(Ok(name), Ok(value)) => return self.append_header((name, value)),
|
(Ok(name), Ok(value)) => return self.append_header((name, value)),
|
||||||
(Err(err), _) => self.err = Some(err.into()),
|
(Err(err), _) => self.error = Some(err.into()),
|
||||||
(_, Err(err)) => self.err = Some(err.into()),
|
(_, Err(err)) => self.error = Some(err.into()),
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
@ -214,18 +209,23 @@ impl HttpResponseBuilder {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
parts.headers.insert(header::CONTENT_TYPE, value);
|
parts.headers.insert(header::CONTENT_TYPE, value);
|
||||||
}
|
}
|
||||||
Err(e) => self.err = Some(e.into()),
|
Err(e) => self.error = Some(e.into()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a cookie.
|
/// Add a cookie to the response.
|
||||||
///
|
///
|
||||||
|
/// To send a "removal" cookie, call [`.make_removal()`](cookie::Cookie::make_removal) on the
|
||||||
|
/// given cookie. See [`HttpResponse::add_removal_cookie()`] to learn more.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// Send a new cookie:
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{HttpResponse, cookie::Cookie};
|
/// use actix_web::{HttpResponse, cookie::Cookie};
|
||||||
///
|
///
|
||||||
/// HttpResponse::Ok()
|
/// let res = HttpResponse::Ok()
|
||||||
/// .cookie(
|
/// .cookie(
|
||||||
/// Cookie::build("name", "value")
|
/// Cookie::build("name", "value")
|
||||||
/// .domain("www.rust-lang.org")
|
/// .domain("www.rust-lang.org")
|
||||||
|
@ -236,45 +236,31 @@ impl HttpResponseBuilder {
|
||||||
/// )
|
/// )
|
||||||
/// .finish();
|
/// .finish();
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "cookies")]
|
|
||||||
pub fn cookie<'c>(&mut self, cookie: cookie::Cookie<'c>) -> &mut Self {
|
|
||||||
if self.cookies.is_none() {
|
|
||||||
let mut jar = cookie::CookieJar::new();
|
|
||||||
jar.add(cookie.into_owned());
|
|
||||||
self.cookies = Some(jar)
|
|
||||||
} else {
|
|
||||||
self.cookies.as_mut().unwrap().add(cookie.into_owned());
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove cookie.
|
|
||||||
///
|
|
||||||
/// A `Set-Cookie` header is added that will delete a cookie with the same name from the client.
|
|
||||||
///
|
///
|
||||||
|
/// Send a removal cookie:
|
||||||
/// ```
|
/// ```
|
||||||
/// use actix_web::{HttpRequest, HttpResponse, Responder};
|
/// use actix_web::{HttpResponse, cookie::Cookie};
|
||||||
///
|
///
|
||||||
/// async fn handler(req: HttpRequest) -> impl Responder {
|
/// // the name, domain and path match the cookie created in the previous example
|
||||||
/// let mut builder = HttpResponse::Ok();
|
/// let mut cookie = Cookie::build("name", "value-does-not-matter")
|
||||||
|
/// .domain("www.rust-lang.org")
|
||||||
|
/// .path("/")
|
||||||
|
/// .finish();
|
||||||
|
/// cookie.make_removal();
|
||||||
///
|
///
|
||||||
/// if let Some(ref cookie) = req.cookie("name") {
|
/// let res = HttpResponse::Ok()
|
||||||
/// builder.del_cookie(cookie);
|
/// .cookie(cookie)
|
||||||
/// }
|
/// .finish();
|
||||||
///
|
|
||||||
/// builder.finish()
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(feature = "cookies")]
|
#[cfg(feature = "cookies")]
|
||||||
pub fn del_cookie(&mut self, cookie: &cookie::Cookie<'_>) -> &mut Self {
|
pub fn cookie(&mut self, cookie: cookie::Cookie<'_>) -> &mut Self {
|
||||||
if self.cookies.is_none() {
|
match cookie.to_string().try_into_value() {
|
||||||
self.cookies = Some(cookie::CookieJar::new())
|
Ok(hdr_val) => self.append_header((header::SET_COOKIE, hdr_val)),
|
||||||
|
Err(err) => {
|
||||||
|
self.error = Some(err.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let jar = self.cookies.as_mut().unwrap();
|
|
||||||
let cookie = cookie.clone().into_owned();
|
|
||||||
jar.add_original(cookie.clone());
|
|
||||||
jar.remove(cookie);
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the response-local data/extensions container.
|
/// Returns a reference to the response-local data/extensions container.
|
||||||
|
@ -297,6 +283,9 @@ impl HttpResponseBuilder {
|
||||||
|
|
||||||
/// Set a body and build the `HttpResponse`.
|
/// Set a body and build the `HttpResponse`.
|
||||||
///
|
///
|
||||||
|
/// Unlike [`message_body`](Self::message_body), errors are converted into error
|
||||||
|
/// responses immediately.
|
||||||
|
///
|
||||||
/// `HttpResponseBuilder` can not be used after this call.
|
/// `HttpResponseBuilder` can not be used after this call.
|
||||||
pub fn body<B>(&mut self, body: B) -> HttpResponse<BoxBody>
|
pub fn body<B>(&mut self, body: B) -> HttpResponse<BoxBody>
|
||||||
where
|
where
|
||||||
|
@ -312,7 +301,7 @@ impl HttpResponseBuilder {
|
||||||
///
|
///
|
||||||
/// `HttpResponseBuilder` can not be used after this call.
|
/// `HttpResponseBuilder` can not be used after this call.
|
||||||
pub fn message_body<B>(&mut self, body: B) -> Result<HttpResponse<B>, Error> {
|
pub fn message_body<B>(&mut self, body: B) -> Result<HttpResponse<B>, Error> {
|
||||||
if let Some(err) = self.err.take() {
|
if let Some(err) = self.error.take() {
|
||||||
return Err(err.into());
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,20 +311,7 @@ impl HttpResponseBuilder {
|
||||||
.expect("cannot reuse response builder")
|
.expect("cannot reuse response builder")
|
||||||
.set_body(body);
|
.set_body(body);
|
||||||
|
|
||||||
#[allow(unused_mut)] // mut is only unused when cookies are disabled
|
Ok(HttpResponse::from(res))
|
||||||
let mut res = HttpResponse::from(res);
|
|
||||||
|
|
||||||
#[cfg(feature = "cookies")]
|
|
||||||
if let Some(ref jar) = self.cookies {
|
|
||||||
for cookie in jar.delta() {
|
|
||||||
match actix_http::header::HeaderValue::from_str(&cookie.to_string()) {
|
|
||||||
Ok(val) => res.headers_mut().append(header::SET_COOKIE, val),
|
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a streaming body and build the `HttpResponse`.
|
/// Set a streaming body and build the `HttpResponse`.
|
||||||
|
@ -384,14 +360,12 @@ impl HttpResponseBuilder {
|
||||||
pub fn take(&mut self) -> Self {
|
pub fn take(&mut self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
res: self.res.take(),
|
res: self.res.take(),
|
||||||
err: self.err.take(),
|
error: self.error.take(),
|
||||||
#[cfg(feature = "cookies")]
|
|
||||||
cookies: self.cookies.take(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inner(&mut self) -> Option<&mut ResponseHead> {
|
fn inner(&mut self) -> Option<&mut ResponseHead> {
|
||||||
if self.err.is_some() {
|
if self.error.is_some() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
cookie::{Cookie, CookieBuilder},
|
cookie::Cookie,
|
||||||
http::{header, StatusCode},
|
http::{header, StatusCode},
|
||||||
middleware::{Compress, NormalizePath, TrailingSlash},
|
middleware::{Compress, NormalizePath, TrailingSlash},
|
||||||
web, App, Error, HttpResponse,
|
web, App, Error, HttpResponse,
|
||||||
|
@ -773,7 +773,7 @@ async fn test_server_cookies() {
|
||||||
App::new().default_service(web::to(|| {
|
App::new().default_service(web::to(|| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.cookie(
|
.cookie(
|
||||||
CookieBuilder::new("first", "first_value")
|
Cookie::build("first", "first_value")
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.finish(),
|
.finish(),
|
||||||
)
|
)
|
||||||
|
@ -787,13 +787,13 @@ async fn test_server_cookies() {
|
||||||
let res = req.send().await.unwrap();
|
let res = req.send().await.unwrap();
|
||||||
assert!(res.status().is_success());
|
assert!(res.status().is_success());
|
||||||
|
|
||||||
let first_cookie = CookieBuilder::new("first", "first_value")
|
let first_cookie = Cookie::build("first", "first_value")
|
||||||
.http_only(true)
|
.http_only(true)
|
||||||
.finish();
|
.finish();
|
||||||
let second_cookie = Cookie::new("second", "second_value");
|
let second_cookie = Cookie::new("second", "first_value");
|
||||||
|
|
||||||
let cookies = res.cookies().expect("To have cookies");
|
let cookies = res.cookies().expect("To have cookies");
|
||||||
assert_eq!(cookies.len(), 2);
|
assert_eq!(cookies.len(), 3);
|
||||||
if cookies[0] == first_cookie {
|
if cookies[0] == first_cookie {
|
||||||
assert_eq!(cookies[1], second_cookie);
|
assert_eq!(cookies[1], second_cookie);
|
||||||
} else {
|
} else {
|
||||||
|
@ -809,7 +809,7 @@ async fn test_server_cookies() {
|
||||||
.get_all(http::header::SET_COOKIE)
|
.get_all(http::header::SET_COOKIE)
|
||||||
.map(|header| header.to_str().expect("To str").to_string())
|
.map(|header| header.to_str().expect("To str").to_string())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
assert_eq!(cookies.len(), 2);
|
assert_eq!(cookies.len(), 3);
|
||||||
if cookies[0] == first_cookie {
|
if cookies[0] == first_cookie {
|
||||||
assert_eq!(cookies[1], second_cookie);
|
assert_eq!(cookies[1], second_cookie);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue