Compare commits

...

3 Commits

Author SHA1 Message Date
Filip Gregor 6532eaddf2
Merge f1a6640cdc into e1da110e92 2025-11-14 07:37:40 +09:00
Ruchir e1da110e92
chore: Add public export for `EitherExtractError` (#3826)
* chore: Export EitherExtractError for public use

* refactor: export EitherExtractError
2025-11-11 15:28:40 +00:00
Filip Gregor f1a6640cdc feat: ignore unparsable cookies in Cookie header 2025-10-30 22:21:37 +01:00
4 changed files with 22 additions and 4 deletions

View File

@ -5,6 +5,7 @@
- `actix_web::response::builder::HttpResponseBuilder::streaming()` now sets `Content-Type` to `application/octet-stream` if `Content-Type` does not exist. - `actix_web::response::builder::HttpResponseBuilder::streaming()` now sets `Content-Type` to `application/octet-stream` if `Content-Type` does not exist.
- `actix_web::response::builder::HttpResponseBuilder::streaming()` now calls `actix_web::response::builder::HttpResponseBuilder::no_chunking()` if `Content-Length` is set by user. - `actix_web::response::builder::HttpResponseBuilder::streaming()` now calls `actix_web::response::builder::HttpResponseBuilder::no_chunking()` if `Content-Length` is set by user.
- Add `ws` crate feature (on-by-default) which forwards to `actix-http` and guards some of its `ResponseError` impls. - Add `ws` crate feature (on-by-default) which forwards to `actix-http` and guards some of its `ResponseError` impls.
- Add public export for `EitherExtractError` in `error` module.
## 4.11.0 ## 4.11.0

View File

@ -21,6 +21,7 @@ mod response_error;
pub(crate) use self::macros::{downcast_dyn, downcast_get_type_id}; pub(crate) use self::macros::{downcast_dyn, downcast_get_type_id};
pub use self::{error::Error, internal::*, response_error::ResponseError}; pub use self::{error::Error, internal::*, response_error::ResponseError};
pub use crate::types::EitherExtractError;
/// A convenience [`Result`](std::result::Result) for Actix Web operations. /// A convenience [`Result`](std::result::Result) for Actix Web operations.
/// ///

View File

@ -349,9 +349,9 @@ impl HttpRequest {
let mut cookies = Vec::new(); let mut cookies = Vec::new();
for hdr in self.headers().get_all(COOKIE) { for hdr in self.headers().get_all(COOKIE) {
let s = str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?; let s = str::from_utf8(hdr.as_bytes()).map_err(CookieParseError::from)?;
for cookie_str in s.split(';').map(|s| s.trim()) { for cookie_str in s.split(';').map(|s| s.trim()).filter(|s| !s.is_empty()) {
if !cookie_str.is_empty() { if let Ok(cookie) = Cookie::parse_encoded(cookie_str) {
cookies.push(Cookie::parse_encoded(cookie_str)?.into_owned()); cookies.push(cookie.into_owned());
} }
} }
} }
@ -602,6 +602,22 @@ mod tests {
assert!(cookie.is_none()); assert!(cookie.is_none());
} }
#[test]
#[cfg(feature = "cookies")]
fn test_empty_key() {
let req = TestRequest::default()
.append_header((header::COOKIE, "cookie1=value1; value2; cookie3=value3"))
.to_http_request();
{
let cookies = req.cookies().unwrap();
assert_eq!(cookies.len(), 2);
assert_eq!(cookies[0].name(), "cookie1");
assert_eq!(cookies[0].value(), "value1");
assert_eq!(cookies[1].name(), "cookie3");
assert_eq!(cookies[1].value(), "value3");
}
}
#[test] #[test]
fn test_request_query() { fn test_request_query() {
let req = TestRequest::with_uri("/?id=test").to_http_request(); let req = TestRequest::with_uri("/?id=test").to_http_request();

View File

@ -11,7 +11,7 @@ mod query;
mod readlines; mod readlines;
pub use self::{ pub use self::{
either::Either, either::{Either, EitherExtractError},
form::{Form, FormConfig, UrlEncoded}, form::{Form, FormConfig, UrlEncoded},
header::Header, header::Header,
html::Html, html::Html,