mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-24 07:53:00 +01:00
refactor types
This commit is contained in:
parent
b15b2dda22
commit
4ca711909b
@ -12,10 +12,10 @@ use time;
|
||||
use tokio_current_thread::spawn;
|
||||
use tokio_timer::{sleep, Delay};
|
||||
|
||||
use super::message::{Request, RequestPool};
|
||||
use super::KeepAlive;
|
||||
use body::Body;
|
||||
use httpresponse::{HttpResponse, HttpResponseBuilder, HttpResponsePool};
|
||||
use request::{Request, RequestPool};
|
||||
use server::KeepAlive;
|
||||
|
||||
// "Sun, 06 Nov 1994 08:49:37 GMT".len()
|
||||
const DATE_VALUE_LENGTH: usize = 29;
|
||||
@ -28,8 +28,6 @@ struct Inner {
|
||||
client_timeout: u64,
|
||||
client_shutdown: u64,
|
||||
ka_enabled: bool,
|
||||
bytes: Rc<SharedBytesPool>,
|
||||
messages: &'static RequestPool,
|
||||
date: UnsafeCell<(bool, Date)>,
|
||||
}
|
||||
|
||||
@ -60,8 +58,6 @@ impl ServiceConfig {
|
||||
ka_enabled,
|
||||
client_timeout,
|
||||
client_shutdown,
|
||||
bytes: Rc::new(SharedBytesPool::new()),
|
||||
messages: RequestPool::pool(),
|
||||
date: UnsafeCell::new((false, Date::new())),
|
||||
}))
|
||||
}
|
||||
@ -83,23 +79,6 @@ impl ServiceConfig {
|
||||
self.0.ka_enabled
|
||||
}
|
||||
|
||||
pub(crate) fn get_bytes(&self) -> BytesMut {
|
||||
self.0.bytes.get_bytes()
|
||||
}
|
||||
|
||||
pub(crate) fn release_bytes(&self, bytes: BytesMut) {
|
||||
self.0.bytes.release_bytes(bytes)
|
||||
}
|
||||
|
||||
pub(crate) fn get_request(&self) -> Request {
|
||||
RequestPool::get(self.0.messages)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn request_pool(&self) -> &'static RequestPool {
|
||||
self.0.messages
|
||||
}
|
||||
|
||||
fn update_date(&self) {
|
||||
// Unsafe: WorkerSetting is !Sync and !Send
|
||||
unsafe { (*self.0.date.get()).0 = false };
|
||||
@ -341,31 +320,6 @@ impl fmt::Write for Date {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SharedBytesPool(RefCell<VecDeque<BytesMut>>);
|
||||
|
||||
impl SharedBytesPool {
|
||||
pub fn new() -> SharedBytesPool {
|
||||
SharedBytesPool(RefCell::new(VecDeque::with_capacity(128)))
|
||||
}
|
||||
|
||||
pub fn get_bytes(&self) -> BytesMut {
|
||||
if let Some(bytes) = self.0.borrow_mut().pop_front() {
|
||||
bytes
|
||||
} else {
|
||||
BytesMut::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn release_bytes(&self, mut bytes: BytesMut) {
|
||||
let v = &mut self.0.borrow_mut();
|
||||
if v.len() < 128 {
|
||||
bytes.clear();
|
||||
v.push_front(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
136
src/error.rs
136
src/error.rs
@ -377,62 +377,56 @@ impl ResponseError for cookie::ParseError {
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of errors that can occur during parsing multipart streams
|
||||
#[derive(Fail, Debug)]
|
||||
pub enum MultipartError {
|
||||
/// Content-Type header is not found
|
||||
#[fail(display = "No Content-type header found")]
|
||||
NoContentType,
|
||||
/// Can not parse Content-Type header
|
||||
#[fail(display = "Can not parse Content-Type header")]
|
||||
ParseContentType,
|
||||
/// Multipart boundary is not found
|
||||
#[fail(display = "Multipart boundary is not found")]
|
||||
Boundary,
|
||||
/// Multipart stream is incomplete
|
||||
#[fail(display = "Multipart stream is incomplete")]
|
||||
Incomplete,
|
||||
/// Error during field parsing
|
||||
#[fail(display = "{}", _0)]
|
||||
Parse(#[cause] ParseError),
|
||||
/// Payload error
|
||||
#[fail(display = "{}", _0)]
|
||||
Payload(#[cause] PayloadError),
|
||||
#[derive(Debug)]
|
||||
/// A set of errors that can occur during dispatching http requests
|
||||
pub enum DispatchError<E: fmt::Debug + fmt::Display> {
|
||||
/// Service error
|
||||
// #[fail(display = "Application specific error: {}", _0)]
|
||||
Service(E),
|
||||
|
||||
/// An `io::Error` that occurred while trying to read or write to a network
|
||||
/// stream.
|
||||
// #[fail(display = "IO error: {}", _0)]
|
||||
Io(io::Error),
|
||||
|
||||
/// Http request parse error.
|
||||
// #[fail(display = "Parse error: {}", _0)]
|
||||
Parse(ParseError),
|
||||
|
||||
/// The first request did not complete within the specified timeout.
|
||||
// #[fail(display = "The first request did not complete within the specified timeout")]
|
||||
SlowRequestTimeout,
|
||||
|
||||
/// Shutdown timeout
|
||||
// #[fail(display = "Connection shutdown timeout")]
|
||||
ShutdownTimeout,
|
||||
|
||||
/// Payload is not consumed
|
||||
// #[fail(display = "Task is completed but request's payload is not consumed")]
|
||||
PayloadIsNotConsumed,
|
||||
|
||||
/// Malformed request
|
||||
// #[fail(display = "Malformed request")]
|
||||
MalformedRequest,
|
||||
|
||||
/// Internal error
|
||||
// #[fail(display = "Internal error")]
|
||||
InternalError,
|
||||
|
||||
/// Unknown error
|
||||
// #[fail(display = "Unknown error")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<ParseError> for MultipartError {
|
||||
fn from(err: ParseError) -> MultipartError {
|
||||
MultipartError::Parse(err)
|
||||
impl<E: fmt::Debug + fmt::Display> From<ParseError> for DispatchError<E> {
|
||||
fn from(err: ParseError) -> Self {
|
||||
DispatchError::Parse(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PayloadError> for MultipartError {
|
||||
fn from(err: PayloadError) -> MultipartError {
|
||||
MultipartError::Payload(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return `BadRequest` for `MultipartError`
|
||||
impl ResponseError for MultipartError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::new(StatusCode::BAD_REQUEST)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error during handling `Expect` header
|
||||
#[derive(Fail, PartialEq, Debug)]
|
||||
pub enum ExpectError {
|
||||
/// Expect header value can not be converted to utf8
|
||||
#[fail(display = "Expect header value can not be converted to utf8")]
|
||||
Encoding,
|
||||
/// Unknown expect value
|
||||
#[fail(display = "Unknown expect value")]
|
||||
UnknownExpect,
|
||||
}
|
||||
|
||||
impl ResponseError for ExpectError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::with_body(StatusCode::EXPECTATION_FAILED, "Unknown Expect")
|
||||
impl<E: fmt::Debug + fmt::Display> From<io::Error> for DispatchError<E> {
|
||||
fn from(err: io::Error) -> Self {
|
||||
DispatchError::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -565,28 +559,6 @@ impl From<ContentTypeError> for ReadlinesError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors which can occur when attempting to interpret a segment string as a
|
||||
/// valid path segment.
|
||||
#[derive(Fail, Debug, PartialEq)]
|
||||
pub enum UriSegmentError {
|
||||
/// The segment started with the wrapped invalid character.
|
||||
#[fail(display = "The segment started with the wrapped invalid character")]
|
||||
BadStart(char),
|
||||
/// The segment contained the wrapped invalid character.
|
||||
#[fail(display = "The segment contained the wrapped invalid character")]
|
||||
BadChar(char),
|
||||
/// The segment ended with the wrapped invalid character.
|
||||
#[fail(display = "The segment ended with the wrapped invalid character")]
|
||||
BadEnd(char),
|
||||
}
|
||||
|
||||
/// Return `BadRequest` for `UriSegmentError`
|
||||
impl ResponseError for UriSegmentError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::new(StatusCode::BAD_REQUEST)
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors which can occur when attempting to generate resource uri.
|
||||
#[derive(Fail, Debug, PartialEq)]
|
||||
pub enum UrlGenerationError {
|
||||
@ -610,24 +582,6 @@ impl From<UrlParseError> for UrlGenerationError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors which can occur when serving static files.
|
||||
#[derive(Fail, Debug, PartialEq)]
|
||||
pub enum StaticFileError {
|
||||
/// Path is not a directory
|
||||
#[fail(display = "Path is not a directory. Unable to serve static files")]
|
||||
IsNotDirectory,
|
||||
/// Cannot render directory
|
||||
#[fail(display = "Unable to render directory without index file")]
|
||||
IsDirectory,
|
||||
}
|
||||
|
||||
/// Return `NotFound` for `StaticFileError`
|
||||
impl ResponseError for StaticFileError {
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
HttpResponse::new(StatusCode::NOT_FOUND)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper type that can wrap any error and generate custom response.
|
||||
///
|
||||
/// In following example any `io::Error` will be converted into "BAD REQUEST"
|
||||
|
@ -4,37 +4,45 @@ use std::io::{self, Write};
|
||||
use bytes::{BufMut, Bytes, BytesMut};
|
||||
use tokio_codec::{Decoder, Encoder};
|
||||
|
||||
use super::h1decoder::{H1Decoder, Message};
|
||||
use super::helpers;
|
||||
use super::message::RequestPool;
|
||||
use super::output::{ResponseInfo, ResponseLength};
|
||||
use super::decoder::H1Decoder;
|
||||
pub use super::decoder::InMessage;
|
||||
use body::Body;
|
||||
use error::ParseError;
|
||||
use helpers;
|
||||
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING};
|
||||
use http::Version;
|
||||
use httpresponse::HttpResponse;
|
||||
use request::RequestPool;
|
||||
use server::output::{ResponseInfo, ResponseLength};
|
||||
|
||||
pub(crate) enum OutMessage {
|
||||
pub enum OutMessage {
|
||||
Response(HttpResponse),
|
||||
Payload(Bytes),
|
||||
}
|
||||
|
||||
pub(crate) struct H1Codec {
|
||||
/// HTTP/1 Codec
|
||||
pub struct Codec {
|
||||
decoder: H1Decoder,
|
||||
encoder: H1Writer,
|
||||
}
|
||||
|
||||
impl H1Codec {
|
||||
pub fn new(pool: &'static RequestPool) -> Self {
|
||||
H1Codec {
|
||||
impl Codec {
|
||||
/// Create HTTP/1 codec
|
||||
pub fn new() -> Self {
|
||||
Codec::with_pool(RequestPool::pool())
|
||||
}
|
||||
|
||||
/// Create HTTP/1 codec with request's pool
|
||||
pub(crate) fn with_pool(pool: &'static RequestPool) -> Self {
|
||||
Codec {
|
||||
decoder: H1Decoder::new(pool),
|
||||
encoder: H1Writer::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decoder for H1Codec {
|
||||
type Item = Message;
|
||||
impl Decoder for Codec {
|
||||
type Item = InMessage;
|
||||
type Error = ParseError;
|
||||
|
||||
fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> {
|
||||
@ -42,7 +50,7 @@ impl Decoder for H1Codec {
|
||||
}
|
||||
}
|
||||
|
||||
impl Encoder for H1Codec {
|
||||
impl Encoder for Codec {
|
||||
type Item = OutMessage;
|
||||
type Error = io::Error;
|
||||
|
@ -4,10 +4,10 @@ use bytes::{Bytes, BytesMut};
|
||||
use futures::{Async, Poll};
|
||||
use httparse;
|
||||
|
||||
use super::message::{MessageFlags, Request, RequestPool};
|
||||
use error::ParseError;
|
||||
use http::header::{HeaderName, HeaderValue};
|
||||
use http::{header, HttpTryFrom, Method, Uri, Version};
|
||||
use request::{MessageFlags, Request, RequestPool};
|
||||
use uri::Url;
|
||||
|
||||
const MAX_BUFFER_SIZE: usize = 131_072;
|
||||
@ -19,7 +19,7 @@ pub(crate) struct H1Decoder {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Message {
|
||||
pub enum InMessage {
|
||||
Message(Request),
|
||||
MessageWithPayload(Request),
|
||||
Chunk(Bytes),
|
||||
@ -34,14 +34,16 @@ impl H1Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(&mut self, src: &mut BytesMut) -> Result<Option<Message>, ParseError> {
|
||||
pub fn decode(
|
||||
&mut self, src: &mut BytesMut,
|
||||
) -> Result<Option<InMessage>, ParseError> {
|
||||
// read payload
|
||||
if self.decoder.is_some() {
|
||||
match self.decoder.as_mut().unwrap().decode(src)? {
|
||||
Async::Ready(Some(bytes)) => return Ok(Some(Message::Chunk(bytes))),
|
||||
Async::Ready(Some(bytes)) => return Ok(Some(InMessage::Chunk(bytes))),
|
||||
Async::Ready(None) => {
|
||||
self.decoder.take();
|
||||
return Ok(Some(Message::Eof));
|
||||
return Ok(Some(InMessage::Eof));
|
||||
}
|
||||
Async::NotReady => return Ok(None),
|
||||
}
|
||||
@ -51,9 +53,9 @@ impl H1Decoder {
|
||||
Async::Ready((msg, decoder)) => {
|
||||
self.decoder = decoder;
|
||||
if self.decoder.is_some() {
|
||||
Ok(Some(Message::MessageWithPayload(msg)))
|
||||
Ok(Some(InMessage::MessageWithPayload(msg)))
|
||||
} else {
|
||||
Ok(Some(Message::Message(msg)))
|
||||
Ok(Some(InMessage::Message(msg)))
|
||||
}
|
||||
}
|
||||
Async::NotReady => {
|
@ -9,21 +9,20 @@ use actix_net::service::Service;
|
||||
use futures::{Async, AsyncSink, Future, Poll, Sink, Stream};
|
||||
use tokio_codec::Framed;
|
||||
// use tokio_current_thread::spawn;
|
||||
use tokio_io::AsyncWrite;
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
// use tokio_timer::Delay;
|
||||
|
||||
use error::{ParseError, PayloadError};
|
||||
use payload::{Payload, PayloadStatus, PayloadWriter};
|
||||
|
||||
use body::Body;
|
||||
use error::DispatchError;
|
||||
use httpresponse::HttpResponse;
|
||||
|
||||
use super::error::HttpDispatchError;
|
||||
use super::h1codec::{H1Codec, OutMessage};
|
||||
use super::h1decoder::Message;
|
||||
use super::input::PayloadType;
|
||||
use super::message::{Request, RequestPool};
|
||||
use super::IoStream;
|
||||
use request::{Request, RequestPool};
|
||||
use server::input::PayloadType;
|
||||
|
||||
use super::codec::{Codec, InMessage, OutMessage};
|
||||
|
||||
const MAX_PIPELINED_MESSAGES: usize = 16;
|
||||
|
||||
@ -41,15 +40,14 @@ bitflags! {
|
||||
}
|
||||
|
||||
/// Dispatcher for HTTP/1.1 protocol
|
||||
pub struct Http1Dispatcher<T: IoStream, S: Service>
|
||||
pub struct Dispatcher<T, S: Service>
|
||||
where
|
||||
S::Error: Debug + Display,
|
||||
{
|
||||
service: S,
|
||||
flags: Flags,
|
||||
addr: Option<SocketAddr>,
|
||||
framed: Framed<T, H1Codec>,
|
||||
error: Option<HttpDispatchError<S::Error>>,
|
||||
framed: Framed<T, Codec>,
|
||||
error: Option<DispatchError<S::Error>>,
|
||||
|
||||
state: State<S>,
|
||||
payload: Option<PayloadType>,
|
||||
@ -74,26 +72,24 @@ impl<S: Service> State<S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> Http1Dispatcher<T, S>
|
||||
impl<T, S> Dispatcher<T, S>
|
||||
where
|
||||
T: IoStream,
|
||||
T: AsyncRead + AsyncWrite,
|
||||
S: Service<Request = Request, Response = HttpResponse>,
|
||||
S::Error: Debug + Display,
|
||||
{
|
||||
pub fn new(stream: T, pool: &'static RequestPool, service: S) -> Self {
|
||||
let addr = stream.peer_addr();
|
||||
/// Create http/1 dispatcher.
|
||||
pub fn new(stream: T, service: S) -> Self {
|
||||
let flags = Flags::FLUSHED;
|
||||
let codec = H1Codec::new(pool);
|
||||
let framed = Framed::new(stream, codec);
|
||||
let framed = Framed::new(stream, Codec::new());
|
||||
|
||||
Http1Dispatcher {
|
||||
Dispatcher {
|
||||
payload: None,
|
||||
state: State::None,
|
||||
error: None,
|
||||
messages: VecDeque::new(),
|
||||
service,
|
||||
flags,
|
||||
addr,
|
||||
framed,
|
||||
}
|
||||
}
|
||||
@ -141,7 +137,7 @@ where
|
||||
}
|
||||
|
||||
/// Flush stream
|
||||
fn poll_flush(&mut self) -> Poll<(), HttpDispatchError<S::Error>> {
|
||||
fn poll_flush(&mut self) -> Poll<(), DispatchError<S::Error>> {
|
||||
if self.flags.contains(Flags::STARTED) && !self.flags.contains(Flags::FLUSHED) {
|
||||
match self.framed.poll_complete() {
|
||||
Ok(Async::NotReady) => Ok(Async::NotReady),
|
||||
@ -153,7 +149,7 @@ where
|
||||
Ok(Async::Ready(_)) => {
|
||||
// if payload is not consumed we can not use connection
|
||||
if self.payload.is_some() && self.state.is_empty() {
|
||||
return Err(HttpDispatchError::PayloadIsNotConsumed);
|
||||
return Err(DispatchError::PayloadIsNotConsumed);
|
||||
}
|
||||
self.flags.insert(Flags::FLUSHED);
|
||||
Ok(Async::Ready(()))
|
||||
@ -164,7 +160,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(self) fn poll_handler(&mut self) -> Result<(), HttpDispatchError<S::Error>> {
|
||||
pub(self) fn poll_handler(&mut self) -> Result<(), DispatchError<S::Error>> {
|
||||
self.poll_io()?;
|
||||
let mut retry = self.can_read();
|
||||
|
||||
@ -185,7 +181,7 @@ where
|
||||
}
|
||||
}
|
||||
Ok(Async::NotReady) => Some(Ok(State::Response(task))),
|
||||
Err(err) => Some(Err(HttpDispatchError::App(err))),
|
||||
Err(err) => Some(Err(DispatchError::Service(err))),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
@ -207,7 +203,7 @@ where
|
||||
Err(err) => {
|
||||
// it is not possible to recover from error
|
||||
// during pipe handling, so just drop connection
|
||||
Some(Err(HttpDispatchError::App(err)))
|
||||
Some(Err(DispatchError::Service(err)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,7 +218,7 @@ where
|
||||
*item = Some(msg);
|
||||
return Ok(());
|
||||
}
|
||||
Err(err) => Some(Err(HttpDispatchError::Io(err))),
|
||||
Err(err) => Some(Err(DispatchError::Io(err))),
|
||||
}
|
||||
}
|
||||
State::SendResponseWithPayload(ref mut item) => {
|
||||
@ -236,7 +232,7 @@ where
|
||||
*item = Some((msg, body));
|
||||
return Ok(());
|
||||
}
|
||||
Err(err) => Some(Err(HttpDispatchError::Io(err))),
|
||||
Err(err) => Some(Err(DispatchError::Io(err))),
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -263,14 +259,11 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn one_message(&mut self, msg: Message) -> Result<(), HttpDispatchError<S::Error>> {
|
||||
fn one_message(&mut self, msg: InMessage) -> Result<(), DispatchError<S::Error>> {
|
||||
self.flags.insert(Flags::STARTED);
|
||||
|
||||
match msg {
|
||||
Message::Message(mut msg) => {
|
||||
// set remote addr
|
||||
msg.inner_mut().addr = self.addr;
|
||||
|
||||
InMessage::Message(msg) => {
|
||||
// handle request early
|
||||
if self.state.is_empty() {
|
||||
let mut task = self.service.call(msg);
|
||||
@ -287,17 +280,14 @@ where
|
||||
Err(err) => {
|
||||
error!("Unhandled application error: {}", err);
|
||||
self.client_disconnected(false);
|
||||
return Err(HttpDispatchError::App(err));
|
||||
return Err(DispatchError::Service(err));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.messages.push_back(msg);
|
||||
}
|
||||
}
|
||||
Message::MessageWithPayload(mut msg) => {
|
||||
// set remote addr
|
||||
msg.inner_mut().addr = self.addr;
|
||||
|
||||
InMessage::MessageWithPayload(msg) => {
|
||||
// payload
|
||||
let (ps, pl) = Payload::new(false);
|
||||
*msg.inner.payload.borrow_mut() = Some(pl);
|
||||
@ -305,24 +295,24 @@ where
|
||||
|
||||
self.messages.push_back(msg);
|
||||
}
|
||||
Message::Chunk(chunk) => {
|
||||
InMessage::Chunk(chunk) => {
|
||||
if let Some(ref mut payload) = self.payload {
|
||||
payload.feed_data(chunk);
|
||||
} else {
|
||||
error!("Internal server error: unexpected payload chunk");
|
||||
self.flags.insert(Flags::READ_DISCONNECTED | Flags::STARTED);
|
||||
// self.push_response_entry(StatusCode::INTERNAL_SERVER_ERROR);
|
||||
self.error = Some(HttpDispatchError::InternalError);
|
||||
self.error = Some(DispatchError::InternalError);
|
||||
}
|
||||
}
|
||||
Message::Eof => {
|
||||
InMessage::Eof => {
|
||||
if let Some(mut payload) = self.payload.take() {
|
||||
payload.feed_eof();
|
||||
} else {
|
||||
error!("Internal server error: unexpected eof");
|
||||
self.flags.insert(Flags::READ_DISCONNECTED | Flags::STARTED);
|
||||
// self.push_response_entry(StatusCode::INTERNAL_SERVER_ERROR);
|
||||
self.error = Some(HttpDispatchError::InternalError);
|
||||
self.error = Some(DispatchError::InternalError);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -330,7 +320,7 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(self) fn poll_io(&mut self) -> Result<bool, HttpDispatchError<S::Error>> {
|
||||
pub(self) fn poll_io(&mut self) -> Result<bool, DispatchError<S::Error>> {
|
||||
let mut updated = false;
|
||||
|
||||
if self.messages.len() < MAX_PIPELINED_MESSAGES {
|
||||
@ -359,7 +349,7 @@ where
|
||||
// Malformed requests should be responded with 400
|
||||
// self.push_response_entry(StatusCode::BAD_REQUEST);
|
||||
self.flags.insert(Flags::READ_DISCONNECTED | Flags::STARTED);
|
||||
self.error = Some(HttpDispatchError::MalformedRequest);
|
||||
self.error = Some(DispatchError::MalformedRequest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -370,14 +360,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> Future for Http1Dispatcher<T, S>
|
||||
impl<T, S> Future for Dispatcher<T, S>
|
||||
where
|
||||
T: IoStream,
|
||||
T: AsyncRead + AsyncWrite,
|
||||
S: Service<Request = Request, Response = HttpResponse>,
|
||||
S::Error: Debug + Display,
|
||||
{
|
||||
type Item = ();
|
||||
type Error = HttpDispatchError<S::Error>;
|
||||
type Error = DispatchError<S::Error>;
|
||||
|
||||
#[inline]
|
||||
fn poll(&mut self) -> Poll<(), Self::Error> {
|
9
src/h1/mod.rs
Normal file
9
src/h1/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//! HTTP/1 implementation
|
||||
mod codec;
|
||||
mod decoder;
|
||||
mod dispatcher;
|
||||
mod service;
|
||||
|
||||
pub use self::codec::Codec;
|
||||
pub use self::dispatcher::Dispatcher;
|
||||
pub use self::service::{H1Service, H1ServiceHandler};
|
125
src/h1/service.rs
Normal file
125
src/h1/service.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::marker::PhantomData;
|
||||
use std::time::Duration;
|
||||
|
||||
use actix_net::service::{IntoNewService, NewService, Service};
|
||||
use futures::future::{ok, FutureResult};
|
||||
use futures::{Async, Future, Poll};
|
||||
use tokio_io::{AsyncRead, AsyncWrite};
|
||||
|
||||
use config::ServiceConfig;
|
||||
use error::DispatchError;
|
||||
use httpresponse::HttpResponse;
|
||||
use request::Request;
|
||||
|
||||
use super::dispatcher::Dispatcher;
|
||||
|
||||
/// `NewService` implementation for HTTP1 transport
|
||||
pub struct H1Service<T, S> {
|
||||
srv: S,
|
||||
cfg: ServiceConfig,
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, S> H1Service<T, S>
|
||||
where
|
||||
S: NewService,
|
||||
{
|
||||
/// Create new `HttpService` instance.
|
||||
pub fn new<F: IntoNewService<S>>(cfg: ServiceConfig, service: F) -> Self {
|
||||
H1Service {
|
||||
cfg,
|
||||
srv: service.into_new_service(),
|
||||
_t: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> NewService for H1Service<T, S>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
S: NewService<Request = Request, Response = HttpResponse> + Clone,
|
||||
S::Service: Clone,
|
||||
S::Error: Debug + Display,
|
||||
{
|
||||
type Request = T;
|
||||
type Response = ();
|
||||
type Error = DispatchError<S::Error>;
|
||||
type InitError = S::InitError;
|
||||
type Service = H1ServiceHandler<T, S::Service>;
|
||||
type Future = H1ServiceResponse<T, S>;
|
||||
|
||||
fn new_service(&self) -> Self::Future {
|
||||
H1ServiceResponse {
|
||||
fut: self.srv.new_service(),
|
||||
cfg: Some(self.cfg.clone()),
|
||||
_t: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct H1ServiceResponse<T, S: NewService> {
|
||||
fut: S::Future,
|
||||
cfg: Option<ServiceConfig>,
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, S> Future for H1ServiceResponse<T, S>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
S: NewService<Request = Request, Response = HttpResponse>,
|
||||
S::Service: Clone,
|
||||
S::Error: Debug + Display,
|
||||
{
|
||||
type Item = H1ServiceHandler<T, S::Service>;
|
||||
type Error = S::InitError;
|
||||
|
||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
||||
let service = try_ready!(self.fut.poll());
|
||||
Ok(Async::Ready(H1ServiceHandler::new(
|
||||
self.cfg.take().unwrap(),
|
||||
service,
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
/// `Service` implementation for HTTP1 transport
|
||||
pub struct H1ServiceHandler<T, S> {
|
||||
srv: S,
|
||||
cfg: ServiceConfig,
|
||||
_t: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, S> H1ServiceHandler<T, S>
|
||||
where
|
||||
S: Service<Request = Request, Response = HttpResponse> + Clone,
|
||||
S::Error: Debug + Display,
|
||||
{
|
||||
fn new(cfg: ServiceConfig, srv: S) -> H1ServiceHandler<T, S> {
|
||||
H1ServiceHandler {
|
||||
srv,
|
||||
cfg,
|
||||
_t: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> Service for H1ServiceHandler<T, S>
|
||||
where
|
||||
T: AsyncRead + AsyncWrite,
|
||||
S: Service<Request = Request, Response = HttpResponse> + Clone,
|
||||
S::Error: Debug + Display,
|
||||
{
|
||||
type Request = T;
|
||||
type Response = ();
|
||||
type Error = DispatchError<S::Error>;
|
||||
type Future = Dispatcher<T, S>;
|
||||
|
||||
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
|
||||
self.srv.poll_ready().map_err(|e| DispatchError::Service(e))
|
||||
}
|
||||
|
||||
fn call(&mut self, req: Self::Request) -> Self::Future {
|
||||
Dispatcher::new(req, self.srv.clone())
|
||||
}
|
||||
}
|
@ -135,6 +135,7 @@ extern crate actix_net;
|
||||
extern crate serde_derive;
|
||||
|
||||
mod body;
|
||||
mod config;
|
||||
mod extensions;
|
||||
mod header;
|
||||
mod httpcodes;
|
||||
@ -142,9 +143,12 @@ mod httpmessage;
|
||||
mod httpresponse;
|
||||
mod json;
|
||||
mod payload;
|
||||
mod request;
|
||||
mod uri;
|
||||
|
||||
pub mod error;
|
||||
pub mod h1;
|
||||
pub(crate) mod helpers;
|
||||
pub mod server;
|
||||
//pub mod test;
|
||||
//pub mod ws;
|
||||
@ -152,10 +156,11 @@ pub use body::{Binary, Body};
|
||||
pub use error::{Error, ResponseError, Result};
|
||||
pub use extensions::Extensions;
|
||||
pub use httpmessage::HttpMessage;
|
||||
//pub use httprequest::HttpRequest;
|
||||
pub use httpresponse::HttpResponse;
|
||||
pub use json::Json;
|
||||
pub use server::Request;
|
||||
pub use request::Request;
|
||||
|
||||
pub use self::config::{ServiceConfig, ServiceConfigBuilder};
|
||||
|
||||
pub mod dev {
|
||||
//! The `actix-web` prelude for library developers
|
||||
|
@ -30,7 +30,6 @@ pub(crate) struct InnerRequest {
|
||||
pub(crate) flags: Cell<MessageFlags>,
|
||||
pub(crate) headers: HeaderMap,
|
||||
pub(crate) extensions: RefCell<Extensions>,
|
||||
pub(crate) addr: Option<SocketAddr>,
|
||||
pub(crate) payload: RefCell<Option<Payload>>,
|
||||
pub(crate) stream_extensions: Option<Rc<Extensions>>,
|
||||
pool: &'static RequestPool,
|
||||
@ -65,8 +64,13 @@ impl HttpMessage for Request {
|
||||
}
|
||||
|
||||
impl Request {
|
||||
/// Create new RequestContext instance
|
||||
pub(crate) fn new(pool: &'static RequestPool) -> Request {
|
||||
/// Create new Request instance
|
||||
pub fn new() -> Request {
|
||||
Request::with_pool(RequestPool::pool())
|
||||
}
|
||||
|
||||
/// Create new Request instance with pool
|
||||
pub(crate) fn with_pool(pool: &'static RequestPool) -> Request {
|
||||
Request {
|
||||
inner: Rc::new(InnerRequest {
|
||||
pool,
|
||||
@ -75,7 +79,6 @@ impl Request {
|
||||
version: Version::HTTP_11,
|
||||
headers: HeaderMap::with_capacity(16),
|
||||
flags: Cell::new(MessageFlags::empty()),
|
||||
addr: None,
|
||||
payload: RefCell::new(None),
|
||||
extensions: RefCell::new(Extensions::new()),
|
||||
stream_extensions: None,
|
||||
@ -134,14 +137,6 @@ impl Request {
|
||||
&mut self.inner_mut().headers
|
||||
}
|
||||
|
||||
/// Peer socket address
|
||||
///
|
||||
/// Peer address is actual socket address, if proxy is used in front of
|
||||
/// actix http server, then peer address would be address of this proxy.
|
||||
pub fn peer_addr(&self) -> Option<SocketAddr> {
|
||||
self.inner().addr
|
||||
}
|
||||
|
||||
/// Checks if a connection should be kept alive.
|
||||
#[inline]
|
||||
pub fn keep_alive(&self) -> bool {
|
||||
@ -170,12 +165,6 @@ impl Request {
|
||||
self.inner().method == Method::CONNECT
|
||||
}
|
||||
|
||||
/// Io stream extensions
|
||||
#[inline]
|
||||
pub fn stream_extensions(&self) -> Option<&Extensions> {
|
||||
self.inner().stream_extensions.as_ref().map(|e| e.as_ref())
|
||||
}
|
||||
|
||||
pub(crate) fn clone(&self) -> Self {
|
||||
Request {
|
||||
inner: self.inner.clone(),
|
||||
@ -213,7 +202,8 @@ impl fmt::Debug for Request {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RequestPool(RefCell<VecDeque<Rc<InnerRequest>>>);
|
||||
/// Request's objects pool
|
||||
pub(crate) struct RequestPool(RefCell<VecDeque<Rc<InnerRequest>>>);
|
||||
|
||||
thread_local!(static POOL: &'static RequestPool = RequestPool::create());
|
||||
|
||||
@ -223,16 +213,18 @@ impl RequestPool {
|
||||
Box::leak(Box::new(pool))
|
||||
}
|
||||
|
||||
pub(crate) fn pool() -> &'static RequestPool {
|
||||
/// Get default request's pool
|
||||
pub fn pool() -> &'static RequestPool {
|
||||
POOL.with(|p| *p)
|
||||
}
|
||||
|
||||
/// Get Request object
|
||||
#[inline]
|
||||
pub fn get(pool: &'static RequestPool) -> Request {
|
||||
if let Some(msg) = pool.0.borrow_mut().pop_front() {
|
||||
Request { inner: msg }
|
||||
} else {
|
||||
Request::new(pool)
|
||||
Request::with_pool(pool)
|
||||
}
|
||||
}
|
||||
|
@ -1,73 +0,0 @@
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::io;
|
||||
|
||||
use futures::{Async, Poll};
|
||||
|
||||
use error::{Error, ParseError};
|
||||
use http::{StatusCode, Version};
|
||||
|
||||
/// Errors produced by `AcceptorError` service.
|
||||
#[derive(Debug)]
|
||||
pub enum AcceptorError<T> {
|
||||
/// The inner service error
|
||||
Service(T),
|
||||
|
||||
/// Io specific error
|
||||
Io(io::Error),
|
||||
|
||||
/// The request did not complete within the specified timeout.
|
||||
Timeout,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// A set of errors that can occur during dispatching http requests
|
||||
pub enum HttpDispatchError<E: Debug + Display> {
|
||||
/// Application error
|
||||
// #[fail(display = "Application specific error: {}", _0)]
|
||||
App(E),
|
||||
|
||||
/// An `io::Error` that occurred while trying to read or write to a network
|
||||
/// stream.
|
||||
// #[fail(display = "IO error: {}", _0)]
|
||||
Io(io::Error),
|
||||
|
||||
/// Http request parse error.
|
||||
// #[fail(display = "Parse error: {}", _0)]
|
||||
Parse(ParseError),
|
||||
|
||||
/// The first request did not complete within the specified timeout.
|
||||
// #[fail(display = "The first request did not complete within the specified timeout")]
|
||||
SlowRequestTimeout,
|
||||
|
||||
/// Shutdown timeout
|
||||
// #[fail(display = "Connection shutdown timeout")]
|
||||
ShutdownTimeout,
|
||||
|
||||
/// Payload is not consumed
|
||||
// #[fail(display = "Task is completed but request's payload is not consumed")]
|
||||
PayloadIsNotConsumed,
|
||||
|
||||
/// Malformed request
|
||||
// #[fail(display = "Malformed request")]
|
||||
MalformedRequest,
|
||||
|
||||
/// Internal error
|
||||
// #[fail(display = "Internal error")]
|
||||
InternalError,
|
||||
|
||||
/// Unknown error
|
||||
// #[fail(display = "Unknown error")]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl<E: Debug + Display> From<ParseError> for HttpDispatchError<E> {
|
||||
fn from(err: ParseError) -> Self {
|
||||
HttpDispatchError::Parse(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Debug + Display> From<io::Error> for HttpDispatchError<E> {
|
||||
fn from(err: io::Error) -> Self {
|
||||
HttpDispatchError::Io(err)
|
||||
}
|
||||
}
|
1289
src/server/h1.rs
1289
src/server/h1.rs
File diff suppressed because it is too large
Load Diff
@ -117,30 +117,11 @@ use tokio_tcp::TcpStream;
|
||||
|
||||
pub use actix_net::server::{PauseServer, ResumeServer, StopServer};
|
||||
|
||||
mod error;
|
||||
// pub(crate) mod h1;
|
||||
#[doc(hidden)]
|
||||
pub mod h1codec;
|
||||
#[doc(hidden)]
|
||||
pub mod h1decoder;
|
||||
pub(crate) mod helpers;
|
||||
pub(crate) mod input;
|
||||
pub(crate) mod message;
|
||||
pub(crate) mod output;
|
||||
// pub(crate) mod service;
|
||||
pub(crate) mod settings;
|
||||
|
||||
pub use self::error::{AcceptorError, HttpDispatchError};
|
||||
pub use self::message::Request;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod h1disp;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use self::settings::{ServiceConfig, ServiceConfigBuilder};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use self::helpers::write_content_length;
|
||||
pub use super::helpers::write_content_length;
|
||||
|
||||
use body::Binary;
|
||||
use extensions::Extensions;
|
||||
|
@ -13,10 +13,10 @@ use flate2::Compression;
|
||||
use http::header::{HeaderValue, ACCEPT_ENCODING, CONTENT_LENGTH};
|
||||
use http::{StatusCode, Version};
|
||||
|
||||
use super::message::InnerRequest;
|
||||
use body::{Binary, Body};
|
||||
use header::ContentEncoding;
|
||||
use httpresponse::HttpResponse;
|
||||
use request::InnerRequest;
|
||||
|
||||
// #[derive(Debug)]
|
||||
// pub(crate) struct RequestInfo {
|
||||
|
@ -12,9 +12,8 @@ use actix_net::service::{IntoNewService, IntoService};
|
||||
use actix_web::{client, test};
|
||||
use futures::future;
|
||||
|
||||
use actix_http::server::h1disp::Http1Dispatcher;
|
||||
use actix_http::server::{KeepAlive, ServiceConfig};
|
||||
use actix_http::{Error, HttpResponse};
|
||||
use actix_http::server::KeepAlive;
|
||||
use actix_http::{h1, Error, HttpResponse, ServiceConfig};
|
||||
|
||||
#[test]
|
||||
fn test_h1_v2() {
|
||||
@ -30,17 +29,10 @@ fn test_h1_v2() {
|
||||
.server_address(addr)
|
||||
.finish();
|
||||
|
||||
(move |io| {
|
||||
let pool = settings.request_pool();
|
||||
Http1Dispatcher::new(
|
||||
io,
|
||||
pool,
|
||||
(|req| {
|
||||
h1::H1Service::new(settings, |req| {
|
||||
println!("REQ: {:?}", req);
|
||||
future::ok::<_, Error>(HttpResponse::Ok().finish())
|
||||
}).into_service(),
|
||||
)
|
||||
}).into_new_service()
|
||||
})
|
||||
}).unwrap()
|
||||
.run();
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user