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 std::io;
|
||||||
|
use bytes::BufMut;
|
||||||
use futures::{Async, Poll};
|
use futures::{Async, Poll};
|
||||||
use tokio_io::AsyncWrite;
|
use tokio_io::AsyncWrite;
|
||||||
use http::Version;
|
use http::Version;
|
||||||
use http::header::{HeaderValue, CONNECTION, DATE, CONTENT_LENGTH};
|
use http::header::{HeaderValue, CONNECTION, DATE};
|
||||||
|
|
||||||
use helpers;
|
use helpers;
|
||||||
use body::Body;
|
use body::Body;
|
||||||
@ -124,8 +125,6 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
|||||||
fn start(&mut self, req: &mut HttpMessage, msg: &mut HttpResponse)
|
fn start(&mut self, req: &mut HttpMessage, msg: &mut HttpResponse)
|
||||||
-> Result<WriterState, io::Error>
|
-> Result<WriterState, io::Error>
|
||||||
{
|
{
|
||||||
//trace!("Prepare response with status: {:?}", msg.status());
|
|
||||||
|
|
||||||
// prepare task
|
// prepare task
|
||||||
self.flags.insert(Flags::STARTED);
|
self.flags.insert(Flags::STARTED);
|
||||||
self.encoder = PayloadEncoder::new(self.buffer.clone(), req, msg);
|
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);
|
buffer.reserve(256 + msg.headers().len() * AVERAGE_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
match version {
|
// status line
|
||||||
Version::HTTP_11 => buffer.extend_from_slice(b"HTTP/1.1 "),
|
helpers::write_status_line(version, msg.status().as_u16(), &mut buffer);
|
||||||
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" ");
|
|
||||||
buffer.extend_from_slice(msg.reason().as_bytes());
|
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 {
|
match body {
|
||||||
Body::Empty => {
|
Body::Empty => {
|
||||||
buffer.extend_from_slice(CONTENT_LENGTH.as_str().as_bytes());
|
buffer.extend_from_slice(b"\r\ncontent-length: 0\r\n");
|
||||||
buffer.extend_from_slice(b": 0\r\n");
|
|
||||||
}
|
}
|
||||||
Body::Binary(ref bytes) => {
|
Body::Binary(ref bytes) => {
|
||||||
buffer.extend_from_slice(CONTENT_LENGTH.as_str().as_bytes());
|
buffer.extend_from_slice(b"\r\ncontent-length: ");
|
||||||
buffer.extend_from_slice(b": ");
|
|
||||||
helpers::convert_usize(bytes.len(), &mut buffer);
|
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
|
// using helpers::date is quite a lot faster
|
||||||
if !msg.headers().contains_key(DATE) {
|
if !msg.headers().contains_key(DATE) {
|
||||||
buffer.reserve(helpers::DATE_VALUE_LENGTH + 8);
|
|
||||||
buffer.extend_from_slice(b"Date: ");
|
|
||||||
helpers::date(&mut buffer);
|
helpers::date(&mut buffer);
|
||||||
|
} else {
|
||||||
|
// msg eof
|
||||||
buffer.extend_from_slice(b"\r\n");
|
buffer.extend_from_slice(b"\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// msg eof
|
|
||||||
buffer.extend_from_slice(b"\r\n");
|
|
||||||
self.headers_size = buffer.len() as u32;
|
self.headers_size = buffer.len() as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
// trace!("Response: {:?}", msg);
|
|
||||||
|
|
||||||
if let Body::Binary(bytes) = body {
|
if let Body::Binary(bytes) = body {
|
||||||
self.encoder.write(bytes.as_ref())?;
|
self.encoder.write(bytes.as_ref())?;
|
||||||
return Ok(WriterState::Done)
|
return Ok(WriterState::Done)
|
||||||
@ -218,6 +206,7 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
|||||||
if self.flags.contains(Flags::STARTED) {
|
if self.flags.contains(Flags::STARTED) {
|
||||||
// TODO: add warning, write after EOF
|
// TODO: add warning, write after EOF
|
||||||
self.encoder.write(payload)?;
|
self.encoder.write(payload)?;
|
||||||
|
return Ok(WriterState::Done)
|
||||||
} else {
|
} else {
|
||||||
// might be response to EXCEPT
|
// might be response to EXCEPT
|
||||||
self.encoder.get_mut().extend_from_slice(payload)
|
self.encoder.get_mut().extend_from_slice(payload)
|
||||||
|
@ -6,6 +6,7 @@ use std::ops::{Deref, DerefMut};
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use time;
|
use time;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
|
use http::Version;
|
||||||
|
|
||||||
use httprequest::HttpMessage;
|
use httprequest::HttpMessage;
|
||||||
|
|
||||||
@ -14,7 +15,11 @@ pub const DATE_VALUE_LENGTH: usize = 29;
|
|||||||
|
|
||||||
pub fn date(dst: &mut BytesMut) {
|
pub fn date(dst: &mut BytesMut) {
|
||||||
CACHED.with(|cache| {
|
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\
|
6061626364656667686970717273747576777879\
|
||||||
8081828384858687888990919293949596979899";
|
8081828384858687888990919293949596979899";
|
||||||
|
|
||||||
pub(crate) fn convert_u16(mut n: u16, bytes: &mut BytesMut) {
|
pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesMut) {
|
||||||
let mut buf: [u8; 39] = unsafe { mem::uninitialized() };
|
let mut buf: [u8; 14] = [b'H', b'T', b'T', b'P', b'/', b'1', b'.', b'1',
|
||||||
let mut curr: isize = 39;
|
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 buf_ptr = buf.as_mut_ptr();
|
||||||
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
|
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// need at least 16 bits for the 4-characters-at-a-time to work.
|
// eagerly decode 4 characters at a time
|
||||||
if mem::size_of::<u16>() >= 2 {
|
while n >= 10_000 {
|
||||||
// eagerly decode 4 characters at a time
|
let rem = (n % 10_000) as isize;
|
||||||
while n >= 10_000 {
|
n /= 10_000;
|
||||||
let rem = (n % 10_000) as isize;
|
|
||||||
n /= 10_000;
|
|
||||||
|
|
||||||
let d1 = (rem / 100) << 1;
|
let d1 = (rem / 100) << 1;
|
||||||
let d2 = (rem % 100) << 1;
|
let d2 = (rem % 100) << 1;
|
||||||
curr -= 4;
|
curr -= 4;
|
||||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
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);
|
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
|
// 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(&buf);
|
||||||
bytes.extend_from_slice(
|
|
||||||
slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn convert_usize(mut n: usize, bytes: &mut BytesMut) {
|
pub(crate) fn convert_usize(mut n: usize, bytes: &mut BytesMut) {
|
||||||
let mut curr: isize = 39;
|
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 buf_ptr = buf.as_mut_ptr();
|
||||||
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
|
let lut_ptr = DEC_DIGITS_LUT.as_ptr();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// need at least 16 bits for the 4-characters-at-a-time to work.
|
// eagerly decode 4 characters at a time
|
||||||
if mem::size_of::<usize>() >= 2 {
|
while n >= 10_000 {
|
||||||
// eagerly decode 4 characters at a time
|
let rem = (n % 10_000) as isize;
|
||||||
while n >= 10_000 {
|
n /= 10_000;
|
||||||
let rem = (n % 10_000) as isize;
|
|
||||||
n /= 10_000;
|
|
||||||
|
|
||||||
let d1 = (rem / 100) << 1;
|
let d1 = (rem / 100) << 1;
|
||||||
let d2 = (rem % 100) << 1;
|
let d2 = (rem % 100) << 1;
|
||||||
curr -= 4;
|
curr -= 4;
|
||||||
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
|
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);
|
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
|
// 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 {
|
unsafe {
|
||||||
bytes.extend_from_slice(
|
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