From 248bd388cadf30003e77b9167a8751653cde08ad Mon Sep 17 00:00:00 2001 From: Douman Date: Thu, 16 Aug 2018 16:11:15 +0300 Subject: [PATCH] Improve HTTP server docs (#470) --- src/lib.rs | 3 +- src/pipeline.rs | 4 +- src/server/http.rs | 4 ++ src/server/mod.rs | 112 ++++++++++++++++++++++++++++++++++++++++++- src/server/server.rs | 28 ++++++----- 5 files changed, 136 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ed02b1b69..c6d3453a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -251,7 +251,8 @@ pub mod dev { pub use context::Drain; pub use extractor::{FormConfig, PayloadConfig}; pub use handler::{AsyncResult, Handler}; - pub use httpmessage::{MessageBody, UrlEncoded}; + pub use httpmessage::{MessageBody, Readlines, UrlEncoded}; + pub use pipeline::Pipeline; pub use httpresponse::HttpResponseBuilder; pub use info::ConnectionInfo; pub use json::{JsonBody, JsonConfig}; diff --git a/src/pipeline.rs b/src/pipeline.rs index 09c5e49d2..7f206a9fd 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -83,7 +83,7 @@ impl PipelineInfo { } impl> Pipeline { - pub fn new( + pub(crate) fn new( req: HttpRequest, mws: Rc>>>, handler: Rc, ) -> Pipeline { let mut info = PipelineInfo { @@ -475,7 +475,7 @@ impl ProcessResponse { } } } - Ok(Async::Ready(None)) => + Ok(Async::Ready(None)) => return Some(FinishingMiddlewares::init( info, mws, self.resp.take().unwrap(), )), diff --git a/src/server/http.rs b/src/server/http.rs index edf8aef60..e3740d955 100644 --- a/src/server/http.rs +++ b/src/server/http.rs @@ -31,6 +31,10 @@ use super::{ }; /// An HTTP Server +/// +/// By default it serves HTTP2 when HTTPs is enabled, +/// in order to change it, use `ServerFlags` that can be provided +/// to acceptor service. pub struct HttpServer where H: IntoHttpHandler + 'static, diff --git a/src/server/mod.rs b/src/server/mod.rs index 67952e433..f33a345e5 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,4 +1,111 @@ -//! Http server +//! Http server module +//! +//! The module contains everything necessary to setup +//! HTTP server. +//! +//! In order to start HTTP server, first you need to create and configure it +//! using factory that can be supplied to [new](fn.new.html). +//! +//! ## Factory +//! +//! Factory is a function that returns Application, describing how +//! to serve incoming HTTP requests. +//! +//! As the server uses worker pool, the factory function is restricted to trait bounds +//! `Sync + Send + 'static` so that each worker would be able to accept Application +//! without a need for synchronization. +//! +//! If you wish to share part of state among all workers you should +//! wrap it in `Arc` and potentially synchronization primitive like +//! [RwLock](https://doc.rust-lang.org/std/sync/struct.RwLock.html) +//! If the wrapped type is not thread safe. +//! +//! Note though that locking is not advisable for asynchronous programming +//! and you should minimize all locks in your request handlers +//! +//! ## HTTPS Support +//! +//! Actix-web provides support for major crates that provides TLS. +//! Each TLS implementation is provided with [AcceptorService](trait.AcceptorService.html) +//! that describes how HTTP Server accepts connections. +//! +//! For `bind` and `listen` there are corresponding `bind_with` and `listen_with` that accepts +//! these services. +//! +//! By default, acceptor would work with both HTTP2 and HTTP1 protocols. +//! But it can be controlled using [ServerFlags](struct.ServerFlags.html) which +//! can be supplied when creating `AcceptorService`. +//! +//! **NOTE:** `native-tls` doesn't support `HTTP2` yet +//! +//! ## Signal handling and shutdown +//! +//! By default HTTP Server listens for system signals +//! and, gracefully shuts down at most after 30 seconds. +//! +//! Both signal handling and shutdown timeout can be controlled +//! using corresponding methods. +//! +//! If worker, for some reason, unable to shut down within timeout +//! it is forcibly dropped. +//! +//! ## Example +//! +//! ```rust,ignore +//!extern crate actix; +//!extern crate actix_web; +//!extern crate rustls; +//! +//!use actix_web::{http, middleware, server, App, Error, HttpRequest, HttpResponse, Responder}; +//!use std::io::BufReader; +//!use rustls::internal::pemfile::{certs, rsa_private_keys}; +//!use rustls::{NoClientAuth, ServerConfig}; +//! +//!fn index(req: &HttpRequest) -> Result { +//! Ok(HttpResponse::Ok().content_type("text/plain").body("Welcome!")) +//!} +//! +//!fn load_ssl() -> ServerConfig { +//! use std::io::BufReader; +//! +//! const CERT: &'static [u8] = include_bytes!("../cert.pem"); +//! const KEY: &'static [u8] = include_bytes!("../key.pem"); +//! +//! let mut cert = BufReader::new(CERT); +//! let mut key = BufReader::new(KEY); +//! +//! let mut config = ServerConfig::new(NoClientAuth::new()); +//! let cert_chain = certs(&mut cert).unwrap(); +//! let mut keys = rsa_private_keys(&mut key).unwrap(); +//! config.set_single_cert(cert_chain, keys.remove(0)).unwrap(); +//! +//! config +//!} +//! +//!fn main() { +//! let sys = actix::System::new("http-server"); +//! // load ssl keys +//! let config = load_ssl(); +//! +//! // Create acceptor service for only HTTP1 protocol +//! // You can use ::new(config) to leave defaults +//! let acceptor = server::RustlsAcceptor::with_flags(config, actix_web::server::ServerFlags::HTTP1); +//! +//! // create and start server at once +//! server::new(|| { +//! App::new() +//! // register simple handler, handle all methods +//! .resource("/index.html", |r| r.f(index)) +//! })) +//! }).bind_with("127.0.0.1:8080", acceptor) +//! .unwrap() +//! .start(); +//! +//! println!("Started http server: 127.0.0.1:8080"); +//! //Run system so that server would start accepting connections +//! let _ = sys.run(); +//!} +//! ``` use std::net::Shutdown; use std::rc::Rc; use std::{io, net, time}; @@ -83,8 +190,11 @@ where } bitflags! { + ///Flags that can be used to configure HTTP Server. pub struct ServerFlags: u8 { + ///Use HTTP1 protocol const HTTP1 = 0b0000_0001; + ///Use HTTP2 protocol const HTTP2 = 0b0000_0010; } } diff --git a/src/server/server.rs b/src/server/server.rs index 9e25efc56..552ba8ee2 100644 --- a/src/server/server.rs +++ b/src/server/server.rs @@ -13,6 +13,8 @@ use super::accept::{AcceptLoop, AcceptNotify, Command}; use super::worker::{StopWorker, Worker, WorkerClient, Conn}; use super::{PauseServer, ResumeServer, StopServer, Token}; +///Describes service that could be used +///with [Server](struct.Server.html) pub trait Service: Send + 'static { /// Clone service fn clone(&self) -> Box; @@ -31,6 +33,8 @@ impl Service for Box { } } +///Describes the way serivce handles incoming +///TCP connections. pub trait ServiceHandler { /// Handle incoming stream fn handle(&mut self, token: Token, io: net::TcpStream, peer: Option); @@ -43,6 +47,7 @@ pub(crate) enum ServerCommand { WorkerDied(usize), } +///Server pub struct Server { threads: usize, workers: Vec<(usize, Addr)>, @@ -80,7 +85,7 @@ impl Server { maxconnrate: 256, } } - + /// Set number of workers to start. /// /// By default http server uses number of available logical cpu as threads @@ -108,7 +113,7 @@ impl Server { /// /// By default max connections is set to a 256. pub fn maxconnrate(mut self, num: usize) -> Self { - self.maxconnrate= num; + self.maxconnrate = num; self } @@ -146,7 +151,7 @@ impl Server { } /// Add new service to server - pub fn service(mut self, srv: T) -> Self + pub fn service(mut self, srv: T) -> Self where T: Into<(Box, Vec<(Token, net::TcpListener)>)> { @@ -171,7 +176,7 @@ impl Server { /// /// fn main() { /// Server::new(). - /// .service( + /// .service( /// HttpServer::new(|| App::new().resource("/", |r| r.h(|_| HttpResponse::Ok()))) /// .bind("127.0.0.1:0") /// .expect("Can not bind to 127.0.0.1:0")) @@ -184,7 +189,7 @@ impl Server { sys.run(); } - /// Start + /// Starts Server Actor and returns its address pub fn start(mut self) -> Addr { if self.sockets.is_empty() { panic!("Service should have at least one bound socket"); @@ -393,7 +398,8 @@ impl StreamHandler for Server { } #[derive(Clone, Default)] -pub struct Connections (Arc); +///Contains information about connection. +pub struct Connections(Arc); impl Connections { fn new(notify: AcceptNotify, maxconn: usize, maxconnrate: usize) -> Self { @@ -458,7 +464,7 @@ impl ConnectionsInner { self.notify.notify(); } } - + fn notify_maxconnrate(&self, connrate: usize) { if connrate > self.maxconnrate_low && connrate <= self.maxconnrate { self.notify.notify(); @@ -468,8 +474,8 @@ impl ConnectionsInner { } /// Type responsible for max connection stat. -/// -/// Max connections stat get updated on drop. +/// +/// Max connections stat get updated on drop. pub struct ConnectionTag(Arc); impl ConnectionTag { @@ -487,8 +493,8 @@ impl Drop for ConnectionTag { } /// Type responsible for max connection rate stat. -/// -/// Max connections rate stat get updated on drop. +/// +/// Max connections rate stat get updated on drop. pub struct ConnectionRateTag (Arc); impl ConnectionRateTag {