1
0
mirror of https://github.com/fafhrd91/actix-web synced 2024-11-24 08:22:59 +01:00

update guide

This commit is contained in:
Nikolay Kim 2017-12-13 22:36:28 -08:00
parent 408ddf0be1
commit b7cde3f4a9
14 changed files with 81 additions and 22 deletions

View File

@ -85,3 +85,5 @@ fn main() {
``` ```
## User sessions ## User sessions
[WIP]

View File

@ -1,10 +1,10 @@
# HTTP/2 # HTTP/2.0
Actix web automatically upgrades connection to *HTTP/2* if possible. Actix web automatically upgrades connection to *HTTP/2.0* if possible.
## Negotiation ## Negotiation
*HTTP/2* protocol over tls without prior knowlage requires *HTTP/2.0* protocol over tls without prior knowlage requires
[tls alpn](https://tools.ietf.org/html/rfc7301). At the moment only [tls alpn](https://tools.ietf.org/html/rfc7301). At the moment only
`rust-openssl` has support. Turn on `alpn` feature to enable `alpn` negotiation. `rust-openssl` has support. Turn on `alpn` feature to enable `alpn` negotiation.
With enable `alpn` feature `HttpServer` provides With enable `alpn` feature `HttpServer` provides
@ -32,7 +32,7 @@ fn main() {
} }
``` ```
Upgrade to *HTTP/2* schema described in Upgrade to *HTTP/2.0* schema described in
[rfc section 3.2](https://http2.github.io/http2-spec/#rfc.section.3.2) is not supported. [rfc section 3.2](https://http2.github.io/http2-spec/#rfc.section.3.2) is not supported.
Starting *HTTP/2* with prior knowledge is supported for both clear text connection Starting *HTTP/2* with prior knowledge is supported for both clear text connection
and tls connection. [rfc section 3.4](https://http2.github.io/http2-spec/#rfc.section.3.4) and tls connection. [rfc section 3.4](https://http2.github.io/http2-spec/#rfc.section.3.4)

View File

@ -49,7 +49,7 @@ request handler with the application's `resource` on a particular *HTTP method*
# } # }
# fn main() { # fn main() {
let app = Application::new() let app = Application::new()
.resource("/", |r| r.method(Method::GET).f(index)) .resource("/", |r| r.f(index))
.finish(); .finish();
# } # }
``` ```

View File

@ -1,5 +1,6 @@
# Server # Server
## Multi-threading ## Multi-threading
Http server automatically starts number of http workers, by default Http server automatically starts number of http workers, by default
@ -52,7 +53,7 @@ fn main() {
} }
``` ```
Note on *HTTP/2* protocol over tls without prior knowlage, it requires Note on *HTTP/2.0* protocol over tls without prior knowlage, it requires
[tls alpn](https://tools.ietf.org/html/rfc7301). At the moment only [tls alpn](https://tools.ietf.org/html/rfc7301). At the moment only
`openssl` has `alpn ` support. `openssl` has `alpn ` support.
@ -99,6 +100,7 @@ use actix_web::*;
fn index(req: HttpRequest) -> HttpResponse { fn index(req: HttpRequest) -> HttpResponse {
HTTPOk.build() HTTPOk.build()
.connection_type(headers::ConnectionType::Close) // <- Close connection .connection_type(headers::ConnectionType::Close) // <- Close connection
.force_close() // <- Alternative method
.finish().unwrap() .finish().unwrap()
} }
# fn main() {} # fn main() {}

View File

@ -82,3 +82,45 @@ fn main() {
.finish(); .finish();
} }
``` ```
## Chunked transfer encoding
Actix automatically decode *chunked* encoding. `HttpRequest::payload()` already contains
decoded bytes stream. If request payload compressed with one of supported
compression codecs (br, gzip, deflate) bytes stream get decompressed.
Chunked encoding on response could be enabled with `HttpResponseBuilder::chunked()` method.
But this takes effect only for `Body::Streaming(BodyStream)` or `Body::StreamingContext` bodies.
Also if response payload compression is enabled and streaming body is used, chunked encoding
get enabled automatically.
Enabling chunked encoding for *HTTP/2.0* responses is forbidden.
```rust
# extern crate actix_web;
use actix_web::*;
use actix_web::headers::ContentEncoding;
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.chunked()
.body(Body::Streaming(Payload::empty().stream())).unwrap()
}
# fn main() {}
```
## Cookies
[WIP]
## Multipart body
[WIP]
## Urlencoded body
[WIP]
## Streaming request
[WIP]

View File

@ -1 +1,4 @@
# WebSockets # WebSockets
[WIP]

View File

@ -6,8 +6,8 @@ use futures::Stream;
use error::Error; use error::Error;
pub(crate) type BodyStream = Box<Stream<Item=Bytes, Error=Error>>; /// Type represent streaming body
pub type BodyStream = Box<Stream<Item=Bytes, Error=Error>>;
/// Represents various types of http message body. /// Represents various types of http message body.
pub enum Body { pub enum Body {

View File

@ -213,6 +213,9 @@ impl From<IoError> for PayloadError {
} }
} }
/// `InternalServerError` for `PayloadError`
impl ResponseError for PayloadError {}
/// Return `BadRequest` for `cookie::ParseError` /// Return `BadRequest` for `cookie::ParseError`
impl ResponseError for cookie::ParseError { impl ResponseError for cookie::ParseError {
fn error_response(&self) -> HttpResponse { fn error_response(&self) -> HttpResponse {

View File

@ -254,7 +254,7 @@ impl<T, H> Http1<T, H>
if self.keepalive_timer.is_none() { if self.keepalive_timer.is_none() {
trace!("Start keep-alive timer"); trace!("Start keep-alive timer");
let mut to = Timeout::new( let mut to = Timeout::new(
Duration::new(keep_alive as u64, 0), Duration::new(keep_alive, 0),
Arbiter::handle()).unwrap(); Arbiter::handle()).unwrap();
// register timeout // register timeout
let _ = to.poll(); let _ = to.poll();

View File

@ -159,7 +159,7 @@ impl<T, H> Http2<T, H>
if keep_alive > 0 && self.keepalive_timer.is_none() { if keep_alive > 0 && self.keepalive_timer.is_none() {
trace!("Start keep-alive timer"); trace!("Start keep-alive timer");
let mut timeout = Timeout::new( let mut timeout = Timeout::new(
Duration::new(keep_alive as u64, 0), Duration::new(keep_alive, 0),
Arbiter::handle()).unwrap(); Arbiter::handle()).unwrap();
// register timeout // register timeout
let _ = timeout.poll(); let _ = timeout.poll();

View File

@ -309,7 +309,7 @@ impl HttpResponseBuilder {
/// Enables automatic chunked transfer encoding /// Enables automatic chunked transfer encoding
#[inline] #[inline]
pub fn enable_chunked(&mut self) -> &mut Self { pub fn chunked(&mut self) -> &mut Self {
if let Some(parts) = parts(&mut self.response, &self.err) { if let Some(parts) = parts(&mut self.response, &self.err) {
parts.chunked = true; parts.chunked = true;
} }

View File

@ -128,6 +128,7 @@ pub mod dev {
//! use actix_web::dev::*; //! use actix_web::dev::*;
//! ``` //! ```
pub use body::BodyStream;
pub use info::ConnectionInfo; pub use info::ConnectionInfo;
pub use handler::Handler; pub use handler::Handler;
pub use router::{Router, Pattern}; pub use router::{Router, Pattern};

View File

@ -7,6 +7,7 @@ use bytes::{Bytes, BytesMut};
use futures::{Async, Poll, Stream}; use futures::{Async, Poll, Stream};
use futures::task::{Task, current as current_task}; use futures::task::{Task, current as current_task};
use body::BodyStream;
use actix::ResponseType; use actix::ResponseType;
use error::PayloadError; use error::PayloadError;
@ -121,6 +122,11 @@ impl Payload {
pub fn set_buffer_size(&self, size: usize) { pub fn set_buffer_size(&self, size: usize) {
self.inner.borrow_mut().set_buffer_size(size) self.inner.borrow_mut().set_buffer_size(size)
} }
/// Convert payload into BodyStream
pub fn stream(self) -> BodyStream {
Box::new(self.map(|item| item.0).map_err(|e| e.into()))
}
} }
impl Stream for Payload { impl Stream for Payload {

View File

@ -94,7 +94,7 @@ pub struct HttpServer<T, A, H, U>
io: PhantomData<T>, io: PhantomData<T>,
addr: PhantomData<A>, addr: PhantomData<A>,
threads: usize, threads: usize,
keep_alive: Option<u16>, keep_alive: Option<u64>,
factory: Arc<Fn() -> U + Send + Sync>, factory: Arc<Fn() -> U + Send + Sync>,
workers: Vec<SyncAddress<Worker<H>>>, workers: Vec<SyncAddress<Worker<H>>>,
} }
@ -152,7 +152,7 @@ impl<T, A, H, U, V> HttpServer<T, A, H, U>
/// - `Some(0)` - disable /// - `Some(0)` - disable
/// ///
/// - `None` - use `SO_KEEPALIVE` socket option /// - `None` - use `SO_KEEPALIVE` socket option
pub fn keep_alive(mut self, val: Option<u16>) -> Self { pub fn keep_alive(mut self, val: Option<u64>) -> Self {
self.keep_alive = val; self.keep_alive = val;
self self
} }
@ -240,7 +240,7 @@ impl<T, A, H, U, V> HttpServer<T, A, H, U>
let (tx, rx) = mpsc::unbounded::<IoStream<Socket>>(); let (tx, rx) = mpsc::unbounded::<IoStream<Socket>>();
let h = handler.clone(); let h = handler.clone();
let ka = self.keep_alive.clone(); let ka = self.keep_alive;
let factory = Arc::clone(&self.factory); let factory = Arc::clone(&self.factory);
let addr = Arbiter::start(move |ctx: &mut Context<_>| { let addr = Arbiter::start(move |ctx: &mut Context<_>| {
let mut apps: Vec<_> = (*factory)() let mut apps: Vec<_> = (*factory)()
@ -396,7 +396,7 @@ impl<T, A, H, U> Handler<IoStream<T>, io::Error> for HttpServer<T, A, H, U>
-> Response<Self, IoStream<T>> -> Response<Self, IoStream<T>>
{ {
Arbiter::handle().spawn( Arbiter::handle().spawn(
HttpChannel::new(Rc::clone(&self.h.as_ref().unwrap()), msg.io, msg.peer, msg.http2)); HttpChannel::new(Rc::clone(self.h.as_ref().unwrap()), msg.io, msg.peer, msg.http2));
Self::empty() Self::empty()
} }
} }
@ -412,21 +412,21 @@ struct Worker<H> {
pub(crate) struct WorkerSettings<H> { pub(crate) struct WorkerSettings<H> {
h: Vec<H>, h: Vec<H>,
keep_alive: Option<u16>, keep_alive: Option<u64>,
} }
impl<H> WorkerSettings<H> { impl<H> WorkerSettings<H> {
pub fn handlers(&self) -> &Vec<H> { pub fn handlers(&self) -> &Vec<H> {
&self.h &self.h
} }
pub fn keep_alive(&self) -> Option<u16> { pub fn keep_alive(&self) -> Option<u64> {
self.keep_alive self.keep_alive
} }
} }
impl<H: 'static> Worker<H> { impl<H: 'static> Worker<H> {
fn new(h: Vec<H>, handler: StreamHandlerType, keep_alive: Option<u16>) -> Worker<H> { fn new(h: Vec<H>, handler: StreamHandlerType, keep_alive: Option<u64>) -> Worker<H> {
Worker { Worker {
h: Rc::new(WorkerSettings{h: h, keep_alive: keep_alive}), h: Rc::new(WorkerSettings{h: h, keep_alive: keep_alive}),
handler: handler, handler: handler,
@ -456,10 +456,10 @@ impl<H> Handler<IoStream<Socket>> for Worker<H>
fn handle(&mut self, msg: IoStream<Socket>, _: &mut Context<Self>) fn handle(&mut self, msg: IoStream<Socket>, _: &mut Context<Self>)
-> Response<Self, IoStream<Socket>> -> Response<Self, IoStream<Socket>>
{ {
if let None = self.h.keep_alive { if self.h.keep_alive.is_none() &&
if msg.io.set_keepalive(Some(Duration::new(75, 0))).is_err() { msg.io.set_keepalive(Some(Duration::new(75, 0))).is_err()
error!("Can not set socket keep-alive option"); {
} error!("Can not set socket keep-alive option");
} }
self.handler.handle(Rc::clone(&self.h), msg); self.handler.handle(Rc::clone(&self.h), msg);
Self::empty() Self::empty()