mirror of
https://github.com/fafhrd91/actix-web
synced 2025-01-18 05:41:50 +01:00
various server optimizations
This commit is contained in:
parent
b61c2a0cf0
commit
c37565cc4a
@ -14,6 +14,7 @@ use brotli2::write::{BrotliDecoder, BrotliEncoder};
|
|||||||
use bytes::{Bytes, BytesMut, BufMut, Writer};
|
use bytes::{Bytes, BytesMut, BufMut, Writer};
|
||||||
|
|
||||||
use helpers;
|
use helpers;
|
||||||
|
use helpers::SharedBytes;
|
||||||
use body::{Body, Binary};
|
use body::{Body, Binary};
|
||||||
use error::PayloadError;
|
use error::PayloadError;
|
||||||
use httprequest::HttpMessage;
|
use httprequest::HttpMessage;
|
||||||
@ -337,15 +338,15 @@ impl PayloadWriter for EncodedPayload {
|
|||||||
|
|
||||||
pub(crate) struct PayloadEncoder(ContentEncoder);
|
pub(crate) struct PayloadEncoder(ContentEncoder);
|
||||||
|
|
||||||
impl Default for PayloadEncoder {
|
|
||||||
fn default() -> PayloadEncoder {
|
|
||||||
PayloadEncoder(ContentEncoder::Identity(TransferEncoding::eof()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PayloadEncoder {
|
impl PayloadEncoder {
|
||||||
|
|
||||||
pub fn new(req: &HttpMessage, resp: &mut HttpResponse) -> PayloadEncoder {
|
pub fn empty(bytes: SharedBytes) -> PayloadEncoder {
|
||||||
|
PayloadEncoder(ContentEncoder::Identity(TransferEncoding::eof(bytes)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(buf: SharedBytes, req: &HttpMessage, resp: &mut HttpResponse)
|
||||||
|
-> PayloadEncoder
|
||||||
|
{
|
||||||
let version = resp.version().unwrap_or_else(|| req.version);
|
let version = resp.version().unwrap_or_else(|| req.version);
|
||||||
let mut body = resp.replace_body(Body::Empty);
|
let mut body = resp.replace_body(Body::Empty);
|
||||||
let has_body = match body {
|
let has_body = match body {
|
||||||
@ -390,11 +391,11 @@ impl PayloadEncoder {
|
|||||||
error!("Chunked transfer is enabled but body is set to Empty");
|
error!("Chunked transfer is enabled but body is set to Empty");
|
||||||
}
|
}
|
||||||
resp.headers_mut().insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
|
resp.headers_mut().insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
|
||||||
TransferEncoding::eof()
|
TransferEncoding::eof(buf)
|
||||||
},
|
},
|
||||||
Body::Binary(ref mut bytes) => {
|
Body::Binary(ref mut bytes) => {
|
||||||
if compression {
|
if compression {
|
||||||
let transfer = TransferEncoding::eof();
|
let transfer = TransferEncoding::eof(SharedBytes::default());
|
||||||
let mut enc = match encoding {
|
let mut enc = match encoding {
|
||||||
ContentEncoding::Deflate => ContentEncoder::Deflate(
|
ContentEncoding::Deflate => ContentEncoder::Deflate(
|
||||||
DeflateEncoder::new(transfer, Compression::Default)),
|
DeflateEncoder::new(transfer, Compression::Default)),
|
||||||
@ -414,11 +415,11 @@ impl PayloadEncoder {
|
|||||||
CONTENT_LENGTH, helpers::convert_into_header(b.len()));
|
CONTENT_LENGTH, helpers::convert_into_header(b.len()));
|
||||||
*bytes = Binary::from(b);
|
*bytes = Binary::from(b);
|
||||||
encoding = ContentEncoding::Identity;
|
encoding = ContentEncoding::Identity;
|
||||||
TransferEncoding::eof()
|
TransferEncoding::eof(buf)
|
||||||
} else {
|
} else {
|
||||||
resp.headers_mut().insert(
|
resp.headers_mut().insert(
|
||||||
CONTENT_LENGTH, helpers::convert_into_header(bytes.len()));
|
CONTENT_LENGTH, helpers::convert_into_header(bytes.len()));
|
||||||
TransferEncoding::eof()
|
TransferEncoding::eof(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Body::Streaming(_) | Body::StreamingContext => {
|
Body::Streaming(_) | Body::StreamingContext => {
|
||||||
@ -429,26 +430,26 @@ impl PayloadEncoder {
|
|||||||
}
|
}
|
||||||
if version == Version::HTTP_2 {
|
if version == Version::HTTP_2 {
|
||||||
resp.headers_mut().remove(TRANSFER_ENCODING);
|
resp.headers_mut().remove(TRANSFER_ENCODING);
|
||||||
TransferEncoding::eof()
|
TransferEncoding::eof(buf)
|
||||||
} else {
|
} else {
|
||||||
resp.headers_mut().insert(
|
resp.headers_mut().insert(
|
||||||
TRANSFER_ENCODING, HeaderValue::from_static("chunked"));
|
TRANSFER_ENCODING, HeaderValue::from_static("chunked"));
|
||||||
TransferEncoding::chunked()
|
TransferEncoding::chunked(buf)
|
||||||
}
|
}
|
||||||
} else if let Some(len) = resp.headers().get(CONTENT_LENGTH) {
|
} else if let Some(len) = resp.headers().get(CONTENT_LENGTH) {
|
||||||
// Content-Length
|
// Content-Length
|
||||||
if let Ok(s) = len.to_str() {
|
if let Ok(s) = len.to_str() {
|
||||||
if let Ok(len) = s.parse::<u64>() {
|
if let Ok(len) = s.parse::<u64>() {
|
||||||
TransferEncoding::length(len)
|
TransferEncoding::length(len, buf)
|
||||||
} else {
|
} else {
|
||||||
debug!("illegal Content-Length: {:?}", len);
|
debug!("illegal Content-Length: {:?}", len);
|
||||||
TransferEncoding::eof()
|
TransferEncoding::eof(buf)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TransferEncoding::eof()
|
TransferEncoding::eof(buf)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TransferEncoding::eof()
|
TransferEncoding::eof(buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Body::Upgrade(_) | Body::UpgradeContext => {
|
Body::Upgrade(_) | Body::UpgradeContext => {
|
||||||
@ -462,7 +463,7 @@ impl PayloadEncoder {
|
|||||||
encoding = ContentEncoding::Identity;
|
encoding = ContentEncoding::Identity;
|
||||||
resp.headers_mut().remove(CONTENT_ENCODING);
|
resp.headers_mut().remove(CONTENT_ENCODING);
|
||||||
}
|
}
|
||||||
TransferEncoding::eof()
|
TransferEncoding::eof(buf)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
resp.replace_body(body);
|
resp.replace_body(body);
|
||||||
@ -540,13 +541,13 @@ impl ContentEncoder {
|
|||||||
pub fn get_ref(&self) -> &BytesMut {
|
pub fn get_ref(&self) -> &BytesMut {
|
||||||
match *self {
|
match *self {
|
||||||
ContentEncoder::Br(ref encoder) =>
|
ContentEncoder::Br(ref encoder) =>
|
||||||
&encoder.get_ref().buffer,
|
encoder.get_ref().buffer.get_ref(),
|
||||||
ContentEncoder::Deflate(ref encoder) =>
|
ContentEncoder::Deflate(ref encoder) =>
|
||||||
&encoder.get_ref().buffer,
|
encoder.get_ref().buffer.get_ref(),
|
||||||
ContentEncoder::Gzip(ref encoder) =>
|
ContentEncoder::Gzip(ref encoder) =>
|
||||||
&encoder.get_ref().buffer,
|
encoder.get_ref().buffer.get_ref(),
|
||||||
ContentEncoder::Identity(ref encoder) =>
|
ContentEncoder::Identity(ref encoder) =>
|
||||||
&encoder.buffer,
|
encoder.buffer.get_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,20 +555,21 @@ impl ContentEncoder {
|
|||||||
pub fn get_mut(&mut self) -> &mut BytesMut {
|
pub fn get_mut(&mut self) -> &mut BytesMut {
|
||||||
match *self {
|
match *self {
|
||||||
ContentEncoder::Br(ref mut encoder) =>
|
ContentEncoder::Br(ref mut encoder) =>
|
||||||
&mut encoder.get_mut().buffer,
|
encoder.get_mut().buffer.get_mut(),
|
||||||
ContentEncoder::Deflate(ref mut encoder) =>
|
ContentEncoder::Deflate(ref mut encoder) =>
|
||||||
&mut encoder.get_mut().buffer,
|
encoder.get_mut().buffer.get_mut(),
|
||||||
ContentEncoder::Gzip(ref mut encoder) =>
|
ContentEncoder::Gzip(ref mut encoder) =>
|
||||||
&mut encoder.get_mut().buffer,
|
encoder.get_mut().buffer.get_mut(),
|
||||||
ContentEncoder::Identity(ref mut encoder) =>
|
ContentEncoder::Identity(ref mut encoder) =>
|
||||||
&mut encoder.buffer,
|
encoder.buffer.get_mut(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
#[cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn write_eof(&mut self) -> Result<(), io::Error> {
|
pub fn write_eof(&mut self) -> Result<(), io::Error> {
|
||||||
let encoder = mem::replace(self, ContentEncoder::Identity(TransferEncoding::eof()));
|
let encoder = mem::replace(
|
||||||
|
self, ContentEncoder::Identity(TransferEncoding::eof(SharedBytes::default())));
|
||||||
|
|
||||||
match encoder {
|
match encoder {
|
||||||
ContentEncoder::Br(encoder) => {
|
ContentEncoder::Br(encoder) => {
|
||||||
@ -639,7 +641,7 @@ impl ContentEncoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ContentEncoder::Identity(ref mut encoder) => {
|
ContentEncoder::Identity(ref mut encoder) => {
|
||||||
encoder.write_all(data)?;
|
encoder.encode(data);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -650,7 +652,7 @@ impl ContentEncoder {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct TransferEncoding {
|
pub(crate) struct TransferEncoding {
|
||||||
kind: TransferEncodingKind,
|
kind: TransferEncodingKind,
|
||||||
buffer: BytesMut,
|
buffer: SharedBytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@ -670,26 +672,26 @@ enum TransferEncodingKind {
|
|||||||
impl TransferEncoding {
|
impl TransferEncoding {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn eof() -> TransferEncoding {
|
pub fn eof(bytes: SharedBytes) -> TransferEncoding {
|
||||||
TransferEncoding {
|
TransferEncoding {
|
||||||
kind: TransferEncodingKind::Eof,
|
kind: TransferEncodingKind::Eof,
|
||||||
buffer: BytesMut::new(),
|
buffer: bytes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn chunked() -> TransferEncoding {
|
pub fn chunked(bytes: SharedBytes) -> TransferEncoding {
|
||||||
TransferEncoding {
|
TransferEncoding {
|
||||||
kind: TransferEncodingKind::Chunked(false),
|
kind: TransferEncodingKind::Chunked(false),
|
||||||
buffer: BytesMut::new(),
|
buffer: bytes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn length(len: u64) -> TransferEncoding {
|
pub fn length(len: u64, bytes: SharedBytes) -> TransferEncoding {
|
||||||
TransferEncoding {
|
TransferEncoding {
|
||||||
kind: TransferEncodingKind::Length(len),
|
kind: TransferEncodingKind::Length(len),
|
||||||
buffer: BytesMut::new(),
|
buffer: bytes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,7 +711,7 @@ impl TransferEncoding {
|
|||||||
pub fn encode(&mut self, msg: &[u8]) -> bool {
|
pub fn encode(&mut self, msg: &[u8]) -> bool {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
TransferEncodingKind::Eof => {
|
TransferEncodingKind::Eof => {
|
||||||
self.buffer.extend_from_slice(msg);
|
self.buffer.get_mut().extend_from_slice(msg);
|
||||||
msg.is_empty()
|
msg.is_empty()
|
||||||
},
|
},
|
||||||
TransferEncodingKind::Chunked(ref mut eof) => {
|
TransferEncodingKind::Chunked(ref mut eof) => {
|
||||||
@ -719,11 +721,11 @@ impl TransferEncoding {
|
|||||||
|
|
||||||
if msg.is_empty() {
|
if msg.is_empty() {
|
||||||
*eof = true;
|
*eof = true;
|
||||||
self.buffer.extend_from_slice(b"0\r\n\r\n");
|
self.buffer.get_mut().extend_from_slice(b"0\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
write!(self.buffer, "{:X}\r\n", msg.len()).unwrap();
|
write!(self.buffer.get_mut(), "{:X}\r\n", msg.len()).unwrap();
|
||||||
self.buffer.extend_from_slice(msg);
|
self.buffer.get_mut().extend_from_slice(msg);
|
||||||
self.buffer.extend_from_slice(b"\r\n");
|
self.buffer.get_mut().extend_from_slice(b"\r\n");
|
||||||
}
|
}
|
||||||
*eof
|
*eof
|
||||||
},
|
},
|
||||||
@ -733,7 +735,7 @@ impl TransferEncoding {
|
|||||||
}
|
}
|
||||||
let max = cmp::min(*remaining, msg.len() as u64);
|
let max = cmp::min(*remaining, msg.len() as u64);
|
||||||
trace!("sized write = {}", max);
|
trace!("sized write = {}", max);
|
||||||
self.buffer.extend_from_slice(msg[..max as usize].as_ref());
|
self.buffer.get_mut().extend_from_slice(msg[..max as usize].as_ref());
|
||||||
|
|
||||||
*remaining -= max as u64;
|
*remaining -= max as u64;
|
||||||
trace!("encoded {} bytes, remaining = {}", max, remaining);
|
trace!("encoded {} bytes, remaining = {}", max, remaining);
|
||||||
@ -750,7 +752,7 @@ impl TransferEncoding {
|
|||||||
TransferEncodingKind::Chunked(ref mut eof) => {
|
TransferEncodingKind::Chunked(ref mut eof) => {
|
||||||
if !*eof {
|
if !*eof {
|
||||||
*eof = true;
|
*eof = true;
|
||||||
self.buffer.extend_from_slice(b"0\r\n\r\n");
|
self.buffer.get_mut().extend_from_slice(b"0\r\n\r\n");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
102
src/h1.rs
102
src/h1.rs
@ -1,4 +1,4 @@
|
|||||||
use std::{self, io, ptr};
|
use std::{self, io};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -16,14 +16,15 @@ use tokio_core::reactor::Timeout;
|
|||||||
use pipeline::Pipeline;
|
use pipeline::Pipeline;
|
||||||
use encoding::PayloadType;
|
use encoding::PayloadType;
|
||||||
use channel::{HttpHandler, HttpHandlerTask};
|
use channel::{HttpHandler, HttpHandlerTask};
|
||||||
use h1writer::H1Writer;
|
use h1writer::{Writer, H1Writer};
|
||||||
use server::WorkerSettings;
|
use server::WorkerSettings;
|
||||||
use httpcodes::HTTPNotFound;
|
use httpcodes::HTTPNotFound;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use error::{ParseError, PayloadError, ResponseError};
|
use error::{ParseError, PayloadError, ResponseError};
|
||||||
use payload::{Payload, PayloadWriter, DEFAULT_BUFFER_SIZE};
|
use payload::{Payload, PayloadWriter, DEFAULT_BUFFER_SIZE};
|
||||||
|
|
||||||
const INIT_BUFFER_SIZE: usize = 8192;
|
const LW_BUFFER_SIZE: usize = 4096;
|
||||||
|
const HW_BUFFER_SIZE: usize = 16_384;
|
||||||
const MAX_BUFFER_SIZE: usize = 131_072;
|
const MAX_BUFFER_SIZE: usize = 131_072;
|
||||||
const MAX_HEADERS: usize = 100;
|
const MAX_HEADERS: usize = 100;
|
||||||
const MAX_PIPELINED_MESSAGES: usize = 16;
|
const MAX_PIPELINED_MESSAGES: usize = 16;
|
||||||
@ -78,10 +79,11 @@ impl<T, H> Http1<T, H>
|
|||||||
H: HttpHandler + 'static
|
H: HttpHandler + 'static
|
||||||
{
|
{
|
||||||
pub fn new(h: Rc<WorkerSettings<H>>, stream: T, addr: Option<SocketAddr>) -> Self {
|
pub fn new(h: Rc<WorkerSettings<H>>, stream: T, addr: Option<SocketAddr>) -> Self {
|
||||||
|
let bytes = h.get_shared_bytes();
|
||||||
Http1{ flags: Flags::KEEPALIVE,
|
Http1{ flags: Flags::KEEPALIVE,
|
||||||
settings: h,
|
settings: h,
|
||||||
addr: addr,
|
addr: addr,
|
||||||
stream: H1Writer::new(stream),
|
stream: H1Writer::new(stream, bytes),
|
||||||
reader: Reader::new(),
|
reader: Reader::new(),
|
||||||
read_buf: BytesMut::new(),
|
read_buf: BytesMut::new(),
|
||||||
tasks: VecDeque::new(),
|
tasks: VecDeque::new(),
|
||||||
@ -92,6 +94,18 @@ impl<T, H> Http1<T, H>
|
|||||||
(self.settings, self.stream.into_inner(), self.addr, self.read_buf.freeze())
|
(self.settings, self.stream.into_inner(), self.addr, self.read_buf.freeze())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn poll_completed(&mut self) -> Result<bool, ()> {
|
||||||
|
// check stream state
|
||||||
|
match self.stream.poll_completed() {
|
||||||
|
Ok(Async::Ready(_)) => Ok(false),
|
||||||
|
Ok(Async::NotReady) => Ok(true),
|
||||||
|
Err(err) => {
|
||||||
|
debug!("Error sending data: {}", err);
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn poll(&mut self) -> Poll<Http1Result, ()> {
|
pub fn poll(&mut self) -> Poll<Http1Result, ()> {
|
||||||
// keep-alive timer
|
// keep-alive timer
|
||||||
if self.keepalive_timer.is_some() {
|
if self.keepalive_timer.is_some() {
|
||||||
@ -116,6 +130,10 @@ impl<T, H> Http1<T, H>
|
|||||||
|
|
||||||
if !io && !item.flags.contains(EntryFlags::EOF) {
|
if !io && !item.flags.contains(EntryFlags::EOF) {
|
||||||
if item.flags.contains(EntryFlags::ERROR) {
|
if item.flags.contains(EntryFlags::ERROR) {
|
||||||
|
// check stream state
|
||||||
|
if let Ok(Async::NotReady) = self.stream.poll_completed() {
|
||||||
|
return Ok(Async::NotReady)
|
||||||
|
}
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +164,12 @@ impl<T, H> Http1<T, H>
|
|||||||
// it is not possible to recover from error
|
// it is not possible to recover from error
|
||||||
// during pipe handling, so just drop connection
|
// during pipe handling, so just drop connection
|
||||||
error!("Unhandled error: {}", err);
|
error!("Unhandled error: {}", err);
|
||||||
|
item.flags.insert(EntryFlags::ERROR);
|
||||||
|
|
||||||
|
// check stream state, we still can have valid data in buffer
|
||||||
|
if let Ok(Async::NotReady) = self.stream.poll_completed() {
|
||||||
|
return Ok(Async::NotReady)
|
||||||
|
}
|
||||||
return Err(())
|
return Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,6 +202,10 @@ impl<T, H> Http1<T, H>
|
|||||||
|
|
||||||
// no keep-alive
|
// no keep-alive
|
||||||
if !self.flags.contains(Flags::KEEPALIVE) && self.tasks.is_empty() {
|
if !self.flags.contains(Flags::KEEPALIVE) && self.tasks.is_empty() {
|
||||||
|
// check stream state
|
||||||
|
if self.poll_completed()? {
|
||||||
|
return Ok(Async::NotReady)
|
||||||
|
}
|
||||||
if self.flags.contains(Flags::H2) {
|
if self.flags.contains(Flags::H2) {
|
||||||
return Ok(Async::Ready(Http1Result::Switch))
|
return Ok(Async::Ready(Http1Result::Switch))
|
||||||
} else {
|
} else {
|
||||||
@ -188,7 +216,9 @@ impl<T, H> Http1<T, H>
|
|||||||
// read incoming data
|
// read incoming data
|
||||||
while !self.flags.contains(Flags::ERROR) && !self.flags.contains(Flags::H2) &&
|
while !self.flags.contains(Flags::ERROR) && !self.flags.contains(Flags::H2) &&
|
||||||
self.tasks.len() < MAX_PIPELINED_MESSAGES {
|
self.tasks.len() < MAX_PIPELINED_MESSAGES {
|
||||||
match self.reader.parse(self.stream.get_mut(), &mut self.read_buf) {
|
match self.reader.parse(self.stream.get_mut(),
|
||||||
|
&mut self.read_buf, &self.settings)
|
||||||
|
{
|
||||||
Ok(Async::Ready(Item::Http1(mut req))) => {
|
Ok(Async::Ready(Item::Http1(mut req))) => {
|
||||||
not_ready = false;
|
not_ready = false;
|
||||||
|
|
||||||
@ -264,10 +294,16 @@ impl<T, H> Http1<T, H>
|
|||||||
self.keepalive_timer = Some(to);
|
self.keepalive_timer = Some(to);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// check stream state
|
||||||
|
if self.poll_completed()? {
|
||||||
|
return Ok(Async::NotReady)
|
||||||
|
}
|
||||||
// keep-alive disable, drop connection
|
// keep-alive disable, drop connection
|
||||||
return Ok(Async::Ready(Http1Result::Done))
|
return Ok(Async::Ready(Http1Result::Done))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// check stream state
|
||||||
|
self.poll_completed()?;
|
||||||
// keep-alive unset, rely on operating system
|
// keep-alive unset, rely on operating system
|
||||||
return Ok(Async::NotReady)
|
return Ok(Async::NotReady)
|
||||||
}
|
}
|
||||||
@ -279,6 +315,11 @@ impl<T, H> Http1<T, H>
|
|||||||
|
|
||||||
// check for parse error
|
// check for parse error
|
||||||
if self.tasks.is_empty() {
|
if self.tasks.is_empty() {
|
||||||
|
// check stream state
|
||||||
|
if self.poll_completed()? {
|
||||||
|
return Ok(Async::NotReady)
|
||||||
|
}
|
||||||
|
|
||||||
if self.flags.contains(Flags::H2) {
|
if self.flags.contains(Flags::H2) {
|
||||||
return Ok(Async::Ready(Http1Result::Switch))
|
return Ok(Async::Ready(Http1Result::Switch))
|
||||||
}
|
}
|
||||||
@ -288,6 +329,7 @@ impl<T, H> Http1<T, H>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if not_ready {
|
if not_ready {
|
||||||
|
self.poll_completed()?;
|
||||||
return Ok(Async::NotReady)
|
return Ok(Async::NotReady)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,7 +400,9 @@ impl Reader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse<T>(&mut self, io: &mut T, buf: &mut BytesMut) -> Poll<Item, ReaderError>
|
pub fn parse<T, H>(&mut self, io: &mut T,
|
||||||
|
buf: &mut BytesMut,
|
||||||
|
settings: &WorkerSettings<H>) -> Poll<Item, ReaderError>
|
||||||
where T: AsyncRead
|
where T: AsyncRead
|
||||||
{
|
{
|
||||||
loop {
|
loop {
|
||||||
@ -394,7 +438,7 @@ impl Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match Reader::parse_message(buf).map_err(ReaderError::Error)? {
|
match Reader::parse_message(buf, settings).map_err(ReaderError::Error)? {
|
||||||
Message::Http1(msg, decoder) => {
|
Message::Http1(msg, decoder) => {
|
||||||
if let Some(payload) = decoder {
|
if let Some(payload) = decoder {
|
||||||
self.payload = Some(payload);
|
self.payload = Some(payload);
|
||||||
@ -465,15 +509,9 @@ impl Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_from_io<T: AsyncRead>(&mut self, io: &mut T, buf: &mut BytesMut)
|
fn read_from_io<T: AsyncRead>(&mut self, io: &mut T, buf: &mut BytesMut)
|
||||||
-> Poll<usize, io::Error>
|
-> Poll<usize, io::Error> {
|
||||||
{
|
if buf.remaining_mut() < LW_BUFFER_SIZE {
|
||||||
if buf.remaining_mut() < INIT_BUFFER_SIZE {
|
buf.reserve(HW_BUFFER_SIZE);
|
||||||
buf.reserve(INIT_BUFFER_SIZE);
|
|
||||||
unsafe { // Zero out unused memory
|
|
||||||
let b = buf.bytes_mut();
|
|
||||||
let len = b.len();
|
|
||||||
ptr::write_bytes(b.as_mut_ptr(), 0, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let n = match io.read(buf.bytes_mut()) {
|
let n = match io.read(buf.bytes_mut()) {
|
||||||
@ -490,7 +528,9 @@ impl Reader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_message(buf: &mut BytesMut) -> Result<Message, ParseError> {
|
fn parse_message<H>(buf: &mut BytesMut, settings: &WorkerSettings<H>)
|
||||||
|
-> Result<Message, ParseError>
|
||||||
|
{
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
return Ok(Message::NotReady);
|
return Ok(Message::NotReady);
|
||||||
}
|
}
|
||||||
@ -537,13 +577,14 @@ impl Reader {
|
|||||||
let uri = Uri::from_shared(path).map_err(ParseError::Uri)?;
|
let uri = Uri::from_shared(path).map_err(ParseError::Uri)?;
|
||||||
|
|
||||||
// convert headers
|
// convert headers
|
||||||
let mut headers = HeaderMap::with_capacity(headers_len);
|
let msg = settings.get_http_message();
|
||||||
|
msg.get_mut().headers.reserve(headers_len);
|
||||||
for header in headers_indices[..headers_len].iter() {
|
for header in headers_indices[..headers_len].iter() {
|
||||||
if let Ok(name) = HeaderName::try_from(slice.slice(header.name.0, header.name.1)) {
|
if let Ok(name) = HeaderName::try_from(slice.slice(header.name.0, header.name.1)) {
|
||||||
if let Ok(value) = HeaderValue::try_from(
|
if let Ok(value) = HeaderValue::try_from(
|
||||||
slice.slice(header.value.0, header.value.1))
|
slice.slice(header.value.0, header.value.1))
|
||||||
{
|
{
|
||||||
headers.append(name, value);
|
msg.get_mut().headers.append(name, value);
|
||||||
} else {
|
} else {
|
||||||
return Err(ParseError::Header)
|
return Err(ParseError::Header)
|
||||||
}
|
}
|
||||||
@ -552,25 +593,27 @@ impl Reader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let decoder = if upgrade(&method, &headers) {
|
let decoder = if upgrade(&method, &msg.get_mut().headers) {
|
||||||
Decoder::eof()
|
Decoder::eof()
|
||||||
} else {
|
} else {
|
||||||
let has_len = headers.contains_key(header::CONTENT_LENGTH);
|
let has_len = msg.get_mut().headers.contains_key(header::CONTENT_LENGTH);
|
||||||
|
|
||||||
// Chunked encoding
|
// Chunked encoding
|
||||||
if chunked(&headers)? {
|
if chunked(&msg.get_mut().headers)? {
|
||||||
if has_len {
|
if has_len {
|
||||||
return Err(ParseError::Header)
|
return Err(ParseError::Header)
|
||||||
}
|
}
|
||||||
Decoder::chunked()
|
Decoder::chunked()
|
||||||
} else {
|
} else {
|
||||||
if !has_len {
|
if !has_len {
|
||||||
let msg = HttpRequest::new(method, uri, version, headers, None);
|
msg.get_mut().uri = uri;
|
||||||
return Ok(Message::Http1(msg, None))
|
msg.get_mut().method = method;
|
||||||
|
msg.get_mut().version = version;
|
||||||
|
return Ok(Message::Http1(HttpRequest::from_message(msg), None))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Content-Length
|
// Content-Length
|
||||||
let len = headers.get(header::CONTENT_LENGTH).unwrap();
|
let len = msg.get_mut().headers.get(header::CONTENT_LENGTH).unwrap();
|
||||||
if let Ok(s) = len.to_str() {
|
if let Ok(s) = len.to_str() {
|
||||||
if let Ok(len) = s.parse::<u64>() {
|
if let Ok(len) = s.parse::<u64>() {
|
||||||
Decoder::length(len)
|
Decoder::length(len)
|
||||||
@ -587,11 +630,14 @@ impl Reader {
|
|||||||
|
|
||||||
let (psender, payload) = Payload::new(false);
|
let (psender, payload) = Payload::new(false);
|
||||||
let info = PayloadInfo {
|
let info = PayloadInfo {
|
||||||
tx: PayloadType::new(&headers, psender),
|
tx: PayloadType::new(&msg.get_mut().headers, psender),
|
||||||
decoder: decoder,
|
decoder: decoder,
|
||||||
};
|
};
|
||||||
let msg = HttpRequest::new(method, uri, version, headers, Some(payload));
|
msg.get_mut().uri = uri;
|
||||||
Ok(Message::Http1(msg, Some(info)))
|
msg.get_mut().method = method;
|
||||||
|
msg.get_mut().version = version;
|
||||||
|
msg.get_mut().payload = Some(payload);
|
||||||
|
Ok(Message::Http1(HttpRequest::from_message(msg), Some(info)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use http::header::{HeaderValue, CONNECTION, DATE};
|
|||||||
|
|
||||||
use helpers;
|
use helpers;
|
||||||
use body::Body;
|
use body::Body;
|
||||||
|
use helpers::SharedBytes;
|
||||||
use encoding::PayloadEncoder;
|
use encoding::PayloadEncoder;
|
||||||
use httprequest::HttpMessage;
|
use httprequest::HttpMessage;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
@ -31,7 +32,7 @@ pub trait Writer {
|
|||||||
|
|
||||||
fn write_eof(&mut self) -> Result<WriterState, io::Error>;
|
fn write_eof(&mut self) -> Result<WriterState, io::Error>;
|
||||||
|
|
||||||
fn poll_complete(&mut self) -> Poll<(), io::Error>;
|
fn poll_completed(&mut self) -> Poll<(), io::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
@ -49,17 +50,19 @@ pub(crate) struct H1Writer<T: AsyncWrite> {
|
|||||||
encoder: PayloadEncoder,
|
encoder: PayloadEncoder,
|
||||||
written: u64,
|
written: u64,
|
||||||
headers_size: u32,
|
headers_size: u32,
|
||||||
|
buffer: SharedBytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: AsyncWrite> H1Writer<T> {
|
impl<T: AsyncWrite> H1Writer<T> {
|
||||||
|
|
||||||
pub fn new(stream: T) -> H1Writer<T> {
|
pub fn new(stream: T, buf: SharedBytes) -> H1Writer<T> {
|
||||||
H1Writer {
|
H1Writer {
|
||||||
flags: Flags::empty(),
|
flags: Flags::empty(),
|
||||||
stream: stream,
|
stream: stream,
|
||||||
encoder: PayloadEncoder::default(),
|
encoder: PayloadEncoder::empty(buf.clone()),
|
||||||
written: 0,
|
written: 0,
|
||||||
headers_size: 0,
|
headers_size: 0,
|
||||||
|
buffer: buf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +128,7 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
|||||||
|
|
||||||
// prepare task
|
// prepare task
|
||||||
self.flags.insert(Flags::STARTED);
|
self.flags.insert(Flags::STARTED);
|
||||||
self.encoder = PayloadEncoder::new(req, msg);
|
self.encoder = PayloadEncoder::new(self.buffer.clone(), req, msg);
|
||||||
if msg.keep_alive().unwrap_or_else(|| req.keep_alive()) {
|
if msg.keep_alive().unwrap_or_else(|| req.keep_alive()) {
|
||||||
self.flags.insert(Flags::KEEPALIVE);
|
self.flags.insert(Flags::KEEPALIVE);
|
||||||
}
|
}
|
||||||
@ -148,9 +151,9 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
|||||||
{
|
{
|
||||||
let mut buffer = self.encoder.get_mut();
|
let mut buffer = self.encoder.get_mut();
|
||||||
if let Body::Binary(ref bytes) = *msg.body() {
|
if let Body::Binary(ref bytes) = *msg.body() {
|
||||||
buffer.reserve(150 + msg.headers().len() * AVERAGE_HEADER_SIZE + bytes.len());
|
buffer.reserve(256 + msg.headers().len() * AVERAGE_HEADER_SIZE + bytes.len());
|
||||||
} else {
|
} else {
|
||||||
buffer.reserve(150 + msg.headers().len() * AVERAGE_HEADER_SIZE);
|
buffer.reserve(256 + msg.headers().len() * AVERAGE_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
match version {
|
match version {
|
||||||
@ -229,7 +232,7 @@ impl<T: AsyncWrite> Writer for H1Writer<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_complete(&mut self) -> Poll<(), io::Error> {
|
fn poll_completed(&mut self) -> Poll<(), io::Error> {
|
||||||
match self.write_to_stream() {
|
match self.write_to_stream() {
|
||||||
Ok(WriterState::Done) => Ok(Async::Ready(())),
|
Ok(WriterState::Done) => Ok(Async::Ready(())),
|
||||||
Ok(WriterState::Pause) => Ok(Async::NotReady),
|
Ok(WriterState::Pause) => Ok(Async::NotReady),
|
||||||
|
@ -8,6 +8,7 @@ use http::header::{HeaderValue, CONNECTION, TRANSFER_ENCODING, DATE};
|
|||||||
|
|
||||||
use helpers;
|
use helpers;
|
||||||
use body::Body;
|
use body::Body;
|
||||||
|
use helpers::SharedBytes;
|
||||||
use encoding::PayloadEncoder;
|
use encoding::PayloadEncoder;
|
||||||
use httprequest::HttpMessage;
|
use httprequest::HttpMessage;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
@ -38,7 +39,7 @@ impl H2Writer {
|
|||||||
H2Writer {
|
H2Writer {
|
||||||
respond: respond,
|
respond: respond,
|
||||||
stream: None,
|
stream: None,
|
||||||
encoder: PayloadEncoder::default(),
|
encoder: PayloadEncoder::empty(SharedBytes::default()),
|
||||||
flags: Flags::empty(),
|
flags: Flags::empty(),
|
||||||
written: 0,
|
written: 0,
|
||||||
}
|
}
|
||||||
@ -115,7 +116,7 @@ impl Writer for H2Writer {
|
|||||||
|
|
||||||
// prepare response
|
// prepare response
|
||||||
self.flags.insert(Flags::STARTED);
|
self.flags.insert(Flags::STARTED);
|
||||||
self.encoder = PayloadEncoder::new(req, msg);
|
self.encoder = PayloadEncoder::new(SharedBytes::default(), req, msg);
|
||||||
if let Body::Empty = *msg.body() {
|
if let Body::Empty = *msg.body() {
|
||||||
self.flags.insert(Flags::EOF);
|
self.flags.insert(Flags::EOF);
|
||||||
}
|
}
|
||||||
@ -193,7 +194,7 @@ impl Writer for H2Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll_complete(&mut self) -> Poll<(), io::Error> {
|
fn poll_completed(&mut self) -> Poll<(), io::Error> {
|
||||||
match self.write_to_stream() {
|
match self.write_to_stream() {
|
||||||
Ok(WriterState::Done) => Ok(Async::Ready(())),
|
Ok(WriterState::Done) => Ok(Async::Ready(())),
|
||||||
Ok(WriterState::Pause) => Ok(Async::NotReady),
|
Ok(WriterState::Pause) => Ok(Async::NotReady),
|
||||||
|
170
src/helpers.rs
170
src/helpers.rs
@ -1,10 +1,15 @@
|
|||||||
use std::{str, mem, ptr, slice};
|
use std::{str, mem, ptr, slice};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::collections::VecDeque;
|
||||||
use time;
|
use time;
|
||||||
use bytes::BytesMut;
|
use bytes::BytesMut;
|
||||||
use http::header::HeaderValue;
|
use http::header::HeaderValue;
|
||||||
|
|
||||||
|
use httprequest::HttpMessage;
|
||||||
|
|
||||||
// "Sun, 06 Nov 1994 08:49:37 GMT".len()
|
// "Sun, 06 Nov 1994 08:49:37 GMT".len()
|
||||||
pub const DATE_VALUE_LENGTH: usize = 29;
|
pub const DATE_VALUE_LENGTH: usize = 29;
|
||||||
|
|
||||||
@ -51,6 +56,171 @@ impl fmt::Write for CachedDate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Internal use only! unsafe
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct SharedBytesPool(RefCell<VecDeque<Rc<BytesMut>>>);
|
||||||
|
|
||||||
|
impl SharedBytesPool {
|
||||||
|
pub fn new() -> SharedBytesPool {
|
||||||
|
SharedBytesPool(RefCell::new(VecDeque::with_capacity(128)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_bytes(&self) -> Rc<BytesMut> {
|
||||||
|
if let Some(bytes) = self.0.borrow_mut().pop_front() {
|
||||||
|
bytes
|
||||||
|
} else {
|
||||||
|
Rc::new(BytesMut::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release_bytes(&self, mut bytes: Rc<BytesMut>) {
|
||||||
|
if self.0.borrow().len() < 128 {
|
||||||
|
Rc::get_mut(&mut bytes).unwrap().take();
|
||||||
|
self.0.borrow_mut().push_front(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct SharedBytes(
|
||||||
|
Option<Rc<BytesMut>>, Option<Rc<SharedBytesPool>>);
|
||||||
|
|
||||||
|
impl Drop for SharedBytes {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(ref pool) = self.1 {
|
||||||
|
if let Some(bytes) = self.0.take() {
|
||||||
|
if Rc::strong_count(&bytes) == 1 {
|
||||||
|
pool.release_bytes(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SharedBytes {
|
||||||
|
|
||||||
|
pub fn new(bytes: Rc<BytesMut>, pool: Rc<SharedBytesPool>) -> SharedBytes {
|
||||||
|
SharedBytes(Some(bytes), Some(pool))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[allow(mutable_transmutes)]
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
|
||||||
|
pub fn get_mut(&self) -> &mut BytesMut {
|
||||||
|
let r: &BytesMut = self.0.as_ref().unwrap().as_ref();
|
||||||
|
unsafe{mem::transmute(r)}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_ref(&self) -> &BytesMut {
|
||||||
|
self.0.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SharedBytes {
|
||||||
|
fn default() -> Self {
|
||||||
|
SharedBytes(Some(Rc::new(BytesMut::new())), None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for SharedBytes {
|
||||||
|
fn clone(&self) -> SharedBytes {
|
||||||
|
SharedBytes(self.0.clone(), self.1.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Internal use only! unsafe
|
||||||
|
pub(crate) struct SharedMessagePool(RefCell<VecDeque<Rc<HttpMessage>>>);
|
||||||
|
|
||||||
|
impl SharedMessagePool {
|
||||||
|
pub fn new() -> SharedMessagePool {
|
||||||
|
SharedMessagePool(RefCell::new(VecDeque::with_capacity(128)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self) -> Rc<HttpMessage> {
|
||||||
|
if let Some(msg) = self.0.borrow_mut().pop_front() {
|
||||||
|
msg
|
||||||
|
} else {
|
||||||
|
Rc::new(HttpMessage::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn release(&self, mut msg: Rc<HttpMessage>) {
|
||||||
|
if self.0.borrow().len() < 128 {
|
||||||
|
Rc::get_mut(&mut msg).unwrap().reset();
|
||||||
|
self.0.borrow_mut().push_front(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct SharedHttpMessage(
|
||||||
|
Option<Rc<HttpMessage>>, Option<Rc<SharedMessagePool>>);
|
||||||
|
|
||||||
|
impl Drop for SharedHttpMessage {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(ref pool) = self.1 {
|
||||||
|
if let Some(msg) = self.0.take() {
|
||||||
|
if Rc::strong_count(&msg) == 1 {
|
||||||
|
pool.release(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for SharedHttpMessage {
|
||||||
|
type Target = HttpMessage;
|
||||||
|
|
||||||
|
fn deref(&self) -> &HttpMessage {
|
||||||
|
self.get_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for SharedHttpMessage {
|
||||||
|
|
||||||
|
fn deref_mut(&mut self) -> &mut HttpMessage {
|
||||||
|
self.get_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for SharedHttpMessage {
|
||||||
|
|
||||||
|
fn clone(&self) -> SharedHttpMessage {
|
||||||
|
SharedHttpMessage(self.0.clone(), self.1.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SharedHttpMessage {
|
||||||
|
|
||||||
|
fn default() -> SharedHttpMessage {
|
||||||
|
SharedHttpMessage(Some(Rc::new(HttpMessage::default())), None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SharedHttpMessage {
|
||||||
|
|
||||||
|
pub fn from_message(msg: HttpMessage) -> SharedHttpMessage {
|
||||||
|
SharedHttpMessage(Some(Rc::new(msg)), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(msg: Rc<HttpMessage>, pool: Rc<SharedMessagePool>) -> SharedHttpMessage {
|
||||||
|
SharedHttpMessage(Some(msg), Some(pool))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
#[allow(mutable_transmutes)]
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref, inline_always))]
|
||||||
|
pub fn get_mut(&self) -> &mut HttpMessage {
|
||||||
|
let r: &HttpMessage = self.0.as_ref().unwrap().as_ref();
|
||||||
|
unsafe{mem::transmute(r)}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_ref(&self) -> &HttpMessage {
|
||||||
|
self.0.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const DEC_DIGITS_LUT: &[u8] =
|
const DEC_DIGITS_LUT: &[u8] =
|
||||||
b"0001020304050607080910111213141516171819\
|
b"0001020304050607080910111213141516171819\
|
||||||
2021222324252627282930313233343536373839\
|
2021222324252627282930313233343536373839\
|
||||||
|
@ -15,6 +15,7 @@ use param::Params;
|
|||||||
use router::Router;
|
use router::Router;
|
||||||
use payload::Payload;
|
use payload::Payload;
|
||||||
use multipart::Multipart;
|
use multipart::Multipart;
|
||||||
|
use helpers::SharedHttpMessage;
|
||||||
use error::{ParseError, PayloadError, UrlGenerationError,
|
use error::{ParseError, PayloadError, UrlGenerationError,
|
||||||
MultipartError, CookieParseError, HttpRangeError, UrlencodedError};
|
MultipartError, CookieParseError, HttpRangeError, UrlencodedError};
|
||||||
|
|
||||||
@ -69,10 +70,20 @@ impl HttpMessage {
|
|||||||
self.version != Version::HTTP_10
|
self.version != Version::HTTP_10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn reset(&mut self) {
|
||||||
|
self.headers.clear();
|
||||||
|
self.extensions.clear();
|
||||||
|
self.params.clear();
|
||||||
|
self.cookies.take();
|
||||||
|
self.addr.take();
|
||||||
|
self.payload.take();
|
||||||
|
self.info.take();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An HTTP Request
|
/// An HTTP Request
|
||||||
pub struct HttpRequest<S=()>(Rc<HttpMessage>, Option<Rc<S>>, Option<Router<S>>);
|
pub struct HttpRequest<S=()>(SharedHttpMessage, Option<Rc<S>>, Option<Router<S>>);
|
||||||
|
|
||||||
impl HttpRequest<()> {
|
impl HttpRequest<()> {
|
||||||
/// Construct a new Request.
|
/// Construct a new Request.
|
||||||
@ -81,7 +92,7 @@ impl HttpRequest<()> {
|
|||||||
version: Version, headers: HeaderMap, payload: Option<Payload>) -> HttpRequest
|
version: Version, headers: HeaderMap, payload: Option<Payload>) -> HttpRequest
|
||||||
{
|
{
|
||||||
HttpRequest(
|
HttpRequest(
|
||||||
Rc::new(HttpMessage {
|
SharedHttpMessage::from_message(HttpMessage {
|
||||||
method: method,
|
method: method,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
version: version,
|
version: version,
|
||||||
@ -98,6 +109,10 @@ impl HttpRequest<()> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_message(msg: SharedHttpMessage) -> HttpRequest {
|
||||||
|
HttpRequest(msg, None, None)
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a new Request.
|
/// Construct a new Request.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -106,7 +121,7 @@ impl HttpRequest<()> {
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
HttpRequest(
|
HttpRequest(
|
||||||
Rc::new(HttpMessage {
|
SharedHttpMessage::from_message(HttpMessage {
|
||||||
method: Method::GET,
|
method: Method::GET,
|
||||||
uri: Uri::from_str(path).unwrap(),
|
uri: Uri::from_str(path).unwrap(),
|
||||||
version: Version::HTTP_11,
|
version: Version::HTTP_11,
|
||||||
@ -133,7 +148,7 @@ impl<S> HttpRequest<S> {
|
|||||||
|
|
||||||
/// Construct new http request without state.
|
/// Construct new http request without state.
|
||||||
pub fn clone_without_state(&self) -> HttpRequest {
|
pub fn clone_without_state(&self) -> HttpRequest {
|
||||||
HttpRequest(Rc::clone(&self.0), None, None)
|
HttpRequest(self.0.clone(), None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get mutable reference for inner message
|
// get mutable reference for inner message
|
||||||
@ -142,10 +157,15 @@ impl<S> HttpRequest<S> {
|
|||||||
#[allow(mutable_transmutes)]
|
#[allow(mutable_transmutes)]
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
|
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
|
||||||
fn as_mut(&self) -> &mut HttpMessage {
|
fn as_mut(&self) -> &mut HttpMessage {
|
||||||
let r: &HttpMessage = self.0.as_ref();
|
self.0.get_mut()
|
||||||
unsafe{mem::transmute(r)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn as_ref(&self) -> &HttpMessage {
|
||||||
|
self.0.get_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
pub(crate) fn get_inner(&mut self) -> &mut HttpMessage {
|
pub(crate) fn get_inner(&mut self) -> &mut HttpMessage {
|
||||||
self.as_mut()
|
self.as_mut()
|
||||||
}
|
}
|
||||||
@ -173,22 +193,22 @@ impl<S> HttpRequest<S> {
|
|||||||
|
|
||||||
/// Read the Request Uri.
|
/// Read the Request Uri.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn uri(&self) -> &Uri { &self.0.uri }
|
pub fn uri(&self) -> &Uri { &self.as_ref().uri }
|
||||||
|
|
||||||
/// Read the Request method.
|
/// Read the Request method.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn method(&self) -> &Method { &self.0.method }
|
pub fn method(&self) -> &Method { &self.as_ref().method }
|
||||||
|
|
||||||
/// Read the Request Version.
|
/// Read the Request Version.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn version(&self) -> Version {
|
pub fn version(&self) -> Version {
|
||||||
self.0.version
|
self.as_ref().version
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the Request Headers.
|
/// Read the Request Headers.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn headers(&self) -> &HeaderMap {
|
pub fn headers(&self) -> &HeaderMap {
|
||||||
&self.0.headers
|
&self.as_ref().headers
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -200,17 +220,17 @@ impl<S> HttpRequest<S> {
|
|||||||
/// The target path of this Request.
|
/// The target path of this Request.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn path(&self) -> &str {
|
pub fn path(&self) -> &str {
|
||||||
self.0.uri.path()
|
self.as_ref().uri.path()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get *ConnectionInfo* for currect request.
|
/// Get *ConnectionInfo* for currect request.
|
||||||
pub fn connection_info(&self) -> &ConnectionInfo {
|
pub fn connection_info(&self) -> &ConnectionInfo {
|
||||||
if self.0.info.is_none() {
|
if self.as_ref().info.is_none() {
|
||||||
let info: ConnectionInfo<'static> = unsafe{
|
let info: ConnectionInfo<'static> = unsafe{
|
||||||
mem::transmute(ConnectionInfo::new(self))};
|
mem::transmute(ConnectionInfo::new(self))};
|
||||||
self.as_mut().info = Some(info);
|
self.as_mut().info = Some(info);
|
||||||
}
|
}
|
||||||
self.0.info.as_ref().unwrap()
|
self.as_ref().info.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url_for<U, I>(&self, name: &str, elements: U) -> Result<Url, UrlGenerationError>
|
pub fn url_for<U, I>(&self, name: &str, elements: U) -> Result<Url, UrlGenerationError>
|
||||||
@ -237,7 +257,7 @@ impl<S> HttpRequest<S> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn peer_addr(&self) -> Option<&SocketAddr> {
|
pub fn peer_addr(&self) -> Option<&SocketAddr> {
|
||||||
self.0.addr.as_ref()
|
self.as_ref().addr.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -248,7 +268,7 @@ impl<S> HttpRequest<S> {
|
|||||||
/// Return a new iterator that yields pairs of `Cow<str>` for query parameters
|
/// Return a new iterator that yields pairs of `Cow<str>` for query parameters
|
||||||
pub fn query(&self) -> HashMap<String, String> {
|
pub fn query(&self) -> HashMap<String, String> {
|
||||||
let mut q: HashMap<String, String> = HashMap::new();
|
let mut q: HashMap<String, String> = HashMap::new();
|
||||||
if let Some(query) = self.0.uri.query().as_ref() {
|
if let Some(query) = self.as_ref().uri.query().as_ref() {
|
||||||
for (key, val) in form_urlencoded::parse(query.as_ref()) {
|
for (key, val) in form_urlencoded::parse(query.as_ref()) {
|
||||||
q.insert(key.to_string(), val.to_string());
|
q.insert(key.to_string(), val.to_string());
|
||||||
}
|
}
|
||||||
@ -261,7 +281,7 @@ impl<S> HttpRequest<S> {
|
|||||||
/// E.g., id=10
|
/// E.g., id=10
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn query_string(&self) -> &str {
|
pub fn query_string(&self) -> &str {
|
||||||
if let Some(query) = self.0.uri.query().as_ref() {
|
if let Some(query) = self.as_ref().uri.query().as_ref() {
|
||||||
query
|
query
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
@ -271,7 +291,7 @@ impl<S> HttpRequest<S> {
|
|||||||
/// Load request cookies.
|
/// Load request cookies.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cookies(&self) -> Result<&Vec<Cookie<'static>>, CookieParseError> {
|
pub fn cookies(&self) -> Result<&Vec<Cookie<'static>>, CookieParseError> {
|
||||||
if self.0.cookies.is_none() {
|
if self.as_ref().cookies.is_none() {
|
||||||
let msg = self.as_mut();
|
let msg = self.as_mut();
|
||||||
let mut cookies = Vec::new();
|
let mut cookies = Vec::new();
|
||||||
if let Some(val) = msg.headers.get(header::COOKIE) {
|
if let Some(val) = msg.headers.get(header::COOKIE) {
|
||||||
@ -283,7 +303,7 @@ impl<S> HttpRequest<S> {
|
|||||||
}
|
}
|
||||||
msg.cookies = Some(cookies)
|
msg.cookies = Some(cookies)
|
||||||
}
|
}
|
||||||
Ok(self.0.cookies.as_ref().unwrap())
|
Ok(self.as_ref().cookies.as_ref().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return request cookie.
|
/// Return request cookie.
|
||||||
@ -304,7 +324,7 @@ impl<S> HttpRequest<S> {
|
|||||||
/// for matching storing that segment of the request url in the Params object.
|
/// for matching storing that segment of the request url in the Params object.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn match_info(&self) -> &Params {
|
pub fn match_info(&self) -> &Params {
|
||||||
unsafe{ mem::transmute(&self.0.params) }
|
unsafe{ mem::transmute(&self.as_ref().params) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set request Params.
|
/// Set request Params.
|
||||||
@ -315,25 +335,25 @@ impl<S> HttpRequest<S> {
|
|||||||
|
|
||||||
/// Checks if a connection should be kept alive.
|
/// Checks if a connection should be kept alive.
|
||||||
pub fn keep_alive(&self) -> bool {
|
pub fn keep_alive(&self) -> bool {
|
||||||
if let Some(conn) = self.0.headers.get(header::CONNECTION) {
|
if let Some(conn) = self.headers().get(header::CONNECTION) {
|
||||||
if let Ok(conn) = conn.to_str() {
|
if let Ok(conn) = conn.to_str() {
|
||||||
if self.0.version == Version::HTTP_10 && conn.contains("keep-alive") {
|
if self.as_ref().version == Version::HTTP_10 && conn.contains("keep-alive") {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
self.0.version == Version::HTTP_11 &&
|
self.as_ref().version == Version::HTTP_11 &&
|
||||||
!(conn.contains("close") || conn.contains("upgrade"))
|
!(conn.contains("close") || conn.contains("upgrade"))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.0.version != Version::HTTP_10
|
self.as_ref().version != Version::HTTP_10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the request content type
|
/// Read the request content type
|
||||||
pub fn content_type(&self) -> &str {
|
pub fn content_type(&self) -> &str {
|
||||||
if let Some(content_type) = self.0.headers.get(header::CONTENT_TYPE) {
|
if let Some(content_type) = self.headers().get(header::CONTENT_TYPE) {
|
||||||
if let Ok(content_type) = content_type.to_str() {
|
if let Ok(content_type) = content_type.to_str() {
|
||||||
return content_type
|
return content_type
|
||||||
}
|
}
|
||||||
@ -343,17 +363,17 @@ impl<S> HttpRequest<S> {
|
|||||||
|
|
||||||
/// Check if request requires connection upgrade
|
/// Check if request requires connection upgrade
|
||||||
pub(crate) fn upgrade(&self) -> bool {
|
pub(crate) fn upgrade(&self) -> bool {
|
||||||
if let Some(conn) = self.0.headers.get(header::CONNECTION) {
|
if let Some(conn) = self.as_ref().headers.get(header::CONNECTION) {
|
||||||
if let Ok(s) = conn.to_str() {
|
if let Ok(s) = conn.to_str() {
|
||||||
return s.to_lowercase().contains("upgrade")
|
return s.to_lowercase().contains("upgrade")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.0.method == Method::CONNECT
|
self.as_ref().method == Method::CONNECT
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if request has chunked transfer encoding
|
/// Check if request has chunked transfer encoding
|
||||||
pub fn chunked(&self) -> Result<bool, ParseError> {
|
pub fn chunked(&self) -> Result<bool, ParseError> {
|
||||||
if let Some(encodings) = self.0.headers.get(header::TRANSFER_ENCODING) {
|
if let Some(encodings) = self.headers().get(header::TRANSFER_ENCODING) {
|
||||||
if let Ok(s) = encodings.to_str() {
|
if let Ok(s) = encodings.to_str() {
|
||||||
Ok(s.to_lowercase().contains("chunked"))
|
Ok(s.to_lowercase().contains("chunked"))
|
||||||
} else {
|
} else {
|
||||||
@ -367,7 +387,7 @@ impl<S> HttpRequest<S> {
|
|||||||
/// Parses Range HTTP header string as per RFC 2616.
|
/// Parses Range HTTP header string as per RFC 2616.
|
||||||
/// `size` is full size of response (file).
|
/// `size` is full size of response (file).
|
||||||
pub fn range(&self, size: u64) -> Result<Vec<HttpRange>, HttpRangeError> {
|
pub fn range(&self, size: u64) -> Result<Vec<HttpRange>, HttpRangeError> {
|
||||||
if let Some(range) = self.0.headers.get(header::RANGE) {
|
if let Some(range) = self.headers().get(header::RANGE) {
|
||||||
HttpRange::parse(unsafe{str::from_utf8_unchecked(range.as_bytes())}, size)
|
HttpRange::parse(unsafe{str::from_utf8_unchecked(range.as_bytes())}, size)
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
} else {
|
} else {
|
||||||
@ -378,7 +398,7 @@ impl<S> HttpRequest<S> {
|
|||||||
/// Returns reference to the associated http payload.
|
/// Returns reference to the associated http payload.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn payload(&self) -> Option<&Payload> {
|
pub fn payload(&self) -> Option<&Payload> {
|
||||||
self.0.payload.as_ref()
|
self.as_ref().payload.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns mutable reference to the associated http payload.
|
/// Returns mutable reference to the associated http payload.
|
||||||
@ -397,7 +417,7 @@ impl<S> HttpRequest<S> {
|
|||||||
///
|
///
|
||||||
/// Content-type: multipart/form-data;
|
/// Content-type: multipart/form-data;
|
||||||
pub fn multipart(&mut self) -> Result<Multipart, MultipartError> {
|
pub fn multipart(&mut self) -> Result<Multipart, MultipartError> {
|
||||||
let boundary = Multipart::boundary(&self.0.headers)?;
|
let boundary = Multipart::boundary(self.headers())?;
|
||||||
if let Some(payload) = self.take_payload() {
|
if let Some(payload) = self.take_payload() {
|
||||||
Ok(Multipart::new(boundary, payload))
|
Ok(Multipart::new(boundary, payload))
|
||||||
} else {
|
} else {
|
||||||
@ -434,7 +454,7 @@ impl<S> HttpRequest<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check content type
|
// check content type
|
||||||
let t = if let Some(content_type) = self.0.headers.get(header::CONTENT_TYPE) {
|
let t = if let Some(content_type) = self.headers().get(header::CONTENT_TYPE) {
|
||||||
if let Ok(content_type) = content_type.to_str() {
|
if let Ok(content_type) = content_type.to_str() {
|
||||||
content_type.to_lowercase() == "application/x-www-form-urlencoded"
|
content_type.to_lowercase() == "application/x-www-form-urlencoded"
|
||||||
} else {
|
} else {
|
||||||
@ -460,29 +480,29 @@ impl Default for HttpRequest<()> {
|
|||||||
|
|
||||||
/// Construct default request
|
/// Construct default request
|
||||||
fn default() -> HttpRequest {
|
fn default() -> HttpRequest {
|
||||||
HttpRequest(Rc::new(HttpMessage::default()), None, None)
|
HttpRequest(SharedHttpMessage::default(), None, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Clone for HttpRequest<S> {
|
impl<S> Clone for HttpRequest<S> {
|
||||||
fn clone(&self) -> HttpRequest<S> {
|
fn clone(&self) -> HttpRequest<S> {
|
||||||
HttpRequest(Rc::clone(&self.0), self.1.clone(), None)
|
HttpRequest(self.0.clone(), self.1.clone(), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> fmt::Debug for HttpRequest<S> {
|
impl<S> fmt::Debug for HttpRequest<S> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let res = write!(f, "\nHttpRequest {:?} {}:{}\n",
|
let res = write!(f, "\nHttpRequest {:?} {}:{}\n",
|
||||||
self.0.version, self.0.method, self.0.uri);
|
self.as_ref().version, self.as_ref().method, self.as_ref().uri);
|
||||||
if !self.query_string().is_empty() {
|
if !self.query_string().is_empty() {
|
||||||
let _ = write!(f, " query: ?{:?}\n", self.query_string());
|
let _ = write!(f, " query: ?{:?}\n", self.query_string());
|
||||||
}
|
}
|
||||||
if !self.match_info().is_empty() {
|
if !self.match_info().is_empty() {
|
||||||
let _ = write!(f, " params: {:?}\n", self.0.params);
|
let _ = write!(f, " params: {:?}\n", self.as_ref().params);
|
||||||
}
|
}
|
||||||
let _ = write!(f, " headers:\n");
|
let _ = write!(f, " headers:\n");
|
||||||
for key in self.0.headers.keys() {
|
for key in self.as_ref().headers.keys() {
|
||||||
let vals: Vec<_> = self.0.headers.get_all(key).iter().collect();
|
let vals: Vec<_> = self.as_ref().headers.get_all(key).iter().collect();
|
||||||
if vals.len() > 1 {
|
if vals.len() > 1 {
|
||||||
let _ = write!(f, " {:?}: {:?}\n", key, vals);
|
let _ = write!(f, " {:?}: {:?}\n", key, vals);
|
||||||
} else {
|
} else {
|
||||||
|
@ -30,6 +30,10 @@ impl<'a> Default for Params<'a> {
|
|||||||
|
|
||||||
impl<'a> Params<'a> {
|
impl<'a> Params<'a> {
|
||||||
|
|
||||||
|
pub(crate) fn clear(&mut self) {
|
||||||
|
self.0.clear();
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn add(&mut self, name: &'a str, value: &'a str) {
|
pub(crate) fn add(&mut self, name: &'a str, value: &'a str) {
|
||||||
self.0.push((name, value));
|
self.0.push((name, value));
|
||||||
}
|
}
|
||||||
|
@ -755,16 +755,18 @@ impl<S> ProcessResponse<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush io
|
// flush io but only if we need to
|
||||||
match io.poll_complete() {
|
if self.running == RunningState::Paused || !self.drain.0.is_empty() {
|
||||||
Ok(Async::Ready(_)) =>
|
match io.poll_completed() {
|
||||||
self.running.resume(),
|
Ok(Async::Ready(_)) =>
|
||||||
Ok(Async::NotReady) =>
|
self.running.resume(),
|
||||||
return Err(PipelineState::Response(self)),
|
Ok(Async::NotReady) =>
|
||||||
Err(err) => {
|
return Err(PipelineState::Response(self)),
|
||||||
debug!("Error sending data: {}", err);
|
Err(err) => {
|
||||||
info.error = Some(err.into());
|
debug!("Error sending data: {}", err);
|
||||||
return Ok(FinishingMiddlewares::init(info, self.resp))
|
info.error = Some(err.into());
|
||||||
|
return Ok(FinishingMiddlewares::init(info, self.resp))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,6 +413,8 @@ pub(crate) struct WorkerSettings<H> {
|
|||||||
h: Vec<H>,
|
h: Vec<H>,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
keep_alive: u64,
|
keep_alive: u64,
|
||||||
|
bytes: Rc<helpers::SharedBytesPool>,
|
||||||
|
messages: Rc<helpers::SharedMessagePool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H> WorkerSettings<H> {
|
impl<H> WorkerSettings<H> {
|
||||||
@ -421,6 +423,8 @@ impl<H> WorkerSettings<H> {
|
|||||||
h: h,
|
h: h,
|
||||||
enabled: if let Some(ka) = keep_alive { ka > 0 } else { false },
|
enabled: if let Some(ka) = keep_alive { ka > 0 } else { false },
|
||||||
keep_alive: keep_alive.unwrap_or(0),
|
keep_alive: keep_alive.unwrap_or(0),
|
||||||
|
bytes: Rc::new(helpers::SharedBytesPool::new()),
|
||||||
|
messages: Rc::new(helpers::SharedMessagePool::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,6 +437,12 @@ impl<H> WorkerSettings<H> {
|
|||||||
pub fn keep_alive_enabled(&self) -> bool {
|
pub fn keep_alive_enabled(&self) -> bool {
|
||||||
self.enabled
|
self.enabled
|
||||||
}
|
}
|
||||||
|
pub fn get_shared_bytes(&self) -> helpers::SharedBytes {
|
||||||
|
helpers::SharedBytes::new(self.bytes.get_bytes(), Rc::clone(&self.bytes))
|
||||||
|
}
|
||||||
|
pub fn get_http_message(&self) -> helpers::SharedHttpMessage {
|
||||||
|
helpers::SharedHttpMessage::new(self.messages.get(), Rc::clone(&self.messages))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H: 'static> Worker<H> {
|
impl<H: 'static> Worker<H> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user