diff --git a/.travis.yml b/.travis.yml
index 4642eb065..50f33316c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,27 @@
language: rust
-
-rust:
- - 1.20.0
- - stable
- - beta
- - nightly-2018-01-03
-
-sudo: required
+sudo: false
dist: trusty
+cache:
+ cargo: true
+ apt: true
+
+matrix:
+ include:
+ - rust: 1.20.0
+ - rust: stable
+ - rust: beta
+ - rust: nightly
+ allow_failures:
+ - rust: nightly
+ - rust: beta
+
+#rust:
+# - 1.20.0
+# - stable
+# - beta
+# - nightly-2018-01-03
+
env:
global:
- RUSTFLAGS="-C link-dead-code"
@@ -29,26 +42,26 @@ before_script:
script:
- |
- if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
+ if [[ "$TRAVIS_RUST_VERSION" == "1.20.0" ]]; then
+ cargo clean
USE_SKEPTIC=1 cargo test --features=alpn
else
- cargo test --features=alpn
+ cargo clean
+ cargo test
+ # --features=alpn
fi
- |
- if [[ "$TRAVIS_RUST_VERSION" == "1.20.0" ]]; then
+ if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
cd examples/basics && cargo check && cd ../..
cd examples/hello-world && cargo check && cd ../..
cd examples/multipart && cargo check && cd ../..
cd examples/json && cargo check && cd ../..
cd examples/template_tera && cargo check && cd ../..
- fi
- - |
- if [[ "$TRAVIS_RUST_VERSION" == "beta" ]]; then
- cd examples/diesel && cargo check && cd ../..
- cd examples/tls && cargo check && cd ../..
- cd examples/websocket-chat && cargo check && cd ../..
- cd examples/websocket && cargo check && cd ../..
+ cd examples/diesel && cargo check && cd ../..
+ cd examples/tls && cargo check && cd ../..
+ cd examples/websocket-chat && cargo check && cd ../..
+ cd examples/websocket && cargo check && cd ../..
fi
- |
if [[ "$TRAVIS_RUST_VERSION" == "nightly" && $CLIPPY ]]; then
@@ -58,7 +71,7 @@ script:
# Upload docs
after_success:
- |
- if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "nightly-2018-01-03" ]]; then
+ if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "1.20.0" ]]; then
cargo doc --features alpn --no-deps &&
echo "" > target/doc/index.html &&
cargo install mdbook &&
diff --git a/CHANGES.md b/CHANGES.md
index 22b422667..1b149db8c 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,7 +1,46 @@
# Changes
+## 0.3.4 (2018-..-..)
-## 0.3.0 (2017-xx-xx)
+* Fix request json loader
+
+* Added HttpRequest::mime_type() method
+
+
+## 0.3.3 (2018-01-25)
+
+* Stop processing any events after context stop
+
+* Re-enable write back-pressure for h1 connections
+
+* Refactor HttpServer::start_ssl() method
+
+* Upgrade openssl to 0.10
+
+
+## 0.3.2 (2018-01-21)
+
+* Fix HEAD requests handling
+
+* Log request processing errors
+
+* Always enable content encoding if encoding explicitly selected
+
+* Allow multiple Applications on a single server with different state #49
+
+* CORS middleware: allowed_headers is defaulting to None #50
+
+
+## 0.3.1 (2018-01-13)
+
+* Fix directory entry path #47
+
+* Do not enable chunked encoding for HTTP/1.0
+
+* Allow explicitly disable chunked encoding
+
+
+## 0.3.0 (2018-01-12)
* HTTP/2 Support
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..599b28c0d
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,46 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at fafhrd91@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/Cargo.toml b/Cargo.toml
index 5f9f27734..46afb692c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "actix-web"
-version = "0.3.0"
+version = "0.3.3"
authors = ["Nikolay Kim "]
description = "Actix web framework"
readme = "README.md"
@@ -11,7 +11,8 @@ documentation = "https://docs.rs/actix-web/"
categories = ["network-programming", "asynchronous",
"web-programming::http-server", "web-programming::websocket"]
license = "MIT/Apache-2.0"
-exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
+exclude = [".gitignore", ".travis.yml", ".cargo/config",
+ "appveyor.yml", "/examples/**"]
build = "build.rs"
[badges]
@@ -33,31 +34,29 @@ tls = ["native-tls", "tokio-tls"]
alpn = ["openssl", "openssl/v102", "openssl/v110", "tokio-openssl"]
[dependencies]
-log = "0.3"
+log = "0.4"
failure = "0.1"
failure_derive = "0.1"
-time = "0.1"
+h2 = "0.1"
http = "^0.1.2"
-httparse = "0.1"
+httparse = "1.2"
http-range = "0.1"
+time = "0.1"
mime = "0.3"
mime_guess = "1.8"
regex = "0.2"
-sha1 = "0.2"
-url = "1.5"
+sha1 = "0.4"
+url = "1.6"
libc = "0.2"
serde = "1.0"
serde_json = "1.0"
-flate2 = "0.2"
brotli2 = "^0.3.2"
percent-encoding = "1.0"
smallvec = "0.6"
bitflags = "1.0"
num_cpus = "1.0"
-
-# temp solution
-# cookie = { version="0.10", features=["percent-encode", "secure"] }
-cookie = { git="https://github.com/alexcrichton/cookie-rs.git", features=["percent-encode", "secure"] }
+flate2 = "1.0"
+cookie = { version="0.10", features=["percent-encode", "secure"] }
# io
mio = "0.6"
@@ -67,25 +66,19 @@ futures = "0.1"
tokio-io = "0.1"
tokio-core = "0.1"
-h2 = { git = 'https://github.com/carllerche/h2' }
-
# native-tls
native-tls = { version="0.1", optional = true }
tokio-tls = { version="0.1", optional = true }
# openssl
-tokio-openssl = { version="0.1", optional = true }
+openssl = { version="0.10", optional = true }
+tokio-openssl = { version="0.2", optional = true }
[dependencies.actix]
-#version = "^0.4.2"
-git = "https://github.com/actix/actix.git"
-
-[dependencies.openssl]
-version = "0.9"
-optional = true
+version = "^0.4.5"
[dev-dependencies]
-env_logger = "0.4"
+env_logger = "0.5"
reqwest = "0.8"
skeptic = "0.13"
serde_derive = "1.0"
@@ -97,7 +90,6 @@ version_check = "0.1"
[profile.release]
lto = true
opt-level = 3
-# debug = true
[workspace]
members = [
diff --git a/README.md b/README.md
index 124fb9e83..83fcc964f 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, down-to-earth, open source rust web framework.
+Actix web is a small, fast, pragmatic, open source rust web framework.
```rust,ignore
extern crate actix_web;
@@ -24,6 +24,7 @@ fn main() {
* [User Guide](http://actix.github.io/actix-web/guide/)
* [API Documentation (Development)](http://actix.github.io/actix-web/actix_web/)
* [API Documentation (Releases)](https://docs.rs/actix-web/)
+* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-web](https://crates.io/crates/actix-web)
* Minimum supported Rust version: 1.20 or later
@@ -39,7 +40,8 @@ fn main() {
* Multipart streams
* 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),
- [DefaultHeaders](https://actix.github.io/actix-web/guide/qs_10.html#default-headers))
+ [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).
## Benchmarks
@@ -48,7 +50,7 @@ Some basic benchmarks could be found in this [respository](https://github.com/fa
## Examples
-* [Basic](https://github.com/actix/actix-web/tree/master/examples/basic/)
+* [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/)
* [Simple websocket session](https://github.com/actix/actix-web/tree/master/examples/websocket/)
@@ -68,4 +70,8 @@ This project is licensed under either of
at your option.
-[![Analytics](https://ga-beacon.appspot.com/UA-110322332-2/actix-web/readme?flat&useReferer)](https://github.com/igrigorik/ga-beacon)
+## Code of Conduct
+
+Contribution to the actix-web crate is organized under the terms of the
+Contributor Covenant, the maintainer of actix-web, @fafhrd91, promises to
+intervene to uphold that code of conduct.
diff --git a/build.rs b/build.rs
index 2346ab169..887444c68 100644
--- a/build.rs
+++ b/build.rs
@@ -25,6 +25,7 @@ fn main() {
"guide/src/qs_10.md",
"guide/src/qs_12.md",
"guide/src/qs_13.md",
+ "guide/src/qs_14.md",
]);
} else {
let _ = fs::File::create(f);
diff --git a/examples/basics/Cargo.toml b/examples/basics/Cargo.toml
index 88b5f61e0..fd1f1ce4f 100644
--- a/examples/basics/Cargo.toml
+++ b/examples/basics/Cargo.toml
@@ -6,6 +6,6 @@ workspace = "../.."
[dependencies]
futures = "*"
-env_logger = "0.4"
+env_logger = "0.5"
actix = "0.4"
-actix-web = { git = "https://github.com/actix/actix-web" }
+actix-web = { path="../.." }
diff --git a/examples/basics/README.md b/examples/basics/README.md
index 154fad9de..82e35e06e 100644
--- a/examples/basics/README.md
+++ b/examples/basics/README.md
@@ -16,4 +16,5 @@ cargo run
- [http://localhost:8080/async/bob](http://localhost:8080/async/bob)
- [http://localhost:8080/user/bob/](http://localhost:8080/user/bob/) plain/text download
- [http://localhost:8080/test](http://localhost:8080/test) (return status switch GET or POST or other)
-- [http://localhost:8080/static/index.html](http://localhost:8080/static/index.html)
\ No newline at end of file
+- [http://localhost:8080/static/index.html](http://localhost:8080/static/index.html)
+- [http://localhost:8080/static/notexit](http://localhost:8080/static/notexit) display 404 page
diff --git a/examples/basics/src/main.rs b/examples/basics/src/main.rs
index 68dc17f30..f52b09544 100644
--- a/examples/basics/src/main.rs
+++ b/examples/basics/src/main.rs
@@ -7,6 +7,7 @@ extern crate env_logger;
extern crate futures;
use futures::Stream;
+use std::{io, env};
use actix_web::*;
use actix_web::middleware::RequestSession;
use futures::future::{FutureResult, result};
@@ -56,17 +57,17 @@ fn index(mut req: HttpRequest) -> Result {
fn p404(req: HttpRequest) -> Result {
// html
- let html = format!(r#"actix - basics
+ let html = r#"actix - basicsback to home
404
-"#);
+"#;
// response
Ok(HttpResponse::build(StatusCode::NOT_FOUND)
.content_type("text/html; charset=utf-8")
- .body(&html).unwrap())
+ .body(html).unwrap())
}
@@ -92,8 +93,9 @@ fn with_param(req: HttpRequest) -> Result
}
fn main() {
- ::std::env::set_var("RUST_LOG", "actix_web=info");
- let _ = env_logger::init();
+ env::set_var("RUST_LOG", "actix_web=debug");
+ env::set_var("RUST_BACKTRACE", "1");
+ env_logger::init();
let sys = actix::System::new("basic-example");
let addr = HttpServer::new(
@@ -121,6 +123,9 @@ fn main() {
_ => httpcodes::HTTPNotFound,
}
}))
+ .resource("/error.html", |r| r.f(|req| {
+ error::ErrorBadRequest(io::Error::new(io::ErrorKind::Other, "test"))
+ }))
// static files
.handler("/static/", fs::StaticFiles::new("../static/", true))
// redirect
diff --git a/examples/diesel/Cargo.toml b/examples/diesel/Cargo.toml
index eb6628375..f9dcf1c78 100644
--- a/examples/diesel/Cargo.toml
+++ b/examples/diesel/Cargo.toml
@@ -5,9 +5,9 @@ authors = ["Nikolay Kim "]
workspace = "../.."
[dependencies]
-env_logger = "0.4"
+env_logger = "0.5"
actix = "0.4"
-actix-web = { git = "https://github.com/actix/actix-web" }
+actix-web = { path = "../../" }
futures = "0.1"
uuid = { version = "0.5", features = ["serde", "v4"] }
diff --git a/examples/diesel/src/db.rs b/examples/diesel/src/db.rs
index 04daa6ed0..4ca85130e 100644
--- a/examples/diesel/src/db.rs
+++ b/examples/diesel/src/db.rs
@@ -8,7 +8,7 @@ use diesel::prelude::*;
use models;
use schema;
-/// This is db executor actor. We are going to run 3 of them in parallele.
+/// This is db executor actor. We are going to run 3 of them in parallel.
pub struct DbExecutor(pub SqliteConnection);
/// This is only message that this actor can handle, but it is easy to extend number of
diff --git a/examples/hello-world/Cargo.toml b/examples/hello-world/Cargo.toml
index 4cb1f70f7..20a93788a 100644
--- a/examples/hello-world/Cargo.toml
+++ b/examples/hello-world/Cargo.toml
@@ -5,6 +5,6 @@ authors = ["Nikolay Kim "]
workspace = "../.."
[dependencies]
-env_logger = "0.4"
+env_logger = "0.5"
actix = "0.4"
actix-web = { path = "../../" }
diff --git a/examples/json/Cargo.toml b/examples/json/Cargo.toml
index 681b63450..3d2680b07 100644
--- a/examples/json/Cargo.toml
+++ b/examples/json/Cargo.toml
@@ -15,4 +15,4 @@ serde_derive = "1.0"
json = "*"
actix = "0.4"
-actix-web = { git = "https://github.com/actix/actix-web" }
+actix-web = { path="../../" }
diff --git a/examples/multipart/Cargo.toml b/examples/multipart/Cargo.toml
index 32edbea61..c8f1c4159 100644
--- a/examples/multipart/Cargo.toml
+++ b/examples/multipart/Cargo.toml
@@ -12,4 +12,4 @@ path = "src/main.rs"
env_logger = "*"
futures = "0.1"
actix = "0.4"
-actix-web = { git = "https://github.com/actix/actix-web" }
+actix-web = { path="../../" }
diff --git a/examples/state/Cargo.toml b/examples/state/Cargo.toml
index 149e8128e..0880ced5f 100644
--- a/examples/state/Cargo.toml
+++ b/examples/state/Cargo.toml
@@ -6,6 +6,6 @@ workspace = "../.."
[dependencies]
futures = "*"
-env_logger = "0.4"
+env_logger = "0.5"
actix = "0.4"
-actix-web = { git = "https://github.com/actix/actix-web" }
\ No newline at end of file
+actix-web = { path = "../../" }
diff --git a/examples/state/src/main.rs b/examples/state/src/main.rs
index 395007aed..5bb7e5043 100644
--- a/examples/state/src/main.rs
+++ b/examples/state/src/main.rs
@@ -1,5 +1,5 @@
#![cfg_attr(feature="cargo-clippy", allow(needless_pass_by_value))]
-//! There are two level of statfulness in actix-web. Application has state
+//! There are two level of statefulness in actix-web. Application has state
//! that is shared across all handlers within same Application.
//! And individual handler can have state.
@@ -33,7 +33,7 @@ struct MyWebSocket {
}
impl Actor for MyWebSocket {
- type Context = HttpContext;
+ type Context = ws::WebsocketContext;
}
impl Handler for MyWebSocket {
@@ -43,9 +43,9 @@ impl Handler for MyWebSocket {
self.counter += 1;
println!("WS({}): {:?}", self.counter, msg);
match msg {
- ws::Message::Ping(msg) => ws::WsWriter::pong(ctx, &msg),
- ws::Message::Text(text) => ws::WsWriter::text(ctx, &text),
- ws::Message::Binary(bin) => ws::WsWriter::binary(ctx, bin),
+ 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 => {
ctx.stop();
}
diff --git a/examples/template_tera/Cargo.toml b/examples/template_tera/Cargo.toml
index 3862fb803..400c367a8 100644
--- a/examples/template_tera/Cargo.toml
+++ b/examples/template_tera/Cargo.toml
@@ -5,7 +5,7 @@ authors = ["Nikolay Kim "]
workspace = "../.."
[dependencies]
-env_logger = "0.4"
+env_logger = "0.5"
actix = "0.4"
-actix-web = { git = "https://github.com/actix/actix-web" }
+actix-web = { path = "../../" }
tera = "*"
diff --git a/examples/tls/Cargo.toml b/examples/tls/Cargo.toml
index e6d39742d..4d227c7c3 100644
--- a/examples/tls/Cargo.toml
+++ b/examples/tls/Cargo.toml
@@ -9,6 +9,7 @@ name = "server"
path = "src/main.rs"
[dependencies]
-env_logger = "0.4"
-actix = "0.4"
-actix-web = { git = "https://github.com/actix/actix-web", features=["alpn"] }
+env_logger = "0.5"
+actix = "^0.4.2"
+actix-web = { path = "../../", features=["alpn"] }
+openssl = { version="0.10", features = ["v110"] }
diff --git a/examples/tls/cert.pem b/examples/tls/cert.pem
new file mode 100644
index 000000000..159aacea2
--- /dev/null
+++ b/examples/tls/cert.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFPjCCAyYCCQDvLYiYD+jqeTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJV
+UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMRAwDgYDVQQKDAdDb21wYW55MQww
+CgYDVQQLDANPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xODAxMjUx
+NzQ2MDFaFw0xOTAxMjUxNzQ2MDFaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJD
+QTELMAkGA1UEBwwCU0YxEDAOBgNVBAoMB0NvbXBhbnkxDDAKBgNVBAsMA09yZzEY
+MBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEA2WzIA2IpVR9Tb9EFhITlxuhE5rY2a3S6qzYNzQVgSFggxXEPn8k1
+sQEcer5BfAP986Sck3H0FvB4Bt/I8PwOtUCmhwcc8KtB5TcGPR4fjXnrpC+MIK5U
+NLkwuyBDKziYzTdBj8kUFX1WxmvEHEgqToPOZfBgsS71cJAR/zOWraDLSRM54jXy
+voLZN4Ti9rQagQrvTQ44Vz5ycDQy7UxtbUGh1CVv69vNVr7/SOOh/Nw5FNOZWLWr
+odGyoec5wh9iqRZgRqiTUc6Lt7V2RWc2X2gjwST2UfI+U46Ip3oaQ7ZD4eAkoqND
+xdniBZAykVG3c/99ux4BAESTF8fsNch6UticBxYMuTu+ouvP0psfI9wwwNliJDmA
+CRUTB9AgRynbL1AzhqQoDfsb98IZfjfNOpwnwuLwpMAPhbgd5KNdZaIJ4Hb6/stI
+yFElOExxd3TAxF2Gshd/lq1JcNHAZ1DSXV5MvOWT/NWgXwbIzUgQ8eIi+HuDYX2U
+UuaB6R8tbd52H7rbUv6HrfinuSlKWqjSYLkiKHkwUpoMw8y9UycRSzs1E9nPwPTO
+vRXb0mNCQeBCV9FvStNVXdCUTT8LGPv87xSD2pmt7LijlE6mHLG8McfcWkzA69un
+CEHIFAFDimTuN7EBljc119xWFTcHMyoZAfFF+oTqwSbBGImruCxnaJECAwEAATAN
+BgkqhkiG9w0BAQsFAAOCAgEApavsgsn7SpPHfhDSN5iZs1ILZQRewJg0Bty0xPfk
+3tynSW6bNH3nSaKbpsdmxxomthNSQgD2heOq1By9YzeOoNR+7Pk3s4FkASnf3ToI
+JNTUasBFFfaCG96s4Yvs8KiWS/k84yaWuU8c3Wb1jXs5Rv1qE1Uvuwat1DSGXSoD
+JNluuIkCsC4kWkyq5pWCGQrabWPRTWsHwC3PTcwSRBaFgYLJaR72SloHB1ot02zL
+d2age9dmFRFLLCBzP+D7RojBvL37qS/HR+rQ4SoQwiVc/JzaeqSe7ZbvEH9sZYEu
+ALowJzgbwro7oZflwTWunSeSGDSltkqKjvWvZI61pwfHKDahUTmZ5h2y67FuGEaC
+CIOUI8dSVSPKITxaq3JL4ze2e9/0Lt7hj19YK2uUmtMAW5Tirz4Yx5lyGH9U8Wur
+y/X8VPxTc4A9TMlJgkyz0hqvhbPOT/zSWB10zXh0glKAsSBryAOEDxV1UygmSir7
+YV8Qaq+oyKUTMc1MFq5vZ07M51EPaietn85t8V2Y+k/8XYltRp32NxsypxAJuyxh
+g/ko6RVTrWa1sMvz/F9LFqAdKiK5eM96lh9IU4xiLg4ob8aS/GRAA8oIFkZFhLrt
+tOwjIUPmEPyHWFi8dLpNuQKYalLYhuwZftG/9xV+wqhKGZO9iPrpHSYBRTap8w2y
+1QU=
+-----END CERTIFICATE-----
diff --git a/examples/tls/identity.pfx b/examples/tls/identity.pfx
deleted file mode 100644
index ac69a0289..000000000
Binary files a/examples/tls/identity.pfx and /dev/null differ
diff --git a/examples/tls/key.pem b/examples/tls/key.pem
new file mode 100644
index 000000000..aac387c64
--- /dev/null
+++ b/examples/tls/key.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/examples/tls/src/main.rs b/examples/tls/src/main.rs
index 15cfcc666..ccdf454df 100644
--- a/examples/tls/src/main.rs
+++ b/examples/tls/src/main.rs
@@ -2,14 +2,13 @@
extern crate actix;
extern crate actix_web;
extern crate env_logger;
-
-use std::fs::File;
-use std::io::Read;
+extern crate openssl;
use actix_web::*;
+use openssl::ssl::{SslMethod, SslAcceptor, SslFiletype};
-/// somple handle
+/// simple handle
fn index(req: HttpRequest) -> Result {
println!("{:?}", req);
Ok(httpcodes::HTTPOk
@@ -20,15 +19,15 @@ fn index(req: HttpRequest) -> Result {
fn main() {
if ::std::env::var("RUST_LOG").is_err() {
- ::std::env::set_var("RUST_LOG", "actix_web=trace");
+ ::std::env::set_var("RUST_LOG", "actix_web=info");
}
let _ = env_logger::init();
let sys = actix::System::new("ws-example");
- let mut file = File::open("identity.pfx").unwrap();
- let mut pkcs12 = vec![];
- file.read_to_end(&mut pkcs12).unwrap();
- let pkcs12 = Pkcs12::from_der(&pkcs12).unwrap().parse("12345").unwrap();
+ // load ssl keys
+ let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
+ builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
+ builder.set_certificate_chain_file("cert.pem").unwrap();
let addr = HttpServer::new(
|| Application::new()
@@ -44,7 +43,7 @@ fn main() {
.body(Body::Empty)
})))
.bind("127.0.0.1:8443").unwrap()
- .start_ssl(&pkcs12).unwrap();
+ .start_ssl(builder).unwrap();
println!("Started http server: 127.0.0.1:8443");
let _ = sys.run();
diff --git a/examples/websocket-chat/Cargo.toml b/examples/websocket-chat/Cargo.toml
index a155e0e11..0eac954dc 100644
--- a/examples/websocket-chat/Cargo.toml
+++ b/examples/websocket-chat/Cargo.toml
@@ -25,6 +25,5 @@ serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
-#actix = "0.4"
-actix = { git = "https://github.com/actix/actix" }
-actix-web = { git = "https://github.com/actix/actix-web" }
+actix = "^0.4.2"
+actix-web = { path="../../" }
diff --git a/examples/websocket-chat/README.md b/examples/websocket-chat/README.md
index 28d734dd3..a01dd68b7 100644
--- a/examples/websocket-chat/README.md
+++ b/examples/websocket-chat/README.md
@@ -16,8 +16,8 @@ Chat server listens for incoming tcp connections. Server can access several type
* `\list` - list all available rooms
* `\join name` - join room, if room does not exist, create new one
* `\name name` - set session name
-* `some message` - just string, send messsage to all peers in same room
-* client has to send heartbeat `Ping` messages, if server does not receive a heartbeat message for 10 seconds connection gets droppped
+* `some message` - just string, send message to all peers in same room
+* client has to send heartbeat `Ping` messages, if server does not receive a heartbeat message for 10 seconds connection gets dropped
To start server use command: `cargo run --bin server`
diff --git a/examples/websocket-chat/src/main.rs b/examples/websocket-chat/src/main.rs
index aec05ec74..8051e0a76 100644
--- a/examples/websocket-chat/src/main.rs
+++ b/examples/websocket-chat/src/main.rs
@@ -52,7 +52,7 @@ struct WsChatSession {
}
impl Actor for WsChatSession {
- type Context = HttpContext;
+ type Context = ws::WebsocketContext;
/// Method is called on actor start.
/// We register ws session with ChatServer
@@ -87,7 +87,7 @@ impl Handler for WsChatSession {
type Result = ();
fn handle(&mut self, msg: session::Message, ctx: &mut Self::Context) {
- ws::WsWriter::text(ctx, &msg.0);
+ ctx.text(&msg.0);
}
}
@@ -98,10 +98,8 @@ impl Handler for WsChatSession {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
println!("WEBSOCKET MESSAGE: {:?}", msg);
match msg {
- ws::Message::Ping(msg) =>
- ws::WsWriter::pong(ctx, &msg),
- ws::Message::Pong(msg) =>
- self.hb = Instant::now(),
+ ws::Message::Ping(msg) => ctx.pong(&msg),
+ ws::Message::Pong(msg) => self.hb = Instant::now(),
ws::Message::Text(text) => {
let m = text.trim();
// we check for /sss type of messages
@@ -115,7 +113,7 @@ impl Handler for WsChatSession {
match res {
Ok(Ok(rooms)) => {
for room in rooms {
- ws::WsWriter::text(ctx, &room);
+ ctx.text(&room);
}
},
_ => println!("Something is wrong"),
@@ -132,20 +130,19 @@ impl Handler for WsChatSession {
ctx.state().addr.send(
server::Join{id: self.id, name: self.room.clone()});
- ws::WsWriter::text(ctx, "joined");
+ ctx.text("joined");
} else {
- ws::WsWriter::text(ctx, "!!! room name is required");
+ ctx.text("!!! room name is required");
}
},
"/name" => {
if v.len() == 2 {
self.name = Some(v[1].to_owned());
} else {
- ws::WsWriter::text(ctx, "!!! name is required");
+ ctx.text("!!! name is required");
}
},
- _ => ws::WsWriter::text(
- ctx, &format!("!!! unknown command: {:?}", m)),
+ _ => ctx.text(&format!("!!! unknown command: {:?}", m)),
}
} else {
let msg = if let Some(ref name) = self.name {
diff --git a/examples/websocket-chat/src/session.rs b/examples/websocket-chat/src/session.rs
index b0725fde4..66062533f 100644
--- a/examples/websocket-chat/src/session.rs
+++ b/examples/websocket-chat/src/session.rs
@@ -16,7 +16,7 @@ use codec::{ChatRequest, ChatResponse, ChatCodec};
#[derive(Message)]
pub struct Message(pub String);
-/// `ChatSession` actor is responsible for tcp peer communitions.
+/// `ChatSession` actor is responsible for tcp peer communications.
pub struct ChatSession {
/// unique session id
id: usize,
@@ -30,7 +30,7 @@ pub struct ChatSession {
impl Actor for ChatSession {
/// For tcp communication we are going to use `FramedContext`.
- /// It is convinient wrapper around `Framed` object from `tokio_io`
+ /// It is convenient wrapper around `Framed` object from `tokio_io`
type Context = FramedContext;
fn started(&mut self, ctx: &mut Self::Context) {
@@ -149,7 +149,7 @@ impl ChatSession {
}
-/// Define tcp server that will accept incomint tcp connection and create
+/// Define tcp server that will accept incoming tcp connection and create
/// chat actors.
pub struct TcpServer {
chat: SyncAddress,
diff --git a/examples/websocket/Cargo.toml b/examples/websocket/Cargo.toml
index e75f5c390..626bfdb48 100644
--- a/examples/websocket/Cargo.toml
+++ b/examples/websocket/Cargo.toml
@@ -10,6 +10,5 @@ path = "src/main.rs"
[dependencies]
env_logger = "*"
futures = "0.1"
-#actix = "0.4"
-actix = { git = "https://github.com/actix/actix.git" }
+actix = "^0.4.2"
actix-web = { git = "https://github.com/actix/actix-web.git" }
diff --git a/examples/websocket/src/main.rs b/examples/websocket/src/main.rs
index fea8929de..a6abac908 100644
--- a/examples/websocket/src/main.rs
+++ b/examples/websocket/src/main.rs
@@ -21,20 +21,20 @@ fn ws_index(r: HttpRequest) -> Result {
struct MyWebSocket;
impl Actor for MyWebSocket {
- type Context = HttpContext;
+ type Context = ws::WebsocketContext;
}
/// Handler for `ws::Message`
impl Handler for MyWebSocket {
type Result = ();
- fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext) {
+ fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
// process websocket messages
println!("WS: {:?}", msg);
match msg {
- ws::Message::Ping(msg) => ws::WsWriter::pong(ctx, &msg),
- ws::Message::Text(text) => ws::WsWriter::text(ctx, &text),
- ws::Message::Binary(bin) => ws::WsWriter::binary(ctx, bin),
+ 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 => {
ctx.stop();
}
diff --git a/guide/src/qs_1.md b/guide/src/qs_1.md
index 8d2ee83c2..c9fbc8f35 100644
--- a/guide/src/qs_1.md
+++ b/guide/src/qs_1.md
@@ -17,7 +17,7 @@ If you already have rustup installed, run this command to ensure you have the la
rustup update
```
-Actix web framework requies rust version 1.20 and up.
+Actix web framework requires rust version 1.20 and up.
## Running Examples
diff --git a/guide/src/qs_10.md b/guide/src/qs_10.md
index 8974f241d..1334ecdbe 100644
--- a/guide/src/qs_10.md
+++ b/guide/src/qs_10.md
@@ -1,7 +1,7 @@
# Middlewares
-Actix middlewares system allows to add additional behaviour to request/response processing.
-Middleware can hook into incomnig request process and modify request or halt request
+Actix middlewares system allows to add additional behavior to request/response processing.
+Middleware can hook into incoming request process and modify request or halt request
processing and return response early. Also it can hook into response processing.
Typically middlewares involves in following actions:
@@ -12,9 +12,9 @@ Typically middlewares involves in following actions:
* Access external services (redis, logging, sessions)
Middlewares are registered for each application and get executed in same order as
-registraton order. In general, *middleware* is a type that implements
+registration order. In general, *middleware* is a type that implements
[*Middleware trait*](../actix_web/middlewares/trait.Middleware.html). Each method
-in this trait has default implementation. Each method can return result immidietly
+in this trait has default implementation. Each method can return result immediately
or *future* object.
Here is example of simple middleware that adds request and response headers:
@@ -34,19 +34,19 @@ impl Middleware for Headers {
/// Method is called when request is ready. It may return
/// future, which should resolve before next middleware get called.
- fn start(&self, req: &mut HttpRequest) -> Started {
+ fn start(&self, req: &mut HttpRequest) -> Result {
req.headers_mut().insert(
header::CONTENT_TYPE, header::HeaderValue::from_static("text/plain"));
- Started::Done
+ Ok(Started::Done)
}
/// Method is called when handler returns response,
/// but before sending http message to peer.
- fn response(&self, req: &mut HttpRequest, mut resp: HttpResponse) -> Response {
+ fn response(&self, req: &mut HttpRequest, mut resp: HttpResponse) -> Result {
resp.headers_mut().insert(
header::HeaderName::try_from("X-VERSION").unwrap(),
header::HeaderValue::from_static("0.2"));
- Response::Done(resp)
+ Ok(Response::Done(resp))
}
}
@@ -148,7 +148,7 @@ fn main() {
## User sessions
Actix provides general solution for session management.
-[*Session storage*](../actix_web/middleware/struct.SessionStorage.html) middleare can be
+[*Session storage*](../actix_web/middleware/struct.SessionStorage.html) middleware can be
use with different backend types to store session data in different backends.
By default only cookie session backend is implemented. Other backend implementations
could be added later.
@@ -162,7 +162,7 @@ You need to pass a random value to the constructor of *CookieSessionBackend*.
This is private key for cookie session. When this value is changed, all session data is lost.
Note that whatever you write into your session is visible by the user (but not modifiable).
-In general case, you cretate
+In general case, you create
[*Session storage*](../actix_web/middleware/struct.SessionStorage.html) middleware
and initializes it with specific backend implementation, like *CookieSessionBackend*.
To access session data
diff --git a/guide/src/qs_13.md b/guide/src/qs_13.md
index 193b2e109..d0d794979 100644
--- a/guide/src/qs_13.md
+++ b/guide/src/qs_13.md
@@ -4,7 +4,7 @@ Actix web automatically upgrades connection to *HTTP/2.0* if possible.
## Negotiation
-*HTTP/2.0* protocol over tls without prior knowlage requires
+*HTTP/2.0* protocol over tls without prior knowledge requires
[tls alpn](https://tools.ietf.org/html/rfc7301). At the moment only
`rust-openssl` has support. Turn on `alpn` feature to enable `alpn` negotiation.
With enable `alpn` feature `HttpServer` provides
@@ -12,24 +12,26 @@ With enable `alpn` feature `HttpServer` provides
```toml
[dependencies]
-actix-web = { git = "https://github.com/actix/actix-web", features=["alpn"] }
+actix-web = { version = "0.3.3", features=["alpn"] }
+openssl = { version="0.10", features = ["v110"] }
```
```rust,ignore
use std::fs::File;
use actix_web::*;
+use openssl::ssl::{SslMethod, SslAcceptor, SslFiletype};
fn main() {
- let mut file = File::open("identity.pfx").unwrap();
- let mut pkcs12 = vec![];
- file.read_to_end(&mut pkcs12).unwrap();
- let pkcs12 = Pkcs12::from_der(&pkcs12).unwrap().parse("12345").unwrap();
+ // load ssl keys
+ let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
+ builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
+ builder.set_certificate_chain_file("cert.pem").unwrap();
HttpServer::new(
|| Application::new()
.resource("/index.html", |r| r.f(index)))
.bind("127.0.0.1:8080").unwrap();
- .serve_ssl(pkcs12).unwrap();
+ .serve_ssl(builder).unwrap();
}
```
diff --git a/guide/src/qs_14.md b/guide/src/qs_14.md
index 26fa4ecfb..f29ce5634 100644
--- a/guide/src/qs_14.md
+++ b/guide/src/qs_14.md
@@ -36,8 +36,9 @@ We can send `CreateUser` message to `DbExecutor` actor, and as result we get
```rust,ignore
impl Handler for DbExecutor {
+ type Result = Result
- fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Response
+ fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result
{
use self::schema::users::dsl::*;
@@ -59,7 +60,7 @@ impl Handler for DbExecutor {
.load::(&self.0)
.expect("Error loading person");
- Self::reply(items.pop().unwrap())
+ Ok(items.pop().unwrap())
}
}
```
@@ -77,7 +78,7 @@ struct State {
fn main() {
let sys = actix::System::new("diesel-example");
- // Start 3 parallele db executors
+ // Start 3 parallel db executors
let addr = SyncArbiter::start(3, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
@@ -94,7 +95,7 @@ fn main() {
}
```
-And finally we can use address in a requst handler. We get message response
+And finally we can use address in a request handler. We get message response
asynchronously, so handler needs to return future object, also `Route::a()` needs to be
used for async handler registration.
diff --git a/guide/src/qs_2.md b/guide/src/qs_2.md
index 3c347ce65..80852895e 100644
--- a/guide/src/qs_2.md
+++ b/guide/src/qs_2.md
@@ -20,8 +20,8 @@ contains the following:
```toml
[dependencies]
-actix = "0.3"
-actix-web = { git = "https://github.com/actix/actix-web" }
+actix = "0.4"
+actix-web = "0.3"
```
In order to implement a web server, first we need to create a request handler.
@@ -69,7 +69,8 @@ Head over to ``http://localhost:8088/`` to see the results.
Here is full source of main.rs file:
-```rust,ignore
+```rust
+# use std::thread;
# extern crate actix_web;
use actix_web::*;
@@ -78,11 +79,13 @@ fn index(req: HttpRequest) -> &'static str {
}
fn main() {
+# thread::spawn(|| {
HttpServer::new(
|| Application::new()
.resource("/", |r| r.f(index)))
.bind("127.0.0.1:8088").expect("Can not bind to 127.0.0.1:8088")
.run();
+# });
}
```
diff --git a/guide/src/qs_3.md b/guide/src/qs_3.md
index c970b3efe..7a90c3b5d 100644
--- a/guide/src/qs_3.md
+++ b/guide/src/qs_3.md
@@ -2,7 +2,7 @@
Actix web provides some primitives to build web servers and applications with Rust.
It provides routing, middlewares, pre-processing of requests, and post-processing of responses,
-websocket protcol handling, multipart streams, etc.
+websocket protocol handling, multipart streams, etc.
All actix web server is built around `Application` instance.
It is used for registering routes for resources, middlewares.
@@ -10,9 +10,9 @@ Also it stores application specific state that is shared across all handlers
within same application.
Application acts as namespace for all routes, i.e all routes for specific application
-has same url path prefix. Application prefix always contains laading "/" slash.
+has same url path prefix. Application prefix always contains leading "/" slash.
If supplied prefix does not contain leading slash, it get inserted.
-Prefix should consists of valud path segments. i.e for application with prefix `/app`
+Prefix should consists of value path segments. i.e for application with prefix `/app`
any request with following paths `/app`, `/app/` or `/app/test` would match,
but path `/application` would not match.
diff --git a/guide/src/qs_3_5.md b/guide/src/qs_3_5.md
index 580f029d9..7982cd272 100644
--- a/guide/src/qs_3_5.md
+++ b/guide/src/qs_3_5.md
@@ -2,7 +2,7 @@
[*HttpServer*](../actix_web/struct.HttpServer.html) type is responsible for
serving http requests. *HttpServer* accept application factory as a parameter,
-Application factory must have `Send` + `Sync` bounderies. More about that in
+Application factory must have `Send` + `Sync` boundaries. More about that in
*multi-threading* section. To bind to specific socket address `bind()` must be used.
This method could be called multiple times. To start http server one of the *start*
methods could be used. `start()` method start simple server, `start_tls()` or `start_ssl()`
@@ -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.
}
```
diff --git a/guide/src/qs_4.md b/guide/src/qs_4.md
index 42afb9219..e7193ae55 100644
--- a/guide/src/qs_4.md
+++ b/guide/src/qs_4.md
@@ -235,3 +235,12 @@ fn main() {
```
Both methods could be combined. (i.e Async response with streaming body)
+
+## Tokio core handle
+
+Any actix web handler runs within properly configured
+[actix system](https://actix.github.io/actix/actix/struct.System.html)
+and [arbiter](https://actix.github.io/actix/actix/struct.Arbiter.html).
+You can always get access to tokio handle via
+[Arbiter::handle()](https://actix.github.io/actix/actix/struct.Arbiter.html#method.handle)
+method.
diff --git a/guide/src/qs_4_5.md b/guide/src/qs_4_5.md
index ef3a982ae..5a11af733 100644
--- a/guide/src/qs_4_5.md
+++ b/guide/src/qs_4_5.md
@@ -5,7 +5,7 @@ and [`ResponseError` trait](../actix_web/error/trait.ResponseError.html)
for handling handler's errors.
Any error that implements `ResponseError` trait can be returned as error value.
*Handler* can return *Result* object, actix by default provides
-`Responder` implemenation for compatible result object. Here is implementation
+`Responder` implementation for compatible result object. Here is implementation
definition:
```rust,ignore
@@ -134,3 +134,18 @@ fn index(req: HttpRequest) -> Result<&'static str> {
```
In this example *BAD REQUEST* response get generated for `MyError` error.
+
+## Error logging
+
+Actix logs all errors with `WARN` log level. If log level set to `DEBUG`
+and `RUST_BACKTRACE` is enabled, backtrace get logged. The Error type uses
+cause's error backtrace if available, if the underlying failure does not provide
+a backtrace, a new backtrace is constructed pointing to that conversion point
+(rather than the origin of the error). This construction only happens if there
+is no underlying backtrace; if it does have a backtrace no new backtrace is constructed.
+
+You can enable backtrace and debug logging with following command:
+
+```
+>> RUST_BACKTRACE=1 RUST_LOG=actix_web=debug cargo run
+```
diff --git a/guide/src/qs_5.md b/guide/src/qs_5.md
index 1aa7edeb0..1589245a2 100644
--- a/guide/src/qs_5.md
+++ b/guide/src/qs_5.md
@@ -2,15 +2,15 @@
URL dispatch provides a simple way to map URLs to `Handler` code using a simple pattern matching
language. *Regex* crate and it's
-[*RegexSet*](https://doc.rust-lang.org/regex/regex/struct.RegexSet.html) is beeing used for
+[*RegexSet*](https://doc.rust-lang.org/regex/regex/struct.RegexSet.html) is being used for
pattern matching. If one of the patterns matches the path information associated with a request,
a particular handler object is invoked. A handler is a specific object that implements
`Handler` trait, defined in your application, that receives the request and returns
-a response object. More informatin is available in [handler section](../qs_4.html).
+a response object. More information is available in [handler section](../qs_4.html).
## Resource configuration
-Resource configuraiton is the act of adding a new resource to an application.
+Resource configuration is the act of adding a new resource to an application.
A resource has a name, which acts as an identifier to be used for URL generation.
The name also allows developers to add routes to existing resources.
A resource also has a pattern, meant to match against the *PATH* portion of a *URL*,
@@ -19,7 +19,7 @@ port, e.g., */foo/bar* in the *URL* *http://localhost:8080/foo/bar?q=value*).
The [Application::resource](../actix_web/struct.Application.html#method.resource) methods
add a single resource to application routing table. This method accepts *path pattern*
-and resource configuration funnction.
+and resource configuration function.
```rust
# extern crate actix_web;
@@ -39,20 +39,20 @@ fn main() {
}
```
-*Configuraiton function* has following type:
+*Configuration function* has following type:
```rust,ignore
FnOnce(&mut Resource<_>) -> ()
```
-*Configration function* can set name and register specific routes.
+*Configuration function* can set name and register specific routes.
If resource does not contain any route or does not have any matching routes it
returns *NOT FOUND* http resources.
## Configuring a Route
Resource contains set of routes. Each route in turn has set of predicates and handler.
-New route could be crearted with `Resource::route()` method which returns reference
+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`.
@@ -91,17 +91,17 @@ builder-like pattern. Following configuration methods are available:
any number of predicates could be registered for each route.
* [*Route::f()*](../actix_web/struct.Route.html#method.f) method registers handler function
- for this route. Only one handler could be registered. Usually handler registeration
- is the last config operation. Handler fanction could be function or closure and has type
+ for this route. Only one handler could be registered. Usually handler registration
+ is the last config operation. Handler function could be function or closure and has type
`Fn(HttpRequest) -> R + 'static`
* [*Route::h()*](../actix_web/struct.Route.html#method.h) method registers handler object
that implements `Handler` trait. This is similar to `f()` method, only one handler could
- be registered. Handler registeration is the last config operation.
+ be registered. Handler registration is the last config operation.
-* [*Route::a()*](../actix_web/struct.Route.html#method.a) method registers asynchandler
- function for this route. Only one handler could be registered. Handler registeration
- is the last config operation. Handler fanction could be function or closure and has type
+* [*Route::a()*](../actix_web/struct.Route.html#method.a) method registers async handler
+ function for this route. Only one handler could be registered. Handler registration
+ is the last config operation. Handler function could be function or closure and has type
`Fn(HttpRequest) -> Future + 'static`
## Route matching
@@ -112,7 +112,7 @@ against a URL path pattern. `path` represents the path portion of the URL that w
The way that *actix* does this is very simple. When a request enters the system,
for each resource configuration registration present in the system, actix checks
the request's path against the pattern declared. *Regex* crate and it's
-[*RegexSet*](https://doc.rust-lang.org/regex/regex/struct.RegexSet.html) is beeing used for
+[*RegexSet*](https://doc.rust-lang.org/regex/regex/struct.RegexSet.html) is being used for
pattern matching. If resource could not be found, *default resource* get used as matched
resource.
@@ -516,7 +516,7 @@ Predicates can have access to application's state via `HttpRequest::state()` met
Also predicates can store extra information in
[requests`s extensions](../actix_web/struct.HttpRequest.html#method.extensions).
-### Modifing predicate values
+### Modifying predicate values
You can invert the meaning of any predicate value by wrapping it in a `Not` predicate.
For example if you want to return "METHOD NOT ALLOWED" response for all methods
diff --git a/guide/src/qs_7.md b/guide/src/qs_7.md
index 7cce5932b..3a96529a0 100644
--- a/guide/src/qs_7.md
+++ b/guide/src/qs_7.md
@@ -4,7 +4,7 @@
Builder-like patter is used to construct an instance of `HttpResponse`.
`HttpResponse` provides several method that returns `HttpResponseBuilder` instance,
-which is implements various convinience methods that helps build response.
+which is implements various convenience methods that helps build response.
Check [documentation](../actix_web/dev/struct.HttpResponseBuilder.html)
for type description. Methods `.body`, `.finish`, `.json` finalizes response creation and
returns constructed *HttpResponse* instance. if this methods get called for the same
@@ -91,7 +91,7 @@ fn index(mut req: HttpRequest) -> Box> {
# fn main() {}
```
-Or you can manually load payload into memory and ther deserialize it.
+Or you can manually load payload into memory and then deserialize it.
Here is simple example. We will deserialize *MyObj* struct. We need to load request
body first and then deserialize json into object.
@@ -200,7 +200,7 @@ fn index(req: HttpRequest) -> Box> {
match item {
// Handle multipart Field
multipart::MultipartItem::Field(field) => {
- println!("==== FIELD ==== {:?} {:?}", field.heders(), field.content_type());
+ println!("==== FIELD ==== {:?} {:?}", field.headers(), field.content_type());
Either::A(
// Field in turn is a stream of *Bytes* objects
@@ -259,7 +259,7 @@ fn index(mut req: HttpRequest) -> Box> {
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 serveral convinience methods that return
+stream combinators. Also *Payload* provides several convenience methods that return
future object that resolve to Bytes object.
* *readany()* method returns *Stream* of *Bytes* objects.
@@ -283,7 +283,7 @@ use futures::{Future, Stream};
fn index(mut req: HttpRequest) -> Box> {
- req.payload_mut()
+ req.payload()
.readany()
.from_err()
.fold((), |_, chunk| {
diff --git a/guide/src/qs_9.md b/guide/src/qs_9.md
index 9c45fbd04..32fe7d3b6 100644
--- a/guide/src/qs_9.md
+++ b/guide/src/qs_9.md
@@ -3,13 +3,14 @@
Actix supports WebSockets out-of-the-box. It is possible to convert request's `Payload`
to a stream of [*ws::Message*](../actix_web/ws/enum.Message.html) with
a [*ws::WsStream*](../actix_web/ws/struct.WsStream.html) and then use stream
-combinators to handle actual messages. But it is simplier to handle websocket communications
+combinators to handle actual messages. But it is simpler to handle websocket communications
with http actor.
-```rust
-extern crate actix;
-extern crate actix_web;
+This is example of simple websocket echo server:
+```rust
+# extern crate actix;
+# extern crate actix_web;
use actix::*;
use actix_web::*;
@@ -17,18 +18,18 @@ use actix_web::*;
struct Ws;
impl Actor for Ws {
- type Context = HttpContext;
+ type Context = ws::WebsocketContext;
}
/// Define Handler for ws::Message message
impl Handler for Ws {
type Result=();
- fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext) {
+ fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
match msg {
- ws::Message::Ping(msg) => ws::WsWriter::pong(ctx, &msg),
- ws::Message::Text(text) => ws::WsWriter::text(ctx, &text),
- ws::Message::Binary(bin) => ws::WsWriter::binary(ctx, bin),
+ ws::Message::Ping(msg) => ctx.pong(&msg),
+ ws::Message::Text(text) => ctx.text(&text),
+ ws::Message::Binary(bin) => ctx.binary(bin),
_ => (),
}
}
diff --git a/src/application.rs b/src/application.rs
index 1e4d8273c..047364b85 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -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 {
@@ -43,8 +42,8 @@ impl PipelineHandler for Inner {
path.split_at(prefix.len()).1.starts_with('/'))
};
if m {
- let path: &'static str = unsafe{
- mem::transmute(&req.path()[self.prefix+prefix.len()..])};
+ let path: &'static str = unsafe {
+ mem::transmute(&req.path()[self.prefix+prefix.len()..]) };
if path.is_empty() {
req.match_info_mut().add("tail", "");
} else {
@@ -60,9 +59,11 @@ impl PipelineHandler for Inner {
#[cfg(test)]
impl HttpApplication {
+ #[cfg(test)]
pub(crate) fn run(&mut self, req: HttpRequest) -> Reply {
self.inner.borrow_mut().handle(req)
}
+ #[cfg(test)]
pub(crate) fn prepare_request(&self, req: HttpRequest) -> HttpRequest {
req.with_state(Rc::clone(&self.state), self.router.clone())
}
@@ -135,7 +136,7 @@ impl Application where S: 'static {
/// Create application with specific state. Application can be
/// configured with builder-like pattern.
///
- /// State is shared with all reousrces within same application and could be
+ /// State is shared with all resources within same application and could be
/// accessed with `HttpRequest::state()` method.
pub fn with_state(state: S) -> Application {
Application {
@@ -155,7 +156,7 @@ impl Application where S: 'static {
/// Set application prefix
///
/// Only requests that matches application's prefix get processed by this application.
- /// Application prefix always contains laading "/" slash. If supplied prefix
+ /// Application prefix always contains leading "/" slash. If supplied prefix
/// does not contain leading slash, it get inserted. Prefix should
/// consists valid path segments. i.e for application with
/// prefix `/app` any request with following paths `/app`, `/app/` or `/app/test`
@@ -321,9 +322,7 @@ impl Application where S: 'static {
}
/// Register a middleware
- pub fn middleware(mut self, mw: T) -> Application
- where T: Middleware + 'static
- {
+ pub fn middleware>(mut self, mw: M) -> Application {
self.parts.as_mut().expect("Use after finish")
.middlewares.push(Box::new(mw));
self
@@ -359,6 +358,40 @@ impl Application where S: 'static {
middlewares: Rc::new(parts.middlewares),
}
}
+
+ /// Convenience method for creating `Box` instance.
+ ///
+ /// This method is useful if you need to register several application instances
+ /// with different state.
+ ///
+ /// ```rust
+ /// # use std::thread;
+ /// # extern crate actix_web;
+ /// use actix_web::*;
+ ///
+ /// struct State1;
+ ///
+ /// struct State2;
+ ///
+ /// fn main() {
+ /// # thread::spawn(|| {
+ /// HttpServer::new(|| { vec![
+ /// Application::with_state(State1)
+ /// .prefix("/app1")
+ /// .resource("/", |r| r.h(httpcodes::HTTPOk))
+ /// .boxed(),
+ /// Application::with_state(State2)
+ /// .prefix("/app2")
+ /// .resource("/", |r| r.h(httpcodes::HTTPOk))
+ /// .boxed() ]})
+ /// .bind("127.0.0.1:8080").unwrap()
+ /// .run()
+ /// # });
+ /// }
+ /// ```
+ pub fn boxed(mut self) -> Box {
+ Box::new(self.finish())
+ }
}
impl IntoHttpHandler for Application {
diff --git a/src/body.rs b/src/body.rs
index 53af6e40e..ebd011e9c 100644
--- a/src/body.rs
+++ b/src/body.rs
@@ -1,4 +1,4 @@
-use std::fmt;
+use std::{fmt, mem};
use std::rc::Rc;
use std::sync::Arc;
use bytes::{Bytes, BytesMut};
@@ -31,13 +31,8 @@ pub enum Binary {
Bytes(Bytes),
/// Static slice
Slice(&'static [u8]),
- /// Shared bytes body
- SharedBytes(Rc),
- /// Shared stirng body
+ /// Shared string body
SharedString(Rc),
- /// Shared bytes body
- #[doc(hidden)]
- ArcSharedBytes(Arc),
/// Shared string body
#[doc(hidden)]
ArcSharedString(Arc),
@@ -118,8 +113,6 @@ impl Binary {
match *self {
Binary::Bytes(ref bytes) => bytes.len(),
Binary::Slice(slice) => slice.len(),
- Binary::SharedBytes(ref bytes) => bytes.len(),
- Binary::ArcSharedBytes(ref bytes) => bytes.len(),
Binary::SharedString(ref s) => s.len(),
Binary::ArcSharedString(ref s) => s.len(),
}
@@ -129,6 +122,33 @@ impl Binary {
pub fn from_slice(s: &[u8]) -> Binary {
Binary::Bytes(Bytes::from(s))
}
+
+ /// Convert Binary to a Bytes instance
+ pub fn take(&mut self) -> Bytes {
+ mem::replace(self, Binary::Slice(b"")).into()
+ }
+}
+
+impl Clone for Binary {
+ fn clone(&self) -> 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())),
+ }
+ }
+}
+
+impl Into for Binary {
+ fn into(self) -> Bytes {
+ match self {
+ Binary::Bytes(bytes) => bytes,
+ Binary::Slice(slice) => Bytes::from(slice),
+ Binary::SharedString(s) => Bytes::from(s.as_str()),
+ Binary::ArcSharedString(s) => Bytes::from(s.as_str()),
+ }
+ }
}
impl From<&'static str> for Binary {
@@ -173,30 +193,6 @@ impl From for Binary {
}
}
-impl From> for Binary {
- fn from(body: Rc) -> Binary {
- Binary::SharedBytes(body)
- }
-}
-
-impl<'a> From<&'a Rc> for Binary {
- fn from(body: &'a Rc) -> Binary {
- Binary::SharedBytes(Rc::clone(body))
- }
-}
-
-impl From> for Binary {
- fn from(body: Arc) -> Binary {
- Binary::ArcSharedBytes(body)
- }
-}
-
-impl<'a> From<&'a Arc> for Binary {
- fn from(body: &'a Arc) -> Binary {
- Binary::ArcSharedBytes(Arc::clone(body))
- }
-}
-
impl From> for Binary {
fn from(body: Rc) -> Binary {
Binary::SharedString(body)
@@ -226,8 +222,6 @@ impl AsRef<[u8]> for Binary {
match *self {
Binary::Bytes(ref bytes) => bytes.as_ref(),
Binary::Slice(slice) => slice,
- Binary::SharedBytes(ref bytes) => bytes.as_ref(),
- Binary::ArcSharedBytes(ref bytes) => bytes.as_ref(),
Binary::SharedString(ref s) => s.as_bytes(),
Binary::ArcSharedString(ref s) => s.as_bytes(),
}
@@ -242,7 +236,6 @@ mod tests {
fn test_body_is_streaming() {
assert_eq!(Body::Empty.is_streaming(), false);
assert_eq!(Body::Binary(Binary::from("")).is_streaming(), false);
- // assert_eq!(Body::Streaming.is_streaming(), true);
}
#[test]
@@ -277,15 +270,6 @@ mod tests {
assert_eq!(Binary::from(Bytes::from("test")).as_ref(), "test".as_bytes());
}
- #[test]
- fn test_rc_bytes() {
- let b = Rc::new(Bytes::from("test"));
- assert_eq!(Binary::from(b.clone()).len(), 4);
- assert_eq!(Binary::from(b.clone()).as_ref(), "test".as_bytes());
- assert_eq!(Binary::from(&b).len(), 4);
- assert_eq!(Binary::from(&b).as_ref(), "test".as_bytes());
- }
-
#[test]
fn test_ref_string() {
let b = Rc::new("test".to_owned());
@@ -302,15 +286,6 @@ mod tests {
assert_eq!(Binary::from(&b).as_ref(), "test".as_bytes());
}
- #[test]
- fn test_arc_bytes() {
- let b = Arc::new(Bytes::from("test"));
- assert_eq!(Binary::from(b.clone()).len(), 4);
- assert_eq!(Binary::from(b.clone()).as_ref(), "test".as_bytes());
- assert_eq!(Binary::from(&b).len(), 4);
- assert_eq!(Binary::from(&b).as_ref(), "test".as_bytes());
- }
-
#[test]
fn test_arc_string() {
let b = Arc::new("test".to_owned());
@@ -335,4 +310,13 @@ mod tests {
assert_eq!(Binary::from(b.clone()).len(), 4);
assert_eq!(Binary::from(b).as_ref(), "test".as_bytes());
}
+
+ #[test]
+ fn test_binary_into() {
+ let bytes = Bytes::from_static(b"test");
+ let b: Bytes = Binary::from("test").into();
+ assert_eq!(b, bytes);
+ let b: Bytes = Binary::from(bytes.clone()).into();
+ assert_eq!(b, bytes);
+ }
}
diff --git a/src/context.rs b/src/context.rs
index 30d03e8ae..cdeb43d16 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -1,15 +1,15 @@
use std;
use std::marker::PhantomData;
-use std::collections::VecDeque;
use futures::{Async, Future, Poll};
use futures::sync::oneshot::Sender;
use futures::unsync::oneshot;
+use smallvec::SmallVec;
use actix::{Actor, ActorState, ActorContext, AsyncContext,
- Handler, Subscriber, ResponseType, SpawnHandle};
+ Address, SyncAddress, Handler, Subscriber, ResponseType, SpawnHandle};
use actix::fut::ActorFuture;
-use actix::dev::{AsyncContextApi, ActorAddressCell,
- ContextImpl, Envelope, ToEnvelope, RemoteEnvelope};
+use actix::dev::{queue, AsyncContextApi,
+ ContextImpl, ContextProtocol, Envelope, ToEnvelope, RemoteEnvelope};
use body::{Body, Binary};
use error::{Error, Result, ErrorInternalServerError};
@@ -18,38 +18,41 @@ use httprequest::HttpRequest;
pub trait ActorHttpContext: 'static {
fn disconnected(&mut self);
- fn poll(&mut self) -> Poll