1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2025-01-10 17:25:36 +00:00

move server protocol impl to submodule

This commit is contained in:
Nikolay Kim 2018-01-11 18:35:05 -08:00
parent fa93701bee
commit 8a058efb4e
15 changed files with 269 additions and 236 deletions

View file

@ -67,7 +67,7 @@ fn main() {
let addr = rx.recv().unwrap();
let _ = addr.call_fut(
dev::StopServer{graceful:true}).wait(); // <- Send `StopServer` message to server.
server::StopServer{graceful:true}).wait(); // <- Send `StopServer` message to server.
}
```

View file

@ -8,10 +8,9 @@ use router::{Router, Pattern};
use resource::Resource;
use handler::{Handler, RouteHandler, WrapHandler};
use httprequest::HttpRequest;
use channel::{HttpHandler, IntoHttpHandler, HttpHandlerTask};
use pipeline::{Pipeline, PipelineHandler};
use middleware::Middleware;
use server::ServerSettings;
use server::{HttpHandler, IntoHttpHandler, HttpHandlerTask, ServerSettings};
/// Application
pub struct HttpApplication<S=()> {

View file

@ -104,13 +104,6 @@ mod param;
mod resource;
mod handler;
mod pipeline;
mod server;
mod worker;
mod channel;
mod h1;
mod h2;
mod h1writer;
mod h2writer;
pub mod fs;
pub mod ws;
@ -121,17 +114,18 @@ pub mod middleware;
pub mod pred;
pub mod test;
pub mod payload;
pub mod server;
pub use error::{Error, Result, ResponseError};
pub use body::{Body, Binary};
pub use json::{Json};
pub use json::Json;
pub use application::Application;
pub use httprequest::HttpRequest;
pub use httpresponse::HttpResponse;
pub use handler::{Reply, Responder, NormalizePath, AsyncResponder};
pub use route::Route;
pub use resource::Resource;
pub use server::HttpServer;
pub use context::HttpContext;
pub use server::HttpServer;
// re-exports
pub use http::{Method, StatusCode, Version};
@ -171,10 +165,7 @@ pub mod dev {
pub use handler::Handler;
pub use json::JsonBody;
pub use router::{Router, Pattern};
pub use channel::{HttpChannel, HttpHandler, IntoHttpHandler};
pub use param::{FromParam, Params};
pub use httprequest::{UrlEncoded, RequestBody};
pub use httpresponse::HttpResponseBuilder;
pub use server::{ServerSettings, PauseServer, ResumeServer, StopServer};
}

View file

@ -6,16 +6,15 @@ use std::marker::PhantomData;
use futures::{Async, Poll, Future, Stream};
use futures::unsync::oneshot;
use channel::HttpHandlerTask;
use body::{Body, BodyStream};
use context::{Frame, ActorHttpContext};
use error::Error;
use handler::{Reply, ReplyItem};
use h1writer::{Writer, WriterState};
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use middleware::{Middleware, Finished, Started, Response};
use application::Inner;
use server::{Writer, WriterState, HttpHandlerTask};
pub(crate) trait PipelineHandler<S> {
fn handle(&mut self, req: HttpRequest<S>) -> Reply;

View file

@ -7,49 +7,10 @@ use futures::{Future, Poll, Async};
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_core::net::TcpStream;
use {h1, h2};
use error::Error;
use h1writer::Writer;
use httprequest::HttpRequest;
use server::ServerSettings;
use worker::WorkerSettings;
use super::{h1, h2, HttpHandler, IoStream};
use super::settings::WorkerSettings;
/// Low level http request handler
#[allow(unused_variables)]
pub trait HttpHandler: 'static {
/// Handle request
fn handle(&mut self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest>;
}
pub trait HttpHandlerTask {
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error>;
fn poll(&mut self) -> Poll<(), Error>;
fn disconnected(&mut self);
}
/// Conversion helper trait
pub trait IntoHttpHandler {
/// The associated type which is result of conversion.
type Handler: HttpHandler;
/// Convert into `HttpHandler` object.
fn into_handler(self, settings: ServerSettings) -> Self::Handler;
}
impl<T: HttpHandler> IntoHttpHandler for T {
type Handler = T;
fn into_handler(self, _: ServerSettings) -> Self::Handler {
self
}
}
enum HttpProtocol<T: IoStream, H: 'static>
{
enum HttpProtocol<T: IoStream, H: 'static> {
H1(h1::Http1<T, H>),
H2(h2::Http2<T, H>),
}
@ -247,16 +208,6 @@ impl Node<()> {
}
}
/// Low-level io stream operations
pub trait IoStream: AsyncRead + AsyncWrite + 'static {
fn shutdown(&mut self, how: Shutdown) -> io::Result<()>;
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()>;
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()>;
}
impl IoStream for TcpStream {
#[inline]
fn shutdown(&mut self, how: Shutdown) -> io::Result<()> {

View file

@ -14,14 +14,16 @@ use tokio_core::reactor::Timeout;
use pipeline::Pipeline;
use encoding::PayloadType;
use channel::{HttpHandler, HttpHandlerTask, IoStream};
use h1writer::{Writer, H1Writer};
use worker::WorkerSettings;
use httpcodes::HTTPNotFound;
use httprequest::HttpRequest;
use error::{ParseError, PayloadError, ResponseError};
use payload::{Payload, PayloadWriter, DEFAULT_BUFFER_SIZE};
use super::Writer;
use super::h1writer::H1Writer;
use super::settings::WorkerSettings;
use super::{HttpHandler, HttpHandlerTask, IoStream};
const LW_BUFFER_SIZE: usize = 4096;
const HW_BUFFER_SIZE: usize = 16_384;
const MAX_BUFFER_SIZE: usize = 131_072;
@ -901,8 +903,8 @@ mod tests {
use super::*;
use application::HttpApplication;
use worker::WorkerSettings;
use channel::IoStream;
use server::settings::WorkerSettings;
use server::IoStream;
struct Buffer {
buf: Bytes,

View file

@ -11,32 +11,9 @@ use helpers::SharedBytes;
use encoding::PayloadEncoder;
use httprequest::HttpMessage;
use httpresponse::HttpResponse;
use server::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
const MAX_WRITE_BUFFER_SIZE: usize = 65_536; // max buffer size 64k
#[derive(Debug)]
pub enum WriterState {
Done,
Pause,
}
/// Send stream
pub trait Writer {
fn written(&self) -> u64;
fn start(&mut self, req: &mut HttpMessage, resp: &mut HttpResponse)
-> Result<WriterState, io::Error>;
fn write(&mut self, payload: &[u8]) -> Result<WriterState, io::Error>;
fn write_eof(&mut self) -> Result<WriterState, io::Error>;
fn flush(&mut self) -> Poll<(), io::Error>;
fn poll_completed(&mut self, shutdown: bool) -> Poll<(), io::Error>;
}
bitflags! {
struct Flags: u8 {

View file

@ -15,15 +15,16 @@ use tokio_io::{AsyncRead, AsyncWrite};
use tokio_core::reactor::Timeout;
use pipeline::Pipeline;
use h2writer::H2Writer;
use worker::WorkerSettings;
use channel::{HttpHandler, HttpHandlerTask};
use error::PayloadError;
use encoding::PayloadType;
use httpcodes::HTTPNotFound;
use httprequest::HttpRequest;
use payload::{Payload, PayloadWriter};
use super::h2writer::H2Writer;
use super::settings::WorkerSettings;
use super::{HttpHandler, HttpHandlerTask};
bitflags! {
struct Flags: u8 {
const DISCONNECTED = 0b0000_0010;

View file

@ -12,10 +12,9 @@ use helpers::SharedBytes;
use encoding::PayloadEncoder;
use httprequest::HttpMessage;
use httpresponse::HttpResponse;
use h1writer::{Writer, WriterState};
use server::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
const CHUNK_SIZE: usize = 16_384;
const MAX_WRITE_BUFFER_SIZE: usize = 65_536; // max buffer size 64k
bitflags! {
struct Flags: u8 {

109
src/server/mod.rs Normal file
View file

@ -0,0 +1,109 @@
//! Http server
use std::{time, io};
use std::net::Shutdown;
use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};
mod srv;
mod worker;
mod channel;
mod h1;
mod h2;
mod h1writer;
mod h2writer;
mod settings;
pub use self::srv::HttpServer;
pub use self::settings::ServerSettings;
use error::Error;
use httprequest::{HttpMessage, HttpRequest};
use httpresponse::HttpResponse;
/// max buffer size 64k
pub(crate) const MAX_WRITE_BUFFER_SIZE: usize = 65_536;
/// Pause accepting incoming connections
///
/// If socket contains some pending connection, they might be dropped.
/// All opened connection remains active.
#[derive(Message)]
pub struct PauseServer;
/// Resume accepting incoming connections
#[derive(Message)]
pub struct ResumeServer;
/// Stop incoming connection processing, stop all workers and exit.
///
/// If server starts with `spawn()` method, then spawned thread get terminated.
#[derive(Message)]
pub struct StopServer {
pub graceful: bool
}
/// Low level http request handler
#[allow(unused_variables)]
pub trait HttpHandler: 'static {
/// Handle request
fn handle(&mut self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest>;
}
pub trait HttpHandlerTask {
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error>;
fn poll(&mut self) -> Poll<(), Error>;
fn disconnected(&mut self);
}
/// Conversion helper trait
pub trait IntoHttpHandler {
/// The associated type which is result of conversion.
type Handler: HttpHandler;
/// Convert into `HttpHandler` object.
fn into_handler(self, settings: ServerSettings) -> Self::Handler;
}
impl<T: HttpHandler> IntoHttpHandler for T {
type Handler = T;
fn into_handler(self, _: ServerSettings) -> Self::Handler {
self
}
}
/// Low-level io stream operations
pub trait IoStream: AsyncRead + AsyncWrite + 'static {
fn shutdown(&mut self, how: Shutdown) -> io::Result<()>;
fn set_nodelay(&mut self, nodelay: bool) -> io::Result<()>;
fn set_linger(&mut self, dur: Option<time::Duration>) -> io::Result<()>;
}
#[derive(Debug)]
pub enum WriterState {
Done,
Pause,
}
/// Stream writer
pub trait Writer {
fn written(&self) -> u64;
fn start(&mut self, req: &mut HttpMessage, resp: &mut HttpResponse)
-> Result<WriterState, io::Error>;
fn write(&mut self, payload: &[u8]) -> Result<WriterState, io::Error>;
fn write_eof(&mut self) -> Result<WriterState, io::Error>;
fn flush(&mut self) -> Poll<(), io::Error>;
fn poll_completed(&mut self, shutdown: bool) -> Poll<(), io::Error>;
}

125
src/server/settings.rs Normal file
View file

@ -0,0 +1,125 @@
use std::net;
use std::rc::Rc;
use std::cell::{Cell, RefCell, RefMut};
use helpers;
use super::channel::Node;
/// Various server settings
#[derive(Debug, Clone)]
pub struct ServerSettings {
addr: Option<net::SocketAddr>,
secure: bool,
host: String,
}
impl Default for ServerSettings {
fn default() -> Self {
ServerSettings {
addr: None,
secure: false,
host: "localhost:8080".to_owned(),
}
}
}
impl ServerSettings {
/// Crate server settings instance
pub(crate) fn new(addr: Option<net::SocketAddr>, host: &Option<String>, secure: bool)
-> ServerSettings
{
let host = if let Some(ref host) = *host {
host.clone()
} else if let Some(ref addr) = addr {
format!("{}", addr)
} else {
"localhost".to_owned()
};
ServerSettings {
addr: addr,
secure: secure,
host: host,
}
}
/// Returns the socket address of the local half of this TCP connection
pub fn local_addr(&self) -> Option<net::SocketAddr> {
self.addr
}
/// Returns true if connection is secure(https)
pub fn secure(&self) -> bool {
self.secure
}
/// Returns host header value
pub fn host(&self) -> &str {
&self.host
}
}
pub(crate) struct WorkerSettings<H> {
h: RefCell<Vec<H>>,
enabled: bool,
keep_alive: u64,
bytes: Rc<helpers::SharedBytesPool>,
messages: Rc<helpers::SharedMessagePool>,
channels: Cell<usize>,
node: Node<()>,
}
impl<H> WorkerSettings<H> {
pub(crate) fn new(h: Vec<H>, keep_alive: Option<u64>) -> WorkerSettings<H> {
WorkerSettings {
h: RefCell::new(h),
enabled: if let Some(ka) = keep_alive { ka > 0 } else { false },
keep_alive: keep_alive.unwrap_or(0),
bytes: Rc::new(helpers::SharedBytesPool::new()),
messages: Rc::new(helpers::SharedMessagePool::new()),
channels: Cell::new(0),
node: Node::head(),
}
}
pub fn num_channels(&self) -> usize {
self.channels.get()
}
pub fn head(&self) -> &Node<()> {
&self.node
}
pub fn handlers(&self) -> RefMut<Vec<H>> {
self.h.borrow_mut()
}
pub fn keep_alive(&self) -> u64 {
self.keep_alive
}
pub fn keep_alive_enabled(&self) -> bool {
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))
}
pub fn add_channel(&self) {
self.channels.set(self.channels.get() + 1);
}
pub fn remove_channel(&self) {
let num = self.channels.get();
if num > 0 {
self.channels.set(num-1);
} else {
error!("Number of removed channels is bigger than added channel. Bug in actix-web");
}
}
}

View file

@ -28,59 +28,12 @@ use openssl::pkcs12::ParsedPkcs12;
use tokio_openssl::SslStream;
use helpers;
use channel::{HttpChannel, HttpHandler, IntoHttpHandler, IoStream, WrapperStream};
use worker::{Conn, Worker, WorkerSettings, StreamHandlerType, StopWorker};
use super::{HttpHandler, IntoHttpHandler, IoStream};
use super::{PauseServer, ResumeServer, StopServer};
use super::channel::{HttpChannel, WrapperStream};
use super::worker::{Conn, Worker, StreamHandlerType, StopWorker};
use super::settings::{ServerSettings, WorkerSettings};
/// Various server settings
#[derive(Debug, Clone)]
pub struct ServerSettings {
addr: Option<net::SocketAddr>,
secure: bool,
host: String,
}
impl Default for ServerSettings {
fn default() -> Self {
ServerSettings {
addr: None,
secure: false,
host: "localhost:8080".to_owned(),
}
}
}
impl ServerSettings {
/// Crate server settings instance
fn new(addr: Option<net::SocketAddr>, host: &Option<String>, secure: bool) -> Self {
let host = if let Some(ref host) = *host {
host.clone()
} else if let Some(ref addr) = addr {
format!("{}", addr)
} else {
"localhost".to_owned()
};
ServerSettings {
addr: addr,
secure: secure,
host: host,
}
}
/// Returns the socket address of the local half of this TCP connection
pub fn local_addr(&self) -> Option<net::SocketAddr> {
self.addr
}
/// Returns true if connection is secure(https)
pub fn secure(&self) -> bool {
self.secure
}
/// Returns host header value
pub fn host(&self) -> &str {
&self.host
}
}
/// An HTTP Server
///
@ -585,25 +538,6 @@ impl<T, A, H, U, V> Handler<io::Result<Conn<T>>> for HttpServer<T, A, H, U>
}
}
/// Pause accepting incoming connections
///
/// If socket contains some pending connection, they might be dropped.
/// All opened connection remains active.
#[derive(Message)]
pub struct PauseServer;
/// Resume accepting incoming connections
#[derive(Message)]
pub struct ResumeServer;
/// Stop incoming connection processing, stop all workers and exit.
///
/// If server starts with `spawn()` method, then spawned thread get terminated.
#[derive(Message)]
pub struct StopServer {
pub graceful: bool
}
impl<T, A, H, U, V> Handler<PauseServer> for HttpServer<T, A, H, U>
where T: IoStream,
H: HttpHandler + 'static,

View file

@ -1,6 +1,5 @@
use std::{net, time};
use std::rc::Rc;
use std::cell::{Cell, RefCell, RefMut};
use futures::Future;
use futures::unsync::oneshot;
use tokio_core::net::TcpStream;
@ -25,7 +24,9 @@ use actix::*;
use actix::msgs::StopArbiter;
use helpers;
use channel::{HttpChannel, HttpHandler, Node};
use server::HttpHandler;
use server::channel::HttpChannel;
use server::settings::WorkerSettings;
#[derive(Message)]
@ -43,60 +44,6 @@ pub(crate) struct StopWorker {
pub graceful: Option<time::Duration>,
}
pub(crate) struct WorkerSettings<H> {
h: RefCell<Vec<H>>,
enabled: bool,
keep_alive: u64,
bytes: Rc<helpers::SharedBytesPool>,
messages: Rc<helpers::SharedMessagePool>,
channels: Cell<usize>,
node: Node<()>,
}
impl<H> WorkerSettings<H> {
pub(crate) fn new(h: Vec<H>, keep_alive: Option<u64>) -> WorkerSettings<H> {
WorkerSettings {
h: RefCell::new(h),
enabled: if let Some(ka) = keep_alive { ka > 0 } else { false },
keep_alive: keep_alive.unwrap_or(0),
bytes: Rc::new(helpers::SharedBytesPool::new()),
messages: Rc::new(helpers::SharedMessagePool::new()),
channels: Cell::new(0),
node: Node::head(),
}
}
pub fn head(&self) -> &Node<()> {
&self.node
}
pub fn handlers(&self) -> RefMut<Vec<H>> {
self.h.borrow_mut()
}
pub fn keep_alive(&self) -> u64 {
self.keep_alive
}
pub fn keep_alive_enabled(&self) -> bool {
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))
}
pub fn add_channel(&self) {
self.channels.set(self.channels.get()+1);
}
pub fn remove_channel(&self) {
let num = self.channels.get();
if num > 0 {
self.channels.set(num-1);
} else {
error!("Number of removed channels is bigger than added channel. Bug in actix-web");
}
}
}
/// Http worker
///
/// Worker accepts Socket objects via unbounded channel and start requests processing.
@ -127,7 +74,7 @@ impl<H: HttpHandler + 'static> Worker<H> {
tx: oneshot::Sender<bool>, dur: time::Duration) {
// sleep for 1 second and then check again
ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
let num = slf.settings.channels.get();
let num = slf.settings.num_channels();
if num == 0 {
let _ = tx.send(true);
Arbiter::arbiter().send(StopArbiter(0));
@ -174,7 +121,7 @@ impl<H> Handler<StopWorker> for Worker<H>
type Result = Response<Self, StopWorker>;
fn handle(&mut self, msg: StopWorker, ctx: &mut Context<Self>) -> Self::Result {
let num = self.settings.channels.get();
let num = self.settings.num_channels();
if num == 0 {
info!("Shutting down http worker, 0 connections");
Self::reply(Ok(true))

View file

@ -16,9 +16,7 @@ use tokio_core::reactor::Core;
use net2::TcpBuilder;
use error::Error;
use server::{HttpServer, ServerSettings};
use handler::{Handler, Responder, ReplyItem};
use channel::{HttpHandler, IntoHttpHandler};
use middleware::Middleware;
use application::{Application, HttpApplication};
use param::Params;
@ -26,6 +24,7 @@ use router::Router;
use payload::Payload;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use server::{HttpServer, HttpHandler, IntoHttpHandler, ServerSettings};
/// The `TestServer` type.
///

View file

@ -72,12 +72,12 @@ fn test_start() {
assert!(reqwest::get(&format!("http://{}/", addr)).unwrap().status().is_success());
// pause
let _ = srv_addr.call_fut(dev::PauseServer).wait();
let _ = srv_addr.call_fut(server::PauseServer).wait();
thread::sleep(time::Duration::from_millis(100));
assert!(net::TcpStream::connect(addr).is_err());
// resume
let _ = srv_addr.call_fut(dev::ResumeServer).wait();
let _ = srv_addr.call_fut(server::ResumeServer).wait();
assert!(reqwest::get(&format!("http://{}/", addr)).unwrap().status().is_success());
}