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
This commit is contained in:
PeterDing 2019-04-03 12:15:55 +08:00
parent 1d0e72c893
commit bb8532c599
No known key found for this signature in database
GPG Key ID: 78EE8C2BCA22AEF3
3 changed files with 73 additions and 1 deletions

View File

@ -45,6 +45,10 @@ pub(crate) trait MessageType: Sized {
fn headers(&self) -> &HeaderMap; fn headers(&self) -> &HeaderMap;
fn upper_camel_case(&self) -> bool {
false
}
fn chunked(&self) -> bool; fn chunked(&self) -> bool;
fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()>; fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()>;
@ -140,8 +144,15 @@ pub(crate) trait MessageType: Sized {
pos += k.len(); pos += k.len();
buf[pos..pos + 2].copy_from_slice(b": "); buf[pos..pos + 2].copy_from_slice(b": ");
pos += 2; 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(); pos += v.len();
buf[pos..pos + 2].copy_from_slice(b"\r\n"); buf[pos..pos + 2].copy_from_slice(b"\r\n");
pos += 2; pos += 2;
remaining -= len; remaining -= len;
@ -200,6 +211,10 @@ impl MessageType for RequestHead {
self.chunked() self.chunked()
} }
fn upper_camel_case(&self) -> bool {
self.upper_camel_case_headers()
}
fn headers(&self) -> &HeaderMap { fn headers(&self) -> &HeaderMap {
&self.headers &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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -40,6 +40,7 @@ pub struct RequestHead {
pub method: Method, pub method: Method,
pub version: Version, pub version: Version,
pub headers: HeaderMap, pub headers: HeaderMap,
pub upper_camel_case_headers: bool,
pub extensions: RefCell<Extensions>, pub extensions: RefCell<Extensions>,
flags: Flags, flags: Flags,
} }
@ -51,6 +52,7 @@ impl Default for RequestHead {
method: Method::default(), method: Method::default(),
version: Version::HTTP_11, version: Version::HTTP_11,
headers: HeaderMap::with_capacity(16), headers: HeaderMap::with_capacity(16),
upper_camel_case_headers: false,
flags: Flags::empty(), flags: Flags::empty(),
extensions: RefCell::new(Extensions::new()), extensions: RefCell::new(Extensions::new()),
} }
@ -92,6 +94,19 @@ impl RequestHead {
&mut self.headers &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] #[inline]
/// Set connection type of the message /// Set connection type of the message
pub fn set_connection_type(&mut self, ctype: ConnectionType) { pub fn set_connection_type(&mut self, ctype: ConnectionType) {

View File

@ -226,6 +226,20 @@ impl ClientRequest {
self 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. /// Force close connection instead of returning it back to connections pool.
/// This setting affect only http/1 connections. /// This setting affect only http/1 connections.
#[inline] #[inline]