mirror of
https://github.com/fafhrd91/actix-web
synced 2025-07-23 09:18:20 +02:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6862aa6ee7 | ||
|
8a22558f25 | ||
|
b5b9f9656e | ||
|
2fffc55d34 | ||
|
7d39f1582e | ||
|
75ed053a35 | ||
|
cfedf5fff4 | ||
|
be73a36339 | ||
|
1ad8ba2604 | ||
|
6848a12095 | ||
|
4797298706 | ||
|
5eaf4cbefd | ||
|
7f1844e541 | ||
|
6c7ac7fc22 | ||
|
42f9e1034b | ||
|
e3cd0fdd13 | ||
|
40ff550460 | ||
|
7119340d44 |
29
CHANGES.md
29
CHANGES.md
@@ -1,5 +1,34 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
|
## [0.6.13] - 2018-06-13
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* http/2 end-of-frame is not set if body is empty bytes #307
|
||||||
|
|
||||||
|
* InternalError can trigger memory unsafety #301
|
||||||
|
|
||||||
|
* Fix docs.rs build
|
||||||
|
|
||||||
|
|
||||||
|
## [0.6.12] - 2018-06-08
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Add `Host` filter #287
|
||||||
|
|
||||||
|
* Allow to filter applications
|
||||||
|
|
||||||
|
* Improved failure interoperability with downcasting #285
|
||||||
|
|
||||||
|
* Allow to use custom resolver for `ClientConnector`
|
||||||
|
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
* `Error::cause()` and introduces failure interoperability functions and downcasting.
|
||||||
|
|
||||||
|
|
||||||
## [0.6.11] - 2018-06-05
|
## [0.6.11] - 2018-06-05
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "actix-web"
|
name = "actix-web"
|
||||||
version = "0.6.11"
|
version = "0.6.13"
|
||||||
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
|
||||||
description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
|
description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
@@ -50,7 +50,7 @@ flate2-rust = ["flate2/rust_backend"]
|
|||||||
features = ["tls", "alpn", "session", "brotli", "flate2-c"]
|
features = ["tls", "alpn", "session", "brotli", "flate2-c"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix = "^0.5.5"
|
actix = "^0.5.8"
|
||||||
|
|
||||||
base64 = "0.9"
|
base64 = "0.9"
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
|
@@ -22,6 +22,7 @@ pub struct HttpApplication<S = ()> {
|
|||||||
prefix_len: usize,
|
prefix_len: usize,
|
||||||
router: Router,
|
router: Router,
|
||||||
inner: Rc<UnsafeCell<Inner<S>>>,
|
inner: Rc<UnsafeCell<Inner<S>>>,
|
||||||
|
filters: Option<Vec<Box<Predicate<S>>>>,
|
||||||
middlewares: Rc<Vec<Box<Middleware<S>>>>,
|
middlewares: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,11 +144,21 @@ impl<S: 'static> HttpHandler for HttpApplication<S> {
|
|||||||
|| path.split_at(self.prefix_len).1.starts_with('/'))
|
|| path.split_at(self.prefix_len).1.starts_with('/'))
|
||||||
};
|
};
|
||||||
if m {
|
if m {
|
||||||
let mut req = req.with_state(Rc::clone(&self.state), self.router.clone());
|
let mut req2 =
|
||||||
let tp = self.get_handler(&mut req);
|
req.clone_with_state(Rc::clone(&self.state), self.router.clone());
|
||||||
|
|
||||||
|
if let Some(ref filters) = self.filters {
|
||||||
|
for filter in filters {
|
||||||
|
if !filter.check(&mut req2) {
|
||||||
|
return Err(req);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let tp = self.get_handler(&mut req2);
|
||||||
let inner = Rc::clone(&self.inner);
|
let inner = Rc::clone(&self.inner);
|
||||||
Ok(Box::new(Pipeline::new(
|
Ok(Box::new(Pipeline::new(
|
||||||
req,
|
req2,
|
||||||
Rc::clone(&self.middlewares),
|
Rc::clone(&self.middlewares),
|
||||||
inner,
|
inner,
|
||||||
tp,
|
tp,
|
||||||
@@ -168,6 +179,7 @@ struct ApplicationParts<S> {
|
|||||||
external: HashMap<String, Resource>,
|
external: HashMap<String, Resource>,
|
||||||
encoding: ContentEncoding,
|
encoding: ContentEncoding,
|
||||||
middlewares: Vec<Box<Middleware<S>>>,
|
middlewares: Vec<Box<Middleware<S>>>,
|
||||||
|
filters: Vec<Box<Predicate<S>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Structure that follows the builder pattern for building application
|
/// Structure that follows the builder pattern for building application
|
||||||
@@ -190,6 +202,7 @@ impl App<()> {
|
|||||||
handlers: Vec::new(),
|
handlers: Vec::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
encoding: ContentEncoding::Auto,
|
encoding: ContentEncoding::Auto,
|
||||||
|
filters: Vec::new(),
|
||||||
middlewares: Vec::new(),
|
middlewares: Vec::new(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@@ -229,6 +242,7 @@ where
|
|||||||
handlers: Vec::new(),
|
handlers: Vec::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
middlewares: Vec::new(),
|
middlewares: Vec::new(),
|
||||||
|
filters: Vec::new(),
|
||||||
encoding: ContentEncoding::Auto,
|
encoding: ContentEncoding::Auto,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@@ -285,6 +299,26 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add match predicate to application.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate actix_web;
|
||||||
|
/// # use actix_web::*;
|
||||||
|
/// # fn main() {
|
||||||
|
/// App::new()
|
||||||
|
/// .filter(pred::Host("www.rust-lang.org"))
|
||||||
|
/// .resource("/path", |r| r.f(|_| HttpResponse::Ok()))
|
||||||
|
/// # .finish();
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn filter<T: Predicate<S> + 'static>(mut self, p: T) -> App<S> {
|
||||||
|
{
|
||||||
|
let parts = self.parts.as_mut().expect("Use after finish");
|
||||||
|
parts.filters.push(Box::new(p));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Configure route for a specific path.
|
/// Configure route for a specific path.
|
||||||
///
|
///
|
||||||
/// This is a simplified version of the `App::resource()` method.
|
/// This is a simplified version of the `App::resource()` method.
|
||||||
@@ -300,10 +334,12 @@ where
|
|||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = App::new()
|
/// let app = App::new()
|
||||||
/// .route("/test", http::Method::GET,
|
/// .route("/test", http::Method::GET, |_: HttpRequest| {
|
||||||
/// |_: HttpRequest| HttpResponse::Ok())
|
/// HttpResponse::Ok()
|
||||||
/// .route("/test", http::Method::POST,
|
/// })
|
||||||
/// |_: HttpRequest| HttpResponse::MethodNotAllowed());
|
/// .route("/test", http::Method::POST, |_: HttpRequest| {
|
||||||
|
/// HttpResponse::MethodNotAllowed()
|
||||||
|
/// });
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn route<T, F, R>(mut self, path: &str, method: Method, f: F) -> App<S>
|
pub fn route<T, F, R>(mut self, path: &str, method: Method, f: F) -> App<S>
|
||||||
@@ -345,9 +381,9 @@ where
|
|||||||
/// use actix_web::{http, App, HttpRequest, HttpResponse};
|
/// use actix_web::{http, App, HttpRequest, HttpResponse};
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = App::new()
|
/// let app = App::new().scope("/{project_id}", |scope| {
|
||||||
/// .scope("/{project_id}", |scope| {
|
/// scope
|
||||||
/// scope.resource("/path1", |r| r.f(|_| HttpResponse::Ok()))
|
/// .resource("/path1", |r| r.f(|_| HttpResponse::Ok()))
|
||||||
/// .resource("/path2", |r| r.f(|_| HttpResponse::Ok()))
|
/// .resource("/path2", |r| r.f(|_| HttpResponse::Ok()))
|
||||||
/// .resource("/path3", |r| r.f(|_| HttpResponse::MethodNotAllowed()))
|
/// .resource("/path3", |r| r.f(|_| HttpResponse::MethodNotAllowed()))
|
||||||
/// });
|
/// });
|
||||||
@@ -402,8 +438,7 @@ where
|
|||||||
/// use actix_web::{http, App, HttpResponse};
|
/// use actix_web::{http, App, HttpResponse};
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = App::new()
|
/// let app = App::new().resource("/users/{userid}/{friend}", |r| {
|
||||||
/// .resource("/users/{userid}/{friend}", |r| {
|
|
||||||
/// r.get().f(|_| HttpResponse::Ok());
|
/// r.get().f(|_| HttpResponse::Ok());
|
||||||
/// r.head().f(|_| HttpResponse::MethodNotAllowed());
|
/// r.head().f(|_| HttpResponse::MethodNotAllowed());
|
||||||
/// });
|
/// });
|
||||||
@@ -514,13 +549,11 @@ where
|
|||||||
/// use actix_web::{http, App, HttpRequest, HttpResponse};
|
/// use actix_web::{http, App, HttpRequest, HttpResponse};
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = App::new()
|
/// let app = App::new().handler("/app", |req: HttpRequest| match *req.method() {
|
||||||
/// .handler("/app", |req: HttpRequest| {
|
|
||||||
/// match *req.method() {
|
|
||||||
/// http::Method::GET => HttpResponse::Ok(),
|
/// http::Method::GET => HttpResponse::Ok(),
|
||||||
/// http::Method::POST => HttpResponse::MethodNotAllowed(),
|
/// http::Method::POST => HttpResponse::MethodNotAllowed(),
|
||||||
/// _ => HttpResponse::NotFound(),
|
/// _ => HttpResponse::NotFound(),
|
||||||
/// }});
|
/// });
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn handler<H: Handler<S>>(mut self, path: &str, handler: H) -> App<S> {
|
pub fn handler<H: Handler<S>>(mut self, path: &str, handler: H) -> App<S> {
|
||||||
@@ -561,12 +594,11 @@ where
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// use actix_web::{App, HttpResponse, fs, middleware};
|
/// use actix_web::{fs, middleware, App, HttpResponse};
|
||||||
///
|
///
|
||||||
/// // this function could be located in different module
|
/// // this function could be located in different module
|
||||||
/// fn config(app: App) -> App {
|
/// fn config(app: App) -> App {
|
||||||
/// app
|
/// app.resource("/test", |r| {
|
||||||
/// .resource("/test", |r| {
|
|
||||||
/// r.get().f(|_| HttpResponse::Ok());
|
/// r.get().f(|_| HttpResponse::Ok());
|
||||||
/// r.head().f(|_| HttpResponse::MethodNotAllowed());
|
/// r.head().f(|_| HttpResponse::MethodNotAllowed());
|
||||||
/// })
|
/// })
|
||||||
@@ -610,6 +642,11 @@ where
|
|||||||
handlers: parts.handlers,
|
handlers: parts.handlers,
|
||||||
resources,
|
resources,
|
||||||
}));
|
}));
|
||||||
|
let filters = if parts.filters.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(parts.filters)
|
||||||
|
};
|
||||||
|
|
||||||
HttpApplication {
|
HttpApplication {
|
||||||
state: Rc::new(parts.state),
|
state: Rc::new(parts.state),
|
||||||
@@ -618,6 +655,7 @@ where
|
|||||||
prefix,
|
prefix,
|
||||||
prefix_len,
|
prefix_len,
|
||||||
inner,
|
inner,
|
||||||
|
filters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,7 +675,8 @@ where
|
|||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// # thread::spawn(|| {
|
/// # thread::spawn(|| {
|
||||||
/// server::new(|| { vec![
|
/// server::new(|| {
|
||||||
|
/// vec![
|
||||||
/// App::with_state(State1)
|
/// App::with_state(State1)
|
||||||
/// .prefix("/app1")
|
/// .prefix("/app1")
|
||||||
/// .resource("/", |r| r.f(|r| HttpResponse::Ok()))
|
/// .resource("/", |r| r.f(|r| HttpResponse::Ok()))
|
||||||
@@ -645,8 +684,10 @@ where
|
|||||||
/// App::with_state(State2)
|
/// App::with_state(State2)
|
||||||
/// .prefix("/app2")
|
/// .prefix("/app2")
|
||||||
/// .resource("/", |r| r.f(|r| HttpResponse::Ok()))
|
/// .resource("/", |r| r.f(|r| HttpResponse::Ok()))
|
||||||
/// .boxed() ]})
|
/// .boxed(),
|
||||||
/// .bind("127.0.0.1:8080").unwrap()
|
/// ]
|
||||||
|
/// }).bind("127.0.0.1:8080")
|
||||||
|
/// .unwrap()
|
||||||
/// .run()
|
/// .run()
|
||||||
/// # });
|
/// # });
|
||||||
/// }
|
/// }
|
||||||
@@ -699,7 +740,8 @@ mod tests {
|
|||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use test::TestRequest;
|
use pred;
|
||||||
|
use test::{TestRequest, TestServer};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_resource() {
|
fn test_default_resource() {
|
||||||
@@ -898,4 +940,21 @@ mod tests {
|
|||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
|
assert_eq!(resp.as_msg().status(), StatusCode::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_filter() {
|
||||||
|
let mut srv = TestServer::with_factory(|| {
|
||||||
|
App::new()
|
||||||
|
.filter(pred::Get())
|
||||||
|
.handler("/test", |_| HttpResponse::Ok())
|
||||||
|
});
|
||||||
|
|
||||||
|
let request = srv.get().uri(srv.url("/test")).finish().unwrap();
|
||||||
|
let response = srv.execute(request.send()).unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
|
|
||||||
|
let request = srv.post().uri(srv.url("/test")).finish().unwrap();
|
||||||
|
let response = srv.execute(request.send()).unwrap();
|
||||||
|
assert_eq!(response.status(), StatusCode::NOT_FOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,8 +9,8 @@ use actix::actors::{Connect as ResolveConnect, Connector, ConnectorError};
|
|||||||
use actix::fut::WrapFuture;
|
use actix::fut::WrapFuture;
|
||||||
use actix::registry::ArbiterService;
|
use actix::registry::ArbiterService;
|
||||||
use actix::{
|
use actix::{
|
||||||
fut, Actor, ActorFuture, ActorResponse, Arbiter, AsyncContext, Context,
|
fut, Actor, ActorFuture, ActorResponse, Addr, Arbiter, AsyncContext, Context,
|
||||||
ContextFutureSpawner, Handler, Message, Recipient, Supervised, Syn,
|
ContextFutureSpawner, Handler, Message, Recipient, Supervised, Syn, Unsync,
|
||||||
};
|
};
|
||||||
|
|
||||||
use futures::task::{current as current_task, Task};
|
use futures::task::{current as current_task, Task};
|
||||||
@@ -181,6 +181,7 @@ pub struct ClientConnector {
|
|||||||
pool: Rc<Pool>,
|
pool: Rc<Pool>,
|
||||||
pool_modified: Rc<Cell<bool>>,
|
pool_modified: Rc<Cell<bool>>,
|
||||||
|
|
||||||
|
resolver: Addr<Unsync, Connector>,
|
||||||
conn_lifetime: Duration,
|
conn_lifetime: Duration,
|
||||||
conn_keep_alive: Duration,
|
conn_keep_alive: Duration,
|
||||||
limit: usize,
|
limit: usize,
|
||||||
@@ -225,6 +226,7 @@ impl Default for ClientConnector {
|
|||||||
pool: Rc::new(Pool::new(Rc::clone(&_modified))),
|
pool: Rc::new(Pool::new(Rc::clone(&_modified))),
|
||||||
pool_modified: _modified,
|
pool_modified: _modified,
|
||||||
connector: builder.build().unwrap(),
|
connector: builder.build().unwrap(),
|
||||||
|
resolver: Connector::from_registry(),
|
||||||
conn_lifetime: Duration::from_secs(75),
|
conn_lifetime: Duration::from_secs(75),
|
||||||
conn_keep_alive: Duration::from_secs(15),
|
conn_keep_alive: Duration::from_secs(15),
|
||||||
limit: 100,
|
limit: 100,
|
||||||
@@ -245,6 +247,7 @@ impl Default for ClientConnector {
|
|||||||
subscriber: None,
|
subscriber: None,
|
||||||
pool: Rc::new(Pool::new(Rc::clone(&_modified))),
|
pool: Rc::new(Pool::new(Rc::clone(&_modified))),
|
||||||
pool_modified: _modified,
|
pool_modified: _modified,
|
||||||
|
resolver: Connector::from_registry(),
|
||||||
conn_lifetime: Duration::from_secs(75),
|
conn_lifetime: Duration::from_secs(75),
|
||||||
conn_keep_alive: Duration::from_secs(15),
|
conn_keep_alive: Duration::from_secs(15),
|
||||||
limit: 100,
|
limit: 100,
|
||||||
@@ -277,9 +280,9 @@ impl ClientConnector {
|
|||||||
/// # use std::io::Write;
|
/// # use std::io::Write;
|
||||||
/// extern crate openssl;
|
/// extern crate openssl;
|
||||||
/// use actix::prelude::*;
|
/// use actix::prelude::*;
|
||||||
/// use actix_web::client::{Connect, ClientConnector};
|
/// use actix_web::client::{ClientConnector, Connect};
|
||||||
///
|
///
|
||||||
/// use openssl::ssl::{SslMethod, SslConnector};
|
/// use openssl::ssl::{SslConnector, SslMethod};
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let sys = System::new("test");
|
/// let sys = System::new("test");
|
||||||
@@ -312,6 +315,7 @@ impl ClientConnector {
|
|||||||
subscriber: None,
|
subscriber: None,
|
||||||
pool: Rc::new(Pool::new(Rc::clone(&modified))),
|
pool: Rc::new(Pool::new(Rc::clone(&modified))),
|
||||||
pool_modified: modified,
|
pool_modified: modified,
|
||||||
|
resolver: Connector::from_registry(),
|
||||||
conn_lifetime: Duration::from_secs(75),
|
conn_lifetime: Duration::from_secs(75),
|
||||||
conn_keep_alive: Duration::from_secs(15),
|
conn_keep_alive: Duration::from_secs(15),
|
||||||
limit: 100,
|
limit: 100,
|
||||||
@@ -371,6 +375,12 @@ impl ClientConnector {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Use custom resolver actor
|
||||||
|
pub fn resolver(mut self, addr: Addr<Unsync, Connector>) -> Self {
|
||||||
|
self.resolver = addr;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn acquire(&mut self, key: &Key) -> Acquire {
|
fn acquire(&mut self, key: &Key) -> Acquire {
|
||||||
// check limits
|
// check limits
|
||||||
if self.limit > 0 {
|
if self.limit > 0 {
|
||||||
@@ -705,7 +715,7 @@ impl Handler<Connect> for ClientConnector {
|
|||||||
|
|
||||||
{
|
{
|
||||||
ActorResponse::async(
|
ActorResponse::async(
|
||||||
Connector::from_registry()
|
self.resolver
|
||||||
.send(
|
.send(
|
||||||
ResolveConnect::host_and_port(&conn.0.host, port)
|
ResolveConnect::host_and_port(&conn.0.host, port)
|
||||||
.timeout(conn_timeout),
|
.timeout(conn_timeout),
|
||||||
@@ -855,7 +865,7 @@ impl fut::ActorFuture for Maintenance {
|
|||||||
let conn = AcquiredConn(key.clone(), Some(Rc::clone(&act.pool)));
|
let conn = AcquiredConn(key.clone(), Some(Rc::clone(&act.pool)));
|
||||||
|
|
||||||
fut::WrapFuture::<ClientConnector>::actfuture(
|
fut::WrapFuture::<ClientConnector>::actfuture(
|
||||||
Connector::from_registry().send(
|
act.resolver.send(
|
||||||
ResolveConnect::host_and_port(&conn.0.host, conn.0.port)
|
ResolveConnect::host_and_port(&conn.0.host, conn.0.port)
|
||||||
.timeout(waiter.conn_timeout),
|
.timeout(waiter.conn_timeout),
|
||||||
),
|
),
|
||||||
|
154
src/error.rs
154
src/error.rs
@@ -1,9 +1,9 @@
|
|||||||
//! Error and Result module
|
//! Error and Result module
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::io::Error as IoError;
|
use std::io::Error as IoError;
|
||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
use std::{fmt, io, result};
|
use std::sync::Mutex;
|
||||||
|
use std::{fmt, io, mem, result};
|
||||||
|
|
||||||
use actix::MailboxError;
|
use actix::MailboxError;
|
||||||
use cookie;
|
use cookie;
|
||||||
@@ -21,9 +21,10 @@ pub use url::ParseError as UrlParseError;
|
|||||||
// re-exports
|
// re-exports
|
||||||
pub use cookie::ParseError as CookieParseError;
|
pub use cookie::ParseError as CookieParseError;
|
||||||
|
|
||||||
|
use body::Body;
|
||||||
use handler::Responder;
|
use handler::Responder;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::{HttpResponse, InnerHttpResponse};
|
||||||
|
|
||||||
/// A specialized [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
|
/// A specialized [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html)
|
||||||
/// for actix web operations
|
/// for actix web operations
|
||||||
@@ -33,21 +34,44 @@ use httpresponse::HttpResponse;
|
|||||||
/// `Result`.
|
/// `Result`.
|
||||||
pub type Result<T, E = Error> = result::Result<T, E>;
|
pub type Result<T, E = Error> = result::Result<T, E>;
|
||||||
|
|
||||||
/// General purpose actix web error
|
/// General purpose actix web error.
|
||||||
|
///
|
||||||
|
/// An actix web error is used to carry errors from `failure` or `std::error`
|
||||||
|
/// through actix in a convenient way. It can be created through through
|
||||||
|
/// converting errors with `into()`.
|
||||||
|
///
|
||||||
|
/// Whenever it is created from an external object a response error is created
|
||||||
|
/// for it that can be used to create an http response from it this means that
|
||||||
|
/// if you have access to an actix `Error` you can always get a
|
||||||
|
/// `ResponseError` reference from it.
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
cause: Box<ResponseError>,
|
cause: Box<ResponseError>,
|
||||||
backtrace: Option<Backtrace>,
|
backtrace: Option<Backtrace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
/// Returns a reference to the underlying cause of this Error.
|
/// Deprecated way to reference the underlying response error.
|
||||||
// this should return &Fail but needs this https://github.com/rust-lang/rust/issues/5665
|
#[deprecated(
|
||||||
|
since = "0.6.0", note = "please use `Error::as_response_error()` instead"
|
||||||
|
)]
|
||||||
pub fn cause(&self) -> &ResponseError {
|
pub fn cause(&self) -> &ResponseError {
|
||||||
self.cause.as_ref()
|
self.cause.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the underlying cause of this `Error` as `Fail`
|
||||||
|
pub fn as_fail(&self) -> &Fail {
|
||||||
|
self.cause.as_fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the reference to the underlying `ResponseError`.
|
||||||
|
pub fn as_response_error(&self) -> &ResponseError {
|
||||||
|
self.cause.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a reference to the Backtrace carried by this error, if it
|
/// Returns a reference to the Backtrace carried by this error, if it
|
||||||
/// carries one.
|
/// carries one.
|
||||||
|
///
|
||||||
|
/// This uses the same `Backtrace` type that `failure` uses.
|
||||||
pub fn backtrace(&self) -> &Backtrace {
|
pub fn backtrace(&self) -> &Backtrace {
|
||||||
if let Some(bt) = self.cause.backtrace() {
|
if let Some(bt) = self.cause.backtrace() {
|
||||||
bt
|
bt
|
||||||
@@ -55,10 +79,65 @@ impl Error {
|
|||||||
self.backtrace.as_ref().unwrap()
|
self.backtrace.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to downcast this `Error` to a particular `Fail` type by
|
||||||
|
/// reference.
|
||||||
|
///
|
||||||
|
/// If the underlying error is not of type `T`, this will return `None`.
|
||||||
|
pub fn downcast_ref<T: Fail>(&self) -> Option<&T> {
|
||||||
|
// in the most trivial way the cause is directly of the requested type.
|
||||||
|
if let Some(rv) = Fail::downcast_ref(self.cause.as_fail()) {
|
||||||
|
return Some(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// in the more complex case the error has been constructed from a failure
|
||||||
|
// error. This happens because we implement From<failure::Error> by
|
||||||
|
// calling compat() and then storing it here. In failure this is
|
||||||
|
// represented by a failure::Error being wrapped in a failure::Compat.
|
||||||
|
//
|
||||||
|
// So we first downcast into that compat, to then further downcast through
|
||||||
|
// the failure's Error downcasting system into the original failure.
|
||||||
|
//
|
||||||
|
// This currently requires a transmute. This could be avoided if failure
|
||||||
|
// provides a deref: https://github.com/rust-lang-nursery/failure/pull/213
|
||||||
|
let compat: Option<&failure::Compat<failure::Error>> =
|
||||||
|
Fail::downcast_ref(self.cause.as_fail());
|
||||||
|
if let Some(compat) = compat {
|
||||||
|
pub struct CompatWrappedError {
|
||||||
|
error: failure::Error,
|
||||||
|
}
|
||||||
|
let compat: &CompatWrappedError = unsafe { ::std::mem::transmute(compat) };
|
||||||
|
compat.error.downcast_ref()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper trait to downcast a response error into a fail.
|
||||||
|
///
|
||||||
|
/// This is currently not exposed because it's unclear if this is the best way
|
||||||
|
/// to achieve the downcasting on `Error` for which this is needed.
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait InternalResponseErrorAsFail {
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn as_fail(&self) -> &Fail;
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn as_mut_fail(&mut self) -> &mut Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
impl<T: ResponseError> InternalResponseErrorAsFail for T {
|
||||||
|
fn as_fail(&self) -> &Fail {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn as_mut_fail(&mut self) -> &mut Fail {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error that can be converted to `HttpResponse`
|
/// Error that can be converted to `HttpResponse`
|
||||||
pub trait ResponseError: Fail {
|
pub trait ResponseError: Fail + InternalResponseErrorAsFail {
|
||||||
/// Create response for error
|
/// Create response for error
|
||||||
///
|
///
|
||||||
/// Internal server error is generated by default.
|
/// Internal server error is generated by default.
|
||||||
@@ -111,11 +190,9 @@ impl<T: ResponseError> From<T> for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compatibility for `failure::Error`
|
/// Compatibility for `failure::Error`
|
||||||
impl<T> ResponseError for failure::Compat<T>
|
impl<T> ResponseError for failure::Compat<T> where
|
||||||
where
|
T: fmt::Display + fmt::Debug + Sync + Send + 'static
|
||||||
T: fmt::Display + fmt::Debug + Sync + Send + 'static,
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<failure::Error> for Error {
|
impl From<failure::Error> for Error {
|
||||||
fn from(err: failure::Error) -> Error {
|
fn from(err: failure::Error) -> Error {
|
||||||
@@ -559,12 +636,9 @@ pub struct InternalError<T> {
|
|||||||
backtrace: Backtrace,
|
backtrace: Backtrace,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<T> Sync for InternalError<T> {}
|
|
||||||
unsafe impl<T> Send for InternalError<T> {}
|
|
||||||
|
|
||||||
enum InternalErrorType {
|
enum InternalErrorType {
|
||||||
Status(StatusCode),
|
Status(StatusCode),
|
||||||
Response(RefCell<Option<HttpResponse>>),
|
Response(Mutex<Option<Box<InnerHttpResponse>>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> InternalError<T> {
|
impl<T> InternalError<T> {
|
||||||
@@ -579,9 +653,21 @@ impl<T> InternalError<T> {
|
|||||||
|
|
||||||
/// Create `InternalError` with predefined `HttpResponse`.
|
/// Create `InternalError` with predefined `HttpResponse`.
|
||||||
pub fn from_response(cause: T, response: HttpResponse) -> Self {
|
pub fn from_response(cause: T, response: HttpResponse) -> Self {
|
||||||
|
let mut resp = response.into_inner();
|
||||||
|
let body = mem::replace(&mut resp.body, Body::Empty);
|
||||||
|
match body {
|
||||||
|
Body::Empty => (),
|
||||||
|
Body::Binary(mut bin) => {
|
||||||
|
resp.body = Body::Binary(bin.take().into());
|
||||||
|
}
|
||||||
|
Body::Streaming(_) | Body::Actor(_) => {
|
||||||
|
error!("Streaming or Actor body is not support by error response");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InternalError {
|
InternalError {
|
||||||
cause,
|
cause,
|
||||||
status: InternalErrorType::Response(RefCell::new(Some(response))),
|
status: InternalErrorType::Response(Mutex::new(Some(resp))),
|
||||||
backtrace: Backtrace::new(),
|
backtrace: Backtrace::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -622,8 +708,8 @@ where
|
|||||||
match self.status {
|
match self.status {
|
||||||
InternalErrorType::Status(st) => HttpResponse::new(st),
|
InternalErrorType::Status(st) => HttpResponse::new(st),
|
||||||
InternalErrorType::Response(ref resp) => {
|
InternalErrorType::Response(ref resp) => {
|
||||||
if let Some(resp) = resp.borrow_mut().take() {
|
if let Some(resp) = resp.lock().unwrap().take() {
|
||||||
resp
|
HttpResponse::from_inner(resp)
|
||||||
} else {
|
} else {
|
||||||
HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR)
|
HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
@@ -833,7 +919,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cause() {
|
fn test_as_fail() {
|
||||||
let orig = io::Error::new(io::ErrorKind::Other, "other");
|
let orig = io::Error::new(io::ErrorKind::Other, "other");
|
||||||
let desc = orig.description().to_owned();
|
let desc = orig.description().to_owned();
|
||||||
let e = ParseError::Io(orig);
|
let e = ParseError::Io(orig);
|
||||||
@@ -851,7 +937,7 @@ mod tests {
|
|||||||
let orig = io::Error::new(io::ErrorKind::Other, "other");
|
let orig = io::Error::new(io::ErrorKind::Other, "other");
|
||||||
let desc = orig.description().to_owned();
|
let desc = orig.description().to_owned();
|
||||||
let e = Error::from(orig);
|
let e = Error::from(orig);
|
||||||
assert_eq!(format!("{}", e.cause()), desc);
|
assert_eq!(format!("{}", e.as_fail()), desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -950,6 +1036,32 @@ mod tests {
|
|||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_error_downcasting_direct() {
|
||||||
|
#[derive(Debug, Fail)]
|
||||||
|
#[fail(display = "demo error")]
|
||||||
|
struct DemoError;
|
||||||
|
|
||||||
|
impl ResponseError for DemoError {}
|
||||||
|
|
||||||
|
let err: Error = DemoError.into();
|
||||||
|
let err_ref: &DemoError = err.downcast_ref().unwrap();
|
||||||
|
assert_eq!(err_ref.to_string(), "demo error");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_error_downcasting_compat() {
|
||||||
|
#[derive(Debug, Fail)]
|
||||||
|
#[fail(display = "demo error")]
|
||||||
|
struct DemoError;
|
||||||
|
|
||||||
|
impl ResponseError for DemoError {}
|
||||||
|
|
||||||
|
let err: Error = failure::Error::from(DemoError).into();
|
||||||
|
let err_ref: &DemoError = err.downcast_ref().unwrap();
|
||||||
|
assert_eq!(err_ref.to_string(), "demo error");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_error_helpers() {
|
fn test_error_helpers() {
|
||||||
let r: HttpResponse = ErrorBadRequest("err").into();
|
let r: HttpResponse = ErrorBadRequest("err").into();
|
||||||
|
@@ -141,6 +141,12 @@ impl HttpRequest<()> {
|
|||||||
pub fn with_state<S>(self, state: Rc<S>, router: Router) -> HttpRequest<S> {
|
pub fn with_state<S>(self, state: Rc<S>, router: Router) -> HttpRequest<S> {
|
||||||
HttpRequest(self.0, Some(state), Some(router))
|
HttpRequest(self.0, Some(state), Some(router))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn clone_with_state<S>(
|
||||||
|
&self, state: Rc<S>, router: Router,
|
||||||
|
) -> HttpRequest<S> {
|
||||||
|
HttpRequest(self.0.clone(), Some(state), Some(router))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> HttpMessage for HttpRequest<S> {
|
impl<S> HttpMessage for HttpRequest<S> {
|
||||||
|
@@ -89,7 +89,7 @@ impl HttpResponse {
|
|||||||
/// Constructs a error response
|
/// Constructs a error response
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_error(error: Error) -> HttpResponse {
|
pub fn from_error(error: Error) -> HttpResponse {
|
||||||
let mut resp = error.cause().error_response();
|
let mut resp = error.as_response_error().error_response();
|
||||||
resp.get_mut().error = Some(error);
|
resp.get_mut().error = Some(error);
|
||||||
resp
|
resp
|
||||||
}
|
}
|
||||||
@@ -241,6 +241,14 @@ impl HttpResponse {
|
|||||||
pub fn set_write_buffer_capacity(&mut self, cap: usize) {
|
pub fn set_write_buffer_capacity(&mut self, cap: usize) {
|
||||||
self.get_mut().write_capacity = cap;
|
self.get_mut().write_capacity = cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn into_inner(mut self) -> Box<InnerHttpResponse> {
|
||||||
|
self.0.take().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_inner(inner: Box<InnerHttpResponse>) -> HttpResponse {
|
||||||
|
HttpResponse(Some(inner), HttpResponsePool::pool())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for HttpResponse {
|
impl fmt::Debug for HttpResponse {
|
||||||
@@ -297,11 +305,13 @@ impl HttpResponseBuilder {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # extern crate actix_web;
|
/// # extern crate actix_web;
|
||||||
/// use actix_web::{HttpRequest, HttpResponse, Result, http};
|
/// use actix_web::{http, HttpRequest, HttpResponse, Result};
|
||||||
///
|
///
|
||||||
/// fn index(req: HttpRequest) -> Result<HttpResponse> {
|
/// fn index(req: HttpRequest) -> Result<HttpResponse> {
|
||||||
/// Ok(HttpResponse::Ok()
|
/// Ok(HttpResponse::Ok()
|
||||||
/// .set(http::header::IfModifiedSince("Sun, 07 Nov 1994 08:48:37 GMT".parse()?))
|
/// .set(http::header::IfModifiedSince(
|
||||||
|
/// "Sun, 07 Nov 1994 08:48:37 GMT".parse()?,
|
||||||
|
/// ))
|
||||||
/// .finish())
|
/// .finish())
|
||||||
/// }
|
/// }
|
||||||
/// fn main() {}
|
/// fn main() {}
|
||||||
@@ -455,7 +465,8 @@ impl HttpResponseBuilder {
|
|||||||
/// .path("/")
|
/// .path("/")
|
||||||
/// .secure(true)
|
/// .secure(true)
|
||||||
/// .http_only(true)
|
/// .http_only(true)
|
||||||
/// .finish())
|
/// .finish(),
|
||||||
|
/// )
|
||||||
/// .finish()
|
/// .finish()
|
||||||
/// }
|
/// }
|
||||||
/// fn main() {}
|
/// fn main() {}
|
||||||
@@ -781,12 +792,12 @@ impl<'a, S> From<&'a HttpRequest<S>> for HttpResponseBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct InnerHttpResponse {
|
pub(crate) struct InnerHttpResponse {
|
||||||
version: Option<Version>,
|
version: Option<Version>,
|
||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
status: StatusCode,
|
status: StatusCode,
|
||||||
reason: Option<&'static str>,
|
reason: Option<&'static str>,
|
||||||
body: Body,
|
pub(crate) body: Body,
|
||||||
chunked: Option<bool>,
|
chunked: Option<bool>,
|
||||||
encoding: Option<ContentEncoding>,
|
encoding: Option<ContentEncoding>,
|
||||||
connection_type: Option<ConnectionType>,
|
connection_type: Option<ConnectionType>,
|
||||||
@@ -795,6 +806,9 @@ struct InnerHttpResponse {
|
|||||||
error: Option<Error>,
|
error: Option<Error>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for InnerHttpResponse {}
|
||||||
|
unsafe impl Send for InnerHttpResponse {}
|
||||||
|
|
||||||
impl InnerHttpResponse {
|
impl InnerHttpResponse {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(status: StatusCode, body: Body) -> InnerHttpResponse {
|
fn new(status: StatusCode, body: Body) -> InnerHttpResponse {
|
||||||
|
@@ -11,10 +11,10 @@
|
|||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! # thread::spawn(|| {
|
//! # thread::spawn(|| {
|
||||||
//! server::new(
|
//! server::new(|| {
|
||||||
//! || App::new()
|
//! App::new().resource("/{name}/{id}/index.html", |r| r.with(index))
|
||||||
//! .resource("/{name}/{id}/index.html", |r| r.with(index)))
|
//! }).bind("127.0.0.1:8080")
|
||||||
//! .bind("127.0.0.1:8080").unwrap()
|
//! .unwrap()
|
||||||
//! .run();
|
//! .run();
|
||||||
//! # });
|
//! # });
|
||||||
//! }
|
//! }
|
||||||
@@ -77,6 +77,7 @@
|
|||||||
//!
|
//!
|
||||||
#![cfg_attr(actix_nightly, feature(
|
#![cfg_attr(actix_nightly, feature(
|
||||||
specialization, // for impl ErrorResponse for std::error::Error
|
specialization, // for impl ErrorResponse for std::error::Error
|
||||||
|
extern_prelude,
|
||||||
))]
|
))]
|
||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
feature = "cargo-clippy",
|
feature = "cargo-clippy",
|
||||||
|
61
src/pred.rs
61
src/pred.rs
@@ -192,6 +192,45 @@ impl<S: 'static> Predicate<S> for HeaderPredicate<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return predicate that matches if request contains specified Host name.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate actix_web;
|
||||||
|
/// use actix_web::{pred, App, HttpResponse};
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// App::new().resource("/index.html", |r| {
|
||||||
|
/// r.route()
|
||||||
|
/// .filter(pred::Host("www.rust-lang.org"))
|
||||||
|
/// .f(|_| HttpResponse::MethodNotAllowed())
|
||||||
|
/// });
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn Host<S: 'static, H: AsRef<str>>(host: H) -> HostPredicate<S> {
|
||||||
|
HostPredicate(host.as_ref().to_string(), None, PhantomData)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub struct HostPredicate<S>(String, Option<String>, PhantomData<S>);
|
||||||
|
|
||||||
|
impl<S> HostPredicate<S> {
|
||||||
|
/// Set reuest scheme to match
|
||||||
|
pub fn scheme<H: AsRef<str>>(&mut self, scheme: H) {
|
||||||
|
self.1 = Some(scheme.as_ref().to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: 'static> Predicate<S> for HostPredicate<S> {
|
||||||
|
fn check(&self, req: &mut HttpRequest<S>) -> bool {
|
||||||
|
let info = req.connection_info();
|
||||||
|
if let Some(ref scheme) = self.1 {
|
||||||
|
self.0 == info.host() && scheme == info.scheme()
|
||||||
|
} else {
|
||||||
|
self.0 == info.host()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -224,6 +263,28 @@ mod tests {
|
|||||||
assert!(!pred.check(&mut req));
|
assert!(!pred.check(&mut req));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_host() {
|
||||||
|
let mut headers = HeaderMap::new();
|
||||||
|
headers.insert(
|
||||||
|
header::HOST,
|
||||||
|
header::HeaderValue::from_static("www.rust-lang.org"),
|
||||||
|
);
|
||||||
|
let mut req = HttpRequest::new(
|
||||||
|
Method::GET,
|
||||||
|
Uri::from_str("/").unwrap(),
|
||||||
|
Version::HTTP_11,
|
||||||
|
headers,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
let pred = Host("www.rust-lang.org");
|
||||||
|
assert!(pred.check(&mut req));
|
||||||
|
|
||||||
|
let pred = Host("localhost");
|
||||||
|
assert!(!pred.check(&mut req));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_methods() {
|
fn test_methods() {
|
||||||
let mut req = HttpRequest::new(
|
let mut req = HttpRequest::new(
|
||||||
|
@@ -89,9 +89,6 @@ impl<H: 'static> Writer for H2Writer<H> {
|
|||||||
self.flags.insert(Flags::STARTED);
|
self.flags.insert(Flags::STARTED);
|
||||||
self.encoder =
|
self.encoder =
|
||||||
ContentEncoder::for_server(self.buffer.clone(), req, msg, encoding);
|
ContentEncoder::for_server(self.buffer.clone(), req, msg, encoding);
|
||||||
if let Body::Empty = *msg.body() {
|
|
||||||
self.flags.insert(Flags::EOF);
|
|
||||||
}
|
|
||||||
|
|
||||||
// http2 specific
|
// http2 specific
|
||||||
msg.headers_mut().remove(CONNECTION);
|
msg.headers_mut().remove(CONNECTION);
|
||||||
@@ -108,6 +105,11 @@ impl<H: 'static> Writer for H2Writer<H> {
|
|||||||
let body = msg.replace_body(Body::Empty);
|
let body = msg.replace_body(Body::Empty);
|
||||||
match body {
|
match body {
|
||||||
Body::Binary(ref bytes) => {
|
Body::Binary(ref bytes) => {
|
||||||
|
if bytes.is_empty() {
|
||||||
|
msg.headers_mut()
|
||||||
|
.insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
|
||||||
|
self.flags.insert(Flags::EOF);
|
||||||
|
} else {
|
||||||
let mut val = BytesMut::new();
|
let mut val = BytesMut::new();
|
||||||
helpers::convert_usize(bytes.len(), &mut val);
|
helpers::convert_usize(bytes.len(), &mut val);
|
||||||
let l = val.len();
|
let l = val.len();
|
||||||
@@ -116,7 +118,9 @@ impl<H: 'static> Writer for H2Writer<H> {
|
|||||||
HeaderValue::try_from(val.split_to(l - 2).freeze()).unwrap(),
|
HeaderValue::try_from(val.split_to(l - 2).freeze()).unwrap(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Body::Empty => {
|
Body::Empty => {
|
||||||
|
self.flags.insert(Flags::EOF);
|
||||||
msg.headers_mut()
|
msg.headers_mut()
|
||||||
.insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
|
.insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
|
||||||
}
|
}
|
||||||
@@ -141,6 +145,9 @@ impl<H: 'static> Writer for H2Writer<H> {
|
|||||||
trace!("Response: {:?}", msg);
|
trace!("Response: {:?}", msg);
|
||||||
|
|
||||||
if let Body::Binary(bytes) = body {
|
if let Body::Binary(bytes) = body {
|
||||||
|
if bytes.is_empty() {
|
||||||
|
Ok(WriterState::Done)
|
||||||
|
} else {
|
||||||
self.flags.insert(Flags::EOF);
|
self.flags.insert(Flags::EOF);
|
||||||
self.written = bytes.len() as u64;
|
self.written = bytes.len() as u64;
|
||||||
self.encoder.write(bytes)?;
|
self.encoder.write(bytes)?;
|
||||||
@@ -149,6 +156,7 @@ impl<H: 'static> Writer for H2Writer<H> {
|
|||||||
stream.reserve_capacity(cmp::min(self.buffer.len(), CHUNK_SIZE));
|
stream.reserve_capacity(cmp::min(self.buffer.len(), CHUNK_SIZE));
|
||||||
}
|
}
|
||||||
Ok(WriterState::Pause)
|
Ok(WriterState::Pause)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
msg.replace_body(body);
|
msg.replace_body(body);
|
||||||
self.buffer_capacity = msg.write_buffer_capacity();
|
self.buffer_capacity = msg.write_buffer_capacity();
|
||||||
@@ -177,10 +185,8 @@ impl<H: 'static> Writer for H2Writer<H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn write_eof(&mut self) -> io::Result<WriterState> {
|
fn write_eof(&mut self) -> io::Result<WriterState> {
|
||||||
self.encoder.write_eof()?;
|
|
||||||
|
|
||||||
self.flags.insert(Flags::EOF);
|
self.flags.insert(Flags::EOF);
|
||||||
if !self.encoder.is_eof() {
|
if !self.encoder.write_eof()? {
|
||||||
Err(io::Error::new(
|
Err(io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
"Last payload item, but eof is not reached",
|
"Last payload item, but eof is not reached",
|
||||||
|
Reference in New Issue
Block a user