1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-05-19 16:58:14 +00:00

remove ambiguous HttpResponseBuilder::del_cookie (#2591)

This commit is contained in:
Rob Ede 2022-01-21 17:18:07 +00:00 committed by GitHub
parent bc89f0bfc2
commit ae7f71e317
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 79 deletions

View file

@ -6,9 +6,11 @@
### Removed
- `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
[#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

View file

@ -157,6 +157,10 @@ awc = { path = "awc" }
name = "test_server"
required-features = ["compress-brotli", "compress-gzip", "compress-zstd", "cookies"]
[[test]]
name = "compression"
required-features = ["compress-brotli", "compress-gzip", "compress-zstd"]
[[example]]
name = "basic"
required-features = ["compress-gzip"]

View file

@ -6,18 +6,17 @@ use std::{
task::{Context, Poll},
};
use actix_http::{
error::HttpError,
header::{self, HeaderName, TryIntoHeaderPair, TryIntoHeaderValue},
ConnectionType, Extensions, Response, ResponseHead, StatusCode,
};
use actix_http::{error::HttpError, Response, ResponseHead};
use bytes::Bytes;
use futures_core::Stream;
use serde::Serialize;
use crate::{
body::{BodyStream, BoxBody, MessageBody},
dev::Extensions,
error::{Error, JsonPayloadError},
http::header::{self, HeaderName, TryIntoHeaderPair, TryIntoHeaderValue},
http::{ConnectionType, StatusCode},
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.
pub struct HttpResponseBuilder {
res: Option<Response<BoxBody>>,
err: Option<HttpError>,
#[cfg(feature = "cookies")]
cookies: Option<cookie::CookieJar>,
error: Option<HttpError>,
}
impl HttpResponseBuilder {
@ -37,9 +34,7 @@ impl HttpResponseBuilder {
pub fn new(status: StatusCode) -> Self {
Self {
res: Some(Response::with_body(status, BoxBody::new(()))),
err: None,
#[cfg(feature = "cookies")]
cookies: None,
error: None,
}
}
@ -68,7 +63,7 @@ impl HttpResponseBuilder {
Ok((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() {
match header.try_into_pair() {
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>,
V: TryIntoHeaderValue,
{
if self.err.is_some() {
if self.error.is_some() {
return self;
}
match (key.try_into(), value.try_into_value()) {
(Ok(name), Ok(value)) => return self.insert_header((name, value)),
(Err(err), _) => self.err = Some(err.into()),
(_, Err(err)) => self.err = Some(err.into()),
(Err(err), _) => self.error = Some(err.into()),
(_, Err(err)) => self.error = Some(err.into()),
}
self
@ -134,14 +129,14 @@ impl HttpResponseBuilder {
K::Error: Into<HttpError>,
V: TryIntoHeaderValue,
{
if self.err.is_some() {
if self.error.is_some() {
return self;
}
match (key.try_into(), value.try_into_value()) {
(Ok(name), Ok(value)) => return self.append_header((name, value)),
(Err(err), _) => self.err = Some(err.into()),
(_, Err(err)) => self.err = Some(err.into()),
(Err(err), _) => self.error = Some(err.into()),
(_, Err(err)) => self.error = Some(err.into()),
}
self
@ -214,18 +209,23 @@ impl HttpResponseBuilder {
Ok(value) => {
parts.headers.insert(header::CONTENT_TYPE, value);
}
Err(e) => self.err = Some(e.into()),
Err(e) => self.error = Some(e.into()),
};
}
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};
///
/// HttpResponse::Ok()
/// let res = HttpResponse::Ok()
/// .cookie(
/// Cookie::build("name", "value")
/// .domain("www.rust-lang.org")
@ -236,45 +236,31 @@ impl HttpResponseBuilder {
/// )
/// .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 {
/// let mut builder = HttpResponse::Ok();
/// // the name, domain and path match the cookie created in the previous example
/// 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") {
/// builder.del_cookie(cookie);
/// }
///
/// builder.finish()
/// }
/// let res = HttpResponse::Ok()
/// .cookie(cookie)
/// .finish();
/// ```
#[cfg(feature = "cookies")]
pub fn del_cookie(&mut self, cookie: &cookie::Cookie<'_>) -> &mut Self {
if self.cookies.is_none() {
self.cookies = Some(cookie::CookieJar::new())
pub fn cookie(&mut self, cookie: cookie::Cookie<'_>) -> &mut Self {
match cookie.to_string().try_into_value() {
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.
@ -297,6 +283,9 @@ impl HttpResponseBuilder {
/// 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.
pub fn body<B>(&mut self, body: B) -> HttpResponse<BoxBody>
where
@ -312,7 +301,7 @@ impl HttpResponseBuilder {
///
/// `HttpResponseBuilder` can not be used after this call.
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());
}
@ -322,20 +311,7 @@ impl HttpResponseBuilder {
.expect("cannot reuse response builder")
.set_body(body);
#[allow(unused_mut)] // mut is only unused when cookies are disabled
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)
Ok(HttpResponse::from(res))
}
/// Set a streaming body and build the `HttpResponse`.
@ -384,14 +360,12 @@ impl HttpResponseBuilder {
pub fn take(&mut self) -> Self {
Self {
res: self.res.take(),
err: self.err.take(),
#[cfg(feature = "cookies")]
cookies: self.cookies.take(),
error: self.error.take(),
}
}
fn inner(&mut self) -> Option<&mut ResponseHead> {
if self.err.is_some() {
if self.error.is_some() {
return None;
}

View file

@ -11,7 +11,7 @@ use std::{
};
use actix_web::{
cookie::{Cookie, CookieBuilder},
cookie::Cookie,
http::{header, StatusCode},
middleware::{Compress, NormalizePath, TrailingSlash},
web, App, Error, HttpResponse,
@ -773,7 +773,7 @@ async fn test_server_cookies() {
App::new().default_service(web::to(|| {
HttpResponse::Ok()
.cookie(
CookieBuilder::new("first", "first_value")
Cookie::build("first", "first_value")
.http_only(true)
.finish(),
)
@ -787,13 +787,13 @@ async fn test_server_cookies() {
let res = req.send().await.unwrap();
assert!(res.status().is_success());
let first_cookie = CookieBuilder::new("first", "first_value")
let first_cookie = Cookie::build("first", "first_value")
.http_only(true)
.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");
assert_eq!(cookies.len(), 2);
assert_eq!(cookies.len(), 3);
if cookies[0] == first_cookie {
assert_eq!(cookies[1], second_cookie);
} else {
@ -809,7 +809,7 @@ async fn test_server_cookies() {
.get_all(http::header::SET_COOKIE)
.map(|header| header.to_str().expect("To str").to_string())
.collect::<Vec<_>>();
assert_eq!(cookies.len(), 2);
assert_eq!(cookies.len(), 3);
if cookies[0] == first_cookie {
assert_eq!(cookies[1], second_cookie);
} else {