1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-28 09:42:40 +01:00

refactor decoder

This commit is contained in:
Nikolay Kim 2018-11-16 19:28:07 -08:00
parent 3b7bc41418
commit 625469f0f4
13 changed files with 493 additions and 495 deletions

View File

@ -13,7 +13,7 @@ use super::{Connect, Connection};
use body::{BodyType, MessageBody, PayloadStream}; use body::{BodyType, MessageBody, PayloadStream};
use error::PayloadError; use error::PayloadError;
use h1; use h1;
use request::RequestHead; use message::RequestHead;
pub(crate) fn send_request<T, I, B>( pub(crate) fn send_request<T, I, B>(
head: RequestHead, head: RequestHead,

View File

@ -16,7 +16,7 @@ use http::{
uri, Error as HttpError, HeaderMap, HeaderName, HeaderValue, HttpTryFrom, Method, uri, Error as HttpError, HeaderMap, HeaderName, HeaderValue, HttpTryFrom, Method,
Uri, Version, Uri, Version,
}; };
use request::RequestHead; use message::RequestHead;
use super::response::ClientResponse; use super::response::ClientResponse;
use super::{pipeline, Connect, Connection, ConnectorError, SendRequestError}; use super::{pipeline, Connect, Connection, ConnectorError, SendRequestError};

View File

@ -1,6 +1,5 @@
use std::cell::{Cell, Ref, RefCell, RefMut}; use std::cell::RefCell;
use std::fmt; use std::fmt;
use std::rc::Rc;
use bytes::Bytes; use bytes::Bytes;
use futures::{Async, Poll, Stream}; use futures::{Async, Poll, Stream};
@ -8,16 +7,14 @@ use http::{HeaderMap, StatusCode, Version};
use body::PayloadStream; use body::PayloadStream;
use error::PayloadError; use error::PayloadError;
use extensions::Extensions;
use httpmessage::HttpMessage; use httpmessage::HttpMessage;
use request::{Message, MessageFlags, MessagePool, RequestHead}; use message::{MessageFlags, ResponseHead};
use uri::Url;
use super::pipeline::Payload; use super::pipeline::Payload;
/// Client Response /// Client Response
pub struct ClientResponse { pub struct ClientResponse {
pub(crate) inner: Rc<Message>, pub(crate) head: ResponseHead,
pub(crate) payload: RefCell<Option<PayloadStream>>, pub(crate) payload: RefCell<Option<PayloadStream>>,
} }
@ -25,7 +22,7 @@ impl HttpMessage for ClientResponse {
type Stream = PayloadStream; type Stream = PayloadStream;
fn headers(&self) -> &HeaderMap { fn headers(&self) -> &HeaderMap {
&self.inner.head.headers &self.head.headers
} }
#[inline] #[inline]
@ -41,75 +38,50 @@ impl HttpMessage for ClientResponse {
impl ClientResponse { impl ClientResponse {
/// Create new Request instance /// Create new Request instance
pub fn new() -> ClientResponse { pub fn new() -> ClientResponse {
ClientResponse::with_pool(MessagePool::pool())
}
/// Create new Request instance with pool
pub(crate) fn with_pool(pool: &'static MessagePool) -> ClientResponse {
ClientResponse { ClientResponse {
inner: Rc::new(Message { head: ResponseHead::default(),
pool,
head: RequestHead::default(),
status: StatusCode::OK,
url: Url::default(),
flags: Cell::new(MessageFlags::empty()),
payload: RefCell::new(None),
extensions: RefCell::new(Extensions::new()),
}),
payload: RefCell::new(None), payload: RefCell::new(None),
} }
} }
#[inline] #[inline]
pub(crate) fn inner(&self) -> &Message { pub(crate) fn head(&self) -> &ResponseHead {
self.inner.as_ref() &self.head
} }
#[inline] #[inline]
pub(crate) fn inner_mut(&mut self) -> &mut Message { pub(crate) fn head_mut(&mut self) -> &mut ResponseHead {
Rc::get_mut(&mut self.inner).expect("Multiple copies exist") &mut self.head
} }
/// Read the Request Version. /// Read the Request Version.
#[inline] #[inline]
pub fn version(&self) -> Version { pub fn version(&self) -> Version {
self.inner().head.version self.head().version.clone().unwrap()
} }
/// Get the status from the server. /// Get the status from the server.
#[inline] #[inline]
pub fn status(&self) -> StatusCode { pub fn status(&self) -> StatusCode {
self.inner().status self.head().status
} }
#[inline] #[inline]
/// Returns Request's headers. /// Returns Request's headers.
pub fn headers(&self) -> &HeaderMap { pub fn headers(&self) -> &HeaderMap {
&self.inner().head.headers &self.head().headers
} }
#[inline] #[inline]
/// Returns mutable Request's headers. /// Returns mutable Request's headers.
pub fn headers_mut(&mut self) -> &mut HeaderMap { pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.inner_mut().head.headers &mut self.head_mut().headers
} }
/// Checks if a connection should be kept alive. /// Checks if a connection should be kept alive.
#[inline] #[inline]
pub fn keep_alive(&self) -> bool { pub fn keep_alive(&self) -> bool {
self.inner().flags.get().contains(MessageFlags::KEEPALIVE) self.head().flags.contains(MessageFlags::KEEPALIVE)
}
/// Request extensions
#[inline]
pub fn extensions(&self) -> Ref<Extensions> {
self.inner().extensions.borrow()
}
/// Mutable reference to a the request's extensions
#[inline]
pub fn extensions_mut(&self) -> RefMut<Extensions> {
self.inner().extensions.borrow_mut()
} }
} }
@ -126,14 +98,6 @@ impl Stream for ClientResponse {
} }
} }
impl Drop for ClientResponse {
fn drop(&mut self) {
if Rc::strong_count(&self.inner) == 1 {
self.inner.pool.release(self.inner.clone());
}
}
}
impl fmt::Debug for ClientResponse { impl fmt::Debug for ClientResponse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "\nClientResponse {:?} {}", self.version(), self.status(),)?; writeln!(f, "\nClientResponse {:?} {}", self.version(), self.status(),)?;

View File

@ -4,7 +4,7 @@ use std::io::{self, Write};
use bytes::{BufMut, Bytes, BytesMut}; use bytes::{BufMut, Bytes, BytesMut};
use tokio_codec::{Decoder, Encoder}; use tokio_codec::{Decoder, Encoder};
use super::decoder::{PayloadDecoder, PayloadItem, PayloadType, ResponseDecoder}; use super::decoder::{MessageDecoder, PayloadDecoder, PayloadItem, PayloadType};
use super::encoder::{RequestEncoder, ResponseLength}; use super::encoder::{RequestEncoder, ResponseLength};
use super::{Message, MessageType}; use super::{Message, MessageType};
use body::{Binary, Body, BodyType}; use body::{Binary, Body, BodyType};
@ -16,7 +16,7 @@ use http::header::{
HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING, UPGRADE, HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING, UPGRADE,
}; };
use http::{Method, Version}; use http::{Method, Version};
use request::{MessagePool, RequestHead}; use message::{MessagePool, RequestHead};
bitflags! { bitflags! {
struct Flags: u8 { struct Flags: u8 {
@ -42,7 +42,7 @@ pub struct ClientPayloadCodec {
struct ClientCodecInner { struct ClientCodecInner {
config: ServiceConfig, config: ServiceConfig,
decoder: ResponseDecoder, decoder: MessageDecoder<ClientResponse>,
payload: Option<PayloadDecoder>, payload: Option<PayloadDecoder>,
version: Version, version: Version,
@ -63,11 +63,6 @@ impl ClientCodec {
/// ///
/// `keepalive_enabled` how response `connection` header get generated. /// `keepalive_enabled` how response `connection` header get generated.
pub fn new(config: ServiceConfig) -> Self { pub fn new(config: ServiceConfig) -> Self {
ClientCodec::with_pool(MessagePool::pool(), config)
}
/// Create HTTP/1 codec with request's pool
pub(crate) fn with_pool(pool: &'static MessagePool, config: ServiceConfig) -> Self {
let flags = if config.keep_alive_enabled() { let flags = if config.keep_alive_enabled() {
Flags::KEEPALIVE_ENABLED Flags::KEEPALIVE_ENABLED
} else { } else {
@ -76,7 +71,7 @@ impl ClientCodec {
ClientCodec { ClientCodec {
inner: ClientCodecInner { inner: ClientCodecInner {
config, config,
decoder: ResponseDecoder::with_pool(pool), decoder: MessageDecoder::default(),
payload: None, payload: None,
version: Version::HTTP_11, version: Version::HTTP_11,
@ -185,10 +180,10 @@ impl Decoder for ClientCodec {
debug_assert!(!self.inner.payload.is_some(), "Payload decoder is set"); debug_assert!(!self.inner.payload.is_some(), "Payload decoder is set");
if let Some((req, payload)) = self.inner.decoder.decode(src)? { if let Some((req, payload)) = self.inner.decoder.decode(src)? {
self.inner // self.inner
.flags // .flags
.set(Flags::HEAD, req.inner.head.method == Method::HEAD); // .set(Flags::HEAD, req.head.method == Method::HEAD);
self.inner.version = req.inner.head.version; // self.inner.version = req.head.version;
if self.inner.flags.contains(Flags::KEEPALIVE_ENABLED) { if self.inner.flags.contains(Flags::KEEPALIVE_ENABLED) {
self.inner.flags.set(Flags::KEEPALIVE, req.keep_alive()); self.inner.flags.set(Flags::KEEPALIVE, req.keep_alive());
} }

View File

@ -5,7 +5,7 @@ use std::io::{self, Write};
use bytes::{BufMut, Bytes, BytesMut}; use bytes::{BufMut, Bytes, BytesMut};
use tokio_codec::{Decoder, Encoder}; use tokio_codec::{Decoder, Encoder};
use super::decoder::{PayloadDecoder, PayloadItem, PayloadType, RequestDecoder}; use super::decoder::{MessageDecoder, PayloadDecoder, PayloadItem, PayloadType};
use super::encoder::{ResponseEncoder, ResponseLength}; use super::encoder::{ResponseEncoder, ResponseLength};
use super::{Message, MessageType}; use super::{Message, MessageType};
use body::{Binary, Body}; use body::{Binary, Body};
@ -14,7 +14,7 @@ use error::ParseError;
use helpers; use helpers;
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING}; use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
use http::{Method, Version}; use http::{Method, Version};
use request::{MessagePool, Request}; use request::Request;
use response::Response; use response::Response;
bitflags! { bitflags! {
@ -32,7 +32,7 @@ const AVERAGE_HEADER_SIZE: usize = 30;
/// HTTP/1 Codec /// HTTP/1 Codec
pub struct Codec { pub struct Codec {
config: ServiceConfig, config: ServiceConfig,
decoder: RequestDecoder, decoder: MessageDecoder<Request>,
payload: Option<PayloadDecoder>, payload: Option<PayloadDecoder>,
version: Version, version: Version,
@ -59,11 +59,6 @@ impl Codec {
/// ///
/// `keepalive_enabled` how response `connection` header get generated. /// `keepalive_enabled` how response `connection` header get generated.
pub fn new(config: ServiceConfig) -> Self { pub fn new(config: ServiceConfig) -> Self {
Codec::with_pool(MessagePool::pool(), config)
}
/// Create HTTP/1 codec with request's pool
pub(crate) fn with_pool(pool: &'static MessagePool, config: ServiceConfig) -> Self {
let flags = if config.keep_alive_enabled() { let flags = if config.keep_alive_enabled() {
Flags::KEEPALIVE_ENABLED Flags::KEEPALIVE_ENABLED
} else { } else {
@ -71,7 +66,7 @@ impl Codec {
}; };
Codec { Codec {
config, config,
decoder: RequestDecoder::with_pool(pool), decoder: MessageDecoder::default(),
payload: None, payload: None,
version: Version::HTTP_11, version: Version::HTTP_11,

View File

@ -1,3 +1,4 @@
use std::marker::PhantomData;
use std::{io, mem}; use std::{io, mem};
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
@ -8,91 +9,68 @@ use tokio_codec::Decoder;
use client::ClientResponse; use client::ClientResponse;
use error::ParseError; use error::ParseError;
use http::header::{HeaderName, HeaderValue}; use http::header::{HeaderName, HeaderValue};
use http::{header, HttpTryFrom, Method, StatusCode, Uri, Version}; use http::{header, HeaderMap, HttpTryFrom, Method, StatusCode, Uri, Version};
use request::{MessageFlags, MessagePool, Request}; use message::MessageFlags;
use uri::Url; use request::Request;
const MAX_BUFFER_SIZE: usize = 131_072; const MAX_BUFFER_SIZE: usize = 131_072;
const MAX_HEADERS: usize = 96; const MAX_HEADERS: usize = 96;
/// Client request decoder /// Incoming messagd decoder
pub struct RequestDecoder(&'static MessagePool); pub(crate) struct MessageDecoder<T: MessageTypeDecoder>(PhantomData<T>);
/// Server response decoder
pub struct ResponseDecoder(&'static MessagePool);
/// Incoming request type /// Incoming request type
pub enum PayloadType { pub(crate) enum PayloadType {
None, None,
Payload(PayloadDecoder), Payload(PayloadDecoder),
Stream(PayloadDecoder), Stream(PayloadDecoder),
} }
impl RequestDecoder { impl<T: MessageTypeDecoder> Default for MessageDecoder<T> {
pub(crate) fn with_pool(pool: &'static MessagePool) -> RequestDecoder { fn default() -> Self {
RequestDecoder(pool) MessageDecoder(PhantomData)
} }
} }
impl Default for RequestDecoder { impl<T: MessageTypeDecoder> Decoder for MessageDecoder<T> {
fn default() -> RequestDecoder { type Item = (T, PayloadType);
RequestDecoder::with_pool(MessagePool::pool())
}
}
impl Decoder for RequestDecoder {
type Item = (Request, PayloadType);
type Error = ParseError; type Error = ParseError;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> { fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
// Parse http message T::decode(src)
}
}
pub(crate) enum PayloadLength {
None,
Chunked,
Upgrade,
Length(u64),
}
pub(crate) trait MessageTypeDecoder: Sized {
fn keep_alive(&mut self);
fn headers_mut(&mut self) -> &mut HeaderMap;
fn decode(src: &mut BytesMut) -> Result<Option<(Self, PayloadType)>, ParseError>;
fn process_headers(
&mut self,
slice: &Bytes,
version: Version,
raw_headers: &[HeaderIndex],
) -> Result<PayloadLength, ParseError> {
let mut ka = version != Version::HTTP_10;
let mut has_upgrade = false; let mut has_upgrade = false;
let mut chunked = false; let mut chunked = false;
let mut content_length = None; let mut content_length = None;
let msg = {
// Unsafe: we read only this data only after httparse parses headers into.
// performance bump for pipeline benchmarks.
let mut headers: [HeaderIndex; MAX_HEADERS] =
unsafe { mem::uninitialized() };
let (len, method, path, version, headers_len) = {
let mut parsed: [httparse::Header; MAX_HEADERS] =
unsafe { mem::uninitialized() };
let mut req = httparse::Request::new(&mut parsed);
match req.parse(src)? {
httparse::Status::Complete(len) => {
let method = Method::from_bytes(req.method.unwrap().as_bytes())
.map_err(|_| ParseError::Method)?;
let path = Url::new(Uri::try_from(req.path.unwrap())?);
let version = if req.version.unwrap() == 1 {
Version::HTTP_11
} else {
Version::HTTP_10
};
HeaderIndex::record(src, req.headers, &mut headers);
(len, method, path, version, req.headers.len())
}
httparse::Status::Partial => return Ok(None),
}
};
let slice = src.split_to(len).freeze();
// convert headers
let mut msg = MessagePool::get_request(self.0);
{ {
let inner = msg.inner_mut(); let headers = self.headers_mut();
inner
.flags
.get_mut()
.set(MessageFlags::KEEPALIVE, version != Version::HTTP_10);
for idx in headers[..headers_len].iter() { for idx in raw_headers.iter() {
if let Ok(name) = if let Ok(name) = HeaderName::from_bytes(&slice[idx.name.0..idx.name.1])
HeaderName::from_bytes(&slice[idx.name.0..idx.name.1])
{ {
// Unsafe: httparse check header value for valid utf-8 // Unsafe: httparse check header value for valid utf-8
let value = unsafe { let value = unsafe {
@ -106,11 +84,11 @@ impl Decoder for RequestDecoder {
if let Ok(len) = s.parse::<u64>() { if let Ok(len) = s.parse::<u64>() {
content_length = Some(len); content_length = Some(len);
} else { } else {
debug!("illegal Content-Length: {:?}", len); debug!("illegal Content-Length: {:?}", s);
return Err(ParseError::Header); return Err(ParseError::Header);
} }
} else { } else {
debug!("illegal Content-Length: {:?}", len); debug!("illegal Content-Length: {:?}", value);
return Err(ParseError::Header); return Err(ParseError::Header);
} }
} }
@ -124,7 +102,7 @@ impl Decoder for RequestDecoder {
} }
// connection keep-alive state // connection keep-alive state
header::CONNECTION => { header::CONNECTION => {
let ka = if let Ok(conn) = value.to_str() { ka = if let Ok(conn) = value.to_str() {
if version == Version::HTTP_10 if version == Version::HTTP_10
&& conn.contains("keep-alive") && conn.contains("keep-alive")
{ {
@ -136,8 +114,7 @@ impl Decoder for RequestDecoder {
} }
} else { } else {
false false
}; }
inner.flags.get_mut().set(MessageFlags::KEEPALIVE, ka);
} }
header::UPGRADE => { header::UPGRADE => {
has_upgrade = true; has_upgrade = true;
@ -152,27 +129,91 @@ impl Decoder for RequestDecoder {
_ => (), _ => (),
} }
inner.head.headers.append(name, value); headers.append(name, value);
} else { } else {
return Err(ParseError::Header); return Err(ParseError::Header);
} }
} }
inner.url = path;
inner.head.method = method;
inner.head.version = version;
} }
msg
if ka {
self.keep_alive();
}
if chunked {
Ok(PayloadLength::Chunked)
} else if let Some(len) = content_length {
Ok(PayloadLength::Length(len))
} else if has_upgrade {
Ok(PayloadLength::Upgrade)
} else {
Ok(PayloadLength::None)
}
}
}
impl MessageTypeDecoder for Request {
fn keep_alive(&mut self) {
self.inner_mut().flags.set(MessageFlags::KEEPALIVE);
}
fn headers_mut(&mut self) -> &mut HeaderMap {
self.headers_mut()
}
fn decode(src: &mut BytesMut) -> Result<Option<(Self, PayloadType)>, ParseError> {
// Unsafe: we read only this data only after httparse parses headers into.
// performance bump for pipeline benchmarks.
let mut headers: [HeaderIndex; MAX_HEADERS] = unsafe { mem::uninitialized() };
let (len, method, uri, version, headers_len) = {
let mut parsed: [httparse::Header; MAX_HEADERS] =
unsafe { mem::uninitialized() };
let mut req = httparse::Request::new(&mut parsed);
match req.parse(src)? {
httparse::Status::Complete(len) => {
let method = Method::from_bytes(req.method.unwrap().as_bytes())
.map_err(|_| ParseError::Method)?;
let uri = Uri::try_from(req.path.unwrap())?;
let version = if req.version.unwrap() == 1 {
Version::HTTP_11
} else {
Version::HTTP_10
};
HeaderIndex::record(src, req.headers, &mut headers);
(len, method, uri, version, req.headers.len())
}
httparse::Status::Partial => return Ok(None),
}
}; };
// convert headers
let mut msg = Request::new();
let len = msg.process_headers(
&src.split_to(len).freeze(),
version,
&headers[..headers_len],
)?;
// https://tools.ietf.org/html/rfc7230#section-3.3.3 // https://tools.ietf.org/html/rfc7230#section-3.3.3
let decoder = if chunked { let decoder = match len {
PayloadLength::Chunked => {
// Chunked encoding // Chunked encoding
PayloadType::Payload(PayloadDecoder::chunked()) PayloadType::Payload(PayloadDecoder::chunked())
} else if let Some(len) = content_length { }
PayloadLength::Length(len) => {
// Content-Length // Content-Length
PayloadType::Payload(PayloadDecoder::length(len)) PayloadType::Payload(PayloadDecoder::length(len))
} else if has_upgrade || msg.inner.head.method == Method::CONNECT { }
PayloadLength::Upgrade => {
// upgrade(websocket) or connect
PayloadType::Stream(PayloadDecoder::eof())
}
PayloadLength::None => {
if method == Method::CONNECT {
// upgrade(websocket) or connect // upgrade(websocket) or connect
PayloadType::Stream(PayloadDecoder::eof()) PayloadType::Stream(PayloadDecoder::eof())
} else if src.len() >= MAX_BUFFER_SIZE { } else if src.len() >= MAX_BUFFER_SIZE {
@ -180,38 +221,35 @@ impl Decoder for RequestDecoder {
return Err(ParseError::TooLarge); return Err(ParseError::TooLarge);
} else { } else {
PayloadType::None PayloadType::None
}
}
}; };
{
let inner = msg.inner_mut();
inner.url.update(&uri);
inner.head.uri = uri;
inner.head.method = method;
inner.head.version = version;
}
Ok(Some((msg, decoder))) Ok(Some((msg, decoder)))
} }
} }
impl ResponseDecoder { impl MessageTypeDecoder for ClientResponse {
pub(crate) fn with_pool(pool: &'static MessagePool) -> ResponseDecoder { fn keep_alive(&mut self) {
ResponseDecoder(pool) self.head.flags.insert(MessageFlags::KEEPALIVE);
}
} }
impl Default for ResponseDecoder { fn headers_mut(&mut self) -> &mut HeaderMap {
fn default() -> ResponseDecoder { self.headers_mut()
ResponseDecoder::with_pool(MessagePool::pool())
}
} }
impl Decoder for ResponseDecoder { fn decode(src: &mut BytesMut) -> Result<Option<(Self, PayloadType)>, ParseError> {
type Item = (ClientResponse, PayloadType);
type Error = ParseError;
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
// Parse http message
let mut chunked = false;
let mut content_length = None;
let msg = {
// Unsafe: we read only this data only after httparse parses headers into. // Unsafe: we read only this data only after httparse parses headers into.
// performance bump for pipeline benchmarks. // performance bump for pipeline benchmarks.
let mut headers: [HeaderIndex; MAX_HEADERS] = let mut headers: [HeaderIndex; MAX_HEADERS] = unsafe { mem::uninitialized() };
unsafe { mem::uninitialized() };
let (len, version, status, headers_len) = { let (len, version, status, headers_len) = {
let mut parsed: [httparse::Header; MAX_HEADERS] = let mut parsed: [httparse::Header; MAX_HEADERS] =
@ -235,91 +273,27 @@ impl Decoder for ResponseDecoder {
} }
}; };
let slice = src.split_to(len).freeze(); let mut msg = ClientResponse::new();
// convert headers // convert headers
let mut msg = MessagePool::get_response(self.0); let len = msg.process_headers(
{ &src.split_to(len).freeze(),
let inner = msg.inner_mut(); version,
inner &headers[..headers_len],
.flags )?;
.get_mut()
.set(MessageFlags::KEEPALIVE, version != Version::HTTP_10);
for idx in headers[..headers_len].iter() {
if let Ok(name) =
HeaderName::from_bytes(&slice[idx.name.0..idx.name.1])
{
// Unsafe: httparse check header value for valid utf-8
let value = unsafe {
HeaderValue::from_shared_unchecked(
slice.slice(idx.value.0, idx.value.1),
)
};
match name {
header::CONTENT_LENGTH => {
if let Ok(s) = value.to_str() {
if let Ok(len) = s.parse::<u64>() {
content_length = Some(len);
} else {
debug!("illegal Content-Length: {:?}", len);
return Err(ParseError::Header);
}
} else {
debug!("illegal Content-Length: {:?}", len);
return Err(ParseError::Header);
}
}
// transfer-encoding
header::TRANSFER_ENCODING => {
if let Ok(s) = value.to_str() {
chunked = s.to_lowercase().contains("chunked");
} else {
return Err(ParseError::Header);
}
}
// connection keep-alive state
header::CONNECTION => {
let ka = if let Ok(conn) = value.to_str() {
if version == Version::HTTP_10
&& conn.contains("keep-alive")
{
true
} else {
version == Version::HTTP_11 && !(conn
.contains("close")
|| conn.contains("upgrade"))
}
} else {
false
};
inner.flags.get_mut().set(MessageFlags::KEEPALIVE, ka);
}
_ => (),
}
inner.head.headers.append(name, value);
} else {
return Err(ParseError::Header);
}
}
inner.status = status;
inner.head.version = version;
}
msg
};
// https://tools.ietf.org/html/rfc7230#section-3.3.3 // https://tools.ietf.org/html/rfc7230#section-3.3.3
let decoder = if chunked { let decoder = match len {
PayloadLength::Chunked => {
// Chunked encoding // Chunked encoding
PayloadType::Payload(PayloadDecoder::chunked()) PayloadType::Payload(PayloadDecoder::chunked())
} else if let Some(len) = content_length { }
PayloadLength::Length(len) => {
// Content-Length // Content-Length
PayloadType::Payload(PayloadDecoder::length(len)) PayloadType::Payload(PayloadDecoder::length(len))
} else if msg.inner.status == StatusCode::SWITCHING_PROTOCOLS }
|| msg.inner.head.method == Method::CONNECT _ => {
{ if status == StatusCode::SWITCHING_PROTOCOLS {
// switching protocol or connect // switching protocol or connect
PayloadType::Stream(PayloadDecoder::eof()) PayloadType::Stream(PayloadDecoder::eof())
} else if src.len() >= MAX_BUFFER_SIZE { } else if src.len() >= MAX_BUFFER_SIZE {
@ -327,8 +301,13 @@ impl Decoder for ResponseDecoder {
return Err(ParseError::TooLarge); return Err(ParseError::TooLarge);
} else { } else {
PayloadType::None PayloadType::None
}
}
}; };
msg.head.status = status;
msg.head.version = Some(version);
Ok(Some((msg, decoder))) Ok(Some((msg, decoder)))
} }
} }
@ -690,7 +669,7 @@ mod tests {
macro_rules! parse_ready { macro_rules! parse_ready {
($e:expr) => {{ ($e:expr) => {{
match RequestDecoder::default().decode($e) { match MessageDecoder::<Request>::default().decode($e) {
Ok(Some((msg, _))) => msg, Ok(Some((msg, _))) => msg,
Ok(_) => unreachable!("Eof during parsing http request"), Ok(_) => unreachable!("Eof during parsing http request"),
Err(err) => unreachable!("Error during parsing http request: {:?}", err), Err(err) => unreachable!("Error during parsing http request: {:?}", err),
@ -700,7 +679,7 @@ mod tests {
macro_rules! expect_parse_err { macro_rules! expect_parse_err {
($e:expr) => {{ ($e:expr) => {{
match RequestDecoder::default().decode($e) { match MessageDecoder::<Request>::default().decode($e) {
Err(err) => match err { Err(err) => match err {
ParseError::Io(_) => unreachable!("Parse error expected"), ParseError::Io(_) => unreachable!("Parse error expected"),
_ => (), _ => (),
@ -779,7 +758,7 @@ mod tests {
fn test_parse() { fn test_parse() {
let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n\r\n"); let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n\r\n");
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
match reader.decode(&mut buf) { match reader.decode(&mut buf) {
Ok(Some((req, _))) => { Ok(Some((req, _))) => {
assert_eq!(req.version(), Version::HTTP_11); assert_eq!(req.version(), Version::HTTP_11);
@ -794,7 +773,7 @@ mod tests {
fn test_parse_partial() { fn test_parse_partial() {
let mut buf = BytesMut::from("PUT /test HTTP/1"); let mut buf = BytesMut::from("PUT /test HTTP/1");
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
assert!(reader.decode(&mut buf).unwrap().is_none()); assert!(reader.decode(&mut buf).unwrap().is_none());
buf.extend(b".1\r\n\r\n"); buf.extend(b".1\r\n\r\n");
@ -808,7 +787,7 @@ mod tests {
fn test_parse_post() { fn test_parse_post() {
let mut buf = BytesMut::from("POST /test2 HTTP/1.0\r\n\r\n"); let mut buf = BytesMut::from("POST /test2 HTTP/1.0\r\n\r\n");
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
let (req, _) = reader.decode(&mut buf).unwrap().unwrap(); let (req, _) = reader.decode(&mut buf).unwrap().unwrap();
assert_eq!(req.version(), Version::HTTP_10); assert_eq!(req.version(), Version::HTTP_10);
assert_eq!(*req.method(), Method::POST); assert_eq!(*req.method(), Method::POST);
@ -820,7 +799,7 @@ mod tests {
let mut buf = let mut buf =
BytesMut::from("GET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody"); BytesMut::from("GET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody");
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap(); let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
let mut pl = pl.unwrap(); let mut pl = pl.unwrap();
assert_eq!(req.version(), Version::HTTP_11); assert_eq!(req.version(), Version::HTTP_11);
@ -837,7 +816,7 @@ mod tests {
let mut buf = let mut buf =
BytesMut::from("\r\nGET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody"); BytesMut::from("\r\nGET /test HTTP/1.1\r\nContent-Length: 4\r\n\r\nbody");
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap(); let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
let mut pl = pl.unwrap(); let mut pl = pl.unwrap();
assert_eq!(req.version(), Version::HTTP_11); assert_eq!(req.version(), Version::HTTP_11);
@ -852,7 +831,7 @@ mod tests {
#[test] #[test]
fn test_parse_partial_eof() { fn test_parse_partial_eof() {
let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n"); let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n");
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
assert!(reader.decode(&mut buf).unwrap().is_none()); assert!(reader.decode(&mut buf).unwrap().is_none());
buf.extend(b"\r\n"); buf.extend(b"\r\n");
@ -866,7 +845,7 @@ mod tests {
fn test_headers_split_field() { fn test_headers_split_field() {
let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n"); let mut buf = BytesMut::from("GET /test HTTP/1.1\r\n");
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
assert!{ reader.decode(&mut buf).unwrap().is_none() } assert!{ reader.decode(&mut buf).unwrap().is_none() }
buf.extend(b"t"); buf.extend(b"t");
@ -890,7 +869,7 @@ mod tests {
Set-Cookie: c1=cookie1\r\n\ Set-Cookie: c1=cookie1\r\n\
Set-Cookie: c2=cookie2\r\n\r\n", Set-Cookie: c2=cookie2\r\n\r\n",
); );
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
let (req, _) = reader.decode(&mut buf).unwrap().unwrap(); let (req, _) = reader.decode(&mut buf).unwrap().unwrap();
let val: Vec<_> = req let val: Vec<_> = req
@ -1090,7 +1069,7 @@ mod tests {
upgrade: websocket\r\n\r\n\ upgrade: websocket\r\n\r\n\
some raw data", some raw data",
); );
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap(); let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
assert!(!req.keep_alive()); assert!(!req.keep_alive());
assert!(req.upgrade()); assert!(req.upgrade());
@ -1139,7 +1118,7 @@ mod tests {
"GET /test HTTP/1.1\r\n\ "GET /test HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\r\n", transfer-encoding: chunked\r\n\r\n",
); );
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap(); let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
let mut pl = pl.unwrap(); let mut pl = pl.unwrap();
assert!(req.chunked().unwrap()); assert!(req.chunked().unwrap());
@ -1162,7 +1141,7 @@ mod tests {
"GET /test HTTP/1.1\r\n\ "GET /test HTTP/1.1\r\n\
transfer-encoding: chunked\r\n\r\n", transfer-encoding: chunked\r\n\r\n",
); );
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap(); let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
let mut pl = pl.unwrap(); let mut pl = pl.unwrap();
assert!(req.chunked().unwrap()); assert!(req.chunked().unwrap());
@ -1193,7 +1172,7 @@ mod tests {
transfer-encoding: chunked\r\n\r\n", transfer-encoding: chunked\r\n\r\n",
); );
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
let (req, pl) = reader.decode(&mut buf).unwrap().unwrap(); let (req, pl) = reader.decode(&mut buf).unwrap().unwrap();
let mut pl = pl.unwrap(); let mut pl = pl.unwrap();
assert!(req.chunked().unwrap()); assert!(req.chunked().unwrap());
@ -1238,7 +1217,7 @@ mod tests {
transfer-encoding: chunked\r\n\r\n"[..], transfer-encoding: chunked\r\n\r\n"[..],
); );
let mut reader = RequestDecoder::default(); let mut reader = MessageDecoder::<Request>::default();
let (msg, pl) = reader.decode(&mut buf).unwrap().unwrap(); let (msg, pl) = reader.decode(&mut buf).unwrap().unwrap();
let mut pl = pl.unwrap(); let mut pl = pl.unwrap();
assert!(msg.chunked().unwrap()); assert!(msg.chunked().unwrap());

View File

@ -11,7 +11,8 @@ use http::{StatusCode, Version};
use body::{Binary, Body}; use body::{Binary, Body};
use header::ContentEncoding; use header::ContentEncoding;
use http::Method; use http::Method;
use request::{Request, RequestHead}; use message::RequestHead;
use request::Request;
use response::Response; use response::Response;
#[derive(Debug)] #[derive(Debug)]

View File

@ -11,7 +11,6 @@ mod service;
pub use self::client::{ClientCodec, ClientPayloadCodec}; pub use self::client::{ClientCodec, ClientPayloadCodec};
pub use self::codec::Codec; pub use self::codec::Codec;
pub use self::decoder::{PayloadDecoder, RequestDecoder};
pub use self::dispatcher::Dispatcher; pub use self::dispatcher::Dispatcher;
pub use self::service::{H1Service, H1ServiceHandler, OneRequest}; pub use self::service::{H1Service, H1ServiceHandler, OneRequest};

View File

@ -117,6 +117,7 @@ mod header;
mod httpcodes; mod httpcodes;
mod httpmessage; mod httpmessage;
mod json; mod json;
mod message;
mod payload; mod payload;
mod request; mod request;
mod response; mod response;

163
src/message.rs Normal file
View File

@ -0,0 +1,163 @@
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::rc::Rc;
use http::{HeaderMap, Method, StatusCode, Uri, Version};
use extensions::Extensions;
use payload::Payload;
use uri::Url;
#[doc(hidden)]
pub trait Head: Default + 'static {
fn clear(&mut self);
fn pool() -> &'static MessagePool<Self>;
}
bitflags! {
pub(crate) struct MessageFlags: u8 {
const KEEPALIVE = 0b0000_0001;
}
}
pub struct RequestHead {
pub uri: Uri,
pub method: Method,
pub version: Version,
pub headers: HeaderMap,
pub(crate) flags: MessageFlags,
}
impl Default for RequestHead {
fn default() -> RequestHead {
RequestHead {
uri: Uri::default(),
method: Method::default(),
version: Version::HTTP_11,
headers: HeaderMap::with_capacity(16),
flags: MessageFlags::empty(),
}
}
}
impl Head for RequestHead {
fn clear(&mut self) {
self.headers.clear();
self.flags = MessageFlags::empty();
}
fn pool() -> &'static MessagePool<Self> {
REQUEST_POOL.with(|p| *p)
}
}
pub struct ResponseHead {
pub version: Option<Version>,
pub status: StatusCode,
pub headers: HeaderMap,
pub reason: Option<&'static str>,
pub(crate) flags: MessageFlags,
}
impl Default for ResponseHead {
fn default() -> ResponseHead {
ResponseHead {
version: None,
status: StatusCode::OK,
headers: HeaderMap::with_capacity(16),
reason: None,
flags: MessageFlags::empty(),
}
}
}
impl Head for ResponseHead {
fn clear(&mut self) {
self.headers.clear();
self.flags = MessageFlags::empty();
}
fn pool() -> &'static MessagePool<Self> {
RESPONSE_POOL.with(|p| *p)
}
}
pub struct Message<T: Head> {
pub head: T,
pub url: Url,
pub status: StatusCode,
pub extensions: RefCell<Extensions>,
pub payload: RefCell<Option<Payload>>,
pub(crate) pool: &'static MessagePool<T>,
pub(crate) flags: Cell<MessageFlags>,
}
impl<T: Head> Message<T> {
#[inline]
/// Reset request instance
pub fn reset(&mut self) {
self.head.clear();
self.extensions.borrow_mut().clear();
self.flags.set(MessageFlags::empty());
*self.payload.borrow_mut() = None;
}
}
impl<T: Head> Default for Message<T> {
fn default() -> Self {
Message {
pool: T::pool(),
url: Url::default(),
head: T::default(),
status: StatusCode::OK,
flags: Cell::new(MessageFlags::empty()),
payload: RefCell::new(None),
extensions: RefCell::new(Extensions::new()),
}
}
}
#[doc(hidden)]
/// Request's objects pool
pub struct MessagePool<T: Head>(RefCell<VecDeque<Rc<Message<T>>>>);
thread_local!(static REQUEST_POOL: &'static MessagePool<RequestHead> = MessagePool::<RequestHead>::create());
thread_local!(static RESPONSE_POOL: &'static MessagePool<ResponseHead> = MessagePool::<ResponseHead>::create());
impl MessagePool<RequestHead> {
/// Get default request's pool
pub fn pool() -> &'static MessagePool<RequestHead> {
REQUEST_POOL.with(|p| *p)
}
/// Get Request object
#[inline]
pub fn get_message() -> Rc<Message<RequestHead>> {
REQUEST_POOL.with(|pool| {
if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
if let Some(r) = Rc::get_mut(&mut msg) {
r.reset();
}
return msg;
}
Rc::new(Message::default())
})
}
}
impl<T: Head> MessagePool<T> {
fn create() -> &'static MessagePool<T> {
let pool = MessagePool(RefCell::new(VecDeque::with_capacity(128)));
Box::leak(Box::new(pool))
}
#[inline]
/// Release request instance
pub(crate) fn release(&self, msg: Rc<Message<T>>) {
let v = &mut self.0.borrow_mut();
if v.len() < 128 {
v.push_front(msg);
}
}
}

View File

@ -1,65 +1,18 @@
use std::cell::{Cell, Ref, RefCell, RefMut}; use std::cell::{Ref, RefMut};
use std::collections::VecDeque;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use http::{header, HeaderMap, Method, StatusCode, Uri, Version}; use http::{header, HeaderMap, Method, Uri, Version};
use client::ClientResponse;
use extensions::Extensions; use extensions::Extensions;
use httpmessage::HttpMessage; use httpmessage::HttpMessage;
use payload::Payload; use payload::Payload;
use uri::Url;
bitflags! { use message::{Message, MessageFlags, MessagePool, RequestHead};
pub(crate) struct MessageFlags: u8 {
const KEEPALIVE = 0b0000_0001;
const CONN_INFO = 0b0000_0010;
}
}
/// Request /// Request
pub struct Request { pub struct Request {
pub(crate) inner: Rc<Message>, pub(crate) inner: Rc<Message<RequestHead>>,
}
pub struct RequestHead {
pub uri: Uri,
pub method: Method,
pub version: Version,
pub headers: HeaderMap,
}
impl Default for RequestHead {
fn default() -> RequestHead {
RequestHead {
uri: Uri::default(),
method: Method::default(),
version: Version::HTTP_11,
headers: HeaderMap::with_capacity(16),
}
}
}
pub struct Message {
pub head: RequestHead,
pub url: Url,
pub status: StatusCode,
pub extensions: RefCell<Extensions>,
pub payload: RefCell<Option<Payload>>,
pub(crate) pool: &'static MessagePool,
pub(crate) flags: Cell<MessageFlags>,
}
impl Message {
#[inline]
/// Reset request instance
pub fn reset(&mut self) {
self.head.clear();
self.extensions.borrow_mut().clear();
self.flags.set(MessageFlags::empty());
*self.payload.borrow_mut() = None;
}
} }
impl HttpMessage for Request { impl HttpMessage for Request {
@ -82,33 +35,35 @@ impl HttpMessage for Request {
impl Request { impl Request {
/// Create new Request instance /// Create new Request instance
pub fn new() -> Request { pub fn new() -> Request {
Request::with_pool(MessagePool::pool()) Request {
inner: MessagePool::get_message(),
}
} }
/// Create new Request instance with pool // /// Create new Request instance with pool
pub(crate) fn with_pool(pool: &'static MessagePool) -> Request { // pub(crate) fn with_pool(pool: &'static MessagePool) -> Request {
Request { // Request {
inner: Rc::new(Message { // inner: Rc::new(Message {
pool, // pool,
url: Url::default(), // url: Url::default(),
head: RequestHead::default(), // head: RequestHead::default(),
status: StatusCode::OK, // status: StatusCode::OK,
flags: Cell::new(MessageFlags::empty()), // flags: Cell::new(MessageFlags::empty()),
payload: RefCell::new(None), // payload: RefCell::new(None),
extensions: RefCell::new(Extensions::new()), // extensions: RefCell::new(Extensions::new()),
}), // }),
} // }
} // }
#[inline] #[inline]
#[doc(hidden)] #[doc(hidden)]
pub fn inner(&self) -> &Message { pub fn inner(&self) -> &Message<RequestHead> {
self.inner.as_ref() self.inner.as_ref()
} }
#[inline] #[inline]
#[doc(hidden)] #[doc(hidden)]
pub fn inner_mut(&mut self) -> &mut Message { pub fn inner_mut(&mut self) -> &mut Message<RequestHead> {
Rc::get_mut(&mut self.inner).expect("Multiple copies exist") Rc::get_mut(&mut self.inner).expect("Multiple copies exist")
} }
@ -139,7 +94,11 @@ impl Request {
/// 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.inner().url.path() if let Some(path) = self.inner().url.path() {
path
} else {
self.inner().head.uri.path()
}
} }
#[inline] #[inline]
@ -219,56 +178,3 @@ impl fmt::Debug for Request {
Ok(()) Ok(())
} }
} }
/// Request's objects pool
pub(crate) struct MessagePool(RefCell<VecDeque<Rc<Message>>>);
thread_local!(static POOL: &'static MessagePool = MessagePool::create());
impl MessagePool {
fn create() -> &'static MessagePool {
let pool = MessagePool(RefCell::new(VecDeque::with_capacity(128)));
Box::leak(Box::new(pool))
}
/// Get default request's pool
pub fn pool() -> &'static MessagePool {
POOL.with(|p| *p)
}
/// Get Request object
#[inline]
pub fn get_request(pool: &'static MessagePool) -> Request {
if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
if let Some(r) = Rc::get_mut(&mut msg) {
r.reset();
}
return Request { inner: msg };
}
Request::with_pool(pool)
}
/// Get Client Response object
#[inline]
pub fn get_response(pool: &'static MessagePool) -> ClientResponse {
if let Some(mut msg) = pool.0.borrow_mut().pop_front() {
if let Some(r) = Rc::get_mut(&mut msg) {
r.reset();
}
return ClientResponse {
inner: msg,
payload: RefCell::new(None),
};
}
ClientResponse::with_pool(pool)
}
#[inline]
/// Release request instance
pub(crate) fn release(&self, msg: Rc<Message>) {
let v = &mut self.0.borrow_mut();
if v.len() < 128 {
v.push_front(msg);
}
}
}

View File

@ -392,7 +392,7 @@ impl TestRequest {
{ {
let inner = req.inner_mut(); let inner = req.inner_mut();
inner.head.method = method; inner.head.method = method;
inner.url = InnerUrl::new(uri); inner.url = InnerUrl::new(&uri);
inner.head.version = version; inner.head.version = version;
inner.head.headers = headers; inner.head.headers = headers;
*inner.payload.borrow_mut() = payload; *inner.payload.borrow_mut() = payload;

View File

@ -37,27 +37,22 @@ lazy_static! {
#[derive(Default, Clone, Debug)] #[derive(Default, Clone, Debug)]
pub struct Url { pub struct Url {
uri: Uri,
path: Option<Rc<String>>, path: Option<Rc<String>>,
} }
impl Url { impl Url {
pub fn new(uri: Uri) -> Url { pub fn new(uri: &Uri) -> Url {
let path = DEFAULT_QUOTER.requote(uri.path().as_bytes()); let path = DEFAULT_QUOTER.requote(uri.path().as_bytes());
Url { uri, path } Url { path }
} }
pub fn uri(&self) -> &Uri { pub(crate) fn update(&mut self, uri: &Uri) {
&self.uri self.path = DEFAULT_QUOTER.requote(uri.path().as_bytes());
} }
pub fn path(&self) -> &str { pub fn path(&self) -> Option<&str> {
if let Some(ref s) = self.path { self.path.as_ref().map(|s| s.as_str())
s
} else {
self.uri.path()
}
} }
} }