1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-02-20 03:14:21 +01:00

use camel case in special headers

fixes #2595
This commit is contained in:
Rob Ede 2022-01-21 20:15:43 +00:00
parent 9668a2396f
commit 141790b200
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
4 changed files with 82 additions and 33 deletions

View File

@ -174,12 +174,15 @@ impl ServiceConfig {
} }
#[doc(hidden)] #[doc(hidden)]
pub fn set_date(&self, dst: &mut BytesMut) { pub fn set_date(&self, dst: &mut BytesMut, camel_case: bool) {
let mut buf: [u8; 39] = [0; 39]; let mut buf: [u8; 39] = [0; 39];
buf[..6].copy_from_slice(b"date: ");
buf[..6].copy_from_slice(if camel_case { b"Date: " } else { b"date: " });
self.0 self.0
.date_service .date_service
.set_date(|date| buf[6..35].copy_from_slice(&date.bytes)); .set_date(|date| buf[6..35].copy_from_slice(&date.bytes));
buf[35..].copy_from_slice(b"\r\n\r\n"); buf[35..].copy_from_slice(b"\r\n\r\n");
dst.extend_from_slice(&buf); dst.extend_from_slice(&buf);
} }
@ -326,6 +329,7 @@ mod tests {
use super::*; use super::*;
use actix_rt::{task::yield_now, time::sleep}; use actix_rt::{task::yield_now, time::sleep};
use memchr::memmem;
#[actix_rt::test] #[actix_rt::test]
async fn test_date_service_update() { async fn test_date_service_update() {
@ -334,7 +338,7 @@ mod tests {
yield_now().await; yield_now().await;
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
settings.set_date(&mut buf1); settings.set_date(&mut buf1, false);
let now1 = settings.now(); let now1 = settings.now();
sleep_until(Instant::now() + Duration::from_secs(2)).await; sleep_until(Instant::now() + Duration::from_secs(2)).await;
@ -342,7 +346,7 @@ mod tests {
let now2 = settings.now(); let now2 = settings.now();
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
settings.set_date(&mut buf2); settings.set_date(&mut buf2, false);
assert_ne!(now1, now2); assert_ne!(now1, now2);
@ -395,11 +399,27 @@ mod tests {
#[actix_rt::test] #[actix_rt::test]
async fn test_date() { async fn test_date() {
let settings = ServiceConfig::new(KeepAlive::Os, 0, 0, false, None); let settings = ServiceConfig::default();
let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); let mut buf1 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
settings.set_date(&mut buf1); settings.set_date(&mut buf1, false);
let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10); let mut buf2 = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
settings.set_date(&mut buf2); settings.set_date(&mut buf2, false);
assert_eq!(buf1, buf2); assert_eq!(buf1, buf2);
} }
#[actix_rt::test]
async fn test_date_camel_case() {
let settings = ServiceConfig::default();
let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
settings.set_date(&mut buf, false);
assert!(memmem::find(&buf, b"date:").is_some());
let mut buf = BytesMut::with_capacity(DATE_VALUE_LENGTH + 10);
settings.set_date(&mut buf, true);
assert!(memmem::find(&buf, b"Date:").is_some());
}
} }

View File

@ -105,7 +105,7 @@ pub(crate) trait MessageType: Sized {
} }
BodySize::Sized(0) if camel_case => dst.put_slice(b"\r\nContent-Length: 0\r\n"), BodySize::Sized(0) if camel_case => dst.put_slice(b"\r\nContent-Length: 0\r\n"),
BodySize::Sized(0) => dst.put_slice(b"\r\ncontent-length: 0\r\n"), BodySize::Sized(0) => dst.put_slice(b"\r\ncontent-length: 0\r\n"),
BodySize::Sized(len) => helpers::write_content_length(len, dst), BodySize::Sized(len) => helpers::write_content_length(len, dst, camel_case),
BodySize::None => dst.put_slice(b"\r\n"), BodySize::None => dst.put_slice(b"\r\n"),
} }
@ -213,7 +213,7 @@ pub(crate) trait MessageType: Sized {
// optimized date header, set_date writes \r\n // optimized date header, set_date writes \r\n
if !has_date { if !has_date {
config.set_date(dst); config.set_date(dst, camel_case);
} else { } else {
// msg eof // msg eof
dst.extend_from_slice(b"\r\n"); dst.extend_from_slice(b"\r\n");

View File

@ -30,15 +30,25 @@ pub(crate) fn write_status_line<B: BufMut>(version: Version, n: u16, buf: &mut B
/// Write out content length header. /// Write out content length header.
/// ///
/// Buffer must to contain enough space or be implicitly extendable. /// Buffer must to contain enough space or be implicitly extendable.
pub fn write_content_length<B: BufMut>(n: u64, buf: &mut B) { pub fn write_content_length<B: BufMut>(n: u64, buf: &mut B, camel_case: bool) {
if n == 0 { if n == 0 {
if camel_case {
buf.put_slice(b"\r\nContent-Length: 0\r\n");
} else {
buf.put_slice(b"\r\ncontent-length: 0\r\n"); buf.put_slice(b"\r\ncontent-length: 0\r\n");
}
return; return;
} }
let mut buffer = itoa::Buffer::new(); let mut buffer = itoa::Buffer::new();
if camel_case {
buf.put_slice(b"\r\nContent-Length: ");
} else {
buf.put_slice(b"\r\ncontent-length: "); buf.put_slice(b"\r\ncontent-length: ");
}
buf.put_slice(buffer.format(n).as_bytes()); buf.put_slice(buffer.format(n).as_bytes());
buf.put_slice(b"\r\n"); buf.put_slice(b"\r\n");
} }
@ -95,77 +105,88 @@ mod tests {
fn test_write_content_length() { fn test_write_content_length() {
let mut bytes = BytesMut::new(); let mut bytes = BytesMut::new();
bytes.reserve(50); bytes.reserve(50);
write_content_length(0, &mut bytes); write_content_length(0, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 0\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 0\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(9, &mut bytes); write_content_length(9, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 9\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 9\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(10, &mut bytes); write_content_length(10, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 10\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 10\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(99, &mut bytes); write_content_length(99, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 99\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 99\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(100, &mut bytes); write_content_length(100, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 100\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 100\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(101, &mut bytes); write_content_length(101, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 101\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 101\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(998, &mut bytes); write_content_length(998, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 998\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 998\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(1000, &mut bytes); write_content_length(1000, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1000\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1000\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(1001, &mut bytes); write_content_length(1001, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1001\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 1001\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(5909, &mut bytes); write_content_length(5909, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 5909\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 5909\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(9999, &mut bytes); write_content_length(9999, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 9999\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 9999\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(10001, &mut bytes); write_content_length(10001, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 10001\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 10001\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(59094, &mut bytes); write_content_length(59094, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 59094\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 59094\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(99999, &mut bytes); write_content_length(99999, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 99999\r\n"[..]); assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 99999\r\n"[..]);
bytes.reserve(50); bytes.reserve(50);
write_content_length(590947, &mut bytes); write_content_length(590947, &mut bytes, false);
assert_eq!( assert_eq!(
bytes.split().freeze(), bytes.split().freeze(),
b"\r\ncontent-length: 590947\r\n"[..] b"\r\ncontent-length: 590947\r\n"[..]
); );
bytes.reserve(50); bytes.reserve(50);
write_content_length(999999, &mut bytes); write_content_length(999999, &mut bytes, false);
assert_eq!( assert_eq!(
bytes.split().freeze(), bytes.split().freeze(),
b"\r\ncontent-length: 999999\r\n"[..] b"\r\ncontent-length: 999999\r\n"[..]
); );
bytes.reserve(50); bytes.reserve(50);
write_content_length(5909471, &mut bytes); write_content_length(5909471, &mut bytes, false);
assert_eq!( assert_eq!(
bytes.split().freeze(), bytes.split().freeze(),
b"\r\ncontent-length: 5909471\r\n"[..] b"\r\ncontent-length: 5909471\r\n"[..]
); );
bytes.reserve(50); bytes.reserve(50);
write_content_length(59094718, &mut bytes); write_content_length(59094718, &mut bytes, false);
assert_eq!( assert_eq!(
bytes.split().freeze(), bytes.split().freeze(),
b"\r\ncontent-length: 59094718\r\n"[..] b"\r\ncontent-length: 59094718\r\n"[..]
); );
bytes.reserve(50); bytes.reserve(50);
write_content_length(4294973728, &mut bytes); write_content_length(4294973728, &mut bytes, false);
assert_eq!( assert_eq!(
bytes.split().freeze(), bytes.split().freeze(),
b"\r\ncontent-length: 4294973728\r\n"[..] b"\r\ncontent-length: 4294973728\r\n"[..]
); );
} }
#[test]
fn write_content_length_camel_case() {
let mut bytes = BytesMut::new();
write_content_length(0, &mut bytes, false);
assert_eq!(bytes.split().freeze(), b"\r\ncontent-length: 0\r\n"[..]);
let mut bytes = BytesMut::new();
write_content_length(0, &mut bytes, true);
assert_eq!(bytes.split().freeze(), b"\r\nContent-Length: 0\r\n"[..]);
}
} }

View File

@ -240,15 +240,23 @@ mod tests {
let _ = stream.read(&mut data); let _ = stream.read(&mut data);
assert_eq!(&data[..17], b"HTTP/1.1 200 OK\r\n"); assert_eq!(&data[..17], b"HTTP/1.1 200 OK\r\n");
assert!(memmem::find(&data, b"Foo-Bar").is_some()); assert!(memmem::find(&data, b"Foo-Bar").is_some());
assert!(!memmem::find(&data, b"foo-bar").is_some()); assert!(memmem::find(&data, b"foo-bar").is_none());
assert!(memmem::find(&data, b"Date").is_some());
assert!(memmem::find(&data, b"date").is_none());
assert!(memmem::find(&data, b"Content-Length").is_some());
assert!(memmem::find(&data, b"content-length").is_none());
let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
let _ = stream.write_all(b"GET /lower HTTP/1.1\r\nConnection: Close\r\n\r\n"); let _ = stream.write_all(b"GET /lower HTTP/1.1\r\nConnection: Close\r\n\r\n");
let mut data = vec![0; 1024]; let mut data = vec![0; 1024];
let _ = stream.read(&mut data); let _ = stream.read(&mut data);
assert_eq!(&data[..17], b"HTTP/1.1 200 OK\r\n"); assert_eq!(&data[..17], b"HTTP/1.1 200 OK\r\n");
assert!(!memmem::find(&data, b"Foo-Bar").is_some()); assert!(memmem::find(&data, b"Foo-Bar").is_none());
assert!(memmem::find(&data, b"foo-bar").is_some()); assert!(memmem::find(&data, b"foo-bar").is_some());
assert!(memmem::find(&data, b"Date").is_none());
assert!(memmem::find(&data, b"date").is_some());
assert!(memmem::find(&data, b"Content-Length").is_none());
assert!(memmem::find(&data, b"content-length").is_some());
srv.stop().await; srv.stop().await;
} }