diff --git a/.travis.yml b/.travis.yml
index b0c4c6e73..640aa1b92 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -47,7 +47,7 @@ script:
USE_SKEPTIC=1 cargo test --features=alpn
else
cargo clean
- cargo test
+ cargo test -- --nocapture
# --features=alpn
fi
@@ -55,8 +55,10 @@ script:
if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
cd examples/basics && cargo check && cd ../..
cd examples/hello-world && cargo check && cd ../..
+ cd examples/http-proxy && cargo check && cd ../..
cd examples/multipart && cargo check && cd ../..
cd examples/json && cargo check && cd ../..
+ cd examples/juniper && cargo check && cd ../..
cd examples/state && cargo check && cd ../..
cd examples/template_tera && cargo check && cd ../..
cd examples/diesel && cargo check && cd ../..
@@ -64,6 +66,7 @@ script:
cd examples/tls && cargo check && cd ../..
cd examples/websocket-chat && cargo check && cd ../..
cd examples/websocket && cargo check && cd ../..
+ cd examples/unix-socket && cargo check && cd ../..
fi
- |
if [[ "$TRAVIS_RUST_VERSION" == "nightly" && $CLIPPY ]]; then
@@ -73,7 +76,7 @@ script:
# Upload docs
after_success:
- |
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "stable" ]]; then
+ if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
cargo doc --features "alpn, tls" --no-deps &&
echo "" > target/doc/index.html &&
cargo install mdbook &&
diff --git a/CHANGES.md b/CHANGES.md
index b623c163f..278e4780e 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,13 +1,60 @@
# Changes
-## 0.4.0 (2018-02-..)
+## 0.4.5 (2018-03-xx)
+
+* Enable compression support for `NamedFile`
+
+* Add `ResponseError` impl for `SendRequestError`.
+ This improves ergonomics of http client.
+
+
+## 0.4.4 (2018-03-04)
+
+* Allow to use Arc> as response/request body
+
+* Fix handling of requests with an encoded body with a length > 8192 #93
+
+## 0.4.3 (2018-03-03)
+
+* Fix request body read bug
+
+* Fix segmentation fault #79
+
+* Set reuse address before bind #90
+
+
+## 0.4.2 (2018-03-02)
+
+* Better naming for websockets implementation
+
+* Add `Pattern::with_prefix()`, make it more usable outside of actix
+
+* Add csrf middleware for filter for cross-site request forgery #89
+
+* Fix disconnect on idle connections
+
+
+## 0.4.1 (2018-03-01)
+
+* Rename `Route::p()` to `Route::filter()`
+
+* Better naming for http codes
+
+* Fix payload parse in situation when socket data is not ready.
+
+* Fix Session mutable borrow lifetime #87
+
+
+## 0.4.0 (2018-02-28)
* Actix 0.5 compatibility
-* Fix request json loader
+* Fix request json/urlencoded loaders
* Simplify HttpServer type definition
+* Added HttpRequest::encoding() method
+
* Added HttpRequest::mime_type() method
* Added HttpRequest::uri_mut(), allows to modify request uri
@@ -16,11 +63,11 @@
* Added http client
-* Added basic websocket client
+* Added websocket client
* Added TestServer::ws(), test websockets client
-* Added TestServer test http client
+* Added TestServer http client support
* Allow to override content encoding on application level
diff --git a/Cargo.toml b/Cargo.toml
index b7999b743..9b69e2560 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,15 +1,17 @@
[package]
name = "actix-web"
-version = "0.4.0"
+version = "0.4.4"
authors = ["Nikolay Kim "]
-description = "Actix web framework"
+description = "Actix web is a small, pragmatic, extremely fast, web framework for Rust."
readme = "README.md"
keywords = ["http", "web", "framework", "async", "futures"]
homepage = "https://github.com/actix/actix-web"
repository = "https://github.com/actix/actix-web.git"
documentation = "https://docs.rs/actix-web/"
categories = ["network-programming", "asynchronous",
- "web-programming::http-server", "web-programming::websocket"]
+ "web-programming::http-server",
+ "web-programming::http-client",
+ "web-programming::websocket"]
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config",
"appveyor.yml", "/examples/**"]
@@ -40,7 +42,7 @@ brotli2 = "^0.3.2"
failure = "0.1.1"
flate2 = "1.0"
h2 = "0.1"
-http = "^0.1.2"
+http = "^0.1.5"
httparse = "1.2"
http-range = "0.1"
libc = "0.2"
@@ -53,10 +55,11 @@ rand = "0.4"
regex = "0.2"
serde = "1.0"
serde_json = "1.0"
-sha1 = "0.4"
+sha1 = "0.6"
smallvec = "0.6"
time = "0.1"
-url = "1.6"
+encoding = "0.2"
+url = { version="1.7", features=["query_encoding"] }
cookie = { version="0.10", features=["percent-encode", "secure"] }
# io
@@ -78,7 +81,7 @@ openssl = { version="0.10", optional = true }
tokio-openssl = { version="0.2", optional = true }
[dependencies.actix]
-version = "0.5"
+version = "^0.5.1"
[dev-dependencies]
env_logger = "0.5"
@@ -98,16 +101,20 @@ codegen-units = 1
members = [
"./",
"examples/basics",
+ "examples/juniper",
"examples/diesel",
"examples/r2d2",
"examples/json",
"examples/hello-world",
+ "examples/http-proxy",
"examples/multipart",
"examples/state",
+ "examples/redis-session",
"examples/template_tera",
"examples/tls",
"examples/websocket",
"examples/websocket-chat",
"examples/web-cors/backend",
+ "examples/unix-socket",
"tools/wsload/",
]
diff --git a/README.md b/README.md
index 47d7db733..7c8ac4e0a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Actix web [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![Build status](https://ci.appveyor.com/api/projects/status/kkdb4yce7qhm5w85/branch/master?svg=true)](https://ci.appveyor.com/project/fafhrd91/actix-web-hdy9d/branch/master) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](http://meritbadge.herokuapp.com/actix-web)](https://crates.io/crates/actix-web) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-Actix web is a small, fast, pragmatic, open source rust web framework.
+Actix web is a small, pragmatic, extremely fast, web framework for Rust.
* Supported *HTTP/1.x* and [*HTTP/2.0*](https://actix.github.io/actix-web/guide/qs_13.html) protocols
* Streaming and pipelining
@@ -10,11 +10,13 @@ Actix web is a small, fast, pragmatic, open source rust web framework.
* Configurable [request routing](https://actix.github.io/actix-web/guide/qs_5.html)
* Graceful server shutdown
* Multipart streams
+* SSL support with openssl or native-tls
* Middlewares ([Logger](https://actix.github.io/actix-web/guide/qs_10.html#logging),
[Session](https://actix.github.io/actix-web/guide/qs_10.html#user-sessions),
+ [Redis sessions](https://github.com/actix/actix-redis),
[DefaultHeaders](https://actix.github.io/actix-web/guide/qs_10.html#default-headers),
[CORS](https://actix.github.io/actix-web/actix_web/middleware/cors/index.html))
-* Built on top of [Actix](https://github.com/actix/actix).
+* Built on top of [Actix actor framework](https://github.com/actix/actix).
## Documentation
@@ -48,7 +50,7 @@ fn main() {
* [Basics](https://github.com/actix/actix-web/tree/master/examples/basics/)
* [Stateful](https://github.com/actix/actix-web/tree/master/examples/state/)
-* [Mulitpart streams](https://github.com/actix/actix-web/tree/master/examples/multipart/)
+* [Multipart streams](https://github.com/actix/actix-web/tree/master/examples/multipart/)
* [Simple websocket session](https://github.com/actix/actix-web/tree/master/examples/websocket/)
* [Tera templates](https://github.com/actix/actix-web/tree/master/examples/template_tera/)
* [Diesel integration](https://github.com/actix/actix-web/tree/master/examples/diesel/)
@@ -57,11 +59,14 @@ fn main() {
* [SockJS Server](https://github.com/actix/actix-sockjs)
* [Json](https://github.com/actix/actix-web/tree/master/examples/json/)
+You may consider checking out
+[this directory](https://github.com/actix/actix-web/tree/master/examples) for more examples.
+
## Benchmarks
* [TechEmpower Framework Benchmark](https://www.techempower.com/benchmarks/#section=data-r15&hw=ph&test=plaintext)
-* Some basic benchmarks could be found in this [respository](https://github.com/fafhrd91/benchmarks).
+* Some basic benchmarks could be found in this [repository](https://github.com/fafhrd91/benchmarks).
## License
diff --git a/examples/basics/src/main.rs b/examples/basics/src/main.rs
index f52b09544..55e4485e0 100644
--- a/examples/basics/src/main.rs
+++ b/examples/basics/src/main.rs
@@ -22,7 +22,7 @@ fn index(mut req: HttpRequest) -> Result {
println!("{:?}", req);
// example of ...
- if let Ok(ch) = req.payload_mut().readany().poll() {
+ if let Ok(ch) = req.poll() {
if let futures::Async::Ready(Some(d)) = ch {
println!("{}", String::from_utf8_lossy(d.as_ref()));
}
@@ -139,7 +139,7 @@ fn main() {
// default
.default_resource(|r| {
r.method(Method::GET).f(p404);
- r.route().p(pred::Not(pred::Get())).f(|req| httpcodes::HTTPMethodNotAllowed);
+ r.route().filter(pred::Not(pred::Get())).f(|req| httpcodes::HTTPMethodNotAllowed);
}))
.bind("127.0.0.1:8080").expect("Can not bind to 127.0.0.1:8080")
diff --git a/examples/http-proxy/Cargo.toml b/examples/http-proxy/Cargo.toml
new file mode 100644
index 000000000..7b9597bff
--- /dev/null
+++ b/examples/http-proxy/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "http-proxy"
+version = "0.1.0"
+authors = ["Nikolay Kim "]
+workspace = "../.."
+
+[dependencies]
+env_logger = "0.5"
+futures = "0.1"
+actix = "0.5"
+actix-web = { path = "../../", features=["alpn"] }
diff --git a/examples/http-proxy/src/main.rs b/examples/http-proxy/src/main.rs
new file mode 100644
index 000000000..551101c97
--- /dev/null
+++ b/examples/http-proxy/src/main.rs
@@ -0,0 +1,59 @@
+extern crate actix;
+extern crate actix_web;
+extern crate futures;
+extern crate env_logger;
+
+use actix_web::*;
+use futures::{Future, Stream};
+
+
+/// Stream client request response and then send body to a server response
+fn index(_req: HttpRequest) -> Box> {
+ client::ClientRequest::get("https://www.rust-lang.org/en-US/")
+ .finish().unwrap()
+ .send()
+ .map_err(error::Error::from) // <- convert SendRequestError to an Error
+ .and_then(
+ |resp| resp.body() // <- this is MessageBody type, resolves to complete body
+ .from_err() // <- convet PayloadError to a Error
+ .and_then(|body| { // <- we got complete body, now send as server response
+ httpcodes::HttpOk.build()
+ .body(body)
+ .map_err(error::Error::from)
+ }))
+ .responder()
+}
+
+/// streaming client request to a streaming server response
+fn streaming(_req: HttpRequest) -> Box> {
+ // send client request
+ client::ClientRequest::get("https://www.rust-lang.org/en-US/")
+ .finish().unwrap()
+ .send() // <- connect to host and send request
+ .map_err(error::Error::from) // <- convert SendRequestError to an Error
+ .and_then(|resp| { // <- we received client response
+ httpcodes::HttpOk.build()
+ // read one chunk from client response and send this chunk to a server response
+ // .from_err() converts PayloadError to a Error
+ .body(Body::Streaming(Box::new(resp.from_err())))
+ .map_err(|e| e.into()) // HttpOk::build() mayb return HttpError, we need to convert it to a Error
+ })
+ .responder()
+}
+
+fn main() {
+ ::std::env::set_var("RUST_LOG", "actix_web=info");
+ env_logger::init();
+ let sys = actix::System::new("http-proxy");
+
+ let _addr = HttpServer::new(
+ || Application::new()
+ .middleware(middleware::Logger::default())
+ .resource("/streaming", |r| r.f(streaming))
+ .resource("/", |r| r.f(index)))
+ .bind("127.0.0.1:8080").unwrap()
+ .start();
+
+ println!("Started http server: 127.0.0.1:8080");
+ let _ = sys.run();
+}
diff --git a/examples/json/src/main.rs b/examples/json/src/main.rs
index 719d74853..3247e5d6c 100644
--- a/examples/json/src/main.rs
+++ b/examples/json/src/main.rs
@@ -34,9 +34,9 @@ fn index(req: HttpRequest) -> Box> {
const MAX_SIZE: usize = 262_144; // max payload size is 256k
/// This handler manually load request payload and parse serde json
-fn index_manual(mut req: HttpRequest) -> Box> {
- // readany() returns asynchronous stream of Bytes objects
- req.payload_mut().readany()
+fn index_manual(req: HttpRequest) -> Box> {
+ // HttpRequest is stream of Bytes objects
+ req
// `Future::from_err` acts like `?` in that it coerces the error type from
// the future into the final error type
.from_err()
@@ -63,8 +63,8 @@ fn index_manual(mut req: HttpRequest) -> Box Box> {
- req.payload_mut().readany().concat2()
+fn index_mjsonrust(req: HttpRequest) -> Box> {
+ req.concat2()
.from_err()
.and_then(|body| {
// body is loaded, now we can deserialize json-rust
diff --git a/examples/juniper/Cargo.toml b/examples/juniper/Cargo.toml
new file mode 100644
index 000000000..9e52b0a83
--- /dev/null
+++ b/examples/juniper/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "juniper-example"
+version = "0.1.0"
+authors = ["pyros2097 "]
+workspace = "../.."
+
+[dependencies]
+env_logger = "0.5"
+actix = "0.5"
+actix-web = { path = "../../" }
+
+futures = "0.1"
+serde = "1.0"
+serde_json = "1.0"
+serde_derive = "1.0"
+
+juniper = "0.9.2"
diff --git a/examples/juniper/README.md b/examples/juniper/README.md
new file mode 100644
index 000000000..2ac0eac4e
--- /dev/null
+++ b/examples/juniper/README.md
@@ -0,0 +1,15 @@
+# juniper
+
+Juniper integration for Actix web
+
+### server
+
+```bash
+cd actix-web/examples/juniper
+cargo run (or ``cargo watch -x run``)
+# Started http server: 127.0.0.1:8080
+```
+
+### web client
+
+[http://127.0.0.1:8080/graphiql](http://127.0.0.1:8080/graphiql)
diff --git a/examples/juniper/src/main.rs b/examples/juniper/src/main.rs
new file mode 100644
index 000000000..c0be2754e
--- /dev/null
+++ b/examples/juniper/src/main.rs
@@ -0,0 +1,110 @@
+//! Actix web juniper example
+//!
+//! A simple example integrating juniper in actix-web
+extern crate serde;
+extern crate serde_json;
+#[macro_use]
+extern crate serde_derive;
+#[macro_use]
+extern crate juniper;
+extern crate futures;
+extern crate actix;
+extern crate actix_web;
+extern crate env_logger;
+
+use actix::*;
+use actix_web::*;
+use juniper::http::graphiql::graphiql_source;
+use juniper::http::GraphQLRequest;
+
+use futures::future::Future;
+
+mod schema;
+
+use schema::Schema;
+use schema::create_schema;
+
+struct State {
+ executor: Addr,
+}
+
+#[derive(Serialize, Deserialize)]
+pub struct GraphQLData(GraphQLRequest);
+
+impl Message for GraphQLData {
+ type Result = Result;
+}
+
+pub struct GraphQLExecutor {
+ schema: std::sync::Arc
+}
+
+impl GraphQLExecutor {
+ fn new(schema: std::sync::Arc) -> GraphQLExecutor {
+ GraphQLExecutor {
+ schema: schema,
+ }
+ }
+}
+
+impl Actor for GraphQLExecutor {
+ type Context = SyncContext;
+}
+
+impl Handler for GraphQLExecutor {
+ type Result = Result;
+
+ fn handle(&mut self, msg: GraphQLData, _: &mut Self::Context) -> Self::Result {
+ let res = msg.0.execute(&self.schema, &());
+ let res_text = serde_json::to_string(&res)?;
+ Ok(res_text)
+ }
+}
+
+fn graphiql(_req: HttpRequest) -> Result {
+ let html = graphiql_source("http://127.0.0.1:8080/graphql");
+ Ok(HttpResponse::build(StatusCode::OK)
+ .content_type("text/html; charset=utf-8")
+ .body(html).unwrap())
+}
+
+fn graphql(req: HttpRequest) -> Box> {
+ let executor = req.state().executor.clone();
+ req.json()
+ .from_err()
+ .and_then(move |val: GraphQLData| {
+ executor.send(val)
+ .from_err()
+ .and_then(|res| {
+ match res {
+ Ok(user) => Ok(httpcodes::HTTPOk.build().body(user)?),
+ Err(_) => Ok(httpcodes::HTTPInternalServerError.into())
+ }
+ })
+ })
+ .responder()
+}
+
+fn main() {
+ ::std::env::set_var("RUST_LOG", "actix_web=info");
+ let _ = env_logger::init();
+ let sys = actix::System::new("juniper-example");
+
+ let schema = std::sync::Arc::new(create_schema());
+ let addr = SyncArbiter::start(3, move || {
+ GraphQLExecutor::new(schema.clone())
+ });
+
+ // Start http server
+ let _addr = HttpServer::new(move || {
+ Application::with_state(State{executor: addr.clone()})
+ // enable logger
+ .middleware(middleware::Logger::default())
+ .resource("/graphql", |r| r.method(Method::POST).a(graphql))
+ .resource("/graphiql", |r| r.method(Method::GET).f(graphiql))})
+ .bind("127.0.0.1:8080").unwrap()
+ .start();
+
+ println!("Started http server: 127.0.0.1:8080");
+ let _ = sys.run();
+}
diff --git a/examples/juniper/src/schema.rs b/examples/juniper/src/schema.rs
new file mode 100644
index 000000000..2b4cf3042
--- /dev/null
+++ b/examples/juniper/src/schema.rs
@@ -0,0 +1,58 @@
+use juniper::FieldResult;
+use juniper::RootNode;
+
+#[derive(GraphQLEnum)]
+enum Episode {
+ NewHope,
+ Empire,
+ Jedi,
+}
+
+#[derive(GraphQLObject)]
+#[graphql(description = "A humanoid creature in the Star Wars universe")]
+struct Human {
+ id: String,
+ name: String,
+ appears_in: Vec,
+ home_planet: String,
+}
+
+#[derive(GraphQLInputObject)]
+#[graphql(description = "A humanoid creature in the Star Wars universe")]
+struct NewHuman {
+ name: String,
+ appears_in: Vec,
+ home_planet: String,
+}
+
+pub struct QueryRoot;
+
+graphql_object!(QueryRoot: () |&self| {
+ field human(&executor, id: String) -> FieldResult {
+ Ok(Human{
+ id: "1234".to_owned(),
+ name: "Luke".to_owned(),
+ appears_in: vec![Episode::NewHope],
+ home_planet: "Mars".to_owned(),
+ })
+ }
+});
+
+pub struct MutationRoot;
+
+graphql_object!(MutationRoot: () |&self| {
+ field createHuman(&executor, new_human: NewHuman) -> FieldResult {
+ Ok(Human{
+ id: "1234".to_owned(),
+ name: new_human.name,
+ appears_in: new_human.appears_in,
+ home_planet: new_human.home_planet,
+ })
+ }
+});
+
+pub type Schema = RootNode<'static, QueryRoot, MutationRoot>;
+
+pub fn create_schema() -> Schema {
+ Schema::new(QueryRoot {}, MutationRoot {})
+}
diff --git a/examples/multipart/src/main.rs b/examples/multipart/src/main.rs
index 7da6145a9..343dde167 100644
--- a/examples/multipart/src/main.rs
+++ b/examples/multipart/src/main.rs
@@ -11,7 +11,7 @@ use futures::{Future, Stream};
use futures::future::{result, Either};
-fn index(mut req: HttpRequest) -> Box>
+fn index(req: HttpRequest) -> Box>
{
println!("{:?}", req);
diff --git a/examples/redis-session/Cargo.toml b/examples/redis-session/Cargo.toml
new file mode 100644
index 000000000..cfa102d11
--- /dev/null
+++ b/examples/redis-session/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "redis-session"
+version = "0.1.0"
+authors = ["Nikolay Kim "]
+workspace = "../.."
+
+[dependencies]
+env_logger = "0.5"
+actix = "0.5"
+actix-web = "0.4"
+actix-redis = { version = "0.2", features = ["web"] }
diff --git a/examples/redis-session/src/main.rs b/examples/redis-session/src/main.rs
new file mode 100644
index 000000000..36df16559
--- /dev/null
+++ b/examples/redis-session/src/main.rs
@@ -0,0 +1,48 @@
+#![allow(unused_variables)]
+
+extern crate actix;
+extern crate actix_web;
+extern crate actix_redis;
+extern crate env_logger;
+
+use actix_web::*;
+use actix_web::middleware::RequestSession;
+use actix_redis::RedisSessionBackend;
+
+
+/// simple handler
+fn index(mut req: HttpRequest) -> Result {
+ println!("{:?}", req);
+
+ // session
+ if let Some(count) = req.session().get::("counter")? {
+ println!("SESSION value: {}", count);
+ req.session().set("counter", count+1)?;
+ } else {
+ req.session().set("counter", 1)?;
+ }
+
+ Ok("Welcome!".into())
+}
+
+fn main() {
+ ::std::env::set_var("RUST_LOG", "actix_web=info,actix_redis=info");
+ env_logger::init();
+ let sys = actix::System::new("basic-example");
+
+ HttpServer::new(
+ || Application::new()
+ // enable logger
+ .middleware(middleware::Logger::default())
+ // cookie session middleware
+ .middleware(middleware::SessionStorage::new(
+ RedisSessionBackend::new("127.0.0.1:6379", &[0; 32])
+ ))
+ // register simple route, handle all methods
+ .resource("/", |r| r.f(index)))
+ .bind("0.0.0.0:8080").unwrap()
+ .threads(1)
+ .start();
+
+ let _ = sys.run();
+}
diff --git a/examples/state/src/main.rs b/examples/state/src/main.rs
index 21eb50483..0f7e0ec3b 100644
--- a/examples/state/src/main.rs
+++ b/examples/state/src/main.rs
@@ -36,8 +36,7 @@ impl Actor for MyWebSocket {
type Context = ws::WebsocketContext;
}
-impl Handler for MyWebSocket {
- type Result = ();
+impl StreamHandler for MyWebSocket {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
self.counter += 1;
@@ -46,7 +45,7 @@ impl Handler for MyWebSocket {
ws::Message::Ping(msg) => ctx.pong(&msg),
ws::Message::Text(text) => ctx.text(text),
ws::Message::Binary(bin) => ctx.binary(bin),
- ws::Message::Closed | ws::Message::Error => {
+ ws::Message::Close(_) => {
ctx.stop();
}
_ => (),
diff --git a/examples/unix-socket/Cargo.toml b/examples/unix-socket/Cargo.toml
new file mode 100644
index 000000000..a7c31f212
--- /dev/null
+++ b/examples/unix-socket/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "unix-socket"
+version = "0.1.0"
+authors = ["Messense Lv "]
+
+[dependencies]
+env_logger = "0.5"
+actix = "0.5"
+actix-web = { path = "../../" }
+tokio-uds = "0.1"
diff --git a/examples/unix-socket/README.md b/examples/unix-socket/README.md
new file mode 100644
index 000000000..03b0066a2
--- /dev/null
+++ b/examples/unix-socket/README.md
@@ -0,0 +1,14 @@
+## Unix domain socket example
+
+```bash
+$ curl --unix-socket /tmp/actix-uds.socket http://localhost/
+Hello world!
+```
+
+Although this will only one thread for handling incoming connections
+according to the
+[documentation](https://actix.github.io/actix-web/actix_web/struct.HttpServer.html#method.start_incoming).
+
+And it does not delete the socket file (`/tmp/actix-uds.socket`) when stopping
+the server so it will fail to start next time you run it unless you delete
+the socket file manually.
diff --git a/examples/unix-socket/src/main.rs b/examples/unix-socket/src/main.rs
new file mode 100644
index 000000000..a56d428a7
--- /dev/null
+++ b/examples/unix-socket/src/main.rs
@@ -0,0 +1,31 @@
+extern crate actix;
+extern crate actix_web;
+extern crate env_logger;
+extern crate tokio_uds;
+
+use actix::*;
+use actix_web::*;
+use tokio_uds::UnixListener;
+
+
+fn index(_req: HttpRequest) -> &'static str {
+ "Hello world!"
+}
+
+fn main() {
+ ::std::env::set_var("RUST_LOG", "actix_web=info");
+ let _ = env_logger::init();
+ let sys = actix::System::new("unix-socket");
+
+ let listener = UnixListener::bind("/tmp/actix-uds.socket", Arbiter::handle()).expect("bind failed");
+ let _addr = HttpServer::new(
+ || Application::new()
+ // enable logger
+ .middleware(middleware::Logger::default())
+ .resource("/index.html", |r| r.f(|_| "Hello world!"))
+ .resource("/", |r| r.f(index)))
+ .start_incoming(listener.incoming(), false);
+
+ println!("Started http server: /tmp/actix-uds.socket");
+ let _ = sys.run();
+}
diff --git a/examples/websocket-chat/src/main.rs b/examples/websocket-chat/src/main.rs
index 821fcfa57..dccd768aa 100644
--- a/examples/websocket-chat/src/main.rs
+++ b/examples/websocket-chat/src/main.rs
@@ -92,8 +92,7 @@ impl Handler for WsChatSession {
}
/// WebSocket message handler
-impl Handler for WsChatSession {
- type Result = ();
+impl StreamHandler for WsChatSession {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
println!("WEBSOCKET MESSAGE: {:?}", msg);
@@ -161,10 +160,9 @@ impl Handler for WsChatSession {
},
ws::Message::Binary(bin) =>
println!("Unexpected binary"),
- ws::Message::Closed | ws::Message::Error => {
+ ws::Message::Close(_) => {
ctx.stop();
}
- _ => (),
}
}
}
diff --git a/examples/websocket/src/client.rs b/examples/websocket/src/client.rs
index e35c71bb1..34ff24372 100644
--- a/examples/websocket/src/client.rs
+++ b/examples/websocket/src/client.rs
@@ -12,7 +12,7 @@ use std::time::Duration;
use actix::*;
use futures::Future;
-use actix_web::ws::{Message, WsClientError, WsClient, WsClientWriter};
+use actix_web::ws::{Message, ProtocolError, Client, ClientWriter};
fn main() {
@@ -21,8 +21,8 @@ fn main() {
let sys = actix::System::new("ws-example");
Arbiter::handle().spawn(
- WsClient::new("http://127.0.0.1:8080/ws/")
- .connect().unwrap()
+ Client::new("http://127.0.0.1:8080/ws/")
+ .connect()
.map_err(|e| {
println!("Error: {}", e);
()
@@ -53,7 +53,7 @@ fn main() {
}
-struct ChatClient(WsClientWriter);
+struct ChatClient(ClientWriter);
#[derive(Message)]
struct ClientCommand(String);
@@ -88,12 +88,12 @@ impl Handler for ChatClient {
type Result = ();
fn handle(&mut self, msg: ClientCommand, ctx: &mut Context) {
- self.0.text(msg.0.as_str())
+ self.0.text(msg.0)
}
}
/// Handle server websocket messages
-impl StreamHandler for ChatClient {
+impl StreamHandler for ChatClient {
fn handle(&mut self, msg: Message, ctx: &mut Context) {
match msg {
diff --git a/examples/websocket/src/main.rs b/examples/websocket/src/main.rs
index 9149ead71..f97b948de 100644
--- a/examples/websocket/src/main.rs
+++ b/examples/websocket/src/main.rs
@@ -25,8 +25,7 @@ impl Actor for MyWebSocket {
}
/// Handler for `ws::Message`
-impl Handler for MyWebSocket {
- type Result = ();
+impl StreamHandler for MyWebSocket {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
// process websocket messages
@@ -35,7 +34,7 @@ impl Handler for MyWebSocket {
ws::Message::Ping(msg) => ctx.pong(&msg),
ws::Message::Text(text) => ctx.text(text),
ws::Message::Binary(bin) => ctx.binary(bin),
- ws::Message::Closed | ws::Message::Error => {
+ ws::Message::Close(_) => {
ctx.stop();
}
_ => (),
diff --git a/guide/src/qs_10.md b/guide/src/qs_10.md
index ed36140c7..3e007bcab 100644
--- a/guide/src/qs_10.md
+++ b/guide/src/qs_10.md
@@ -53,7 +53,7 @@ impl Middleware for Headers {
fn main() {
Application::new()
.middleware(Headers) // <- Register middleware, this method could be called multiple times
- .resource("/", |r| r.h(httpcodes::HTTPOk));
+ .resource("/", |r| r.h(httpcodes::HttpOk));
}
```
@@ -144,8 +144,8 @@ fn main() {
.header("X-Version", "0.2")
.finish())
.resource("/test", |r| {
- r.method(Method::GET).f(|req| httpcodes::HTTPOk);
- r.method(Method::HEAD).f(|req| httpcodes::HTTPMethodNotAllowed);
+ r.method(Method::GET).f(|req| httpcodes::HttpOk);
+ r.method(Method::HEAD).f(|req| httpcodes::HttpMethodNotAllowed);
})
.finish();
}
diff --git a/guide/src/qs_14.md b/guide/src/qs_14.md
index c318bcaad..72827e4eb 100644
--- a/guide/src/qs_14.md
+++ b/guide/src/qs_14.md
@@ -12,7 +12,7 @@ We have to define sync actor and connection that this actor will use. Same appro
could be used for other databases.
```rust,ignore
-use actix::prelude::*;*
+use actix::prelude::*;
struct DbExecutor(SqliteConnection);
@@ -36,7 +36,7 @@ We can send `CreateUser` message to `DbExecutor` actor, and as result we get
```rust,ignore
impl Handler for DbExecutor {
- type Result = Result
+ type Result = Result;
fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result
{
@@ -110,8 +110,8 @@ fn index(req: HttpRequest) -> Box>
.from_err()
.and_then(|res| {
match res {
- Ok(user) => Ok(httpcodes::HTTPOk.build().json(user)?),
- Err(_) => Ok(httpcodes::HTTPInternalServerError.into())
+ Ok(user) => Ok(httpcodes::HttpOk.build().json(user)?),
+ Err(_) => Ok(httpcodes::HttpInternalServerError.into())
}
})
.responder()
diff --git a/guide/src/qs_2.md b/guide/src/qs_2.md
index ac53d8707..01cb98499 100644
--- a/guide/src/qs_2.md
+++ b/guide/src/qs_2.md
@@ -20,8 +20,8 @@ contains the following:
```toml
[dependencies]
-actix = "0.4"
-actix-web = "0.3"
+actix = "0.5"
+actix-web = "0.4"
```
In order to implement a web server, first we need to create a request handler.
diff --git a/guide/src/qs_3.md b/guide/src/qs_3.md
index 6d9c1a426..341b62cc0 100644
--- a/guide/src/qs_3.md
+++ b/guide/src/qs_3.md
@@ -49,12 +49,12 @@ fn main() {
HttpServer::new(|| vec![
Application::new()
.prefix("/app1")
- .resource("/", |r| r.f(|r| httpcodes::HTTPOk)),
+ .resource("/", |r| r.f(|r| httpcodes::HttpOk)),
Application::new()
.prefix("/app2")
- .resource("/", |r| r.f(|r| httpcodes::HTTPOk)),
+ .resource("/", |r| r.f(|r| httpcodes::HttpOk)),
Application::new()
- .resource("/", |r| r.f(|r| httpcodes::HTTPOk)),
+ .resource("/", |r| r.f(|r| httpcodes::HttpOk)),
]);
}
```
diff --git a/guide/src/qs_3_5.md b/guide/src/qs_3_5.md
index 99c2bcd9a..3f1fff00e 100644
--- a/guide/src/qs_3_5.md
+++ b/guide/src/qs_3_5.md
@@ -20,7 +20,7 @@ fn main() {
HttpServer::new(
|| Application::new()
- .resource("/", |r| r.h(httpcodes::HTTPOk)))
+ .resource("/", |r| r.h(httpcodes::HttpOk)))
.bind("127.0.0.1:59080").unwrap()
.start();
@@ -57,7 +57,7 @@ fn main() {
let sys = actix::System::new("http-server");
let addr = HttpServer::new(
|| Application::new()
- .resource("/", |r| r.h(httpcodes::HTTPOk)))
+ .resource("/", |r| r.h(httpcodes::HttpOk)))
.bind("127.0.0.1:0").expect("Can not bind to 127.0.0.1:0")
.shutdown_timeout(60) // <- Set shutdown timeout to 60 seconds
.start();
@@ -85,7 +85,7 @@ use actix_web::*;
fn main() {
HttpServer::new(
|| Application::new()
- .resource("/", |r| r.h(httpcodes::HTTPOk)))
+ .resource("/", |r| r.h(httpcodes::HttpOk)))
.threads(4); // <- Start 4 workers
}
```
@@ -146,7 +146,7 @@ use actix_web::*;
fn main() {
HttpServer::new(||
Application::new()
- .resource("/", |r| r.h(httpcodes::HTTPOk)))
+ .resource("/", |r| r.h(httpcodes::HttpOk)))
.keep_alive(None); // <- Use `SO_KEEPALIVE` socket option.
}
```
@@ -155,7 +155,7 @@ If first option is selected then *keep alive* state
calculated based on response's *connection-type*. By default
`HttpResponse::connection_type` is not defined in that case *keep alive*
defined by request's http version. Keep alive is off for *HTTP/1.0*
-and is on for *HTTP/1.1* and "HTTP/2.0".
+and is on for *HTTP/1.1* and *HTTP/2.0*.
*Connection type* could be change with `HttpResponseBuilder::connection_type()` method.
@@ -165,7 +165,7 @@ and is on for *HTTP/1.1* and "HTTP/2.0".
use actix_web::*;
fn index(req: HttpRequest) -> HttpResponse {
- HTTPOk.build()
+ HttpOk.build()
.connection_type(headers::ConnectionType::Close) // <- Close connection
.force_close() // <- Alternative method
.finish().unwrap()
diff --git a/guide/src/qs_4.md b/guide/src/qs_4.md
index c7cbc6c94..486e9df58 100644
--- a/guide/src/qs_4.md
+++ b/guide/src/qs_4.md
@@ -65,7 +65,7 @@ impl Handler for MyHandler {
/// Handle request
fn handle(&mut self, req: HttpRequest) -> Self::Result {
self.0 += 1;
- httpcodes::HTTPOk.into()
+ httpcodes::HttpOk.into()
}
}
# fn main() {}
@@ -90,7 +90,7 @@ impl Handler for MyHandler {
/// Handle request
fn handle(&mut self, req: HttpRequest) -> Self::Result {
self.0.fetch_add(1, Ordering::Relaxed);
- httpcodes::HTTPOk.into()
+ httpcodes::HttpOk.into()
}
}
diff --git a/guide/src/qs_4_5.md b/guide/src/qs_4_5.md
index 5a11af733..01808c605 100644
--- a/guide/src/qs_4_5.md
+++ b/guide/src/qs_4_5.md
@@ -14,7 +14,7 @@ impl> Responder for Result
And any error that implements `ResponseError` can be converted into `Error` object.
For example if *handler* function returns `io::Error`, it would be converted
-into `HTTPInternalServerError` response. Implementation for `io::Error` is provided
+into `HttpInternalServerError` response. Implementation for `io::Error` is provided
by default.
```rust
diff --git a/guide/src/qs_5.md b/guide/src/qs_5.md
index c1e8b615c..21b2f8c64 100644
--- a/guide/src/qs_5.md
+++ b/guide/src/qs_5.md
@@ -32,7 +32,7 @@ fn main() {
Application::new()
.resource("/prefix", |r| r.f(index))
.resource("/user/{name}",
- |r| r.method(Method::GET).f(|req| HTTPOk))
+ |r| r.method(Method::GET).f(|req| HttpOk))
.finish();
}
```
@@ -52,7 +52,7 @@ returns *NOT FOUND* http resources.
Resource contains set of routes. Each route in turn has set of predicates and handler.
New route could be created with `Resource::route()` method which returns reference
to new *Route* instance. By default *route* does not contain any predicates, so matches
-all requests and default handler is `HTTPNotFound`.
+all requests and default handler is `HttpNotFound`.
Application routes incoming requests based on route criteria which is defined during
resource registration and route registration. Resource matches all routes it contains in
@@ -68,9 +68,9 @@ fn main() {
Application::new()
.resource("/path", |resource|
resource.route()
- .p(pred::Get())
- .p(pred::Header("content-type", "text/plain"))
- .f(|req| HTTPOk)
+ .filter(pred::Get())
+ .filter(pred::Header("content-type", "text/plain"))
+ .f(|req| HttpOk)
)
.finish();
}
@@ -85,7 +85,7 @@ If resource can not match any route "NOT FOUND" response get returned.
[*Route*](../actix_web/struct.Route.html) object. Route can be configured with
builder-like pattern. Following configuration methods are available:
-* [*Route::p()*](../actix_web/struct.Route.html#method.p) method registers new predicate,
+* [*Route::filter()*](../actix_web/struct.Route.html#method.filter) method registers new predicate,
any number of predicates could be registered for each route.
* [*Route::f()*](../actix_web/struct.Route.html#method.f) method registers handler function
@@ -336,14 +336,14 @@ resource with the name "foo" and the pattern "{a}/{b}/{c}", you might do this.
#
fn index(req: HttpRequest) -> HttpResponse {
let url = req.url_for("foo", &["1", "2", "3"]); // <- generate url for "foo" resource
- HTTPOk.into()
+ HttpOk.into()
}
fn main() {
let app = Application::new()
.resource("/test/{a}/{b}/{c}", |r| {
r.name("foo"); // <- set resource name, then it could be used in `url_for`
- r.method(Method::GET).f(|_| httpcodes::HTTPOk);
+ r.method(Method::GET).f(|_| httpcodes::HttpOk);
})
.finish();
}
@@ -367,7 +367,7 @@ use actix_web::*;
fn index(mut req: HttpRequest) -> Result {
let url = req.url_for("youtube", &["oHg5SJYRHA0"])?;
assert_eq!(url.as_str(), "https://youtube.com/watch/oHg5SJYRHA0");
- Ok(httpcodes::HTTPOk.into())
+ Ok(httpcodes::HttpOk.into())
}
fn main() {
@@ -404,7 +404,7 @@ This handler designed to be use as a handler for application's *default resource
# use actix_web::*;
#
# fn index(req: HttpRequest) -> httpcodes::StaticResponse {
-# httpcodes::HTTPOk
+# httpcodes::HttpOk
# }
fn main() {
let app = Application::new()
@@ -429,7 +429,7 @@ It is possible to register path normalization only for *GET* requests only
# use actix_web::*;
#
# fn index(req: HttpRequest) -> httpcodes::StaticResponse {
-# httpcodes::HTTPOk
+# httpcodes::HttpOk
# }
fn main() {
let app = Application::new()
@@ -502,8 +502,8 @@ fn main() {
Application::new()
.resource("/index.html", |r|
r.route()
- .p(ContentTypeHeader)
- .h(HTTPOk));
+ .filter(ContentTypeHeader)
+ .h(HttpOk));
}
```
@@ -530,8 +530,8 @@ fn main() {
Application::new()
.resource("/index.html", |r|
r.route()
- .p(pred::Not(pred::Get()))
- .f(|req| HTTPMethodNotAllowed))
+ .filter(pred::Not(pred::Get()))
+ .f(|req| HttpMethodNotAllowed))
.finish();
}
```
@@ -567,8 +567,8 @@ use actix_web::httpcodes::*;
fn main() {
Application::new()
.default_resource(|r| {
- r.method(Method::GET).f(|req| HTTPNotFound);
- r.route().p(pred::Not(pred::Get())).f(|req| HTTPMethodNotAllowed);
+ r.method(Method::GET).f(|req| HttpNotFound);
+ r.route().filter(pred::Not(pred::Get())).f(|req| HttpMethodNotAllowed);
})
# .finish();
}
diff --git a/guide/src/qs_7.md b/guide/src/qs_7.md
index 3a96529a0..e7c6bc88b 100644
--- a/guide/src/qs_7.md
+++ b/guide/src/qs_7.md
@@ -84,7 +84,7 @@ fn index(mut req: HttpRequest) -> Box> {
req.json().from_err()
.and_then(|val: MyObj| {
println!("model: {:?}", val);
- Ok(httpcodes::HTTPOk.build().json(val)?) // <- send response
+ Ok(httpcodes::HttpOk.build().json(val)?) // <- send response
})
.responder()
}
@@ -106,10 +106,10 @@ use futures::{Future, Stream};
#[derive(Serialize, Deserialize)]
struct MyObj {name: String, number: i32}
-fn index(mut req: HttpRequest) -> Box> {
+fn index(req: HttpRequest) -> Box> {
// `concat2` will asynchronously read each chunk of the request body and
// return a single, concatenated, chunk
- req.payload_mut().readany().concat2()
+ req.concat2()
// `Future::from_err` acts like `?` in that it coerces the error type from
// the future into the final error type
.from_err()
@@ -117,7 +117,7 @@ fn index(mut req: HttpRequest) -> Box> {
// synchronous workflow
.and_then(|body| { // <- body is loaded, now we can deserialize json
let obj = serde_json::from_slice::(&body)?;
- Ok(httpcodes::HTTPOk.build().json(obj)?) // <- send response
+ Ok(httpcodes::HttpOk.build().json(obj)?) // <- send response
})
.responder()
}
@@ -169,13 +169,18 @@ get enabled automatically.
Enabling chunked encoding for *HTTP/2.0* responses is forbidden.
```rust
+# extern crate bytes;
# extern crate actix_web;
+# extern crate futures;
+# use futures::Stream;
use actix_web::*;
+use bytes::Bytes;
+use futures::stream::once;
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.chunked()
- .body(Body::Streaming(payload::Payload::empty().stream())).unwrap()
+ .body(Body::Streaming(Box::new(once(Ok(Bytes::from_static(b"data")))))).unwrap()
}
# fn main() {}
```
@@ -246,7 +251,7 @@ fn index(mut req: HttpRequest) -> Box> {
.from_err()
.and_then(|params| { // <- url encoded parameters
println!("==== BODY ==== {:?}", params);
- ok(httpcodes::HTTPOk.into())
+ ok(httpcodes::HttpOk.into())
})
.responder()
}
@@ -256,21 +261,8 @@ fn index(mut req: HttpRequest) -> Box> {
## Streaming request
-Actix uses [*Payload*](../actix_web/payload/struct.Payload.html) object as request payload stream.
-*HttpRequest* provides several methods, which can be used for payload access.
-At the same time *Payload* implements *Stream* trait, so it could be used with various
-stream combinators. Also *Payload* provides several convenience methods that return
-future object that resolve to Bytes object.
-
-* *readany()* method returns *Stream* of *Bytes* objects.
-
-* *readexactly()* method returns *Future* that resolves when specified number of bytes
- get received.
-
-* *readline()* method returns *Future* that resolves when `\n` get received.
-
-* *readuntil()* method returns *Future* that resolves when specified bytes string
- matches in input bytes stream
+*HttpRequest* is a stream of `Bytes` objects. It could be used to read request
+body payload.
In this example handle reads request payload chunk by chunk and prints every chunk.
@@ -283,9 +275,7 @@ use futures::{Future, Stream};
fn index(mut req: HttpRequest) -> Box> {
- req.payload()
- .readany()
- .from_err()
+ req.from_err()
.fold((), |_, chunk| {
println!("Chunk: {:?}", chunk);
result::<_, error::PayloadError>(Ok(()))
diff --git a/guide/src/qs_8.md b/guide/src/qs_8.md
index 2e2b54201..74e7421d2 100644
--- a/guide/src/qs_8.md
+++ b/guide/src/qs_8.md
@@ -20,10 +20,10 @@ use actix_web::test::TestRequest;
fn index(req: HttpRequest) -> HttpResponse {
if let Some(hdr) = req.headers().get(header::CONTENT_TYPE) {
if let Ok(s) = hdr.to_str() {
- return httpcodes::HTTPOk.into()
+ return httpcodes::HttpOk.into()
}
}
- httpcodes::HTTPBadRequest.into()
+ httpcodes::HttpBadRequest.into()
}
fn main() {
@@ -59,16 +59,16 @@ use actix_web::*;
use actix_web::test::TestServer;
fn index(req: HttpRequest) -> HttpResponse {
- httpcodes::HTTPOk.into()
+ httpcodes::HttpOk.into()
}
fn main() {
let mut srv = TestServer::new(|app| app.handler(index)); // <- Start new test server
-
+
let request = srv.get().finish().unwrap(); // <- create client request
let response = srv.execute(request.send()).unwrap(); // <- send request to the server
assert!(response.status().is_success()); // <- check response
-
+
let bytes = srv.execute(response.body()).unwrap(); // <- read response body
}
```
@@ -84,7 +84,7 @@ use actix_web::*;
use actix_web::test::TestServer;
fn index(req: HttpRequest) -> HttpResponse {
- httpcodes::HTTPOk.into()
+ httpcodes::HttpOk.into()
}
/// This function get called by http server.
@@ -130,8 +130,7 @@ impl Actor for Ws {
type Context = ws::WebsocketContext;
}
-impl Handler for Ws {
- type Result = ();
+impl StreamHandler for Ws {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
match msg {
diff --git a/guide/src/qs_9.md b/guide/src/qs_9.md
index dbca38384..fa8b979ae 100644
--- a/guide/src/qs_9.md
+++ b/guide/src/qs_9.md
@@ -21,9 +21,8 @@ impl Actor for Ws {
type Context = ws::WebsocketContext;
}
-/// Define Handler for ws::Message message
-impl Handler for Ws {
- type Result=();
+/// Handler for ws::Message message
+impl StreamHandler for Ws {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
match msg {
@@ -43,7 +42,7 @@ fn main() {
```
Simple websocket echo server example is available in
-[examples directory](https://github.com/actix/actix-web/blob/master/examples/websocket.rs).
+[examples directory](https://github.com/actix/actix-web/blob/master/examples/websocket).
Example chat server with ability to chat over websocket connection or tcp connection
is available in [websocket-chat directory](https://github.com/actix/actix-web/tree/master/examples/websocket-chat/)
diff --git a/src/application.rs b/src/application.rs
index c7c1bcacb..9f0e399b3 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -149,7 +149,7 @@ impl Application where S: 'static {
pub fn with_state(state: S) -> Application {
Application {
parts: Some(ApplicationParts {
- state: state,
+ state,
prefix: "/".to_owned(),
settings: ServerSettings::default(),
default: Resource::default_not_found(),
@@ -183,8 +183,8 @@ impl Application where S: 'static {
/// let app = Application::new()
/// .prefix("/app")
/// .resource("/test", |r| {
- /// r.method(Method::GET).f(|_| httpcodes::HTTPOk);
- /// r.method(Method::HEAD).f(|_| httpcodes::HTTPMethodNotAllowed);
+ /// r.method(Method::GET).f(|_| httpcodes::HttpOk);
+ /// r.method(Method::HEAD).f(|_| httpcodes::HttpMethodNotAllowed);
/// })
/// .finish();
/// }
@@ -226,8 +226,8 @@ impl Application where S: 'static {
/// fn main() {
/// let app = Application::new()
/// .resource("/test", |r| {
- /// r.method(Method::GET).f(|_| httpcodes::HTTPOk);
- /// r.method(Method::HEAD).f(|_| httpcodes::HTTPMethodNotAllowed);
+ /// r.method(Method::GET).f(|_| httpcodes::HttpOk);
+ /// r.method(Method::HEAD).f(|_| httpcodes::HttpMethodNotAllowed);
/// });
/// }
/// ```
@@ -281,7 +281,7 @@ impl Application where S: 'static {
/// fn index(mut req: HttpRequest) -> Result {
/// let url = req.url_for("youtube", &["oHg5SJYRHA0"])?;
/// assert_eq!(url.as_str(), "https://youtube.com/watch/oHg5SJYRHA0");
- /// Ok(httpcodes::HTTPOk.into())
+ /// Ok(httpcodes::HttpOk.into())
/// }
///
/// fn main() {
@@ -320,9 +320,9 @@ impl Application where S: 'static {
/// let app = Application::new()
/// .handler("/app", |req: HttpRequest| {
/// match *req.method() {
- /// Method::GET => httpcodes::HTTPOk,
- /// Method::POST => httpcodes::HTTPMethodNotAllowed,
- /// _ => httpcodes::HTTPNotFound,
+ /// Method::GET => httpcodes::HttpOk,
+ /// Method::POST => httpcodes::HttpMethodNotAllowed,
+ /// _ => httpcodes::HttpNotFound,
/// }});
/// }
/// ```
@@ -361,17 +361,17 @@ impl Application where S: 'static {
default: parts.default,
encoding: parts.encoding,
router: router.clone(),
- resources: resources,
handlers: parts.handlers,
+ resources,
}
));
HttpApplication {
state: Rc::new(parts.state),
prefix: prefix.to_owned(),
- inner: inner,
router: router.clone(),
middlewares: Rc::new(parts.middlewares),
+ inner,
}
}
@@ -394,11 +394,11 @@ impl Application where S: 'static {
/// HttpServer::new(|| { vec![
/// Application::with_state(State1)
/// .prefix("/app1")
- /// .resource("/", |r| r.h(httpcodes::HTTPOk))
+ /// .resource("/", |r| r.h(httpcodes::HttpOk))
/// .boxed(),
/// Application::with_state(State2)
/// .prefix("/app2")
- /// .resource("/", |r| r.h(httpcodes::HTTPOk))
+ /// .resource("/", |r| r.h(httpcodes::HttpOk))
/// .boxed() ]})
/// .bind("127.0.0.1:8080").unwrap()
/// .run()
@@ -459,7 +459,7 @@ mod tests {
#[test]
fn test_default_resource() {
let mut app = Application::new()
- .resource("/test", |r| r.h(httpcodes::HTTPOk))
+ .resource("/test", |r| r.h(httpcodes::HttpOk))
.finish();
let req = TestRequest::with_uri("/test").finish();
@@ -471,7 +471,7 @@ mod tests {
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
let mut app = Application::new()
- .default_resource(|r| r.h(httpcodes::HTTPMethodNotAllowed))
+ .default_resource(|r| r.h(httpcodes::HttpMethodNotAllowed))
.finish();
let req = TestRequest::with_uri("/blah").finish();
let resp = app.run(req);
@@ -482,7 +482,7 @@ mod tests {
fn test_unhandled_prefix() {
let mut app = Application::new()
.prefix("/test")
- .resource("/test", |r| r.h(httpcodes::HTTPOk))
+ .resource("/test", |r| r.h(httpcodes::HttpOk))
.finish();
assert!(app.handle(HttpRequest::default()).is_err());
}
@@ -490,7 +490,7 @@ mod tests {
#[test]
fn test_state() {
let mut app = Application::with_state(10)
- .resource("/", |r| r.h(httpcodes::HTTPOk))
+ .resource("/", |r| r.h(httpcodes::HttpOk))
.finish();
let req = HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone());
let resp = app.run(req);
@@ -501,7 +501,7 @@ mod tests {
fn test_prefix() {
let mut app = Application::new()
.prefix("/test")
- .resource("/blah", |r| r.h(httpcodes::HTTPOk))
+ .resource("/blah", |r| r.h(httpcodes::HttpOk))
.finish();
let req = TestRequest::with_uri("/test").finish();
let resp = app.handle(req);
@@ -523,7 +523,7 @@ mod tests {
#[test]
fn test_handler() {
let mut app = Application::new()
- .handler("/test", httpcodes::HTTPOk)
+ .handler("/test", httpcodes::HttpOk)
.finish();
let req = TestRequest::with_uri("/test").finish();
@@ -551,7 +551,7 @@ mod tests {
fn test_handler_prefix() {
let mut app = Application::new()
.prefix("/app")
- .handler("/test", httpcodes::HTTPOk)
+ .handler("/test", httpcodes::HttpOk)
.finish();
let req = TestRequest::with_uri("/test").finish();
diff --git a/src/body.rs b/src/body.rs
index ebd011e9c..fe6303438 100644
--- a/src/body.rs
+++ b/src/body.rs
@@ -36,6 +36,8 @@ pub enum Binary {
/// Shared string body
#[doc(hidden)]
ArcSharedString(Arc),
+ /// Shared vec body
+ SharedVec(Arc>),
}
impl Body {
@@ -115,6 +117,7 @@ impl Binary {
Binary::Slice(slice) => slice.len(),
Binary::SharedString(ref s) => s.len(),
Binary::ArcSharedString(ref s) => s.len(),
+ Binary::SharedVec(ref s) => s.len(),
}
}
@@ -134,8 +137,9 @@ impl Clone for Binary {
match *self {
Binary::Bytes(ref bytes) => Binary::Bytes(bytes.clone()),
Binary::Slice(slice) => Binary::Bytes(Bytes::from(slice)),
- Binary::SharedString(ref s) => Binary::Bytes(Bytes::from(s.as_str())),
- Binary::ArcSharedString(ref s) => Binary::Bytes(Bytes::from(s.as_str())),
+ Binary::SharedString(ref s) => Binary::SharedString(s.clone()),
+ Binary::ArcSharedString(ref s) => Binary::ArcSharedString(s.clone()),
+ Binary::SharedVec(ref s) => Binary::SharedVec(s.clone()),
}
}
}
@@ -147,6 +151,7 @@ impl Into for Binary {
Binary::Slice(slice) => Bytes::from(slice),
Binary::SharedString(s) => Bytes::from(s.as_str()),
Binary::ArcSharedString(s) => Bytes::from(s.as_str()),
+ Binary::SharedVec(s) => Bytes::from(AsRef::<[u8]>::as_ref(s.as_ref())),
}
}
}
@@ -217,6 +222,18 @@ impl<'a> From<&'a Arc> for Binary {
}
}
+impl From>> for Binary {
+ fn from(body: Arc>) -> Binary {
+ Binary::SharedVec(body)
+ }
+}
+
+impl<'a> From<&'a Arc>> for Binary {
+ fn from(body: &'a Arc>) -> Binary {
+ Binary::SharedVec(Arc::clone(body))
+ }
+}
+
impl AsRef<[u8]> for Binary {
fn as_ref(&self) -> &[u8] {
match *self {
@@ -224,6 +241,7 @@ impl AsRef<[u8]> for Binary {
Binary::Slice(slice) => slice,
Binary::SharedString(ref s) => s.as_bytes(),
Binary::ArcSharedString(ref s) => s.as_bytes(),
+ Binary::SharedVec(ref s) => s.as_ref().as_ref(),
}
}
}
@@ -304,6 +322,15 @@ mod tests {
assert_eq!(Binary::from(&b).as_ref(), "test".as_bytes());
}
+ #[test]
+ fn test_shared_vec() {
+ let b = Arc::new(Vec::from(&b"test"[..]));
+ assert_eq!(Binary::from(b.clone()).len(), 4);
+ assert_eq!(Binary::from(b.clone()).as_ref(), &b"test"[..]);
+ assert_eq!(Binary::from(&b).len(), 4);
+ assert_eq!(Binary::from(&b).as_ref(), &b"test"[..]);
+ }
+
#[test]
fn test_bytes_mut() {
let b = BytesMut::from("test");
diff --git a/src/client/connector.rs b/src/client/connector.rs
index 7acd4ed28..4e8ac214b 100644
--- a/src/client/connector.rs
+++ b/src/client/connector.rs
@@ -1,25 +1,22 @@
-#![allow(unused_imports, dead_code)]
use std::{io, time};
-use std::net::{SocketAddr, Shutdown};
-use std::collections::VecDeque;
-use std::time::Duration;
+use std::net::Shutdown;
-use actix::{fut, Actor, ActorFuture, Arbiter, Context,
+use actix::{fut, Actor, ActorFuture, Context,
Handler, Message, ActorResponse, Supervised};
use actix::registry::ArbiterService;
use actix::fut::WrapFuture;
use actix::actors::{Connector, ConnectorError, Connect as ResolveConnect};
use http::{Uri, HttpTryFrom, Error as HttpError};
-use futures::{Async, Future, Poll};
-use tokio_core::reactor::Timeout;
-use tokio_core::net::{TcpStream, TcpStreamNew};
+use futures::Poll;
use tokio_io::{AsyncRead, AsyncWrite};
#[cfg(feature="alpn")]
-use openssl::ssl::{SslMethod, SslConnector, SslVerifyMode, Error as OpensslError};
+use openssl::ssl::{SslMethod, SslConnector, Error as OpensslError};
#[cfg(feature="alpn")]
use tokio_openssl::SslConnectorExt;
+#[cfg(feature="alpn")]
+use futures::Future;
use HAS_OPENSSL;
use server::IoStream;
@@ -97,7 +94,7 @@ impl Default for ClientConnector {
fn default() -> ClientConnector {
#[cfg(feature="alpn")]
{
- let mut builder = SslConnector::builder(SslMethod::tls()).unwrap();
+ let builder = SslConnector::builder(SslMethod::tls()).unwrap();
ClientConnector {
connector: builder.build()
}
@@ -154,9 +151,7 @@ impl ClientConnector {
/// }
/// ```
pub fn with_connector(connector: SslConnector) -> ClientConnector {
- ClientConnector {
- connector: connector
- }
+ ClientConnector { connector }
}
}
@@ -201,7 +196,7 @@ impl Handler for ClientConnector {
if proto.is_secure() {
fut::Either::A(
_act.connector.connect_async(&host, stream)
- .map_err(|e| ClientConnectorError::SslError(e))
+ .map_err(ClientConnectorError::SslError)
.map(|stream| Connection{stream: Box::new(stream)})
.into_actor(_act))
} else {
diff --git a/src/client/mod.rs b/src/client/mod.rs
index f7b735437..a4ee14178 100644
--- a/src/client/mod.rs
+++ b/src/client/mod.rs
@@ -8,7 +8,24 @@ mod writer;
pub use self::pipeline::{SendRequest, SendRequestError};
pub use self::request::{ClientRequest, ClientRequestBuilder};
-pub use self::response::{ClientResponse, ResponseBody, JsonResponse, UrlEncoded};
+pub use self::response::ClientResponse;
pub use self::connector::{Connect, Connection, ClientConnector, ClientConnectorError};
pub(crate) use self::writer::HttpClientWriter;
pub(crate) use self::parser::{HttpResponseParser, HttpResponseParserError};
+
+
+use httpcodes;
+use httpresponse::HttpResponse;
+use error::ResponseError;
+
+
+/// Convert `SendRequestError` to a `HttpResponse`
+impl ResponseError for SendRequestError {
+
+ fn error_response(&self) -> HttpResponse {
+ match *self {
+ SendRequestError::Connector(_) => httpcodes::HttpBadGateway.into(),
+ _ => httpcodes::HttpInternalServerError.into(),
+ }
+ }
+}
diff --git a/src/client/parser.rs b/src/client/parser.rs
index b4ce9b2b2..8fe399009 100644
--- a/src/client/parser.rs
+++ b/src/client/parser.rs
@@ -37,25 +37,22 @@ impl HttpResponseParser {
where T: IoStream
{
// if buf is empty parse_message will always return NotReady, let's avoid that
- let read = if buf.is_empty() {
+ if buf.is_empty() {
match utils::read_from_io(io, buf) {
- Ok(Async::Ready(0)) => {
- // debug!("Ignored premature client disconnection");
- return Err(HttpResponseParserError::Disconnect);
- },
+ Ok(Async::Ready(0)) =>
+ return Err(HttpResponseParserError::Disconnect),
Ok(Async::Ready(_)) => (),
Ok(Async::NotReady) =>
return Ok(Async::NotReady),
Err(err) =>
return Err(HttpResponseParserError::Error(err.into()))
}
- false
- } else {
- true
- };
+ }
loop {
- match HttpResponseParser::parse_message(buf).map_err(HttpResponseParserError::Error)? {
+ match HttpResponseParser::parse_message(buf)
+ .map_err(HttpResponseParserError::Error)?
+ {
Async::Ready((msg, decoder)) => {
self.decoder = decoder;
return Ok(Async::Ready(msg));
@@ -64,15 +61,13 @@ impl HttpResponseParser {
if buf.capacity() >= MAX_BUFFER_SIZE {
return Err(HttpResponseParserError::Error(ParseError::TooLarge));
}
- if read {
- match utils::read_from_io(io, buf) {
- Ok(Async::Ready(0)) => return Err(HttpResponseParserError::Disconnect),
- Ok(Async::Ready(_)) => (),
- Ok(Async::NotReady) => return Ok(Async::NotReady),
- Err(err) => return Err(HttpResponseParserError::Error(err.into())),
- }
- } else {
- return Ok(Async::NotReady)
+ match utils::read_from_io(io, buf) {
+ Ok(Async::Ready(0)) =>
+ return Err(HttpResponseParserError::Disconnect),
+ Ok(Async::Ready(_)) => (),
+ Ok(Async::NotReady) => return Ok(Async::NotReady),
+ Err(err) =>
+ return Err(HttpResponseParserError::Error(err.into())),
}
},
}
@@ -83,20 +78,44 @@ impl HttpResponseParser {
-> Poll