mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-30 18:34:36 +01:00
write response optimizations
This commit is contained in:
parent
89c9dfb5bc
commit
5b65987f6a
@ -1,8 +1,9 @@
|
||||
use std::io;
|
||||
use bytes::BufMut;
|
||||
use futures::{Async, Poll};
|
||||
use tokio_io::AsyncWrite;
|
||||
use http::Version;
|
||||
use http::header::{HeaderValue, CONNECTION, DATE, CONTENT_LENGTH};
|
||||
use http::header::{HeaderValue, CONNECTION, DATE};
|
||||
|
||||
use helpers;
|
||||
use body::Body;
|
||||
@ -124,8 +125,6 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
||||
fn start(&mut self, req: &mut HttpMessage, msg: &mut HttpResponse)
|
||||
-> Result<WriterState, io::Error>
|
||||
{
|
||||
//trace!("Prepare response with status: {:?}", msg.status());
|
||||
|
||||
// prepare task
|
||||
self.flags.insert(Flags::STARTED);
|
||||
self.encoder = PayloadEncoder::new(self.buffer.clone(), req, msg);
|
||||
@ -157,53 +156,42 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
||||
buffer.reserve(256 + msg.headers().len() * AVERAGE_HEADER_SIZE);
|
||||
}
|
||||
|
||||
match version {
|
||||
Version::HTTP_11 => buffer.extend_from_slice(b"HTTP/1.1 "),
|
||||
Version::HTTP_2 => buffer.extend_from_slice(b"HTTP/2.0 "),
|
||||
Version::HTTP_10 => buffer.extend_from_slice(b"HTTP/1.0 "),
|
||||
Version::HTTP_09 => buffer.extend_from_slice(b"HTTP/0.9 "),
|
||||
}
|
||||
helpers::convert_u16(msg.status().as_u16(), &mut buffer);
|
||||
buffer.extend_from_slice(b" ");
|
||||
// status line
|
||||
helpers::write_status_line(version, msg.status().as_u16(), &mut buffer);
|
||||
buffer.extend_from_slice(msg.reason().as_bytes());
|
||||
buffer.extend_from_slice(b"\r\n");
|
||||
|
||||
for (key, value) in msg.headers() {
|
||||
buffer.extend_from_slice(key.as_str().as_bytes());
|
||||
buffer.extend_from_slice(b": ");
|
||||
buffer.extend_from_slice(value.as_ref());
|
||||
buffer.extend_from_slice(b"\r\n");
|
||||
}
|
||||
|
||||
match body {
|
||||
Body::Empty => {
|
||||
buffer.extend_from_slice(CONTENT_LENGTH.as_str().as_bytes());
|
||||
buffer.extend_from_slice(b": 0\r\n");
|
||||
buffer.extend_from_slice(b"\r\ncontent-length: 0\r\n");
|
||||
}
|
||||
Body::Binary(ref bytes) => {
|
||||
buffer.extend_from_slice(CONTENT_LENGTH.as_str().as_bytes());
|
||||
buffer.extend_from_slice(b": ");
|
||||
buffer.extend_from_slice(b"\r\ncontent-length: ");
|
||||
helpers::convert_usize(bytes.len(), &mut buffer);
|
||||
buffer.extend_from_slice(b"\r\n");
|
||||
}
|
||||
_ => ()
|
||||
_ => buffer.extend_from_slice(b"\r\n"),
|
||||
}
|
||||
|
||||
// write headers
|
||||
for (key, value) in msg.headers() {
|
||||
let v = value.as_ref();
|
||||
let k = key.as_str().as_bytes();
|
||||
buffer.reserve(k.len() + v.len() + 4);
|
||||
buffer.put_slice(k);
|
||||
buffer.put_slice(b": ");
|
||||
buffer.put_slice(v);
|
||||
buffer.put_slice(b"\r\n");
|
||||
}
|
||||
|
||||
// using helpers::date is quite a lot faster
|
||||
if !msg.headers().contains_key(DATE) {
|
||||
buffer.reserve(helpers::DATE_VALUE_LENGTH + 8);
|
||||
buffer.extend_from_slice(b"Date: ");
|
||||
helpers::date(&mut buffer);
|
||||
} else {
|
||||
// msg eof
|
||||
buffer.extend_from_slice(b"\r\n");
|
||||
}
|
||||
|
||||
// msg eof
|
||||
buffer.extend_from_slice(b"\r\n");
|
||||
self.headers_size = buffer.len() as u32;
|
||||
}
|
||||
|
||||
// trace!("Response: {:?}", msg);
|
||||
|
||||
if let Body::Binary(bytes) = body {
|
||||
self.encoder.write(bytes.as_ref())?;
|
||||
return Ok(WriterState::Done)
|
||||
@ -218,6 +206,7 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
||||
if self.flags.contains(Flags::STARTED) {
|
||||
// TODO: add warning, write after EOF
|
||||
self.encoder.write(payload)?;
|
||||
return Ok(WriterState::Done)
|
||||
} else {
|
||||
// might be response to EXCEPT
|
||||
self.encoder.get_mut().extend_from_slice(payload)
|
||||
|
@ -6,6 +6,7 @@ use std::ops::{Deref, DerefMut};
|
||||
use std::collections::VecDeque;
|
||||
use time;
|
||||
use bytes::BytesMut;
|
||||
use http::Version;
|
||||
|
||||
use httprequest::HttpMessage;
|
||||
|
||||
@ -14,7 +15,11 @@ pub const DATE_VALUE_LENGTH: usize = 29;
|
||||
|
||||
pub fn date(dst: &mut BytesMut) {
|
||||
CACHED.with(|cache| {
|
||||
dst.extend_from_slice(cache.borrow().buffer());
|
||||
let mut buf: [u8; 39] = unsafe { mem::uninitialized() };
|
||||
buf[..6].copy_from_slice(b"date: ");
|
||||
buf[6..35].copy_from_slice(cache.borrow().buffer());
|
||||
buf[35..].copy_from_slice(b"\r\n\r\n");
|
||||
dst.extend_from_slice(&buf);
|
||||
})
|
||||
}
|
||||
|
||||
@ -234,26 +239,31 @@ const DEC_DIGITS_LUT: &[u8] =
|
||||
6061626364656667686970717273747576777879\
|
||||
8081828384858687888990919293949596979899";
|
||||
|
||||
pub(crate) fn convert_u16(mut n: u16, bytes: &mut BytesMut) {
|
||||
let mut buf: [u8; 39] = unsafe { mem::uninitialized() };
|
||||
let mut curr: isize = 39;
|
||||
pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesMut) {
|
||||
let mut buf: [u8; 14] = [b'H', b'T', b'T', b'P', b'/', b'1', b'.', b'1',
|
||||
b' ', b' ', b' ', b' ', b' ', b' '];
|
||||
match version {
|
||||
Version::HTTP_2 => buf[5] = b'2',
|
||||
Version::HTTP_10 => buf[7] = b'0',
|
||||
Version::HTTP_09 => {buf[5] = b'0'; buf[7] = b'9';},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
let mut curr: isize = 13;
|
||||
let buf_ptr = buf.as_mut_ptr();
|
||||
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
|
||||
|
||||
unsafe {
|
||||
// need at least 16 bits for the 4-characters-at-a-time to work.
|
||||
if mem::size_of::<u16>() >= 2 {
|
||||
// eagerly decode 4 characters at a time
|
||||
while n >= 10_000 {
|
||||
let rem = (n % 10_000) as isize;
|
||||
n /= 10_000;
|
||||
// eagerly decode 4 characters at a time
|
||||
while n >= 10_000 {
|
||||
let rem = (n % 10_000) as isize;
|
||||
n /= 10_000;
|
||||
|
||||
let d1 = (rem / 100) << 1;
|
||||
let d2 = (rem % 100) << 1;
|
||||
curr -= 4;
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
|
||||
}
|
||||
let d1 = (rem / 100) << 1;
|
||||
let d2 = (rem % 100) << 1;
|
||||
curr -= 4;
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
|
||||
}
|
||||
|
||||
// if we reach here numbers are <= 9999, so at most 4 chars long
|
||||
@ -278,32 +288,28 @@ pub(crate) fn convert_u16(mut n: u16, bytes: &mut BytesMut) {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
bytes.extend_from_slice(
|
||||
slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize));
|
||||
}
|
||||
bytes.extend_from_slice(&buf);
|
||||
}
|
||||
|
||||
pub(crate) fn convert_usize(mut n: usize, bytes: &mut BytesMut) {
|
||||
let mut curr: isize = 39;
|
||||
let mut buf: [u8; 39] = unsafe { mem::uninitialized() };
|
||||
let mut buf: [u8; 41] = unsafe { mem::uninitialized() };
|
||||
buf[39] = b'\r';
|
||||
buf[40] = b'\n';
|
||||
let buf_ptr = buf.as_mut_ptr();
|
||||
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
|
||||
|
||||
unsafe {
|
||||
// need at least 16 bits for the 4-characters-at-a-time to work.
|
||||
if mem::size_of::<usize>() >= 2 {
|
||||
// eagerly decode 4 characters at a time
|
||||
while n >= 10_000 {
|
||||
let rem = (n % 10_000) as isize;
|
||||
n /= 10_000;
|
||||
// eagerly decode 4 characters at a time
|
||||
while n >= 10_000 {
|
||||
let rem = (n % 10_000) as isize;
|
||||
n /= 10_000;
|
||||
|
||||
let d1 = (rem / 100) << 1;
|
||||
let d2 = (rem % 100) << 1;
|
||||
curr -= 4;
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
|
||||
}
|
||||
let d1 = (rem / 100) << 1;
|
||||
let d2 = (rem % 100) << 1;
|
||||
curr -= 4;
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
||||
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
|
||||
}
|
||||
|
||||
// if we reach here numbers are <= 9999, so at most 4 chars long
|
||||
@ -330,7 +336,7 @@ pub(crate) fn convert_usize(mut n: usize, bytes: &mut BytesMut) {
|
||||
|
||||
unsafe {
|
||||
bytes.extend_from_slice(
|
||||
slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize));
|
||||
slice::from_raw_parts(buf_ptr.offset(curr), 41 - curr as usize));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user