mirror of https://github.com/fafhrd91/actix-web
refactor: remove Option from RequestHeadType::Rc extra headers
Replace `RequestHeadType::Rc(Rc<RequestHead>, Option<HeaderMap>)` with `RequestHeadType::Rc(Rc<RequestHead>, HeaderMap)`, using an empty HeaderMap as the default instead of None. This enables: - `RequestHeadType::extra_headers_mut()` for modifying headers on both Owned and Rc variants - `ConnectRequest::headers_mut()` for middleware to insert headers without destructuring the request Closes #2477
This commit is contained in:
parent
7ded7ee478
commit
0160b00a90
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
- Remove `Option` wrapper from `RequestHeadType::Rc` extra headers; add `RequestHeadType::extra_headers_mut()` method.
|
||||
- When configured, gracefully close HTTP/1 connections after early responses to unread request bodies. [#3967]
|
||||
- Wake HTTP/1 payload receivers with an incomplete-payload error when the sender is dropped before EOF. [#3100]
|
||||
- Update `foldhash` dependency to `0.2`.
|
||||
|
|
|
|||
|
|
@ -648,7 +648,7 @@ mod tests {
|
|||
);
|
||||
extra_headers.insert(DATE, HeaderValue::from_static("date"));
|
||||
|
||||
let mut head = RequestHeadType::Rc(Rc::new(head), Some(extra_headers));
|
||||
let mut head = RequestHeadType::Rc(Rc::new(head), extra_headers);
|
||||
|
||||
let _ = head.encode_headers(
|
||||
&mut bytes,
|
||||
|
|
|
|||
|
|
@ -150,14 +150,32 @@ impl RequestHead {
|
|||
#[derive(Debug)]
|
||||
pub enum RequestHeadType {
|
||||
Owned(RequestHead),
|
||||
Rc(Rc<RequestHead>, Option<HeaderMap>),
|
||||
Rc(Rc<RequestHead>, HeaderMap),
|
||||
}
|
||||
|
||||
impl RequestHeadType {
|
||||
pub fn extra_headers(&self) -> Option<&HeaderMap> {
|
||||
match self {
|
||||
RequestHeadType::Owned(_) => None,
|
||||
RequestHeadType::Rc(_, headers) => headers.as_ref(),
|
||||
RequestHeadType::Rc(_, headers) => {
|
||||
if headers.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(headers)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the headers that can be modified on this request.
|
||||
///
|
||||
/// For `Owned` variants, this returns the main header map.
|
||||
/// For `Rc` variants, this returns the extra headers map (which overrides base headers
|
||||
/// during encoding).
|
||||
pub fn extra_headers_mut(&mut self) -> &mut HeaderMap {
|
||||
match self {
|
||||
RequestHeadType::Owned(head) => &mut head.headers,
|
||||
RequestHeadType::Rc(_, headers) => headers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
## Unreleased
|
||||
|
||||
- Add `ConnectRequest::headers_mut()` to allow middleware to modify request headers.
|
||||
- Add camel-case header controls to `WebsocketsRequest` via `camel_case_headers()` and `set_camel_case_headers()`. [#3953]
|
||||
- Update `hickory-resolver` dependency to `0.26.1`.
|
||||
- Update `rand` dependency to `0.10`.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use actix_http::{
|
|||
body::{BodySize, MessageBody},
|
||||
error::PayloadError,
|
||||
h1,
|
||||
header::{HeaderMap, TryIntoHeaderValue, EXPECT, HOST},
|
||||
header::{TryIntoHeaderValue, EXPECT, HOST},
|
||||
Payload, RequestHeadType, ResponseHead, StatusCode,
|
||||
};
|
||||
use actix_utils::future::poll_fn;
|
||||
|
|
@ -76,15 +76,9 @@ where
|
|||
};
|
||||
|
||||
match wrt.get_mut().split().freeze().try_into_value() {
|
||||
Ok(value) => match head {
|
||||
RequestHeadType::Owned(ref mut head) => {
|
||||
head.headers.insert(HOST, value);
|
||||
Ok(value) => {
|
||||
head.extra_headers_mut().insert(HOST, value);
|
||||
}
|
||||
RequestHeadType::Rc(_, ref mut extra_headers) => {
|
||||
let headers = extra_headers.get_or_insert(HeaderMap::new());
|
||||
headers.insert(HOST, value);
|
||||
}
|
||||
},
|
||||
Err(err) => log::error!("Can not set HOST header {err}"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,10 +77,9 @@ where
|
|||
// Extracting extra headers from RequestHeadType. HeaderMap::new() does not allocate.
|
||||
let (head, extra_headers) = match head {
|
||||
RequestHeadType::Owned(head) => (RequestHeadType::Owned(head), HeaderMap::new()),
|
||||
RequestHeadType::Rc(head, extra_headers) => (
|
||||
RequestHeadType::Rc(head, None),
|
||||
extra_headers.unwrap_or_else(HeaderMap::new),
|
||||
),
|
||||
RequestHeadType::Rc(head, extra_headers) => {
|
||||
(RequestHeadType::Rc(head, HeaderMap::new()), extra_headers)
|
||||
}
|
||||
};
|
||||
|
||||
// merging headers from head and extra headers.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,19 @@ pub enum ConnectRequest {
|
|||
Tunnel(RequestHead, Option<net::SocketAddr>),
|
||||
}
|
||||
|
||||
impl ConnectRequest {
|
||||
/// Returns a mutable reference to the request headers.
|
||||
///
|
||||
/// For `Client` requests using the `Rc` variant, this returns the extra headers map
|
||||
/// (which takes priority over base headers during encoding).
|
||||
pub fn headers_mut(&mut self) -> &mut actix_http::header::HeaderMap {
|
||||
match self {
|
||||
ConnectRequest::Client(head, ..) => head.extra_headers_mut(),
|
||||
ConnectRequest::Tunnel(head, ..) => &mut head.headers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Combined HTTP response & WebSocket tunnel type returned from connection service.
|
||||
pub enum ConnectResponse {
|
||||
/// Standard HTTP response.
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ impl FrozenClientRequest {
|
|||
where
|
||||
B: MessageBody + 'static,
|
||||
{
|
||||
RequestSender::Rc(Rc::clone(&self.head), None).send_body(
|
||||
RequestSender::Rc(Rc::clone(&self.head), HeaderMap::new()).send_body(
|
||||
self.addr,
|
||||
self.response_decompress,
|
||||
self.timeout,
|
||||
|
|
@ -60,7 +60,7 @@ impl FrozenClientRequest {
|
|||
|
||||
/// Send a json body.
|
||||
pub fn send_json<T: Serialize>(&self, value: &T) -> SendClientRequest {
|
||||
RequestSender::Rc(Rc::clone(&self.head), None).send_json(
|
||||
RequestSender::Rc(Rc::clone(&self.head), HeaderMap::new()).send_json(
|
||||
self.addr,
|
||||
self.response_decompress,
|
||||
self.timeout,
|
||||
|
|
@ -71,7 +71,7 @@ impl FrozenClientRequest {
|
|||
|
||||
/// Send an urlencoded body.
|
||||
pub fn send_form<T: Serialize>(&self, value: &T) -> SendClientRequest {
|
||||
RequestSender::Rc(Rc::clone(&self.head), None).send_form(
|
||||
RequestSender::Rc(Rc::clone(&self.head), HeaderMap::new()).send_form(
|
||||
self.addr,
|
||||
self.response_decompress,
|
||||
self.timeout,
|
||||
|
|
@ -86,7 +86,7 @@ impl FrozenClientRequest {
|
|||
S: Stream<Item = Result<Bytes, E>> + 'static,
|
||||
E: Into<BoxError> + 'static,
|
||||
{
|
||||
RequestSender::Rc(Rc::clone(&self.head), None).send_stream(
|
||||
RequestSender::Rc(Rc::clone(&self.head), HeaderMap::new()).send_stream(
|
||||
self.addr,
|
||||
self.response_decompress,
|
||||
self.timeout,
|
||||
|
|
@ -97,7 +97,7 @@ impl FrozenClientRequest {
|
|||
|
||||
/// Send an empty body.
|
||||
pub fn send(&self) -> SendClientRequest {
|
||||
RequestSender::Rc(Rc::clone(&self.head), None).send(
|
||||
RequestSender::Rc(Rc::clone(&self.head), HeaderMap::new()).send(
|
||||
self.addr,
|
||||
self.response_decompress,
|
||||
self.timeout,
|
||||
|
|
@ -151,7 +151,7 @@ impl FrozenSendBuilder {
|
|||
return err.into();
|
||||
}
|
||||
|
||||
RequestSender::Rc(self.req.head, Some(self.extra_headers)).send_body(
|
||||
RequestSender::Rc(self.req.head, self.extra_headers).send_body(
|
||||
self.req.addr,
|
||||
self.req.response_decompress,
|
||||
self.req.timeout,
|
||||
|
|
@ -166,7 +166,7 @@ impl FrozenSendBuilder {
|
|||
return err.into();
|
||||
}
|
||||
|
||||
RequestSender::Rc(self.req.head, Some(self.extra_headers)).send_json(
|
||||
RequestSender::Rc(self.req.head, self.extra_headers).send_json(
|
||||
self.req.addr,
|
||||
self.req.response_decompress,
|
||||
self.req.timeout,
|
||||
|
|
@ -181,7 +181,7 @@ impl FrozenSendBuilder {
|
|||
return err.into();
|
||||
}
|
||||
|
||||
RequestSender::Rc(self.req.head, Some(self.extra_headers)).send_form(
|
||||
RequestSender::Rc(self.req.head, self.extra_headers).send_form(
|
||||
self.req.addr,
|
||||
self.req.response_decompress,
|
||||
self.req.timeout,
|
||||
|
|
@ -200,7 +200,7 @@ impl FrozenSendBuilder {
|
|||
return err.into();
|
||||
}
|
||||
|
||||
RequestSender::Rc(self.req.head, Some(self.extra_headers)).send_stream(
|
||||
RequestSender::Rc(self.req.head, self.extra_headers).send_stream(
|
||||
self.req.addr,
|
||||
self.req.response_decompress,
|
||||
self.req.timeout,
|
||||
|
|
@ -215,7 +215,7 @@ impl FrozenSendBuilder {
|
|||
return err.into();
|
||||
}
|
||||
|
||||
RequestSender::Rc(self.req.head, Some(self.extra_headers)).send(
|
||||
RequestSender::Rc(self.req.head, self.extra_headers).send(
|
||||
self.req.addr,
|
||||
self.req.response_decompress,
|
||||
self.req.timeout,
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ impl From<PrepForSendingError> for SendClientRequest {
|
|||
#[derive(Debug)]
|
||||
pub(crate) enum RequestSender {
|
||||
Owned(RequestHead),
|
||||
Rc(Rc<RequestHead>, Option<HeaderMap>),
|
||||
Rc(Rc<RequestHead>, HeaderMap),
|
||||
}
|
||||
|
||||
impl RequestSender {
|
||||
|
|
@ -296,14 +296,9 @@ impl RequestSender {
|
|||
}
|
||||
}
|
||||
RequestSender::Rc(head, extra_headers) => {
|
||||
if !head.headers.contains_key(&key)
|
||||
&& !extra_headers.iter().any(|h| h.contains_key(&key))
|
||||
{
|
||||
if !head.headers.contains_key(&key) && !extra_headers.contains_key(&key) {
|
||||
match value.try_into_value() {
|
||||
Ok(v) => {
|
||||
let h = extra_headers.get_or_insert(HeaderMap::new());
|
||||
h.insert(key, v)
|
||||
}
|
||||
Ok(v) => extra_headers.insert(key, v),
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue