From bb8532c599a9e41a4a1c00faf0a525f5ba197831 Mon Sep 17 00:00:00 2001 From: PeterDing Date: Wed, 3 Apr 2019 12:15:55 +0800 Subject: [PATCH] Support upper Camel-Case headers * [actix-http] Add field `upper_camel_case_headers` for `RequestHead` * [actix-http] Add code for `MessageType` to support upper camel case * [awc] Add functions for `ClientRequest` to set upper camel case --- actix-http/src/h1/encoder.rs | 45 +++++++++++++++++++++++++++++++++++- actix-http/src/message.rs | 15 ++++++++++++ awc/src/request.rs | 14 +++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/actix-http/src/h1/encoder.rs b/actix-http/src/h1/encoder.rs index 382ebe5f1..068237b0c 100644 --- a/actix-http/src/h1/encoder.rs +++ b/actix-http/src/h1/encoder.rs @@ -45,6 +45,10 @@ pub(crate) trait MessageType: Sized { fn headers(&self) -> &HeaderMap; + fn upper_camel_case(&self) -> bool { + false + } + fn chunked(&self) -> bool; fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()>; @@ -140,8 +144,15 @@ pub(crate) trait MessageType: Sized { pos += k.len(); buf[pos..pos + 2].copy_from_slice(b": "); pos += 2; - buf[pos..pos + v.len()].copy_from_slice(v); + + // use upper Camel-Case + if self.upper_camel_case() { + write_upper_camel_case(v, &mut buf[pos..pos + v.len()]); + } else { + buf[pos..pos + v.len()].copy_from_slice(v); + } pos += v.len(); + buf[pos..pos + 2].copy_from_slice(b"\r\n"); pos += 2; remaining -= len; @@ -200,6 +211,10 @@ impl MessageType for RequestHead { self.chunked() } + fn upper_camel_case(&self) -> bool { + self.upper_camel_case_headers() + } + fn headers(&self) -> &HeaderMap { &self.headers } @@ -396,6 +411,34 @@ impl<'a> io::Write for Writer<'a> { } } +fn write_upper_camel_case(value: &[u8], buffer: &mut [u8]) { + let mut index = 0; + let key = value; + let mut key_iter = key.iter(); + + if let Some(c) = key_iter.next() { + if *c >= b'a' && *c <= b'z' { + buffer[index] = *c ^ b' '; + index += 1; + } + } else { + return; + } + + while let Some(c) = key_iter.next() { + buffer[index] = *c; + index += 1; + if *c == b'-' { + if let Some(c) = key_iter.next() { + if *c >= b'a' && *c <= b'z' { + buffer[index] = *c ^ b' '; + index += 1; + } + } + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/actix-http/src/message.rs b/actix-http/src/message.rs index 3466f66df..cbdf72bb8 100644 --- a/actix-http/src/message.rs +++ b/actix-http/src/message.rs @@ -40,6 +40,7 @@ pub struct RequestHead { pub method: Method, pub version: Version, pub headers: HeaderMap, + pub upper_camel_case_headers: bool, pub extensions: RefCell, flags: Flags, } @@ -51,6 +52,7 @@ impl Default for RequestHead { method: Method::default(), version: Version::HTTP_11, headers: HeaderMap::with_capacity(16), + upper_camel_case_headers: false, flags: Flags::empty(), extensions: RefCell::new(Extensions::new()), } @@ -92,6 +94,19 @@ impl RequestHead { &mut self.headers } + /// Is to uppercase headers with Camel-Case. + /// Befault is `false` + #[inline] + pub fn upper_camel_case_headers(&self) -> bool { + self.upper_camel_case_headers + } + + /// Set `true` to send headers which are uppercased with Camel-Case. + #[inline] + pub fn set_upper_camel_case_headers(&mut self, value: bool) { + self.upper_camel_case_headers = value; + } + #[inline] /// Set connection type of the message pub fn set_connection_type(&mut self, ctype: ConnectionType) { diff --git a/awc/src/request.rs b/awc/src/request.rs index b96b39e2f..ad0a667ec 100644 --- a/awc/src/request.rs +++ b/awc/src/request.rs @@ -226,6 +226,20 @@ impl ClientRequest { self } + /// Is to uppercase headers with Camel-Case. + /// Befault is `false` + #[inline] + pub fn upper_camel_case_headers(&self) -> bool { + self.head.upper_camel_case_headers() + } + + /// Set `true` to send headers which are uppercased with Camel-Case. + #[inline] + pub fn set_upper_camel_case_headers(&mut self, value: bool) -> &mut Self { + self.head.set_upper_camel_case_headers(value); + self + } + /// Force close connection instead of returning it back to connections pool. /// This setting affect only http/1 connections. #[inline]