mirror of
https://github.com/fafhrd91/actix-web
synced 2024-12-18 01:43:58 +01:00
clippy warnings; fmt
This commit is contained in:
parent
a38c3985f6
commit
de49796fd1
@ -1,7 +1,7 @@
|
|||||||
max_width = 89
|
max_width = 89
|
||||||
reorder_imports = true
|
reorder_imports = true
|
||||||
reorder_imports_in_group = true
|
#reorder_imports_in_group = true
|
||||||
reorder_imported_names = true
|
#reorder_imported_names = true
|
||||||
wrap_comments = true
|
wrap_comments = true
|
||||||
fn_args_density = "Compressed"
|
fn_args_density = "Compressed"
|
||||||
#use_small_heuristics = false
|
use_small_heuristics = false
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::mem;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use handler::Reply;
|
use handler::Reply;
|
||||||
@ -74,7 +73,7 @@ impl<S: 'static> HttpApplication<S> {
|
|||||||
|
|
||||||
if m {
|
if m {
|
||||||
let path: &'static str = unsafe {
|
let path: &'static str = unsafe {
|
||||||
mem::transmute(&req.path()[inner.prefix + prefix.len()..])
|
&*(&req.path()[inner.prefix + prefix.len()..] as *const _)
|
||||||
};
|
};
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
req.match_info_mut().add("tail", "");
|
req.match_info_mut().add("tail", "");
|
||||||
@ -112,12 +111,7 @@ impl<S: 'static> HttpHandler for HttpApplication<S> {
|
|||||||
let mut req = req.with_state(Rc::clone(&self.state), self.router.clone());
|
let mut req = req.with_state(Rc::clone(&self.state), self.router.clone());
|
||||||
let tp = self.get_handler(&mut req);
|
let tp = self.get_handler(&mut req);
|
||||||
let inner = Rc::clone(&self.inner);
|
let inner = Rc::clone(&self.inner);
|
||||||
Ok(Box::new(Pipeline::new(
|
Ok(Box::new(Pipeline::new(req, Rc::clone(&self.middlewares), inner, tp)))
|
||||||
req,
|
|
||||||
Rc::clone(&self.middlewares),
|
|
||||||
inner,
|
|
||||||
tp,
|
|
||||||
)))
|
|
||||||
} else {
|
} else {
|
||||||
Err(req)
|
Err(req)
|
||||||
}
|
}
|
||||||
@ -280,7 +274,7 @@ where
|
|||||||
{
|
{
|
||||||
{
|
{
|
||||||
let parts: &mut ApplicationParts<S> = unsafe {
|
let parts: &mut ApplicationParts<S> = unsafe {
|
||||||
mem::transmute(self.parts.as_mut().expect("Use after finish"))
|
&mut *(self.parts.as_mut().expect("Use after finish") as *mut _)
|
||||||
};
|
};
|
||||||
|
|
||||||
// get resource handler
|
// get resource handler
|
||||||
@ -455,20 +449,14 @@ where
|
|||||||
}
|
}
|
||||||
let parts = self.parts.as_mut().expect("Use after finish");
|
let parts = self.parts.as_mut().expect("Use after finish");
|
||||||
|
|
||||||
parts
|
parts.handlers.push((path, Box::new(WrapHandler::new(handler))));
|
||||||
.handlers
|
|
||||||
.push((path, Box::new(WrapHandler::new(handler))));
|
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a middleware.
|
/// Register a middleware.
|
||||||
pub fn middleware<M: Middleware<S>>(mut self, mw: M) -> App<S> {
|
pub fn middleware<M: Middleware<S>>(mut self, mw: M) -> App<S> {
|
||||||
self.parts
|
self.parts.as_mut().expect("Use after finish").middlewares.push(Box::new(mw));
|
||||||
.as_mut()
|
|
||||||
.expect("Use after finish")
|
|
||||||
.middlewares
|
|
||||||
.push(Box::new(mw));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,9 +611,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_resource() {
|
fn test_default_resource() {
|
||||||
let mut app = App::new()
|
let mut app =
|
||||||
.resource("/test", |r| r.f(|_| HttpResponse::Ok()))
|
App::new().resource("/test", |r| r.f(|_| HttpResponse::Ok())).finish();
|
||||||
.finish();
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/test").finish();
|
let req = TestRequest::with_uri("/test").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
@ -633,20 +620,14 @@ mod tests {
|
|||||||
|
|
||||||
let req = TestRequest::with_uri("/blah").finish();
|
let req = TestRequest::with_uri("/blah").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut app = App::new()
|
let mut app = App::new()
|
||||||
.default_resource(|r| r.f(|_| HttpResponse::MethodNotAllowed()))
|
.default_resource(|r| r.f(|_| HttpResponse::MethodNotAllowed()))
|
||||||
.finish();
|
.finish();
|
||||||
let req = TestRequest::with_uri("/blah").finish();
|
let req = TestRequest::with_uri("/blah").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::METHOD_NOT_ALLOWED);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::METHOD_NOT_ALLOWED
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -660,9 +641,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_state() {
|
fn test_state() {
|
||||||
let mut app = App::with_state(10)
|
let mut app =
|
||||||
.resource("/", |r| r.f(|_| HttpResponse::Ok()))
|
App::with_state(10).resource("/", |r| r.f(|_| HttpResponse::Ok())).finish();
|
||||||
.finish();
|
|
||||||
let req =
|
let req =
|
||||||
HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone());
|
HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone());
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
@ -694,9 +674,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_handler() {
|
fn test_handler() {
|
||||||
let mut app = App::new()
|
let mut app = App::new().handler("/test", |_| HttpResponse::Ok()).finish();
|
||||||
.handler("/test", |_| HttpResponse::Ok())
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/test").finish();
|
let req = TestRequest::with_uri("/test").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
@ -712,24 +690,16 @@ mod tests {
|
|||||||
|
|
||||||
let req = TestRequest::with_uri("/testapp").finish();
|
let req = TestRequest::with_uri("/testapp").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/blah").finish();
|
let req = TestRequest::with_uri("/blah").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_handler2() {
|
fn test_handler2() {
|
||||||
let mut app = App::new()
|
let mut app = App::new().handler("test", |_| HttpResponse::Ok()).finish();
|
||||||
.handler("test", |_| HttpResponse::Ok())
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/test").finish();
|
let req = TestRequest::with_uri("/test").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
@ -745,17 +715,11 @@ mod tests {
|
|||||||
|
|
||||||
let req = TestRequest::with_uri("/testapp").finish();
|
let req = TestRequest::with_uri("/testapp").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/blah").finish();
|
let req = TestRequest::with_uri("/blah").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -779,68 +743,41 @@ mod tests {
|
|||||||
|
|
||||||
let req = TestRequest::with_uri("/prefix/testapp").finish();
|
let req = TestRequest::with_uri("/prefix/testapp").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/prefix/blah").finish();
|
let req = TestRequest::with_uri("/prefix/blah").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_route() {
|
fn test_route() {
|
||||||
let mut app = App::new()
|
let mut app = App::new()
|
||||||
.route("/test", Method::GET, |_: HttpRequest| {
|
.route("/test", Method::GET, |_: HttpRequest| HttpResponse::Ok())
|
||||||
HttpResponse::Ok()
|
.route("/test", Method::POST, |_: HttpRequest| HttpResponse::Created())
|
||||||
})
|
|
||||||
.route("/test", Method::POST, |_: HttpRequest| {
|
|
||||||
HttpResponse::Created()
|
|
||||||
})
|
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/test")
|
let req = TestRequest::with_uri("/test").method(Method::GET).finish();
|
||||||
.method(Method::GET)
|
|
||||||
.finish();
|
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::OK);
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/test")
|
let req = TestRequest::with_uri("/test").method(Method::POST).finish();
|
||||||
.method(Method::POST)
|
|
||||||
.finish();
|
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::CREATED);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::CREATED
|
|
||||||
);
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/test")
|
let req = TestRequest::with_uri("/test").method(Method::HEAD).finish();
|
||||||
.method(Method::HEAD)
|
|
||||||
.finish();
|
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_handler_prefix() {
|
fn test_handler_prefix() {
|
||||||
let mut app = App::new()
|
let mut app =
|
||||||
.prefix("/app")
|
App::new().prefix("/app").handler("/test", |_| HttpResponse::Ok()).finish();
|
||||||
.handler("/test", |_| HttpResponse::Ok())
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/test").finish();
|
let req = TestRequest::with_uri("/test").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/app/test").finish();
|
let req = TestRequest::with_uri("/app/test").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
@ -856,16 +793,10 @@ mod tests {
|
|||||||
|
|
||||||
let req = TestRequest::with_uri("/app/testapp").finish();
|
let req = TestRequest::with_uri("/app/testapp").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
|
|
||||||
let req = TestRequest::with_uri("/app/blah").finish();
|
let req = TestRequest::with_uri("/app/blah").finish();
|
||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
resp.as_response().unwrap().status(),
|
|
||||||
StatusCode::NOT_FOUND
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -258,9 +258,7 @@ impl Responder for Binary {
|
|||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn respond_to(self, _: HttpRequest) -> Result<HttpResponse, Error> {
|
fn respond_to(self, _: HttpRequest) -> Result<HttpResponse, Error> {
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok().content_type("application/octet-stream").body(self))
|
||||||
.content_type("application/octet-stream")
|
|
||||||
.body(self))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,13 +94,17 @@ pub struct Pause {
|
|||||||
impl Pause {
|
impl Pause {
|
||||||
/// Create message with pause duration parameter
|
/// Create message with pause duration parameter
|
||||||
pub fn new(time: Duration) -> Pause {
|
pub fn new(time: Duration) -> Pause {
|
||||||
Pause { time: Some(time) }
|
Pause {
|
||||||
|
time: Some(time),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Pause {
|
impl Default for Pause {
|
||||||
fn default() -> Pause {
|
fn default() -> Pause {
|
||||||
Pause { time: None }
|
Pause {
|
||||||
|
time: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,8 +431,7 @@ impl ClientConnector {
|
|||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
self.acquired_per_host
|
self.acquired_per_host.insert(key.clone(), per_host + 1);
|
||||||
.insert(key.clone(), per_host + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_key(&mut self, key: &Key) {
|
fn release_key(&mut self, key: &Key) {
|
||||||
@ -439,8 +442,7 @@ impl ClientConnector {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if per_host > 1 {
|
if per_host > 1 {
|
||||||
self.acquired_per_host
|
self.acquired_per_host.insert(key.clone(), per_host - 1);
|
||||||
.insert(key.clone(), per_host - 1);
|
|
||||||
} else {
|
} else {
|
||||||
self.acquired_per_host.remove(key);
|
self.acquired_per_host.remove(key);
|
||||||
}
|
}
|
||||||
@ -516,9 +518,7 @@ impl ClientConnector {
|
|||||||
fn collect_periodic(&mut self, ctx: &mut Context<Self>) {
|
fn collect_periodic(&mut self, ctx: &mut Context<Self>) {
|
||||||
self.collect(true);
|
self.collect(true);
|
||||||
// re-schedule next collect period
|
// re-schedule next collect period
|
||||||
ctx.run_later(Duration::from_secs(1), |act, ctx| {
|
ctx.run_later(Duration::from_secs(1), |act, ctx| act.collect_periodic(ctx));
|
||||||
act.collect_periodic(ctx)
|
|
||||||
});
|
|
||||||
|
|
||||||
// send stats
|
// send stats
|
||||||
let stats = mem::replace(&mut self.stats, ClientConnectorStats::default());
|
let stats = mem::replace(&mut self.stats, ClientConnectorStats::default());
|
||||||
@ -570,7 +570,7 @@ impl ClientConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wait_for(
|
fn wait_for(
|
||||||
&mut self, key: Key, wait: Duration, conn_timeout: Duration
|
&mut self, key: Key, wait: Duration, conn_timeout: Duration,
|
||||||
) -> oneshot::Receiver<Result<Connection, ClientConnectorError>> {
|
) -> oneshot::Receiver<Result<Connection, ClientConnectorError>> {
|
||||||
// connection is not available, wait
|
// connection is not available, wait
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
@ -583,10 +583,7 @@ impl ClientConnector {
|
|||||||
wait,
|
wait,
|
||||||
conn_timeout,
|
conn_timeout,
|
||||||
};
|
};
|
||||||
self.waiters
|
self.waiters.entry(key).or_insert_with(VecDeque::new).push_back(waiter);
|
||||||
.entry(key)
|
|
||||||
.or_insert_with(VecDeque::new)
|
|
||||||
.push_back(waiter);
|
|
||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -810,7 +807,7 @@ impl fut::ActorFuture for Maintenance {
|
|||||||
type Actor = ClientConnector;
|
type Actor = ClientConnector;
|
||||||
|
|
||||||
fn poll(
|
fn poll(
|
||||||
&mut self, act: &mut ClientConnector, ctx: &mut Context<ClientConnector>
|
&mut self, act: &mut ClientConnector, ctx: &mut Context<ClientConnector>,
|
||||||
) -> Poll<Self::Item, Self::Error> {
|
) -> Poll<Self::Item, Self::Error> {
|
||||||
// check pause duration
|
// check pause duration
|
||||||
let done = if let Some(Some(ref pause)) = act.paused {
|
let done = if let Some(Some(ref pause)) = act.paused {
|
||||||
@ -1105,10 +1102,7 @@ impl Pool {
|
|||||||
if self.to_close.borrow().is_empty() {
|
if self.to_close.borrow().is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(mem::replace(
|
Some(mem::replace(&mut *self.to_close.borrow_mut(), Vec::new()))
|
||||||
&mut *self.to_close.borrow_mut(),
|
|
||||||
Vec::new(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1116,10 +1110,7 @@ impl Pool {
|
|||||||
if self.to_release.borrow().is_empty() {
|
if self.to_release.borrow().is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(mem::replace(
|
Some(mem::replace(&mut *self.to_release.borrow_mut(), Vec::new()))
|
||||||
&mut *self.to_release.borrow_mut(),
|
|
||||||
Vec::new(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,9 @@ use error::Error;
|
|||||||
use error::PayloadError;
|
use error::PayloadError;
|
||||||
use header::ContentEncoding;
|
use header::ContentEncoding;
|
||||||
use httpmessage::HttpMessage;
|
use httpmessage::HttpMessage;
|
||||||
use server::WriterState;
|
|
||||||
use server::encoding::PayloadStream;
|
use server::encoding::PayloadStream;
|
||||||
use server::shared::SharedBytes;
|
use server::shared::SharedBytes;
|
||||||
|
use server::WriterState;
|
||||||
|
|
||||||
/// A set of errors that can occur during request sending and response reading
|
/// A set of errors that can occur during request sending and response reading
|
||||||
#[derive(Fail, Debug)]
|
#[derive(Fail, Debug)]
|
||||||
@ -80,7 +80,7 @@ impl SendRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn with_connector(
|
pub(crate) fn with_connector(
|
||||||
req: ClientRequest, conn: Addr<Unsync, ClientConnector>
|
req: ClientRequest, conn: Addr<Unsync, ClientConnector>,
|
||||||
) -> SendRequest {
|
) -> SendRequest {
|
||||||
SendRequest {
|
SendRequest {
|
||||||
req,
|
req,
|
||||||
@ -269,11 +269,7 @@ impl Pipeline {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn parse(&mut self) -> Poll<ClientResponse, HttpResponseParserError> {
|
fn parse(&mut self) -> Poll<ClientResponse, HttpResponseParserError> {
|
||||||
if let Some(ref mut conn) = self.conn {
|
if let Some(ref mut conn) = self.conn {
|
||||||
match self.parser
|
match self.parser.as_mut().unwrap().parse(conn, &mut self.parser_buf) {
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.parse(conn, &mut self.parser_buf)
|
|
||||||
{
|
|
||||||
Ok(Async::Ready(resp)) => {
|
Ok(Async::Ready(resp)) => {
|
||||||
// check content-encoding
|
// check content-encoding
|
||||||
if self.should_decompress {
|
if self.should_decompress {
|
||||||
@ -469,9 +465,7 @@ impl Pipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// flush io but only if we need to
|
// flush io but only if we need to
|
||||||
match self.writer
|
match self.writer.poll_completed(self.conn.as_mut().unwrap(), false) {
|
||||||
.poll_completed(self.conn.as_mut().unwrap(), false)
|
|
||||||
{
|
|
||||||
Ok(Async::Ready(_)) => {
|
Ok(Async::Ready(_)) => {
|
||||||
if self.disconnected
|
if self.disconnected
|
||||||
|| (self.body_completed && self.writer.is_completed())
|
|| (self.body_completed && self.writer.is_completed())
|
||||||
|
@ -499,10 +499,7 @@ impl ClientRequestBuilder {
|
|||||||
jar.add(cookie.into_owned());
|
jar.add(cookie.into_owned());
|
||||||
self.cookies = Some(jar)
|
self.cookies = Some(jar)
|
||||||
} else {
|
} else {
|
||||||
self.cookies
|
self.cookies.as_mut().unwrap().add(cookie.into_owned());
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.add(cookie.into_owned());
|
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -594,11 +591,7 @@ impl ClientRequestBuilder {
|
|||||||
if self.default_headers {
|
if self.default_headers {
|
||||||
// enable br only for https
|
// enable br only for https
|
||||||
let https = if let Some(parts) = parts(&mut self.request, &self.err) {
|
let https = if let Some(parts) = parts(&mut self.request, &self.err) {
|
||||||
parts
|
parts.uri.scheme_part().map(|s| s == &uri::Scheme::HTTPS).unwrap_or(true)
|
||||||
.uri
|
|
||||||
.scheme_part()
|
|
||||||
.map(|s| s == &uri::Scheme::HTTPS)
|
|
||||||
.unwrap_or(true)
|
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
@ -610,9 +603,7 @@ impl ClientRequestBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut request = self.request
|
let mut request = self.request.take().expect("cannot reuse request builder");
|
||||||
.take()
|
|
||||||
.expect("cannot reuse request builder");
|
|
||||||
|
|
||||||
// set cookies
|
// set cookies
|
||||||
if let Some(ref mut jar) = self.cookies {
|
if let Some(ref mut jar) = self.cookies {
|
||||||
@ -657,9 +648,7 @@ impl ClientRequestBuilder {
|
|||||||
S: Stream<Item = Bytes, Error = E> + 'static,
|
S: Stream<Item = Bytes, Error = E> + 'static,
|
||||||
E: Into<Error>,
|
E: Into<Error>,
|
||||||
{
|
{
|
||||||
self.body(Body::Streaming(Box::new(
|
self.body(Body::Streaming(Box::new(stream.map_err(|e| e.into()))))
|
||||||
stream.map_err(|e| e.into()),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set an empty body and generate `ClientRequest`
|
/// Set an empty body and generate `ClientRequest`
|
||||||
@ -682,7 +671,7 @@ impl ClientRequestBuilder {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn parts<'a>(
|
fn parts<'a>(
|
||||||
parts: &'a mut Option<ClientRequest>, err: &Option<HttpError>
|
parts: &'a mut Option<ClientRequest>, err: &Option<HttpError>,
|
||||||
) -> Option<&'a mut ClientRequest> {
|
) -> Option<&'a mut ClientRequest> {
|
||||||
if err.is_some() {
|
if err.is_some() {
|
||||||
return None;
|
return None;
|
||||||
|
@ -103,12 +103,7 @@ impl ClientResponse {
|
|||||||
|
|
||||||
impl fmt::Debug for ClientResponse {
|
impl fmt::Debug for ClientResponse {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let res = writeln!(
|
let res = writeln!(f, "\nClientResponse {:?} {}", self.version(), self.status());
|
||||||
f,
|
|
||||||
"\nClientResponse {:?} {}",
|
|
||||||
self.version(),
|
|
||||||
self.status()
|
|
||||||
);
|
|
||||||
let _ = writeln!(f, " headers:");
|
let _ = writeln!(f, " headers:");
|
||||||
for (key, val) in self.headers().iter() {
|
for (key, val) in self.headers().iter() {
|
||||||
let _ = writeln!(f, " {:?}: {:?}", key, val);
|
let _ = writeln!(f, " {:?}: {:?}", key, val);
|
||||||
@ -138,14 +133,12 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_debug() {
|
fn test_debug() {
|
||||||
let resp = ClientResponse::new(ClientMessage::default());
|
let resp = ClientResponse::new(ClientMessage::default());
|
||||||
resp.as_mut().headers.insert(
|
resp.as_mut()
|
||||||
header::COOKIE,
|
.headers
|
||||||
HeaderValue::from_static("cookie1=value1"),
|
.insert(header::COOKIE, HeaderValue::from_static("cookie1=value1"));
|
||||||
);
|
resp.as_mut()
|
||||||
resp.as_mut().headers.insert(
|
.headers
|
||||||
header::COOKIE,
|
.insert(header::COOKIE, HeaderValue::from_static("cookie2=value2"));
|
||||||
HeaderValue::from_static("cookie2=value2"),
|
|
||||||
);
|
|
||||||
|
|
||||||
let dbg = format!("{:?}", resp);
|
let dbg = format!("{:?}", resp);
|
||||||
assert!(dbg.contains("ClientResponse"));
|
assert!(dbg.contains("ClientResponse"));
|
||||||
|
@ -114,10 +114,7 @@ impl HttpClientWriter {
|
|||||||
self.buffer,
|
self.buffer,
|
||||||
"{} {} {:?}\r",
|
"{} {} {:?}\r",
|
||||||
msg.method(),
|
msg.method(),
|
||||||
msg.uri()
|
msg.uri().path_and_query().map(|u| u.as_str()).unwrap_or("/"),
|
||||||
.path_and_query()
|
|
||||||
.map(|u| u.as_str())
|
|
||||||
.unwrap_or("/"),
|
|
||||||
msg.version()
|
msg.version()
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -253,10 +250,8 @@ fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> ContentEncoder
|
|||||||
}
|
}
|
||||||
let mut b = BytesMut::new();
|
let mut b = BytesMut::new();
|
||||||
let _ = write!(b, "{}", bytes.len());
|
let _ = write!(b, "{}", bytes.len());
|
||||||
req.headers_mut().insert(
|
req.headers_mut()
|
||||||
CONTENT_LENGTH,
|
.insert(CONTENT_LENGTH, HeaderValue::try_from(b.freeze()).unwrap());
|
||||||
HeaderValue::try_from(b.freeze()).unwrap(),
|
|
||||||
);
|
|
||||||
TransferEncoding::eof(buf)
|
TransferEncoding::eof(buf)
|
||||||
}
|
}
|
||||||
Body::Streaming(_) | Body::Actor(_) => {
|
Body::Streaming(_) | Body::Actor(_) => {
|
||||||
@ -279,10 +274,8 @@ fn content_encoder(buf: SharedBytes, req: &mut ClientRequest) -> ContentEncoder
|
|||||||
};
|
};
|
||||||
|
|
||||||
if encoding.is_compression() {
|
if encoding.is_compression() {
|
||||||
req.headers_mut().insert(
|
req.headers_mut()
|
||||||
CONTENT_ENCODING,
|
.insert(CONTENT_ENCODING, HeaderValue::from_static(encoding.as_str()));
|
||||||
HeaderValue::from_static(encoding.as_str()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req.replace_body(body);
|
req.replace_body(body);
|
||||||
|
@ -3,7 +3,6 @@ use futures::unsync::oneshot;
|
|||||||
use futures::{Async, Future, Poll};
|
use futures::{Async, Future, Poll};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use actix::dev::{ContextImpl, SyncEnvelope, ToEnvelope};
|
use actix::dev::{ContextImpl, SyncEnvelope, ToEnvelope};
|
||||||
use actix::fut::ActorFuture;
|
use actix::fut::ActorFuture;
|
||||||
@ -174,7 +173,9 @@ where
|
|||||||
if self.stream.is_none() {
|
if self.stream.is_none() {
|
||||||
self.stream = Some(SmallVec::new());
|
self.stream = Some(SmallVec::new());
|
||||||
}
|
}
|
||||||
self.stream.as_mut().map(|s| s.push(frame));
|
if let Some(s) = self.stream.as_mut() {
|
||||||
|
s.push(frame)
|
||||||
|
}
|
||||||
self.inner.modify();
|
self.inner.modify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +200,7 @@ where
|
|||||||
|
|
||||||
fn poll(&mut self) -> Poll<Option<SmallVec<[Frame; 4]>>, Error> {
|
fn poll(&mut self) -> Poll<Option<SmallVec<[Frame; 4]>>, Error> {
|
||||||
let ctx: &mut HttpContext<A, S> =
|
let ctx: &mut HttpContext<A, S> =
|
||||||
unsafe { mem::transmute(self as &mut HttpContext<A, S>) };
|
unsafe { &mut *(self as &mut HttpContext<A, S> as *mut _) };
|
||||||
|
|
||||||
if self.inner.alive() {
|
if self.inner.alive() {
|
||||||
match self.inner.poll(ctx) {
|
match self.inner.poll(ctx) {
|
||||||
@ -261,7 +262,7 @@ impl<A: Actor> ActorFuture for Drain<A> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn poll(
|
fn poll(
|
||||||
&mut self, _: &mut A, _: &mut <Self::Actor as Actor>::Context
|
&mut self, _: &mut A, _: &mut <Self::Actor as Actor>::Context,
|
||||||
) -> Poll<Self::Item, Self::Error> {
|
) -> Poll<Self::Item, Self::Error> {
|
||||||
self.fut.poll().map_err(|_| ())
|
self.fut.poll().map_err(|_| ())
|
||||||
}
|
}
|
||||||
|
49
src/de.rs
49
src/de.rs
@ -41,7 +41,9 @@ pub struct PathDeserializer<'de, S: 'de> {
|
|||||||
|
|
||||||
impl<'de, S: 'de> PathDeserializer<'de, S> {
|
impl<'de, S: 'de> PathDeserializer<'de, S> {
|
||||||
pub fn new(req: &'de HttpRequest<S>) -> Self {
|
pub fn new(req: &'de HttpRequest<S>) -> Self {
|
||||||
PathDeserializer { req }
|
PathDeserializer {
|
||||||
|
req,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +61,7 @@ impl<'de, S: 'de> Deserializer<'de> for PathDeserializer<'de, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_struct<V>(
|
fn deserialize_struct<V>(
|
||||||
self, _: &'static str, _: &'static [&'static str], visitor: V
|
self, _: &'static str, _: &'static [&'static str], visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -75,7 +77,7 @@ impl<'de, S: 'de> Deserializer<'de> for PathDeserializer<'de, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_unit_struct<V>(
|
fn deserialize_unit_struct<V>(
|
||||||
self, _: &'static str, visitor: V
|
self, _: &'static str, visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -84,7 +86,7 @@ impl<'de, S: 'de> Deserializer<'de> for PathDeserializer<'de, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_newtype_struct<V>(
|
fn deserialize_newtype_struct<V>(
|
||||||
self, _: &'static str, visitor: V
|
self, _: &'static str, visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -93,7 +95,7 @@ impl<'de, S: 'de> Deserializer<'de> for PathDeserializer<'de, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_tuple<V>(
|
fn deserialize_tuple<V>(
|
||||||
self, len: usize, visitor: V
|
self, len: usize, visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -114,7 +116,7 @@ impl<'de, S: 'de> Deserializer<'de> for PathDeserializer<'de, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_tuple_struct<V>(
|
fn deserialize_tuple_struct<V>(
|
||||||
self, _: &'static str, len: usize, visitor: V
|
self, _: &'static str, len: usize, visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -135,7 +137,7 @@ impl<'de, S: 'de> Deserializer<'de> for PathDeserializer<'de, S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_enum<V>(
|
fn deserialize_enum<V>(
|
||||||
self, _: &'static str, _: &'static [&'static str], _: V
|
self, _: &'static str, _: &'static [&'static str], _: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -202,11 +204,12 @@ impl<'de> de::MapAccess<'de> for ParamsDeserializer<'de> {
|
|||||||
where
|
where
|
||||||
K: de::DeserializeSeed<'de>,
|
K: de::DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
self.current = self.params
|
self.current =
|
||||||
.next()
|
self.params.next().map(|&(ref k, ref v)| (k.as_ref(), v.as_ref()));
|
||||||
.map(|&(ref k, ref v)| (k.as_ref(), v.as_ref()));
|
|
||||||
match self.current {
|
match self.current {
|
||||||
Some((key, _)) => Ok(Some(seed.deserialize(Key { key })?)),
|
Some((key, _)) => Ok(Some(seed.deserialize(Key {
|
||||||
|
key,
|
||||||
|
})?)),
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,7 +219,9 @@ impl<'de> de::MapAccess<'de> for ParamsDeserializer<'de> {
|
|||||||
V: de::DeserializeSeed<'de>,
|
V: de::DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
if let Some((_, value)) = self.current.take() {
|
if let Some((_, value)) = self.current.take() {
|
||||||
seed.deserialize(Value { value })
|
seed.deserialize(Value {
|
||||||
|
value,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(de::value::Error::custom("unexpected item"))
|
Err(de::value::Error::custom("unexpected item"))
|
||||||
}
|
}
|
||||||
@ -301,7 +306,7 @@ impl<'de> Deserializer<'de> for Value<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_unit_struct<V>(
|
fn deserialize_unit_struct<V>(
|
||||||
self, _: &'static str, visitor: V
|
self, _: &'static str, visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -331,7 +336,7 @@ impl<'de> Deserializer<'de> for Value<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_enum<V>(
|
fn deserialize_enum<V>(
|
||||||
self, _: &'static str, _: &'static [&'static str], visitor: V
|
self, _: &'static str, _: &'static [&'static str], visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -342,7 +347,7 @@ impl<'de> Deserializer<'de> for Value<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_newtype_struct<V>(
|
fn deserialize_newtype_struct<V>(
|
||||||
self, _: &'static str, visitor: V
|
self, _: &'static str, visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -358,7 +363,7 @@ impl<'de> Deserializer<'de> for Value<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_struct<V>(
|
fn deserialize_struct<V>(
|
||||||
self, _: &'static str, _: &'static [&'static str], _: V
|
self, _: &'static str, _: &'static [&'static str], _: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
@ -367,14 +372,12 @@ impl<'de> Deserializer<'de> for Value<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_tuple_struct<V>(
|
fn deserialize_tuple_struct<V>(
|
||||||
self, _: &'static str, _: usize, _: V
|
self, _: &'static str, _: usize, _: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
{
|
{
|
||||||
Err(de::value::Error::custom(
|
Err(de::value::Error::custom("unsupported type: tuple struct"))
|
||||||
"unsupported type: tuple struct",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsupported_type!(deserialize_any, "any");
|
unsupported_type!(deserialize_any, "any");
|
||||||
@ -416,7 +419,9 @@ impl<'de> de::EnumAccess<'de> for ValueEnum<'de> {
|
|||||||
V: de::DeserializeSeed<'de>,
|
V: de::DeserializeSeed<'de>,
|
||||||
{
|
{
|
||||||
Ok((
|
Ok((
|
||||||
seed.deserialize(Key { key: self.value })?,
|
seed.deserialize(Key {
|
||||||
|
key: self.value,
|
||||||
|
})?,
|
||||||
UnitVariant,
|
UnitVariant,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -446,7 +451,7 @@ impl<'de> de::VariantAccess<'de> for UnitVariant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn struct_variant<V>(
|
fn struct_variant<V>(
|
||||||
self, _: &'static [&'static str], _: V
|
self, _: &'static [&'static str], _: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error>
|
||||||
where
|
where
|
||||||
V: Visitor<'de>,
|
V: Visitor<'de>,
|
||||||
|
16
src/error.rs
16
src/error.rs
@ -68,12 +68,7 @@ impl fmt::Debug for Error {
|
|||||||
if let Some(bt) = self.cause.backtrace() {
|
if let Some(bt) = self.cause.backtrace() {
|
||||||
write!(f, "{:?}\n\n{:?}", &self.cause, bt)
|
write!(f, "{:?}\n\n{:?}", &self.cause, bt)
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(f, "{:?}\n\n{:?}", &self.cause, self.backtrace.as_ref().unwrap())
|
||||||
f,
|
|
||||||
"{:?}\n\n{:?}",
|
|
||||||
&self.cause,
|
|
||||||
self.backtrace.as_ref().unwrap()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,17 +293,16 @@ pub enum HttpRangeError {
|
|||||||
/// Returned if first-byte-pos of all of the byte-range-spec
|
/// Returned if first-byte-pos of all of the byte-range-spec
|
||||||
/// values is greater than the content size.
|
/// values is greater than the content size.
|
||||||
/// See `https://github.com/golang/go/commit/aa9b3d7`
|
/// See `https://github.com/golang/go/commit/aa9b3d7`
|
||||||
#[fail(display = "First-byte-pos of all of the byte-range-spec values is greater than the content size")]
|
#[fail(
|
||||||
|
display = "First-byte-pos of all of the byte-range-spec values is greater than the content size"
|
||||||
|
)]
|
||||||
NoOverlap,
|
NoOverlap,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `BadRequest` for `HttpRangeError`
|
/// Return `BadRequest` for `HttpRangeError`
|
||||||
impl ResponseError for HttpRangeError {
|
impl ResponseError for HttpRangeError {
|
||||||
fn error_response(&self) -> HttpResponse {
|
fn error_response(&self) -> HttpResponse {
|
||||||
HttpResponse::with_body(
|
HttpResponse::with_body(StatusCode::BAD_REQUEST, "Invalid Range header provided")
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"Invalid Range header provided",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,9 @@ where
|
|||||||
result(
|
result(
|
||||||
de::Deserialize::deserialize(PathDeserializer::new(&req))
|
de::Deserialize::deserialize(PathDeserializer::new(&req))
|
||||||
.map_err(|e| e.into())
|
.map_err(|e| e.into())
|
||||||
.map(|inner| Path { inner }),
|
.map(|inner| Path {
|
||||||
|
inner,
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,12 +248,7 @@ where
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
|
fn from_request(req: &HttpRequest<S>, cfg: &Self::Config) -> Self::Result {
|
||||||
Box::new(
|
Box::new(UrlEncoded::new(req.clone()).limit(cfg.limit).from_err().map(Form))
|
||||||
UrlEncoded::new(req.clone())
|
|
||||||
.limit(cfg.limit)
|
|
||||||
.from_err()
|
|
||||||
.map(Form),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +293,9 @@ impl FormConfig {
|
|||||||
|
|
||||||
impl Default for FormConfig {
|
impl Default for FormConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
FormConfig { limit: 262_144 }
|
FormConfig {
|
||||||
|
limit: 262_144,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,11 +336,7 @@ impl<S: 'static> FromRequest<S> for Bytes {
|
|||||||
return Either::A(result(Err(e)));
|
return Either::A(result(Err(e)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Either::B(Box::new(
|
Either::B(Box::new(MessageBody::new(req.clone()).limit(cfg.limit).from_err()))
|
||||||
MessageBody::new(req.clone())
|
|
||||||
.limit(cfg.limit)
|
|
||||||
.from_err(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,18 +382,14 @@ impl<S: 'static> FromRequest<S> for String {
|
|||||||
// check charset
|
// check charset
|
||||||
let encoding = match req.encoding() {
|
let encoding = match req.encoding() {
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
return Either::A(result(Err(ErrorBadRequest(
|
return Either::A(result(Err(ErrorBadRequest("Unknown request charset"))))
|
||||||
"Unknown request charset",
|
|
||||||
))))
|
|
||||||
}
|
}
|
||||||
Ok(encoding) => encoding,
|
Ok(encoding) => encoding,
|
||||||
};
|
};
|
||||||
|
|
||||||
Either::B(Box::new(
|
Either::B(Box::new(
|
||||||
MessageBody::new(req.clone())
|
MessageBody::new(req.clone()).limit(cfg.limit).from_err().and_then(
|
||||||
.limit(cfg.limit)
|
move |body| {
|
||||||
.from_err()
|
|
||||||
.and_then(move |body| {
|
|
||||||
let enc: *const Encoding = encoding as *const Encoding;
|
let enc: *const Encoding = encoding as *const Encoding;
|
||||||
if enc == UTF_8 {
|
if enc == UTF_8 {
|
||||||
Ok(str::from_utf8(body.as_ref())
|
Ok(str::from_utf8(body.as_ref())
|
||||||
@ -409,7 +400,8 @@ impl<S: 'static> FromRequest<S> for String {
|
|||||||
.decode(&body, DecoderTrap::Strict)
|
.decode(&body, DecoderTrap::Strict)
|
||||||
.map_err(|_| ErrorBadRequest("Can not decode body"))?)
|
.map_err(|_| ErrorBadRequest("Can not decode body"))?)
|
||||||
}
|
}
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -485,8 +477,7 @@ mod tests {
|
|||||||
fn test_bytes() {
|
fn test_bytes() {
|
||||||
let cfg = PayloadConfig::default();
|
let cfg = PayloadConfig::default();
|
||||||
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11").finish();
|
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11").finish();
|
||||||
req.payload_mut()
|
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
||||||
.unread_data(Bytes::from_static(b"hello=world"));
|
|
||||||
|
|
||||||
match Bytes::from_request(&req, &cfg).poll().unwrap() {
|
match Bytes::from_request(&req, &cfg).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
@ -500,8 +491,7 @@ mod tests {
|
|||||||
fn test_string() {
|
fn test_string() {
|
||||||
let cfg = PayloadConfig::default();
|
let cfg = PayloadConfig::default();
|
||||||
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11").finish();
|
let mut req = TestRequest::with_header(header::CONTENT_LENGTH, "11").finish();
|
||||||
req.payload_mut()
|
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
||||||
.unread_data(Bytes::from_static(b"hello=world"));
|
|
||||||
|
|
||||||
match String::from_request(&req, &cfg).poll().unwrap() {
|
match String::from_request(&req, &cfg).poll().unwrap() {
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
@ -518,8 +508,7 @@ mod tests {
|
|||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
).header(header::CONTENT_LENGTH, "11")
|
).header(header::CONTENT_LENGTH, "11")
|
||||||
.finish();
|
.finish();
|
||||||
req.payload_mut()
|
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
||||||
.unread_data(Bytes::from_static(b"hello=world"));
|
|
||||||
|
|
||||||
let mut cfg = FormConfig::default();
|
let mut cfg = FormConfig::default();
|
||||||
cfg.limit(4096);
|
cfg.limit(4096);
|
||||||
@ -573,17 +562,11 @@ mod tests {
|
|||||||
let mut resource = ResourceHandler::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let mut routes = Vec::new();
|
let mut routes = Vec::new();
|
||||||
routes.push((
|
routes.push((Resource::new("index", "/{key}/{value}/"), Some(resource)));
|
||||||
Resource::new("index", "/{key}/{value}/"),
|
|
||||||
Some(resource),
|
|
||||||
));
|
|
||||||
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
let (router, _) = Router::new("", ServerSettings::default(), routes);
|
||||||
assert!(router.recognize(&mut req).is_some());
|
assert!(router.recognize(&mut req).is_some());
|
||||||
|
|
||||||
match Path::<MyStruct>::from_request(&req, &())
|
match Path::<MyStruct>::from_request(&req, &()).poll().unwrap() {
|
||||||
.poll()
|
|
||||||
.unwrap()
|
|
||||||
{
|
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.key, "name");
|
assert_eq!(s.key, "name");
|
||||||
assert_eq!(s.value, "user1");
|
assert_eq!(s.value, "user1");
|
||||||
@ -591,10 +574,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Path::<(String, String)>::from_request(&req, &())
|
match Path::<(String, String)>::from_request(&req, &()).poll().unwrap() {
|
||||||
.poll()
|
|
||||||
.unwrap()
|
|
||||||
{
|
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.0, "name");
|
assert_eq!(s.0, "name");
|
||||||
assert_eq!(s.1, "user1");
|
assert_eq!(s.1, "user1");
|
||||||
@ -620,10 +600,7 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Path::<(String, u8)>::from_request(&req, &())
|
match Path::<(String, u8)>::from_request(&req, &()).poll().unwrap() {
|
||||||
.poll()
|
|
||||||
.unwrap()
|
|
||||||
{
|
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(s.0, "name");
|
assert_eq!(s.0, "name");
|
||||||
assert_eq!(s.1, 32);
|
assert_eq!(s.1, 32);
|
||||||
@ -631,15 +608,9 @@ mod tests {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
match Path::<Vec<String>>::from_request(&req, &())
|
match Path::<Vec<String>>::from_request(&req, &()).poll().unwrap() {
|
||||||
.poll()
|
|
||||||
.unwrap()
|
|
||||||
{
|
|
||||||
Async::Ready(s) => {
|
Async::Ready(s) => {
|
||||||
assert_eq!(
|
assert_eq!(s.into_inner(), vec!["name".to_owned(), "32".to_owned()]);
|
||||||
s.into_inner(),
|
|
||||||
vec!["name".to_owned(), "32".to_owned()]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
110
src/fs.rs
110
src/fs.rs
@ -202,15 +202,12 @@ impl Responder for NamedFile {
|
|||||||
if self.status_code != StatusCode::OK {
|
if self.status_code != StatusCode::OK {
|
||||||
let mut resp = HttpResponse::build(self.status_code);
|
let mut resp = HttpResponse::build(self.status_code);
|
||||||
resp.if_some(self.path().extension(), |ext, resp| {
|
resp.if_some(self.path().extension(), |ext, resp| {
|
||||||
resp.set(header::ContentType(get_mime_type(
|
resp.set(header::ContentType(get_mime_type(&ext.to_string_lossy())));
|
||||||
&ext.to_string_lossy(),
|
|
||||||
)));
|
|
||||||
});
|
});
|
||||||
let reader = ChunkedReadFile {
|
let reader = ChunkedReadFile {
|
||||||
size: self.md.len(),
|
size: self.md.len(),
|
||||||
offset: 0,
|
offset: 0,
|
||||||
cpu_pool: self.cpu_pool
|
cpu_pool: self.cpu_pool.unwrap_or_else(|| req.cpu_pool().clone()),
|
||||||
.unwrap_or_else(|| req.cpu_pool().clone()),
|
|
||||||
file: Some(self.file),
|
file: Some(self.file),
|
||||||
fut: None,
|
fut: None,
|
||||||
};
|
};
|
||||||
@ -253,9 +250,7 @@ impl Responder for NamedFile {
|
|||||||
let mut resp = HttpResponse::build(self.status_code);
|
let mut resp = HttpResponse::build(self.status_code);
|
||||||
|
|
||||||
resp.if_some(self.path().extension(), |ext, resp| {
|
resp.if_some(self.path().extension(), |ext, resp| {
|
||||||
resp.set(header::ContentType(get_mime_type(
|
resp.set(header::ContentType(get_mime_type(&ext.to_string_lossy())));
|
||||||
&ext.to_string_lossy(),
|
|
||||||
)));
|
|
||||||
}).if_some(last_modified, |lm, resp| {
|
}).if_some(last_modified, |lm, resp| {
|
||||||
resp.set(header::LastModified(lm));
|
resp.set(header::LastModified(lm));
|
||||||
})
|
})
|
||||||
@ -275,8 +270,7 @@ impl Responder for NamedFile {
|
|||||||
let reader = ChunkedReadFile {
|
let reader = ChunkedReadFile {
|
||||||
size: self.md.len(),
|
size: self.md.len(),
|
||||||
offset: 0,
|
offset: 0,
|
||||||
cpu_pool: self.cpu_pool
|
cpu_pool: self.cpu_pool.unwrap_or_else(|| req.cpu_pool().clone()),
|
||||||
.unwrap_or_else(|| req.cpu_pool().clone()),
|
|
||||||
file: Some(self.file),
|
file: Some(self.file),
|
||||||
fut: None,
|
fut: None,
|
||||||
};
|
};
|
||||||
@ -344,7 +338,10 @@ pub struct Directory {
|
|||||||
|
|
||||||
impl Directory {
|
impl Directory {
|
||||||
pub fn new(base: PathBuf, path: PathBuf) -> Directory {
|
pub fn new(base: PathBuf, path: PathBuf) -> Directory {
|
||||||
Directory { base, path }
|
Directory {
|
||||||
|
base,
|
||||||
|
path,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_list(&self, entry: &io::Result<DirEntry>) -> bool {
|
fn can_list(&self, entry: &io::Result<DirEntry>) -> bool {
|
||||||
@ -414,9 +411,7 @@ impl Responder for Directory {
|
|||||||
</ul></body>\n</html>",
|
</ul></body>\n</html>",
|
||||||
index_of, index_of, body
|
index_of, index_of, body
|
||||||
);
|
);
|
||||||
Ok(HttpResponse::Ok()
|
Ok(HttpResponse::Ok().content_type("text/html; charset=utf-8").body(html))
|
||||||
.content_type("text/html; charset=utf-8")
|
|
||||||
.body(html))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,13 +536,12 @@ impl<S: 'static> Handler<S> for StaticFiles<S> {
|
|||||||
if !self.accessible {
|
if !self.accessible {
|
||||||
Ok(self.default.handle(req))
|
Ok(self.default.handle(req))
|
||||||
} else {
|
} else {
|
||||||
let relpath = match req.match_info()
|
let relpath =
|
||||||
.get("tail")
|
match req.match_info().get("tail").map(|tail| PathBuf::from_param(tail))
|
||||||
.map(|tail| PathBuf::from_param(tail))
|
{
|
||||||
{
|
Some(Ok(path)) => path,
|
||||||
Some(Ok(path)) => path,
|
_ => return Ok(self.default.handle(req)),
|
||||||
_ => return Ok(self.default.handle(req)),
|
};
|
||||||
};
|
|
||||||
|
|
||||||
// full filepath
|
// full filepath
|
||||||
let path = self.directory.join(&relpath).canonicalize()?;
|
let path = self.directory.join(&relpath).canonicalize()?;
|
||||||
@ -597,9 +591,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_named_file() {
|
fn test_named_file() {
|
||||||
assert!(NamedFile::open("test--").is_err());
|
assert!(NamedFile::open("test--").is_err());
|
||||||
let mut file = NamedFile::open("Cargo.toml")
|
let mut file =
|
||||||
.unwrap()
|
NamedFile::open("Cargo.toml").unwrap().set_cpu_pool(CpuPool::new(1));
|
||||||
.set_cpu_pool(CpuPool::new(1));
|
|
||||||
{
|
{
|
||||||
file.file();
|
file.file();
|
||||||
let _f: &File = &file;
|
let _f: &File = &file;
|
||||||
@ -609,10 +602,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let resp = file.respond_to(HttpRequest::default()).unwrap();
|
let resp = file.respond_to(HttpRequest::default()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(resp.headers().get(header::CONTENT_TYPE).unwrap(), "text/x-toml")
|
||||||
resp.headers().get(header::CONTENT_TYPE).unwrap(),
|
|
||||||
"text/x-toml"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -630,10 +620,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let resp = file.respond_to(HttpRequest::default()).unwrap();
|
let resp = file.respond_to(HttpRequest::default()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(resp.headers().get(header::CONTENT_TYPE).unwrap(), "text/x-toml");
|
||||||
resp.headers().get(header::CONTENT_TYPE).unwrap(),
|
|
||||||
"text/x-toml"
|
|
||||||
);
|
|
||||||
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
|
assert_eq!(resp.status(), StatusCode::NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,9 +663,7 @@ mod tests {
|
|||||||
req.match_info_mut().add("tail", "");
|
req.match_info_mut().add("tail", "");
|
||||||
|
|
||||||
st.show_index = true;
|
st.show_index = true;
|
||||||
let resp = st.handle(req)
|
let resp = st.handle(req).respond_to(HttpRequest::default()).unwrap();
|
||||||
.respond_to(HttpRequest::default())
|
|
||||||
.unwrap();
|
|
||||||
let resp = resp.as_response().expect("HTTP Response");
|
let resp = resp.as_response().expect("HTTP Response");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resp.headers().get(header::CONTENT_TYPE).unwrap(),
|
resp.headers().get(header::CONTENT_TYPE).unwrap(),
|
||||||
@ -694,28 +679,18 @@ mod tests {
|
|||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
req.match_info_mut().add("tail", "tests");
|
req.match_info_mut().add("tail", "tests");
|
||||||
|
|
||||||
let resp = st.handle(req)
|
let resp = st.handle(req).respond_to(HttpRequest::default()).unwrap();
|
||||||
.respond_to(HttpRequest::default())
|
|
||||||
.unwrap();
|
|
||||||
let resp = resp.as_response().expect("HTTP Response");
|
let resp = resp.as_response().expect("HTTP Response");
|
||||||
assert_eq!(resp.status(), StatusCode::FOUND);
|
assert_eq!(resp.status(), StatusCode::FOUND);
|
||||||
assert_eq!(
|
assert_eq!(resp.headers().get(header::LOCATION).unwrap(), "/tests/index.html");
|
||||||
resp.headers().get(header::LOCATION).unwrap(),
|
|
||||||
"/tests/index.html"
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
req.match_info_mut().add("tail", "tests/");
|
req.match_info_mut().add("tail", "tests/");
|
||||||
|
|
||||||
let resp = st.handle(req)
|
let resp = st.handle(req).respond_to(HttpRequest::default()).unwrap();
|
||||||
.respond_to(HttpRequest::default())
|
|
||||||
.unwrap();
|
|
||||||
let resp = resp.as_response().expect("HTTP Response");
|
let resp = resp.as_response().expect("HTTP Response");
|
||||||
assert_eq!(resp.status(), StatusCode::FOUND);
|
assert_eq!(resp.status(), StatusCode::FOUND);
|
||||||
assert_eq!(
|
assert_eq!(resp.headers().get(header::LOCATION).unwrap(), "/tests/index.html");
|
||||||
resp.headers().get(header::LOCATION).unwrap(),
|
|
||||||
"/tests/index.html"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -724,9 +699,7 @@ mod tests {
|
|||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
req.match_info_mut().add("tail", "tools/wsload");
|
req.match_info_mut().add("tail", "tools/wsload");
|
||||||
|
|
||||||
let resp = st.handle(req)
|
let resp = st.handle(req).respond_to(HttpRequest::default()).unwrap();
|
||||||
.respond_to(HttpRequest::default())
|
|
||||||
.unwrap();
|
|
||||||
let resp = resp.as_response().expect("HTTP Response");
|
let resp = resp.as_response().expect("HTTP Response");
|
||||||
assert_eq!(resp.status(), StatusCode::FOUND);
|
assert_eq!(resp.status(), StatusCode::FOUND);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -746,23 +719,13 @@ mod tests {
|
|||||||
let request = srv.get().uri(srv.url("/public")).finish().unwrap();
|
let request = srv.get().uri(srv.url("/public")).finish().unwrap();
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert_eq!(response.status(), StatusCode::FOUND);
|
assert_eq!(response.status(), StatusCode::FOUND);
|
||||||
let loc = response
|
let loc = response.headers().get(header::LOCATION).unwrap().to_str().unwrap();
|
||||||
.headers()
|
|
||||||
.get(header::LOCATION)
|
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(loc, "/public/Cargo.toml");
|
assert_eq!(loc, "/public/Cargo.toml");
|
||||||
|
|
||||||
let request = srv.get().uri(srv.url("/public/")).finish().unwrap();
|
let request = srv.get().uri(srv.url("/public/")).finish().unwrap();
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert_eq!(response.status(), StatusCode::FOUND);
|
assert_eq!(response.status(), StatusCode::FOUND);
|
||||||
let loc = response
|
let loc = response.headers().get(header::LOCATION).unwrap().to_str().unwrap();
|
||||||
.headers()
|
|
||||||
.get(header::LOCATION)
|
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(loc, "/public/Cargo.toml");
|
assert_eq!(loc, "/public/Cargo.toml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -775,23 +738,13 @@ mod tests {
|
|||||||
let request = srv.get().uri(srv.url("/test")).finish().unwrap();
|
let request = srv.get().uri(srv.url("/test")).finish().unwrap();
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert_eq!(response.status(), StatusCode::FOUND);
|
assert_eq!(response.status(), StatusCode::FOUND);
|
||||||
let loc = response
|
let loc = response.headers().get(header::LOCATION).unwrap().to_str().unwrap();
|
||||||
.headers()
|
|
||||||
.get(header::LOCATION)
|
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(loc, "/test/Cargo.toml");
|
assert_eq!(loc, "/test/Cargo.toml");
|
||||||
|
|
||||||
let request = srv.get().uri(srv.url("/test/")).finish().unwrap();
|
let request = srv.get().uri(srv.url("/test/")).finish().unwrap();
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert_eq!(response.status(), StatusCode::FOUND);
|
assert_eq!(response.status(), StatusCode::FOUND);
|
||||||
let loc = response
|
let loc = response.headers().get(header::LOCATION).unwrap().to_str().unwrap();
|
||||||
.headers()
|
|
||||||
.get(header::LOCATION)
|
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(loc, "/test/Cargo.toml");
|
assert_eq!(loc, "/test/Cargo.toml");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -801,10 +754,7 @@ mod tests {
|
|||||||
App::new().handler("test", StaticFiles::new(".").index_file("Cargo.toml"))
|
App::new().handler("test", StaticFiles::new(".").index_file("Cargo.toml"))
|
||||||
});
|
});
|
||||||
|
|
||||||
let request = srv.get()
|
let request = srv.get().uri(srv.url("/test/%43argo.toml")).finish().unwrap();
|
||||||
.uri(srv.url("/test/%43argo.toml"))
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert_eq!(response.status(), StatusCode::OK);
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use futures::Poll;
|
|
||||||
use futures::future::{err, ok, Future, FutureResult};
|
use futures::future::{err, ok, Future, FutureResult};
|
||||||
|
use futures::Poll;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
@ -296,14 +296,13 @@ where
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn respond_to(self, req: HttpRequest) -> Result<Reply, Error> {
|
fn respond_to(self, req: HttpRequest) -> Result<Reply, Error> {
|
||||||
let fut = self.map_err(|e| e.into())
|
let fut = self.map_err(|e| e.into()).then(move |r| match r.respond_to(req) {
|
||||||
.then(move |r| match r.respond_to(req) {
|
Ok(reply) => match reply.into().0 {
|
||||||
Ok(reply) => match reply.into().0 {
|
ReplyItem::Message(resp) => ok(resp),
|
||||||
ReplyItem::Message(resp) => ok(resp),
|
_ => panic!("Nested async replies are not supported"),
|
||||||
_ => panic!("Nested async replies are not supported"),
|
},
|
||||||
},
|
Err(e) => err(e),
|
||||||
Err(e) => err(e),
|
});
|
||||||
});
|
|
||||||
Ok(Reply::async(fut))
|
Ok(Reply::async(fut))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,10 @@ impl EntityTag {
|
|||||||
/// If the tag contains invalid characters.
|
/// If the tag contains invalid characters.
|
||||||
pub fn new(weak: bool, tag: String) -> EntityTag {
|
pub fn new(weak: bool, tag: String) -> EntityTag {
|
||||||
assert!(check_slice_validity(&tag), "Invalid tag: {:?}", tag);
|
assert!(check_slice_validity(&tag), "Invalid tag: {:?}", tag);
|
||||||
EntityTag { weak, tag }
|
EntityTag {
|
||||||
|
weak,
|
||||||
|
tag,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new weak EntityTag.
|
/// Constructs a new weak EntityTag.
|
||||||
@ -196,11 +199,7 @@ mod tests {
|
|||||||
fn test_etag_parse_failures() {
|
fn test_etag_parse_failures() {
|
||||||
// Expected failures
|
// Expected failures
|
||||||
assert!("no-dquotes".parse::<EntityTag>().is_err());
|
assert!("no-dquotes".parse::<EntityTag>().is_err());
|
||||||
assert!(
|
assert!("w/\"the-first-w-is-case-sensitive\"".parse::<EntityTag>().is_err());
|
||||||
"w/\"the-first-w-is-case-sensitive\""
|
|
||||||
.parse::<EntityTag>()
|
|
||||||
.is_err()
|
|
||||||
);
|
|
||||||
assert!("".parse::<EntityTag>().is_err());
|
assert!("".parse::<EntityTag>().is_err());
|
||||||
assert!("\"unmatched-dquotes1".parse::<EntityTag>().is_err());
|
assert!("\"unmatched-dquotes1".parse::<EntityTag>().is_err());
|
||||||
assert!("unmatched-dquotes2\"".parse::<EntityTag>().is_err());
|
assert!("unmatched-dquotes2\"".parse::<EntityTag>().is_err());
|
||||||
@ -209,26 +208,14 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_etag_fmt() {
|
fn test_etag_fmt() {
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", EntityTag::strong("foobar".to_owned())), "\"foobar\"");
|
||||||
format!("{}", EntityTag::strong("foobar".to_owned())),
|
assert_eq!(format!("{}", EntityTag::strong("".to_owned())), "\"\"");
|
||||||
"\"foobar\""
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
format!("{}", EntityTag::strong("".to_owned())),
|
|
||||||
"\"\""
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
format!("{}", EntityTag::weak("weak-etag".to_owned())),
|
format!("{}", EntityTag::weak("weak-etag".to_owned())),
|
||||||
"W/\"weak-etag\""
|
"W/\"weak-etag\""
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", EntityTag::weak("\u{0065}".to_owned())), "W/\"\x65\"");
|
||||||
format!("{}", EntityTag::weak("\u{0065}".to_owned())),
|
assert_eq!(format!("{}", EntityTag::weak("".to_owned())), "W/\"\"");
|
||||||
"W/\"\x65\""
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
format!("{}", EntityTag::weak("".to_owned())),
|
|
||||||
"W/\"\""
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -64,11 +64,7 @@ impl IntoHeaderValue for HttpDate {
|
|||||||
fn try_into(self) -> Result<HeaderValue, Self::Error> {
|
fn try_into(self) -> Result<HeaderValue, Self::Error> {
|
||||||
let mut wrt = BytesMut::with_capacity(29).writer();
|
let mut wrt = BytesMut::with_capacity(29).writer();
|
||||||
write!(wrt, "{}", self.0.rfc822()).unwrap();
|
write!(wrt, "{}", self.0.rfc822()).unwrap();
|
||||||
unsafe {
|
unsafe { Ok(HeaderValue::from_shared_unchecked(wrt.get_mut().take().freeze())) }
|
||||||
Ok(HeaderValue::from_shared_unchecked(
|
|
||||||
wrt.get_mut().take().freeze(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,24 +100,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date() {
|
fn test_date() {
|
||||||
|
assert_eq!("Sun, 07 Nov 1994 08:48:37 GMT".parse::<HttpDate>().unwrap(), NOV_07);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"Sun, 07 Nov 1994 08:48:37 GMT"
|
"Sunday, 07-Nov-94 08:48:37 GMT".parse::<HttpDate>().unwrap(),
|
||||||
.parse::<HttpDate>()
|
|
||||||
.unwrap(),
|
|
||||||
NOV_07
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
"Sunday, 07-Nov-94 08:48:37 GMT"
|
|
||||||
.parse::<HttpDate>()
|
|
||||||
.unwrap(),
|
|
||||||
NOV_07
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
"Sun Nov 7 08:48:37 1994"
|
|
||||||
.parse::<HttpDate>()
|
|
||||||
.unwrap(),
|
|
||||||
NOV_07
|
NOV_07
|
||||||
);
|
);
|
||||||
|
assert_eq!("Sun Nov 7 08:48:37 1994".parse::<HttpDate>().unwrap(), NOV_07);
|
||||||
assert!("this-is-no-date".parse::<HttpDate>().is_err());
|
assert!("this-is-no-date".parse::<HttpDate>().is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,10 @@ impl<T> QualityItem<T> {
|
|||||||
/// The item can be of any type.
|
/// The item can be of any type.
|
||||||
/// The quality should be a value in the range [0, 1].
|
/// The quality should be a value in the range [0, 1].
|
||||||
pub fn new(item: T, quality: Quality) -> QualityItem<T> {
|
pub fn new(item: T, quality: Quality) -> QualityItem<T> {
|
||||||
QualityItem { item, quality }
|
QualityItem {
|
||||||
|
item,
|
||||||
|
quality,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,11 +66,7 @@ impl<T: fmt::Display> fmt::Display for QualityItem<T> {
|
|||||||
match self.quality.0 {
|
match self.quality.0 {
|
||||||
1000 => Ok(()),
|
1000 => Ok(()),
|
||||||
0 => f.write_str("; q=0"),
|
0 => f.write_str("; q=0"),
|
||||||
x => write!(
|
x => write!(f, "; q=0.{}", format!("{:03}", x).trim_right_matches('0')),
|
||||||
f,
|
|
||||||
"; q=0.{}",
|
|
||||||
format!("{:03}", x).trim_right_matches('0')
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,10 +119,7 @@ fn from_f32(f: f32) -> Quality {
|
|||||||
// this function is only used internally. A check that `f` is within range
|
// this function is only used internally. A check that `f` is within range
|
||||||
// should be done before calling this method. Just in case, this
|
// should be done before calling this method. Just in case, this
|
||||||
// debug_assert should catch if we were forgetful
|
// debug_assert should catch if we were forgetful
|
||||||
debug_assert!(
|
debug_assert!(f >= 0f32 && f <= 1f32, "q value must be between 0.0 and 1.0");
|
||||||
f >= 0f32 && f <= 1f32,
|
|
||||||
"q value must be between 0.0 and 1.0"
|
|
||||||
);
|
|
||||||
Quality((f * 1000f32) as u16)
|
Quality((f * 1000f32) as u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,10 +152,7 @@ mod internal {
|
|||||||
|
|
||||||
impl IntoQuality for f32 {
|
impl IntoQuality for f32 {
|
||||||
fn into_quality(self) -> Quality {
|
fn into_quality(self) -> Quality {
|
||||||
assert!(
|
assert!(self >= 0f32 && self <= 1f32, "float must be between 0.0 and 1.0");
|
||||||
self >= 0f32 && self <= 1f32,
|
|
||||||
"float must be between 0.0 and 1.0"
|
|
||||||
);
|
|
||||||
super::from_f32(self)
|
super::from_f32(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,10 +288,6 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_fuzzing_bugs() {
|
fn test_fuzzing_bugs() {
|
||||||
assert!("99999;".parse::<QualityItem<String>>().is_err());
|
assert!("99999;".parse::<QualityItem<String>>().is_err());
|
||||||
assert!(
|
assert!("\x0d;;;=\u{d6aa}==".parse::<QualityItem<String>>().is_err())
|
||||||
"\x0d;;;=\u{d6aa}=="
|
|
||||||
.parse::<QualityItem<String>>()
|
|
||||||
.is_err()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
186
src/helpers.rs
186
src/helpers.rs
@ -190,16 +190,8 @@ mod tests {
|
|||||||
// trailing slashes
|
// trailing slashes
|
||||||
let params = vec![
|
let params = vec![
|
||||||
("/resource1", "", StatusCode::OK),
|
("/resource1", "", StatusCode::OK),
|
||||||
(
|
("/resource1/", "/resource1", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource1/",
|
("/resource2", "/resource2/", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource1",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"/resource2",
|
|
||||||
"/resource2/",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
("/resource2/", "", StatusCode::OK),
|
("/resource2/", "", StatusCode::OK),
|
||||||
("/resource1?p1=1&p2=2", "", StatusCode::OK),
|
("/resource1?p1=1&p2=2", "", StatusCode::OK),
|
||||||
(
|
(
|
||||||
@ -222,11 +214,7 @@ mod tests {
|
|||||||
if !target.is_empty() {
|
if !target.is_empty() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
target,
|
target,
|
||||||
r.headers()
|
r.headers().get(header::LOCATION).unwrap().to_str().unwrap()
|
||||||
.get(header::LOCATION)
|
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.unwrap()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,11 +226,7 @@ mod tests {
|
|||||||
.resource("/resource1", |r| r.method(Method::GET).f(index))
|
.resource("/resource1", |r| r.method(Method::GET).f(index))
|
||||||
.resource("/resource2/", |r| r.method(Method::GET).f(index))
|
.resource("/resource2/", |r| r.method(Method::GET).f(index))
|
||||||
.default_resource(|r| {
|
.default_resource(|r| {
|
||||||
r.h(NormalizePath::new(
|
r.h(NormalizePath::new(false, true, StatusCode::MOVED_PERMANENTLY))
|
||||||
false,
|
|
||||||
true,
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
))
|
|
||||||
})
|
})
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
@ -276,46 +260,14 @@ mod tests {
|
|||||||
// trailing slashes
|
// trailing slashes
|
||||||
let params = vec![
|
let params = vec![
|
||||||
("/resource1/a/b", "", StatusCode::OK),
|
("/resource1/a/b", "", StatusCode::OK),
|
||||||
(
|
("/resource1/", "/resource1", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource1/",
|
("/resource1//", "/resource1", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource1",
|
("//resource1//a//b", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
("//resource1//a//b/", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
),
|
("//resource1//a//b//", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
(
|
("///resource1//a//b", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource1//",
|
("/////resource1/a///b", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource1",
|
("/////resource1/a//b/", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"//resource1//a//b",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"//resource1//a//b/",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"//resource1//a//b//",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"///resource1//a//b",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"/////resource1/a///b",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"/////resource1/a//b/",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
("/resource1/a/b?p=1", "", StatusCode::OK),
|
("/resource1/a/b?p=1", "", StatusCode::OK),
|
||||||
(
|
(
|
||||||
"//resource1//a//b?p=1",
|
"//resource1//a//b?p=1",
|
||||||
@ -356,11 +308,7 @@ mod tests {
|
|||||||
if !target.is_empty() {
|
if !target.is_empty() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
target,
|
target,
|
||||||
r.headers()
|
r.headers().get(header::LOCATION).unwrap().to_str().unwrap()
|
||||||
.get(header::LOCATION)
|
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.unwrap()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -379,88 +327,24 @@ mod tests {
|
|||||||
// trailing slashes
|
// trailing slashes
|
||||||
let params = vec![
|
let params = vec![
|
||||||
("/resource1/a/b", "", StatusCode::OK),
|
("/resource1/a/b", "", StatusCode::OK),
|
||||||
(
|
("/resource1/a/b/", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource1/a/b/",
|
("//resource2//a//b", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource1/a/b",
|
("//resource2//a//b/", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
("//resource2//a//b//", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
),
|
("///resource1//a//b", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
(
|
("///resource1//a//b/", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
"//resource2//a//b",
|
("/////resource1/a///b", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource2/a/b/",
|
("/////resource1/a///b/", "/resource1/a/b", StatusCode::MOVED_PERMANENTLY),
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
("/resource2/a/b", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
),
|
|
||||||
(
|
|
||||||
"//resource2//a//b/",
|
|
||||||
"/resource2/a/b/",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"//resource2//a//b//",
|
|
||||||
"/resource2/a/b/",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"///resource1//a//b",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"///resource1//a//b/",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"/////resource1/a///b",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"/////resource1/a///b/",
|
|
||||||
"/resource1/a/b",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"/resource2/a/b",
|
|
||||||
"/resource2/a/b/",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
("/resource2/a/b/", "", StatusCode::OK),
|
("/resource2/a/b/", "", StatusCode::OK),
|
||||||
(
|
("//resource2//a//b", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
"//resource2//a//b",
|
("//resource2//a//b/", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource2/a/b/",
|
("///resource2//a//b", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
("///resource2//a//b/", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
),
|
("/////resource2/a///b", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
(
|
("/////resource2/a///b/", "/resource2/a/b/", StatusCode::MOVED_PERMANENTLY),
|
||||||
"//resource2//a//b/",
|
|
||||||
"/resource2/a/b/",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"///resource2//a//b",
|
|
||||||
"/resource2/a/b/",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"///resource2//a//b/",
|
|
||||||
"/resource2/a/b/",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"/////resource2/a///b",
|
|
||||||
"/resource2/a/b/",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"/////resource2/a///b/",
|
|
||||||
"/resource2/a/b/",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
("/resource1/a/b?p=1", "", StatusCode::OK),
|
("/resource1/a/b?p=1", "", StatusCode::OK),
|
||||||
(
|
("/resource1/a/b/?p=1", "/resource1/a/b?p=1", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource1/a/b/?p=1",
|
|
||||||
"/resource1/a/b?p=1",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
"//resource2//a//b?p=1",
|
"//resource2//a//b?p=1",
|
||||||
"/resource2/a/b/?p=1",
|
"/resource2/a/b/?p=1",
|
||||||
@ -496,11 +380,7 @@ mod tests {
|
|||||||
"/resource1/a/b?p=1",
|
"/resource1/a/b?p=1",
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
StatusCode::MOVED_PERMANENTLY,
|
||||||
),
|
),
|
||||||
(
|
("/resource2/a/b?p=1", "/resource2/a/b/?p=1", StatusCode::MOVED_PERMANENTLY),
|
||||||
"/resource2/a/b?p=1",
|
|
||||||
"/resource2/a/b/?p=1",
|
|
||||||
StatusCode::MOVED_PERMANENTLY,
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
"//resource2//a//b?p=1",
|
"//resource2//a//b?p=1",
|
||||||
"/resource2/a/b/?p=1",
|
"/resource2/a/b/?p=1",
|
||||||
@ -540,11 +420,7 @@ mod tests {
|
|||||||
if !target.is_empty() {
|
if !target.is_empty() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
target,
|
target,
|
||||||
r.headers()
|
r.headers().get(header::LOCATION).unwrap().to_str().unwrap()
|
||||||
.get(header::LOCATION)
|
|
||||||
.unwrap()
|
|
||||||
.to_str()
|
|
||||||
.unwrap()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
161
src/httpcodes.rs
161
src/httpcodes.rs
@ -14,32 +14,37 @@ pub const HttpOk: StaticResponse = StaticResponse(StatusCode::OK);
|
|||||||
pub const HttpCreated: StaticResponse = StaticResponse(StatusCode::CREATED);
|
pub const HttpCreated: StaticResponse = StaticResponse(StatusCode::CREATED);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Accepted()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Accepted()` instead")]
|
||||||
pub const HttpAccepted: StaticResponse = StaticResponse(StatusCode::ACCEPTED);
|
pub const HttpAccepted: StaticResponse = StaticResponse(StatusCode::ACCEPTED);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::pNonAuthoritativeInformation()` instead")]
|
since = "0.5.0",
|
||||||
|
note = "please use `HttpResponse::pNonAuthoritativeInformation()` instead"
|
||||||
|
)]
|
||||||
pub const HttpNonAuthoritativeInformation: StaticResponse =
|
pub const HttpNonAuthoritativeInformation: StaticResponse =
|
||||||
StaticResponse(StatusCode::NON_AUTHORITATIVE_INFORMATION);
|
StaticResponse(StatusCode::NON_AUTHORITATIVE_INFORMATION);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::NoContent()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::NoContent()` instead")]
|
||||||
pub const HttpNoContent: StaticResponse = StaticResponse(StatusCode::NO_CONTENT);
|
pub const HttpNoContent: StaticResponse = StaticResponse(StatusCode::NO_CONTENT);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::ResetContent()` instead")]
|
||||||
note = "please use `HttpResponse::ResetContent()` instead")]
|
|
||||||
pub const HttpResetContent: StaticResponse = StaticResponse(StatusCode::RESET_CONTENT);
|
pub const HttpResetContent: StaticResponse = StaticResponse(StatusCode::RESET_CONTENT);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::PartialContent()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::PartialContent()` instead"
|
||||||
|
)]
|
||||||
pub const HttpPartialContent: StaticResponse =
|
pub const HttpPartialContent: StaticResponse =
|
||||||
StaticResponse(StatusCode::PARTIAL_CONTENT);
|
StaticResponse(StatusCode::PARTIAL_CONTENT);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::MultiStatus()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::MultiStatus()` instead")]
|
||||||
pub const HttpMultiStatus: StaticResponse = StaticResponse(StatusCode::MULTI_STATUS);
|
pub const HttpMultiStatus: StaticResponse = StaticResponse(StatusCode::MULTI_STATUS);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::AlreadyReported()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::AlreadyReported()` instead"
|
||||||
|
)]
|
||||||
pub const HttpAlreadyReported: StaticResponse =
|
pub const HttpAlreadyReported: StaticResponse =
|
||||||
StaticResponse(StatusCode::ALREADY_REPORTED);
|
StaticResponse(StatusCode::ALREADY_REPORTED);
|
||||||
|
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::MultipleChoices()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::MultipleChoices()` instead"
|
||||||
|
)]
|
||||||
pub const HttpMultipleChoices: StaticResponse =
|
pub const HttpMultipleChoices: StaticResponse =
|
||||||
StaticResponse(StatusCode::MULTIPLE_CHOICES);
|
StaticResponse(StatusCode::MULTIPLE_CHOICES);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::MovedPermanently()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::MovedPermanently()` instead"
|
||||||
|
)]
|
||||||
pub const HttpMovedPermanently: StaticResponse =
|
pub const HttpMovedPermanently: StaticResponse =
|
||||||
StaticResponse(StatusCode::MOVED_PERMANENTLY);
|
StaticResponse(StatusCode::MOVED_PERMANENTLY);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Found()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Found()` instead")]
|
||||||
@ -50,106 +55,125 @@ pub const HttpSeeOther: StaticResponse = StaticResponse(StatusCode::SEE_OTHER);
|
|||||||
pub const HttpNotModified: StaticResponse = StaticResponse(StatusCode::NOT_MODIFIED);
|
pub const HttpNotModified: StaticResponse = StaticResponse(StatusCode::NOT_MODIFIED);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::UseProxy()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::UseProxy()` instead")]
|
||||||
pub const HttpUseProxy: StaticResponse = StaticResponse(StatusCode::USE_PROXY);
|
pub const HttpUseProxy: StaticResponse = StaticResponse(StatusCode::USE_PROXY);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::TemporaryRedirect()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::TemporaryRedirect()` instead"
|
||||||
|
)]
|
||||||
pub const HttpTemporaryRedirect: StaticResponse =
|
pub const HttpTemporaryRedirect: StaticResponse =
|
||||||
StaticResponse(StatusCode::TEMPORARY_REDIRECT);
|
StaticResponse(StatusCode::TEMPORARY_REDIRECT);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::PermanentRedirect()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::PermanentRedirect()` instead"
|
||||||
|
)]
|
||||||
pub const HttpPermanentRedirect: StaticResponse =
|
pub const HttpPermanentRedirect: StaticResponse =
|
||||||
StaticResponse(StatusCode::PERMANENT_REDIRECT);
|
StaticResponse(StatusCode::PERMANENT_REDIRECT);
|
||||||
|
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::BadRequest()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::BadRequest()` instead")]
|
||||||
pub const HttpBadRequest: StaticResponse = StaticResponse(StatusCode::BAD_REQUEST);
|
pub const HttpBadRequest: StaticResponse = StaticResponse(StatusCode::BAD_REQUEST);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Unauthorized()` instead")]
|
||||||
note = "please use `HttpResponse::Unauthorized()` instead")]
|
|
||||||
pub const HttpUnauthorized: StaticResponse = StaticResponse(StatusCode::UNAUTHORIZED);
|
pub const HttpUnauthorized: StaticResponse = StaticResponse(StatusCode::UNAUTHORIZED);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::PaymentRequired()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::PaymentRequired()` instead"
|
||||||
|
)]
|
||||||
pub const HttpPaymentRequired: StaticResponse =
|
pub const HttpPaymentRequired: StaticResponse =
|
||||||
StaticResponse(StatusCode::PAYMENT_REQUIRED);
|
StaticResponse(StatusCode::PAYMENT_REQUIRED);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Forbidden()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Forbidden()` instead")]
|
||||||
pub const HttpForbidden: StaticResponse = StaticResponse(StatusCode::FORBIDDEN);
|
pub const HttpForbidden: StaticResponse = StaticResponse(StatusCode::FORBIDDEN);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::NotFound()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::NotFound()` instead")]
|
||||||
pub const HttpNotFound: StaticResponse = StaticResponse(StatusCode::NOT_FOUND);
|
pub const HttpNotFound: StaticResponse = StaticResponse(StatusCode::NOT_FOUND);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::MethodNotAllowed()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::MethodNotAllowed()` instead"
|
||||||
|
)]
|
||||||
pub const HttpMethodNotAllowed: StaticResponse =
|
pub const HttpMethodNotAllowed: StaticResponse =
|
||||||
StaticResponse(StatusCode::METHOD_NOT_ALLOWED);
|
StaticResponse(StatusCode::METHOD_NOT_ALLOWED);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::NotAcceptable()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::NotAcceptable()` instead"
|
||||||
|
)]
|
||||||
pub const HttpNotAcceptable: StaticResponse = StaticResponse(StatusCode::NOT_ACCEPTABLE);
|
pub const HttpNotAcceptable: StaticResponse = StaticResponse(StatusCode::NOT_ACCEPTABLE);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::ProxyAuthenticationRequired()` instead")]
|
since = "0.5.0",
|
||||||
|
note = "please use `HttpResponse::ProxyAuthenticationRequired()` instead"
|
||||||
|
)]
|
||||||
pub const HttpProxyAuthenticationRequired: StaticResponse =
|
pub const HttpProxyAuthenticationRequired: StaticResponse =
|
||||||
StaticResponse(StatusCode::PROXY_AUTHENTICATION_REQUIRED);
|
StaticResponse(StatusCode::PROXY_AUTHENTICATION_REQUIRED);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::RequestTimeout()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::RequestTimeout()` instead"
|
||||||
|
)]
|
||||||
pub const HttpRequestTimeout: StaticResponse =
|
pub const HttpRequestTimeout: StaticResponse =
|
||||||
StaticResponse(StatusCode::REQUEST_TIMEOUT);
|
StaticResponse(StatusCode::REQUEST_TIMEOUT);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Conflict()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Conflict()` instead")]
|
||||||
pub const HttpConflict: StaticResponse = StaticResponse(StatusCode::CONFLICT);
|
pub const HttpConflict: StaticResponse = StaticResponse(StatusCode::CONFLICT);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Gone()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::Gone()` instead")]
|
||||||
pub const HttpGone: StaticResponse = StaticResponse(StatusCode::GONE);
|
pub const HttpGone: StaticResponse = StaticResponse(StatusCode::GONE);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::LengthRequired()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::LengthRequired()` instead"
|
||||||
|
)]
|
||||||
pub const HttpLengthRequired: StaticResponse =
|
pub const HttpLengthRequired: StaticResponse =
|
||||||
StaticResponse(StatusCode::LENGTH_REQUIRED);
|
StaticResponse(StatusCode::LENGTH_REQUIRED);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::PreconditionFailed()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::PreconditionFailed()` instead"
|
||||||
|
)]
|
||||||
pub const HttpPreconditionFailed: StaticResponse =
|
pub const HttpPreconditionFailed: StaticResponse =
|
||||||
StaticResponse(StatusCode::PRECONDITION_FAILED);
|
StaticResponse(StatusCode::PRECONDITION_FAILED);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::PayloadTooLarge()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::PayloadTooLarge()` instead"
|
||||||
|
)]
|
||||||
pub const HttpPayloadTooLarge: StaticResponse =
|
pub const HttpPayloadTooLarge: StaticResponse =
|
||||||
StaticResponse(StatusCode::PAYLOAD_TOO_LARGE);
|
StaticResponse(StatusCode::PAYLOAD_TOO_LARGE);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::UriTooLong()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::UriTooLong()` instead")]
|
||||||
pub const HttpUriTooLong: StaticResponse = StaticResponse(StatusCode::URI_TOO_LONG);
|
pub const HttpUriTooLong: StaticResponse = StaticResponse(StatusCode::URI_TOO_LONG);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::UnsupportedMediaType()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::UnsupportedMediaType()` instead"
|
||||||
|
)]
|
||||||
pub const HttpUnsupportedMediaType: StaticResponse =
|
pub const HttpUnsupportedMediaType: StaticResponse =
|
||||||
StaticResponse(StatusCode::UNSUPPORTED_MEDIA_TYPE);
|
StaticResponse(StatusCode::UNSUPPORTED_MEDIA_TYPE);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::RangeNotSatisfiable()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::RangeNotSatisfiable()` instead"
|
||||||
|
)]
|
||||||
pub const HttpRangeNotSatisfiable: StaticResponse =
|
pub const HttpRangeNotSatisfiable: StaticResponse =
|
||||||
StaticResponse(StatusCode::RANGE_NOT_SATISFIABLE);
|
StaticResponse(StatusCode::RANGE_NOT_SATISFIABLE);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::ExpectationFailed()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::ExpectationFailed()` instead"
|
||||||
|
)]
|
||||||
pub const HttpExpectationFailed: StaticResponse =
|
pub const HttpExpectationFailed: StaticResponse =
|
||||||
StaticResponse(StatusCode::EXPECTATION_FAILED);
|
StaticResponse(StatusCode::EXPECTATION_FAILED);
|
||||||
|
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::InternalServerError()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::InternalServerError()` instead"
|
||||||
|
)]
|
||||||
pub const HttpInternalServerError: StaticResponse =
|
pub const HttpInternalServerError: StaticResponse =
|
||||||
StaticResponse(StatusCode::INTERNAL_SERVER_ERROR);
|
StaticResponse(StatusCode::INTERNAL_SERVER_ERROR);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::NotImplemented()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::NotImplemented()` instead"
|
||||||
|
)]
|
||||||
pub const HttpNotImplemented: StaticResponse =
|
pub const HttpNotImplemented: StaticResponse =
|
||||||
StaticResponse(StatusCode::NOT_IMPLEMENTED);
|
StaticResponse(StatusCode::NOT_IMPLEMENTED);
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::BadGateway()` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::BadGateway()` instead")]
|
||||||
pub const HttpBadGateway: StaticResponse = StaticResponse(StatusCode::BAD_GATEWAY);
|
pub const HttpBadGateway: StaticResponse = StaticResponse(StatusCode::BAD_GATEWAY);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::ServiceUnavailable()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::ServiceUnavailable()` instead"
|
||||||
|
)]
|
||||||
pub const HttpServiceUnavailable: StaticResponse =
|
pub const HttpServiceUnavailable: StaticResponse =
|
||||||
StaticResponse(StatusCode::SERVICE_UNAVAILABLE);
|
StaticResponse(StatusCode::SERVICE_UNAVAILABLE);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::GatewayTimeout()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::GatewayTimeout()` instead"
|
||||||
|
)]
|
||||||
pub const HttpGatewayTimeout: StaticResponse =
|
pub const HttpGatewayTimeout: StaticResponse =
|
||||||
StaticResponse(StatusCode::GATEWAY_TIMEOUT);
|
StaticResponse(StatusCode::GATEWAY_TIMEOUT);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::VersionNotSupported()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::VersionNotSupported()` instead"
|
||||||
|
)]
|
||||||
pub const HttpVersionNotSupported: StaticResponse =
|
pub const HttpVersionNotSupported: StaticResponse =
|
||||||
StaticResponse(StatusCode::HTTP_VERSION_NOT_SUPPORTED);
|
StaticResponse(StatusCode::HTTP_VERSION_NOT_SUPPORTED);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::VariantAlsoNegotiates()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::VariantAlsoNegotiates()` instead"
|
||||||
|
)]
|
||||||
pub const HttpVariantAlsoNegotiates: StaticResponse =
|
pub const HttpVariantAlsoNegotiates: StaticResponse =
|
||||||
StaticResponse(StatusCode::VARIANT_ALSO_NEGOTIATES);
|
StaticResponse(StatusCode::VARIANT_ALSO_NEGOTIATES);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(
|
||||||
note = "please use `HttpResponse::InsufficientStorage()` instead")]
|
since = "0.5.0", note = "please use `HttpResponse::InsufficientStorage()` instead"
|
||||||
|
)]
|
||||||
pub const HttpInsufficientStorage: StaticResponse =
|
pub const HttpInsufficientStorage: StaticResponse =
|
||||||
StaticResponse(StatusCode::INSUFFICIENT_STORAGE);
|
StaticResponse(StatusCode::INSUFFICIENT_STORAGE);
|
||||||
#[deprecated(since = "0.5.0",
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse::LoopDetected()` instead")]
|
||||||
note = "please use `HttpResponse::LoopDetected()` instead")]
|
|
||||||
pub const HttpLoopDetected: StaticResponse = StaticResponse(StatusCode::LOOP_DETECTED);
|
pub const HttpLoopDetected: StaticResponse = StaticResponse(StatusCode::LOOP_DETECTED);
|
||||||
|
|
||||||
#[deprecated(since = "0.5.0", note = "please use `HttpResponse` instead")]
|
#[deprecated(since = "0.5.0", note = "please use `HttpResponse` instead")]
|
||||||
@ -221,10 +245,7 @@ impl HttpResponse {
|
|||||||
STATIC_RESP!(Ok, StatusCode::OK);
|
STATIC_RESP!(Ok, StatusCode::OK);
|
||||||
STATIC_RESP!(Created, StatusCode::CREATED);
|
STATIC_RESP!(Created, StatusCode::CREATED);
|
||||||
STATIC_RESP!(Accepted, StatusCode::ACCEPTED);
|
STATIC_RESP!(Accepted, StatusCode::ACCEPTED);
|
||||||
STATIC_RESP!(
|
STATIC_RESP!(NonAuthoritativeInformation, StatusCode::NON_AUTHORITATIVE_INFORMATION);
|
||||||
NonAuthoritativeInformation,
|
|
||||||
StatusCode::NON_AUTHORITATIVE_INFORMATION
|
|
||||||
);
|
|
||||||
|
|
||||||
STATIC_RESP!(NoContent, StatusCode::NO_CONTENT);
|
STATIC_RESP!(NoContent, StatusCode::NO_CONTENT);
|
||||||
STATIC_RESP!(ResetContent, StatusCode::RESET_CONTENT);
|
STATIC_RESP!(ResetContent, StatusCode::RESET_CONTENT);
|
||||||
@ -249,10 +270,7 @@ impl HttpResponse {
|
|||||||
STATIC_RESP!(Forbidden, StatusCode::FORBIDDEN);
|
STATIC_RESP!(Forbidden, StatusCode::FORBIDDEN);
|
||||||
STATIC_RESP!(MethodNotAllowed, StatusCode::METHOD_NOT_ALLOWED);
|
STATIC_RESP!(MethodNotAllowed, StatusCode::METHOD_NOT_ALLOWED);
|
||||||
STATIC_RESP!(NotAcceptable, StatusCode::NOT_ACCEPTABLE);
|
STATIC_RESP!(NotAcceptable, StatusCode::NOT_ACCEPTABLE);
|
||||||
STATIC_RESP!(
|
STATIC_RESP!(ProxyAuthenticationRequired, StatusCode::PROXY_AUTHENTICATION_REQUIRED);
|
||||||
ProxyAuthenticationRequired,
|
|
||||||
StatusCode::PROXY_AUTHENTICATION_REQUIRED
|
|
||||||
);
|
|
||||||
STATIC_RESP!(RequestTimeout, StatusCode::REQUEST_TIMEOUT);
|
STATIC_RESP!(RequestTimeout, StatusCode::REQUEST_TIMEOUT);
|
||||||
STATIC_RESP!(Conflict, StatusCode::CONFLICT);
|
STATIC_RESP!(Conflict, StatusCode::CONFLICT);
|
||||||
STATIC_RESP!(Gone, StatusCode::GONE);
|
STATIC_RESP!(Gone, StatusCode::GONE);
|
||||||
@ -260,10 +278,7 @@ impl HttpResponse {
|
|||||||
STATIC_RESP!(PreconditionFailed, StatusCode::PRECONDITION_FAILED);
|
STATIC_RESP!(PreconditionFailed, StatusCode::PRECONDITION_FAILED);
|
||||||
STATIC_RESP!(PayloadTooLarge, StatusCode::PAYLOAD_TOO_LARGE);
|
STATIC_RESP!(PayloadTooLarge, StatusCode::PAYLOAD_TOO_LARGE);
|
||||||
STATIC_RESP!(UriTooLong, StatusCode::URI_TOO_LONG);
|
STATIC_RESP!(UriTooLong, StatusCode::URI_TOO_LONG);
|
||||||
STATIC_RESP!(
|
STATIC_RESP!(UnsupportedMediaType, StatusCode::UNSUPPORTED_MEDIA_TYPE);
|
||||||
UnsupportedMediaType,
|
|
||||||
StatusCode::UNSUPPORTED_MEDIA_TYPE
|
|
||||||
);
|
|
||||||
STATIC_RESP!(RangeNotSatisfiable, StatusCode::RANGE_NOT_SATISFIABLE);
|
STATIC_RESP!(RangeNotSatisfiable, StatusCode::RANGE_NOT_SATISFIABLE);
|
||||||
STATIC_RESP!(ExpectationFailed, StatusCode::EXPECTATION_FAILED);
|
STATIC_RESP!(ExpectationFailed, StatusCode::EXPECTATION_FAILED);
|
||||||
|
|
||||||
@ -272,14 +287,8 @@ impl HttpResponse {
|
|||||||
STATIC_RESP!(BadGateway, StatusCode::BAD_GATEWAY);
|
STATIC_RESP!(BadGateway, StatusCode::BAD_GATEWAY);
|
||||||
STATIC_RESP!(ServiceUnavailable, StatusCode::SERVICE_UNAVAILABLE);
|
STATIC_RESP!(ServiceUnavailable, StatusCode::SERVICE_UNAVAILABLE);
|
||||||
STATIC_RESP!(GatewayTimeout, StatusCode::GATEWAY_TIMEOUT);
|
STATIC_RESP!(GatewayTimeout, StatusCode::GATEWAY_TIMEOUT);
|
||||||
STATIC_RESP!(
|
STATIC_RESP!(VersionNotSupported, StatusCode::HTTP_VERSION_NOT_SUPPORTED);
|
||||||
VersionNotSupported,
|
STATIC_RESP!(VariantAlsoNegotiates, StatusCode::VARIANT_ALSO_NEGOTIATES);
|
||||||
StatusCode::HTTP_VERSION_NOT_SUPPORTED
|
|
||||||
);
|
|
||||||
STATIC_RESP!(
|
|
||||||
VariantAlsoNegotiates,
|
|
||||||
StatusCode::VARIANT_ALSO_NEGOTIATES
|
|
||||||
);
|
|
||||||
STATIC_RESP!(InsufficientStorage, StatusCode::INSUFFICIENT_STORAGE);
|
STATIC_RESP!(InsufficientStorage, StatusCode::INSUFFICIENT_STORAGE);
|
||||||
STATIC_RESP!(LoopDetected, StatusCode::LOOP_DETECTED);
|
STATIC_RESP!(LoopDetected, StatusCode::LOOP_DETECTED);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use encoding::EncodingRef;
|
|
||||||
use encoding::all::UTF_8;
|
use encoding::all::UTF_8;
|
||||||
use encoding::label::encoding_from_whatwg_label;
|
use encoding::label::encoding_from_whatwg_label;
|
||||||
use encoding::types::{DecoderTrap, Encoding};
|
use encoding::types::{DecoderTrap, Encoding};
|
||||||
|
use encoding::EncodingRef;
|
||||||
use futures::{Future, Poll, Stream};
|
use futures::{Future, Poll, Stream};
|
||||||
use http::{header, HeaderMap};
|
use http::{header, HeaderMap};
|
||||||
use http_range::HttpRange;
|
use http_range::HttpRange;
|
||||||
@ -96,10 +96,8 @@ pub trait HttpMessage {
|
|||||||
/// `size` is full size of response (file).
|
/// `size` is full size of response (file).
|
||||||
fn range(&self, size: u64) -> Result<Vec<HttpRange>, HttpRangeError> {
|
fn range(&self, size: u64) -> Result<Vec<HttpRange>, HttpRangeError> {
|
||||||
if let Some(range) = self.headers().get(header::RANGE) {
|
if let Some(range) = self.headers().get(header::RANGE) {
|
||||||
HttpRange::parse(
|
HttpRange::parse(unsafe { str::from_utf8_unchecked(range.as_bytes()) }, size)
|
||||||
unsafe { str::from_utf8_unchecked(range.as_bytes()) },
|
.map_err(|e| e.into())
|
||||||
size,
|
|
||||||
).map_err(|e| e.into())
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
}
|
}
|
||||||
@ -325,10 +323,7 @@ where
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fut
|
self.fut.as_mut().expect("UrlEncoded could not be used second time").poll()
|
||||||
.as_mut()
|
|
||||||
.expect("UrlEncoded could not be used second time")
|
|
||||||
.poll()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,8 +380,7 @@ where
|
|||||||
if req.content_type().to_lowercase() != "application/x-www-form-urlencoded" {
|
if req.content_type().to_lowercase() != "application/x-www-form-urlencoded" {
|
||||||
return Err(UrlencodedError::ContentType);
|
return Err(UrlencodedError::ContentType);
|
||||||
}
|
}
|
||||||
let encoding = req.encoding()
|
let encoding = req.encoding().map_err(|_| UrlencodedError::ContentType)?;
|
||||||
.map_err(|_| UrlencodedError::ContentType)?;
|
|
||||||
|
|
||||||
// future
|
// future
|
||||||
let limit = self.limit;
|
let limit = self.limit;
|
||||||
@ -415,18 +409,15 @@ where
|
|||||||
self.fut = Some(Box::new(fut));
|
self.fut = Some(Box::new(fut));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fut
|
self.fut.as_mut().expect("UrlEncoded could not be used second time").poll()
|
||||||
.as_mut()
|
|
||||||
.expect("UrlEncoded could not be used second time")
|
|
||||||
.poll()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use encoding::Encoding;
|
|
||||||
use encoding::all::ISO_8859_2;
|
use encoding::all::ISO_8859_2;
|
||||||
|
use encoding::Encoding;
|
||||||
use futures::Async;
|
use futures::Async;
|
||||||
use http::{Method, Uri, Version};
|
use http::{Method, Uri, Version};
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
@ -488,19 +479,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_encoding_error() {
|
fn test_encoding_error() {
|
||||||
let req = TestRequest::with_header("content-type", "applicatjson").finish();
|
let req = TestRequest::with_header("content-type", "applicatjson").finish();
|
||||||
assert_eq!(
|
assert_eq!(Some(ContentTypeError::ParseError), req.encoding().err());
|
||||||
Some(ContentTypeError::ParseError),
|
|
||||||
req.encoding().err()
|
|
||||||
);
|
|
||||||
|
|
||||||
let req = TestRequest::with_header(
|
let req = TestRequest::with_header(
|
||||||
"content-type",
|
"content-type",
|
||||||
"application/json; charset=kkkttktk",
|
"application/json; charset=kkkttktk",
|
||||||
).finish();
|
).finish();
|
||||||
assert_eq!(
|
assert_eq!(Some(ContentTypeError::UnknownEncoding), req.encoding().err());
|
||||||
Some(ContentTypeError::UnknownEncoding),
|
|
||||||
req.encoding().err()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -621,8 +606,7 @@ mod tests {
|
|||||||
"application/x-www-form-urlencoded",
|
"application/x-www-form-urlencoded",
|
||||||
).header(header::CONTENT_LENGTH, "11")
|
).header(header::CONTENT_LENGTH, "11")
|
||||||
.finish();
|
.finish();
|
||||||
req.payload_mut()
|
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
||||||
.unread_data(Bytes::from_static(b"hello=world"));
|
|
||||||
|
|
||||||
let result = req.urlencoded::<Info>().poll().ok().unwrap();
|
let result = req.urlencoded::<Info>().poll().ok().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -637,8 +621,7 @@ mod tests {
|
|||||||
"application/x-www-form-urlencoded; charset=utf-8",
|
"application/x-www-form-urlencoded; charset=utf-8",
|
||||||
).header(header::CONTENT_LENGTH, "11")
|
).header(header::CONTENT_LENGTH, "11")
|
||||||
.finish();
|
.finish();
|
||||||
req.payload_mut()
|
req.payload_mut().unread_data(Bytes::from_static(b"hello=world"));
|
||||||
.unread_data(Bytes::from_static(b"hello=world"));
|
|
||||||
|
|
||||||
let result = req.urlencoded().poll().ok().unwrap();
|
let result = req.urlencoded().poll().ok().unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -664,16 +647,14 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
req.payload_mut()
|
req.payload_mut().unread_data(Bytes::from_static(b"test"));
|
||||||
.unread_data(Bytes::from_static(b"test"));
|
|
||||||
match req.body().poll().ok().unwrap() {
|
match req.body().poll().ok().unwrap() {
|
||||||
Async::Ready(bytes) => assert_eq!(bytes, Bytes::from_static(b"test")),
|
Async::Ready(bytes) => assert_eq!(bytes, Bytes::from_static(b"test")),
|
||||||
_ => unreachable!("error"),
|
_ => unreachable!("error"),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
req.payload_mut()
|
req.payload_mut().unread_data(Bytes::from_static(b"11111111111111"));
|
||||||
.unread_data(Bytes::from_static(b"11111111111111"));
|
|
||||||
match req.body().limit(5).poll().err().unwrap() {
|
match req.body().limit(5).poll().err().unwrap() {
|
||||||
PayloadError::Overflow => (),
|
PayloadError::Overflow => (),
|
||||||
_ => unreachable!("error"),
|
_ => unreachable!("error"),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
//! HTTP Request message related code.
|
//! HTTP Request message related code.
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ptr))]
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use cookie::Cookie;
|
use cookie::Cookie;
|
||||||
use failure;
|
use failure;
|
||||||
@ -314,7 +315,7 @@ impl<S> HttpRequest<S> {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn url_for<U, I>(
|
pub fn url_for<U, I>(
|
||||||
&self, name: &str, elements: U
|
&self, name: &str, elements: U,
|
||||||
) -> Result<Url, UrlGenerationError>
|
) -> Result<Url, UrlGenerationError>
|
||||||
where
|
where
|
||||||
U: IntoIterator<Item = I>,
|
U: IntoIterator<Item = I>,
|
||||||
@ -326,12 +327,7 @@ impl<S> HttpRequest<S> {
|
|||||||
let path = self.router().unwrap().resource_path(name, elements)?;
|
let path = self.router().unwrap().resource_path(name, elements)?;
|
||||||
if path.starts_with('/') {
|
if path.starts_with('/') {
|
||||||
let conn = self.connection_info();
|
let conn = self.connection_info();
|
||||||
Ok(Url::parse(&format!(
|
Ok(Url::parse(&format!("{}://{}{}", conn.scheme(), conn.host(), path))?)
|
||||||
"{}://{}{}",
|
|
||||||
conn.scheme(),
|
|
||||||
conn.host(),
|
|
||||||
path
|
|
||||||
))?)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Url::parse(&path)?)
|
Ok(Url::parse(&path)?)
|
||||||
}
|
}
|
||||||
@ -681,12 +677,8 @@ mod tests {
|
|||||||
|
|
||||||
let mut resource = ResourceHandler::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let routes = vec![
|
let routes =
|
||||||
(
|
vec![(Resource::new("index", "/user/{name}.{ext}"), Some(resource))];
|
||||||
Resource::new("index", "/user/{name}.{ext}"),
|
|
||||||
Some(resource),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
let (router, _) = Router::new("/", ServerSettings::default(), routes);
|
let (router, _) = Router::new("/", ServerSettings::default(), routes);
|
||||||
assert!(router.has_route("/user/test.html"));
|
assert!(router.has_route("/user/test.html"));
|
||||||
assert!(!router.has_route("/test/unknown"));
|
assert!(!router.has_route("/test/unknown"));
|
||||||
@ -715,12 +707,8 @@ mod tests {
|
|||||||
|
|
||||||
let mut resource = ResourceHandler::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let routes = vec![
|
let routes =
|
||||||
(
|
vec![(Resource::new("index", "/user/{name}.{ext}"), Some(resource))];
|
||||||
Resource::new("index", "/user/{name}.{ext}"),
|
|
||||||
Some(resource),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
let (router, _) = Router::new("/prefix/", ServerSettings::default(), routes);
|
let (router, _) = Router::new("/prefix/", ServerSettings::default(), routes);
|
||||||
assert!(router.has_route("/user/test.html"));
|
assert!(router.has_route("/user/test.html"));
|
||||||
assert!(!router.has_route("/prefix/user/test.html"));
|
assert!(!router.has_route("/prefix/user/test.html"));
|
||||||
@ -739,20 +727,15 @@ mod tests {
|
|||||||
|
|
||||||
let mut resource = ResourceHandler::<()>::default();
|
let mut resource = ResourceHandler::<()>::default();
|
||||||
resource.name("index");
|
resource.name("index");
|
||||||
let routes = vec![
|
let routes = vec![(
|
||||||
(
|
Resource::external("youtube", "https://youtube.com/watch/{video_id}"),
|
||||||
Resource::external("youtube", "https://youtube.com/watch/{video_id}"),
|
None,
|
||||||
None,
|
)];
|
||||||
),
|
|
||||||
];
|
|
||||||
let (router, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
let (router, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
assert!(!router.has_route("https://youtube.com/watch/unknown"));
|
assert!(!router.has_route("https://youtube.com/watch/unknown"));
|
||||||
|
|
||||||
let req = req.with_state(Rc::new(()), router);
|
let req = req.with_state(Rc::new(()), router);
|
||||||
let url = req.url_for("youtube", &["oHg5SJYRHA0"]);
|
let url = req.url_for("youtube", &["oHg5SJYRHA0"]);
|
||||||
assert_eq!(
|
assert_eq!(url.ok().unwrap().as_str(), "https://youtube.com/watch/oHg5SJYRHA0");
|
||||||
url.ok().unwrap().as_str(),
|
|
||||||
"https://youtube.com/watch/oHg5SJYRHA0"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,10 +150,7 @@ impl HttpResponse {
|
|||||||
if let Some(reason) = self.get_ref().reason {
|
if let Some(reason) = self.get_ref().reason {
|
||||||
reason
|
reason
|
||||||
} else {
|
} else {
|
||||||
self.get_ref()
|
self.get_ref().status.canonical_reason().unwrap_or("<unknown status code>")
|
||||||
.status
|
|
||||||
.canonical_reason()
|
|
||||||
.unwrap_or("<unknown status code>")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,10 +463,7 @@ impl HttpResponseBuilder {
|
|||||||
jar.add(cookie.into_owned());
|
jar.add(cookie.into_owned());
|
||||||
self.cookies = Some(jar)
|
self.cookies = Some(jar)
|
||||||
} else {
|
} else {
|
||||||
self.cookies
|
self.cookies.as_mut().unwrap().add(cookie.into_owned());
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.add(cookie.into_owned());
|
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -534,9 +528,7 @@ impl HttpResponseBuilder {
|
|||||||
if let Some(e) = self.err.take() {
|
if let Some(e) = self.err.take() {
|
||||||
return Error::from(e).into();
|
return Error::from(e).into();
|
||||||
}
|
}
|
||||||
let mut response = self.response
|
let mut response = self.response.take().expect("cannot reuse response builder");
|
||||||
.take()
|
|
||||||
.expect("cannot reuse response builder");
|
|
||||||
if let Some(ref jar) = self.cookies {
|
if let Some(ref jar) = self.cookies {
|
||||||
for cookie in jar.delta() {
|
for cookie in jar.delta() {
|
||||||
match HeaderValue::from_str(&cookie.to_string()) {
|
match HeaderValue::from_str(&cookie.to_string()) {
|
||||||
@ -558,9 +550,7 @@ impl HttpResponseBuilder {
|
|||||||
S: Stream<Item = Bytes, Error = E> + 'static,
|
S: Stream<Item = Bytes, Error = E> + 'static,
|
||||||
E: Into<Error>,
|
E: Into<Error>,
|
||||||
{
|
{
|
||||||
self.body(Body::Streaming(Box::new(
|
self.body(Body::Streaming(Box::new(stream.map_err(|e| e.into()))))
|
||||||
stream.map_err(|e| e.into()),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a json body and generate `HttpResponse`
|
/// Set a json body and generate `HttpResponse`
|
||||||
@ -607,7 +597,7 @@ impl HttpResponseBuilder {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(borrowed_box))]
|
#[cfg_attr(feature = "cargo-clippy", allow(borrowed_box))]
|
||||||
fn parts<'a>(
|
fn parts<'a>(
|
||||||
parts: &'a mut Option<Box<InnerHttpResponse>>, err: &Option<HttpError>
|
parts: &'a mut Option<Box<InnerHttpResponse>>, err: &Option<HttpError>,
|
||||||
) -> Option<&'a mut Box<InnerHttpResponse>> {
|
) -> Option<&'a mut Box<InnerHttpResponse>> {
|
||||||
if err.is_some() {
|
if err.is_some() {
|
||||||
return None;
|
return None;
|
||||||
@ -643,9 +633,7 @@ impl Responder for HttpResponseBuilder {
|
|||||||
|
|
||||||
impl From<&'static str> for HttpResponse {
|
impl From<&'static str> for HttpResponse {
|
||||||
fn from(val: &'static str) -> Self {
|
fn from(val: &'static str) -> Self {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().content_type("text/plain; charset=utf-8").body(val)
|
||||||
.content_type("text/plain; charset=utf-8")
|
|
||||||
.body(val)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,9 +650,7 @@ impl Responder for &'static str {
|
|||||||
|
|
||||||
impl From<&'static [u8]> for HttpResponse {
|
impl From<&'static [u8]> for HttpResponse {
|
||||||
fn from(val: &'static [u8]) -> Self {
|
fn from(val: &'static [u8]) -> Self {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().content_type("application/octet-stream").body(val)
|
||||||
.content_type("application/octet-stream")
|
|
||||||
.body(val)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -681,9 +667,7 @@ impl Responder for &'static [u8] {
|
|||||||
|
|
||||||
impl From<String> for HttpResponse {
|
impl From<String> for HttpResponse {
|
||||||
fn from(val: String) -> Self {
|
fn from(val: String) -> Self {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().content_type("text/plain; charset=utf-8").body(val)
|
||||||
.content_type("text/plain; charset=utf-8")
|
|
||||||
.body(val)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -719,9 +703,7 @@ impl<'a> Responder for &'a String {
|
|||||||
|
|
||||||
impl From<Bytes> for HttpResponse {
|
impl From<Bytes> for HttpResponse {
|
||||||
fn from(val: Bytes) -> Self {
|
fn from(val: Bytes) -> Self {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().content_type("application/octet-stream").body(val)
|
||||||
.content_type("application/octet-stream")
|
|
||||||
.body(val)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -738,9 +720,7 @@ impl Responder for Bytes {
|
|||||||
|
|
||||||
impl From<BytesMut> for HttpResponse {
|
impl From<BytesMut> for HttpResponse {
|
||||||
fn from(val: BytesMut) -> Self {
|
fn from(val: BytesMut) -> Self {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().content_type("application/octet-stream").body(val)
|
||||||
.content_type("application/octet-stream")
|
|
||||||
.body(val)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -772,9 +752,7 @@ impl<'a> From<&'a ClientResponse> for HttpResponseBuilder {
|
|||||||
impl<'a, S> From<&'a HttpRequest<S>> for HttpResponseBuilder {
|
impl<'a, S> From<&'a HttpRequest<S>> for HttpResponseBuilder {
|
||||||
fn from(req: &'a HttpRequest<S>) -> HttpResponseBuilder {
|
fn from(req: &'a HttpRequest<S>) -> HttpResponseBuilder {
|
||||||
if let Some(router) = req.router() {
|
if let Some(router) = req.router() {
|
||||||
router
|
router.server_settings().get_response_builder(StatusCode::OK)
|
||||||
.server_settings()
|
|
||||||
.get_response_builder(StatusCode::OK)
|
|
||||||
} else {
|
} else {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
}
|
}
|
||||||
@ -822,14 +800,12 @@ thread_local!(static POOL: Rc<UnsafeCell<HttpResponsePool>> = HttpResponsePool::
|
|||||||
|
|
||||||
impl HttpResponsePool {
|
impl HttpResponsePool {
|
||||||
pub fn pool() -> Rc<UnsafeCell<HttpResponsePool>> {
|
pub fn pool() -> Rc<UnsafeCell<HttpResponsePool>> {
|
||||||
Rc::new(UnsafeCell::new(HttpResponsePool(
|
Rc::new(UnsafeCell::new(HttpResponsePool(VecDeque::with_capacity(128))))
|
||||||
VecDeque::with_capacity(128),
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_builder(
|
pub fn get_builder(
|
||||||
pool: &Rc<UnsafeCell<HttpResponsePool>>, status: StatusCode
|
pool: &Rc<UnsafeCell<HttpResponsePool>>, status: StatusCode,
|
||||||
) -> HttpResponseBuilder {
|
) -> HttpResponseBuilder {
|
||||||
let p = unsafe { &mut *pool.as_ref().get() };
|
let p = unsafe { &mut *pool.as_ref().get() };
|
||||||
if let Some(mut msg) = p.0.pop_front() {
|
if let Some(mut msg) = p.0.pop_front() {
|
||||||
@ -853,7 +829,7 @@ impl HttpResponsePool {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_response(
|
pub fn get_response(
|
||||||
pool: &Rc<UnsafeCell<HttpResponsePool>>, status: StatusCode, body: Body
|
pool: &Rc<UnsafeCell<HttpResponsePool>>, status: StatusCode, body: Body,
|
||||||
) -> HttpResponse {
|
) -> HttpResponse {
|
||||||
let p = unsafe { &mut *pool.as_ref().get() };
|
let p = unsafe { &mut *pool.as_ref().get() };
|
||||||
if let Some(mut msg) = p.0.pop_front() {
|
if let Some(mut msg) = p.0.pop_front() {
|
||||||
@ -879,7 +855,7 @@ impl HttpResponsePool {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local, inline_always))]
|
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local, inline_always))]
|
||||||
fn release(
|
fn release(
|
||||||
pool: &Rc<UnsafeCell<HttpResponsePool>>, mut inner: Box<InnerHttpResponse>
|
pool: &Rc<UnsafeCell<HttpResponsePool>>, mut inner: Box<InnerHttpResponse>,
|
||||||
) {
|
) {
|
||||||
let pool = unsafe { &mut *pool.as_ref().get() };
|
let pool = unsafe { &mut *pool.as_ref().get() };
|
||||||
if pool.0.len() < 128 {
|
if pool.0.len() < 128 {
|
||||||
@ -975,9 +951,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_force_close() {
|
fn test_force_close() {
|
||||||
let resp = HttpResponse::build(StatusCode::OK)
|
let resp = HttpResponse::build(StatusCode::OK).force_close().finish();
|
||||||
.force_close()
|
|
||||||
.finish();
|
|
||||||
assert!(!resp.keep_alive().unwrap())
|
assert!(!resp.keep_alive().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -986,10 +960,7 @@ mod tests {
|
|||||||
let resp = HttpResponse::build(StatusCode::OK)
|
let resp = HttpResponse::build(StatusCode::OK)
|
||||||
.content_type("text/plain")
|
.content_type("text/plain")
|
||||||
.body(Body::Empty);
|
.body(Body::Empty);
|
||||||
assert_eq!(
|
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "text/plain")
|
||||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
|
||||||
"text/plain"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1073,10 +1044,7 @@ mod tests {
|
|||||||
HeaderValue::from_static("application/octet-stream")
|
HeaderValue::from_static("application/octet-stream")
|
||||||
);
|
);
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(resp.body().binary().unwrap(), &Binary::from(b"test".as_ref()));
|
||||||
resp.body().binary().unwrap(),
|
|
||||||
&Binary::from(b"test".as_ref())
|
|
||||||
);
|
|
||||||
|
|
||||||
let resp: HttpResponse = b"test".as_ref().respond_to(req.clone()).ok().unwrap();
|
let resp: HttpResponse = b"test".as_ref().respond_to(req.clone()).ok().unwrap();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
@ -1085,10 +1053,7 @@ mod tests {
|
|||||||
HeaderValue::from_static("application/octet-stream")
|
HeaderValue::from_static("application/octet-stream")
|
||||||
);
|
);
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(resp.body().binary().unwrap(), &Binary::from(b"test".as_ref()));
|
||||||
resp.body().binary().unwrap(),
|
|
||||||
&Binary::from(b"test".as_ref())
|
|
||||||
);
|
|
||||||
|
|
||||||
let resp: HttpResponse = "test".to_owned().into();
|
let resp: HttpResponse = "test".to_owned().into();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
@ -1097,26 +1062,16 @@ mod tests {
|
|||||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||||
);
|
);
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(resp.body().binary().unwrap(), &Binary::from("test".to_owned()));
|
||||||
resp.body().binary().unwrap(),
|
|
||||||
&Binary::from("test".to_owned())
|
|
||||||
);
|
|
||||||
|
|
||||||
let resp: HttpResponse = "test"
|
let resp: HttpResponse = "test".to_owned().respond_to(req.clone()).ok().unwrap();
|
||||||
.to_owned()
|
|
||||||
.respond_to(req.clone())
|
|
||||||
.ok()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||||
);
|
);
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(resp.body().binary().unwrap(), &Binary::from("test".to_owned()));
|
||||||
resp.body().binary().unwrap(),
|
|
||||||
&Binary::from("test".to_owned())
|
|
||||||
);
|
|
||||||
|
|
||||||
let resp: HttpResponse = (&"test".to_owned()).into();
|
let resp: HttpResponse = (&"test".to_owned()).into();
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
@ -1125,25 +1080,17 @@ mod tests {
|
|||||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||||
);
|
);
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(resp.body().binary().unwrap(), &Binary::from(&"test".to_owned()));
|
||||||
resp.body().binary().unwrap(),
|
|
||||||
&Binary::from(&"test".to_owned())
|
|
||||||
);
|
|
||||||
|
|
||||||
let resp: HttpResponse = (&"test".to_owned())
|
let resp: HttpResponse =
|
||||||
.respond_to(req.clone())
|
(&"test".to_owned()).respond_to(req.clone()).ok().unwrap();
|
||||||
.ok()
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resp.headers().get(CONTENT_TYPE).unwrap(),
|
resp.headers().get(CONTENT_TYPE).unwrap(),
|
||||||
HeaderValue::from_static("text/plain; charset=utf-8")
|
HeaderValue::from_static("text/plain; charset=utf-8")
|
||||||
);
|
);
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(resp.body().binary().unwrap(), &Binary::from(&"test".to_owned()));
|
||||||
resp.body().binary().unwrap(),
|
|
||||||
&Binary::from(&"test".to_owned())
|
|
||||||
);
|
|
||||||
|
|
||||||
let b = Bytes::from_static(b"test");
|
let b = Bytes::from_static(b"test");
|
||||||
let resp: HttpResponse = b.into();
|
let resp: HttpResponse = b.into();
|
||||||
@ -1179,10 +1126,7 @@ mod tests {
|
|||||||
HeaderValue::from_static("application/octet-stream")
|
HeaderValue::from_static("application/octet-stream")
|
||||||
);
|
);
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(resp.body().binary().unwrap(), &Binary::from(BytesMut::from("test")));
|
||||||
resp.body().binary().unwrap(),
|
|
||||||
&Binary::from(BytesMut::from("test"))
|
|
||||||
);
|
|
||||||
|
|
||||||
let b = BytesMut::from("test");
|
let b = BytesMut::from("test");
|
||||||
let resp: HttpResponse = b.respond_to(req.clone()).ok().unwrap();
|
let resp: HttpResponse = b.respond_to(req.clone()).ok().unwrap();
|
||||||
@ -1192,10 +1136,7 @@ mod tests {
|
|||||||
HeaderValue::from_static("application/octet-stream")
|
HeaderValue::from_static("application/octet-stream")
|
||||||
);
|
);
|
||||||
assert_eq!(resp.status(), StatusCode::OK);
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
assert_eq!(
|
assert_eq!(resp.body().binary().unwrap(), &Binary::from(BytesMut::from("test")));
|
||||||
resp.body().binary().unwrap(),
|
|
||||||
&Binary::from(BytesMut::from("test"))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
18
src/info.rs
18
src/info.rs
@ -53,8 +53,8 @@ impl<'a> ConnectionInfo<'a> {
|
|||||||
|
|
||||||
// scheme
|
// scheme
|
||||||
if scheme.is_none() {
|
if scheme.is_none() {
|
||||||
if let Some(h) = req.headers()
|
if let Some(h) =
|
||||||
.get(HeaderName::from_str(X_FORWARDED_PROTO).unwrap())
|
req.headers().get(HeaderName::from_str(X_FORWARDED_PROTO).unwrap())
|
||||||
{
|
{
|
||||||
if let Ok(h) = h.to_str() {
|
if let Ok(h) = h.to_str() {
|
||||||
scheme = h.split(',').next().map(|v| v.trim());
|
scheme = h.split(',').next().map(|v| v.trim());
|
||||||
@ -74,8 +74,8 @@ impl<'a> ConnectionInfo<'a> {
|
|||||||
|
|
||||||
// host
|
// host
|
||||||
if host.is_none() {
|
if host.is_none() {
|
||||||
if let Some(h) = req.headers()
|
if let Some(h) =
|
||||||
.get(HeaderName::from_str(X_FORWARDED_HOST).unwrap())
|
req.headers().get(HeaderName::from_str(X_FORWARDED_HOST).unwrap())
|
||||||
{
|
{
|
||||||
if let Ok(h) = h.to_str() {
|
if let Ok(h) = h.to_str() {
|
||||||
host = h.split(',').next().map(|v| v.trim());
|
host = h.split(',').next().map(|v| v.trim());
|
||||||
@ -98,8 +98,8 @@ impl<'a> ConnectionInfo<'a> {
|
|||||||
|
|
||||||
// remote addr
|
// remote addr
|
||||||
if remote.is_none() {
|
if remote.is_none() {
|
||||||
if let Some(h) = req.headers()
|
if let Some(h) =
|
||||||
.get(HeaderName::from_str(X_FORWARDED_FOR).unwrap())
|
req.headers().get(HeaderName::from_str(X_FORWARDED_FOR).unwrap())
|
||||||
{
|
{
|
||||||
if let Ok(h) = h.to_str() {
|
if let Ok(h) = h.to_str() {
|
||||||
remote = h.split(',').next().map(|v| v.trim());
|
remote = h.split(',').next().map(|v| v.trim());
|
||||||
@ -189,10 +189,8 @@ mod tests {
|
|||||||
assert_eq!(info.remote(), Some("192.0.2.60"));
|
assert_eq!(info.remote(), Some("192.0.2.60"));
|
||||||
|
|
||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
req.headers_mut().insert(
|
req.headers_mut()
|
||||||
header::HOST,
|
.insert(header::HOST, HeaderValue::from_static("rust-lang.org"));
|
||||||
HeaderValue::from_static("rust-lang.org"),
|
|
||||||
);
|
|
||||||
|
|
||||||
let info = ConnectionInfo::new(&req);
|
let info = ConnectionInfo::new(&req);
|
||||||
assert_eq!(info.scheme(), "http");
|
assert_eq!(info.scheme(), "http");
|
||||||
|
55
src/json.rs
55
src/json.rs
@ -6,8 +6,8 @@ use std::ops::{Deref, DerefMut};
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use mime;
|
use mime;
|
||||||
use serde::Serialize;
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
|
use serde::Serialize;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
use error::{Error, JsonPayloadError, PayloadError};
|
use error::{Error, JsonPayloadError, PayloadError};
|
||||||
@ -308,10 +308,7 @@ where
|
|||||||
self.fut = Some(Box::new(fut));
|
self.fut = Some(Box::new(fut));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fut
|
self.fut.as_mut().expect("JsonBody could not be used second time").poll()
|
||||||
.as_mut()
|
|
||||||
.expect("JsonBody could not be used second time")
|
|
||||||
.poll()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,10 +359,7 @@ mod tests {
|
|||||||
fn test_json_body() {
|
fn test_json_body() {
|
||||||
let req = HttpRequest::default();
|
let req = HttpRequest::default();
|
||||||
let mut json = req.json::<MyObject>();
|
let mut json = req.json::<MyObject>();
|
||||||
assert_eq!(
|
assert_eq!(json.poll().err().unwrap(), JsonPayloadError::ContentType);
|
||||||
json.poll().err().unwrap(),
|
|
||||||
JsonPayloadError::ContentType
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
req.headers_mut().insert(
|
req.headers_mut().insert(
|
||||||
@ -373,20 +367,15 @@ mod tests {
|
|||||||
header::HeaderValue::from_static("application/text"),
|
header::HeaderValue::from_static("application/text"),
|
||||||
);
|
);
|
||||||
let mut json = req.json::<MyObject>();
|
let mut json = req.json::<MyObject>();
|
||||||
assert_eq!(
|
assert_eq!(json.poll().err().unwrap(), JsonPayloadError::ContentType);
|
||||||
json.poll().err().unwrap(),
|
|
||||||
JsonPayloadError::ContentType
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
req.headers_mut().insert(
|
req.headers_mut().insert(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("application/json"),
|
header::HeaderValue::from_static("application/json"),
|
||||||
);
|
);
|
||||||
req.headers_mut().insert(
|
req.headers_mut()
|
||||||
header::CONTENT_LENGTH,
|
.insert(header::CONTENT_LENGTH, header::HeaderValue::from_static("10000"));
|
||||||
header::HeaderValue::from_static("10000"),
|
|
||||||
);
|
|
||||||
let mut json = req.json::<MyObject>().limit(100);
|
let mut json = req.json::<MyObject>().limit(100);
|
||||||
assert_eq!(json.poll().err().unwrap(), JsonPayloadError::Overflow);
|
assert_eq!(json.poll().err().unwrap(), JsonPayloadError::Overflow);
|
||||||
|
|
||||||
@ -395,12 +384,9 @@ mod tests {
|
|||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("application/json"),
|
header::HeaderValue::from_static("application/json"),
|
||||||
);
|
);
|
||||||
req.headers_mut().insert(
|
req.headers_mut()
|
||||||
header::CONTENT_LENGTH,
|
.insert(header::CONTENT_LENGTH, header::HeaderValue::from_static("16"));
|
||||||
header::HeaderValue::from_static("16"),
|
req.payload_mut().unread_data(Bytes::from_static(b"{\"name\": \"test\"}"));
|
||||||
);
|
|
||||||
req.payload_mut()
|
|
||||||
.unread_data(Bytes::from_static(b"{\"name\": \"test\"}"));
|
|
||||||
let mut json = req.json::<MyObject>();
|
let mut json = req.json::<MyObject>();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
json.poll().ok().unwrap(),
|
json.poll().ok().unwrap(),
|
||||||
@ -417,12 +403,7 @@ mod tests {
|
|||||||
let mut handler = With::new(|data: Json<MyObject>| data, cfg);
|
let mut handler = With::new(|data: Json<MyObject>| data, cfg);
|
||||||
|
|
||||||
let req = HttpRequest::default();
|
let req = HttpRequest::default();
|
||||||
let err = handler
|
let err = handler.handle(req).as_response().unwrap().error().is_some();
|
||||||
.handle(req)
|
|
||||||
.as_response()
|
|
||||||
.unwrap()
|
|
||||||
.error()
|
|
||||||
.is_some();
|
|
||||||
assert!(err);
|
assert!(err);
|
||||||
|
|
||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
@ -430,18 +411,10 @@ mod tests {
|
|||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
header::HeaderValue::from_static("application/json"),
|
header::HeaderValue::from_static("application/json"),
|
||||||
);
|
);
|
||||||
req.headers_mut().insert(
|
req.headers_mut()
|
||||||
header::CONTENT_LENGTH,
|
.insert(header::CONTENT_LENGTH, header::HeaderValue::from_static("16"));
|
||||||
header::HeaderValue::from_static("16"),
|
req.payload_mut().unread_data(Bytes::from_static(b"{\"name\": \"test\"}"));
|
||||||
);
|
let ok = handler.handle(req).as_response().unwrap().error().is_none();
|
||||||
req.payload_mut()
|
|
||||||
.unread_data(Bytes::from_static(b"{\"name\": \"test\"}"));
|
|
||||||
let ok = handler
|
|
||||||
.handle(req)
|
|
||||||
.as_response()
|
|
||||||
.unwrap()
|
|
||||||
.error()
|
|
||||||
.is_none();
|
|
||||||
assert!(ok)
|
assert!(ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,26 +64,36 @@ use resource::ResourceHandler;
|
|||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
pub enum CorsError {
|
pub enum CorsError {
|
||||||
/// The HTTP request header `Origin` is required but was not provided
|
/// The HTTP request header `Origin` is required but was not provided
|
||||||
#[fail(display = "The HTTP request header `Origin` is required but was not provided")]
|
#[fail(
|
||||||
|
display = "The HTTP request header `Origin` is required but was not provided"
|
||||||
|
)]
|
||||||
MissingOrigin,
|
MissingOrigin,
|
||||||
/// The HTTP request header `Origin` could not be parsed correctly.
|
/// The HTTP request header `Origin` could not be parsed correctly.
|
||||||
#[fail(display = "The HTTP request header `Origin` could not be parsed correctly.")]
|
#[fail(display = "The HTTP request header `Origin` could not be parsed correctly.")]
|
||||||
BadOrigin,
|
BadOrigin,
|
||||||
/// The request header `Access-Control-Request-Method` is required but is
|
/// The request header `Access-Control-Request-Method` is required but is
|
||||||
/// missing
|
/// missing
|
||||||
#[fail(display = "The request header `Access-Control-Request-Method` is required but is missing")]
|
#[fail(
|
||||||
|
display = "The request header `Access-Control-Request-Method` is required but is missing"
|
||||||
|
)]
|
||||||
MissingRequestMethod,
|
MissingRequestMethod,
|
||||||
/// The request header `Access-Control-Request-Method` has an invalid value
|
/// The request header `Access-Control-Request-Method` has an invalid value
|
||||||
#[fail(display = "The request header `Access-Control-Request-Method` has an invalid value")]
|
#[fail(
|
||||||
|
display = "The request header `Access-Control-Request-Method` has an invalid value"
|
||||||
|
)]
|
||||||
BadRequestMethod,
|
BadRequestMethod,
|
||||||
/// The request header `Access-Control-Request-Headers` has an invalid
|
/// The request header `Access-Control-Request-Headers` has an invalid
|
||||||
/// value
|
/// value
|
||||||
#[fail(display = "The request header `Access-Control-Request-Headers` has an invalid value")]
|
#[fail(
|
||||||
|
display = "The request header `Access-Control-Request-Headers` has an invalid value"
|
||||||
|
)]
|
||||||
BadRequestHeaders,
|
BadRequestHeaders,
|
||||||
/// The request header `Access-Control-Request-Headers` is required but is
|
/// The request header `Access-Control-Request-Headers` is required but is
|
||||||
/// missing.
|
/// missing.
|
||||||
#[fail(display = "The request header `Access-Control-Request-Headers` is required but is
|
#[fail(
|
||||||
missing")]
|
display = "The request header `Access-Control-Request-Headers` is required but is
|
||||||
|
missing"
|
||||||
|
)]
|
||||||
MissingRequestHeaders,
|
MissingRequestHeaders,
|
||||||
/// Origin is not allowed to make this request
|
/// Origin is not allowed to make this request
|
||||||
#[fail(display = "Origin is not allowed to make this request")]
|
#[fail(display = "Origin is not allowed to make this request")]
|
||||||
@ -265,9 +275,7 @@ impl Cors {
|
|||||||
/// `ResourceHandler::middleware()` method, but in that case *Cors*
|
/// `ResourceHandler::middleware()` method, but in that case *Cors*
|
||||||
/// middleware wont be able to handle *OPTIONS* requests.
|
/// middleware wont be able to handle *OPTIONS* requests.
|
||||||
pub fn register<S: 'static>(self, resource: &mut ResourceHandler<S>) {
|
pub fn register<S: 'static>(self, resource: &mut ResourceHandler<S>) {
|
||||||
resource
|
resource.method(Method::OPTIONS).h(|_| HttpResponse::Ok());
|
||||||
.method(Method::OPTIONS)
|
|
||||||
.h(|_| HttpResponse::Ok());
|
|
||||||
resource.middleware(self);
|
resource.middleware(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,11 +300,9 @@ impl Cors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate_allowed_method<S>(
|
fn validate_allowed_method<S>(
|
||||||
&self, req: &mut HttpRequest<S>
|
&self, req: &mut HttpRequest<S>,
|
||||||
) -> Result<(), CorsError> {
|
) -> Result<(), CorsError> {
|
||||||
if let Some(hdr) = req.headers()
|
if let Some(hdr) = req.headers().get(header::ACCESS_CONTROL_REQUEST_METHOD) {
|
||||||
.get(header::ACCESS_CONTROL_REQUEST_METHOD)
|
|
||||||
{
|
|
||||||
if let Ok(meth) = hdr.to_str() {
|
if let Ok(meth) = hdr.to_str() {
|
||||||
if let Ok(method) = Method::try_from(meth) {
|
if let Ok(method) = Method::try_from(meth) {
|
||||||
return self.inner
|
return self.inner
|
||||||
@ -313,13 +319,13 @@ impl Cors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate_allowed_headers<S>(
|
fn validate_allowed_headers<S>(
|
||||||
&self, req: &mut HttpRequest<S>
|
&self, req: &mut HttpRequest<S>,
|
||||||
) -> Result<(), CorsError> {
|
) -> Result<(), CorsError> {
|
||||||
match self.inner.headers {
|
match self.inner.headers {
|
||||||
AllOrSome::All => Ok(()),
|
AllOrSome::All => Ok(()),
|
||||||
AllOrSome::Some(ref allowed_headers) => {
|
AllOrSome::Some(ref allowed_headers) => {
|
||||||
if let Some(hdr) = req.headers()
|
if let Some(hdr) =
|
||||||
.get(header::ACCESS_CONTROL_REQUEST_HEADERS)
|
req.headers().get(header::ACCESS_CONTROL_REQUEST_HEADERS)
|
||||||
{
|
{
|
||||||
if let Ok(headers) = hdr.to_str() {
|
if let Ok(headers) = hdr.to_str() {
|
||||||
let mut hdrs = HashSet::new();
|
let mut hdrs = HashSet::new();
|
||||||
@ -361,8 +367,8 @@ impl<S> Middleware<S> for Cors {
|
|||||||
.as_str()[1..],
|
.as_str()[1..],
|
||||||
).unwrap(),
|
).unwrap(),
|
||||||
)
|
)
|
||||||
} else if let Some(hdr) = req.headers()
|
} else if let Some(hdr) =
|
||||||
.get(header::ACCESS_CONTROL_REQUEST_HEADERS)
|
req.headers().get(header::ACCESS_CONTROL_REQUEST_HEADERS)
|
||||||
{
|
{
|
||||||
Some(hdr.clone())
|
Some(hdr.clone())
|
||||||
} else {
|
} else {
|
||||||
@ -419,7 +425,7 @@ impl<S> Middleware<S> for Cors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn response(
|
fn response(
|
||||||
&self, req: &mut HttpRequest<S>, mut resp: HttpResponse
|
&self, req: &mut HttpRequest<S>, mut resp: HttpResponse,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
match self.inner.origins {
|
match self.inner.origins {
|
||||||
AllOrSome::All => {
|
AllOrSome::All => {
|
||||||
@ -506,7 +512,7 @@ pub struct CorsBuilder<S = ()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cors<'a>(
|
fn cors<'a>(
|
||||||
parts: &'a mut Option<Inner>, err: &Option<http::Error>
|
parts: &'a mut Option<Inner>, err: &Option<http::Error>,
|
||||||
) -> Option<&'a mut Inner> {
|
) -> Option<&'a mut Inner> {
|
||||||
if err.is_some() {
|
if err.is_some() {
|
||||||
return None;
|
return None;
|
||||||
@ -813,17 +819,13 @@ impl<S: 'static> CorsBuilder<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let AllOrSome::Some(ref origins) = cors.origins {
|
if let AllOrSome::Some(ref origins) = cors.origins {
|
||||||
let s = origins
|
let s = origins.iter().fold(String::new(), |s, v| s + &v.to_string());
|
||||||
.iter()
|
|
||||||
.fold(String::new(), |s, v| s + &format!("{}", v));
|
|
||||||
cors.origins_str = Some(HeaderValue::try_from(s.as_str()).unwrap());
|
cors.origins_str = Some(HeaderValue::try_from(s.as_str()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.expose_hdrs.is_empty() {
|
if !self.expose_hdrs.is_empty() {
|
||||||
cors.expose_hdrs = Some(
|
cors.expose_hdrs = Some(
|
||||||
self.expose_hdrs
|
self.expose_hdrs.iter().fold(String::new(), |s, v| s + v.as_str())[1..]
|
||||||
.iter()
|
|
||||||
.fold(String::new(), |s, v| s + v.as_str())[1..]
|
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -901,27 +903,19 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Credentials are allowed, but the Origin is set to")]
|
#[should_panic(expected = "Credentials are allowed, but the Origin is set to")]
|
||||||
fn cors_validates_illegal_allow_credentials() {
|
fn cors_validates_illegal_allow_credentials() {
|
||||||
Cors::build()
|
Cors::build().supports_credentials().send_wildcard().finish();
|
||||||
.supports_credentials()
|
|
||||||
.send_wildcard()
|
|
||||||
.finish();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "No resources are registered")]
|
#[should_panic(expected = "No resources are registered")]
|
||||||
fn no_resource() {
|
fn no_resource() {
|
||||||
Cors::build()
|
Cors::build().supports_credentials().send_wildcard().register();
|
||||||
.supports_credentials()
|
|
||||||
.send_wildcard()
|
|
||||||
.register();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "Cors::for_app(app)")]
|
#[should_panic(expected = "Cors::for_app(app)")]
|
||||||
fn no_resource2() {
|
fn no_resource2() {
|
||||||
Cors::build()
|
Cors::build().resource("/test", |r| r.f(|_| HttpResponse::Ok())).register();
|
||||||
.resource("/test", |r| r.f(|_| HttpResponse::Ok()))
|
|
||||||
.register();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -958,27 +952,18 @@ mod tests {
|
|||||||
|
|
||||||
let mut req = TestRequest::with_header("Origin", "https://www.example.com")
|
let mut req = TestRequest::with_header("Origin", "https://www.example.com")
|
||||||
.header(header::ACCESS_CONTROL_REQUEST_METHOD, "POST")
|
.header(header::ACCESS_CONTROL_REQUEST_METHOD, "POST")
|
||||||
.header(
|
.header(header::ACCESS_CONTROL_REQUEST_HEADERS, "AUTHORIZATION,ACCEPT")
|
||||||
header::ACCESS_CONTROL_REQUEST_HEADERS,
|
|
||||||
"AUTHORIZATION,ACCEPT",
|
|
||||||
)
|
|
||||||
.method(Method::OPTIONS)
|
.method(Method::OPTIONS)
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
let resp = cors.start(&mut req).unwrap().response();
|
let resp = cors.start(&mut req).unwrap().response();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&b"*"[..],
|
&b"*"[..],
|
||||||
resp.headers()
|
resp.headers().get(header::ACCESS_CONTROL_ALLOW_ORIGIN).unwrap().as_bytes()
|
||||||
.get(header::ACCESS_CONTROL_ALLOW_ORIGIN)
|
|
||||||
.unwrap()
|
|
||||||
.as_bytes()
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&b"3600"[..],
|
&b"3600"[..],
|
||||||
resp.headers()
|
resp.headers().get(header::ACCESS_CONTROL_MAX_AGE).unwrap().as_bytes()
|
||||||
.get(header::ACCESS_CONTROL_MAX_AGE)
|
|
||||||
.unwrap()
|
|
||||||
.as_bytes()
|
|
||||||
);
|
);
|
||||||
//assert_eq!(
|
//assert_eq!(
|
||||||
// &b"authorization,accept,content-type"[..],
|
// &b"authorization,accept,content-type"[..],
|
||||||
@ -995,9 +980,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "MissingOrigin")]
|
#[should_panic(expected = "MissingOrigin")]
|
||||||
fn test_validate_missing_origin() {
|
fn test_validate_missing_origin() {
|
||||||
let cors = Cors::build()
|
let cors = Cors::build().allowed_origin("https://www.example.com").finish();
|
||||||
.allowed_origin("https://www.example.com")
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
let mut req = HttpRequest::default();
|
let mut req = HttpRequest::default();
|
||||||
cors.start(&mut req).unwrap();
|
cors.start(&mut req).unwrap();
|
||||||
@ -1006,9 +989,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "OriginNotAllowed")]
|
#[should_panic(expected = "OriginNotAllowed")]
|
||||||
fn test_validate_not_allowed_origin() {
|
fn test_validate_not_allowed_origin() {
|
||||||
let cors = Cors::build()
|
let cors = Cors::build().allowed_origin("https://www.example.com").finish();
|
||||||
.allowed_origin("https://www.example.com")
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
let mut req = TestRequest::with_header("Origin", "https://www.unknown.com")
|
let mut req = TestRequest::with_header("Origin", "https://www.unknown.com")
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
@ -1018,9 +999,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_validate_origin() {
|
fn test_validate_origin() {
|
||||||
let cors = Cors::build()
|
let cors = Cors::build().allowed_origin("https://www.example.com").finish();
|
||||||
.allowed_origin("https://www.example.com")
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
let mut req = TestRequest::with_header("Origin", "https://www.example.com")
|
let mut req = TestRequest::with_header("Origin", "https://www.example.com")
|
||||||
.method(Method::GET)
|
.method(Method::GET)
|
||||||
@ -1036,11 +1015,7 @@ mod tests {
|
|||||||
let mut req = TestRequest::default().method(Method::GET).finish();
|
let mut req = TestRequest::default().method(Method::GET).finish();
|
||||||
let resp: HttpResponse = HttpResponse::Ok().into();
|
let resp: HttpResponse = HttpResponse::Ok().into();
|
||||||
let resp = cors.response(&mut req, resp).unwrap().response();
|
let resp = cors.response(&mut req, resp).unwrap().response();
|
||||||
assert!(
|
assert!(resp.headers().get(header::ACCESS_CONTROL_ALLOW_ORIGIN).is_none());
|
||||||
resp.headers()
|
|
||||||
.get(header::ACCESS_CONTROL_ALLOW_ORIGIN)
|
|
||||||
.is_none()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut req = TestRequest::with_header("Origin", "https://www.example.com")
|
let mut req = TestRequest::with_header("Origin", "https://www.example.com")
|
||||||
.method(Method::OPTIONS)
|
.method(Method::OPTIONS)
|
||||||
@ -1048,10 +1023,7 @@ mod tests {
|
|||||||
let resp = cors.response(&mut req, resp).unwrap().response();
|
let resp = cors.response(&mut req, resp).unwrap().response();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&b"https://www.example.com"[..],
|
&b"https://www.example.com"[..],
|
||||||
resp.headers()
|
resp.headers().get(header::ACCESS_CONTROL_ALLOW_ORIGIN).unwrap().as_bytes()
|
||||||
.get(header::ACCESS_CONTROL_ALLOW_ORIGIN)
|
|
||||||
.unwrap()
|
|
||||||
.as_bytes()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1074,19 +1046,12 @@ mod tests {
|
|||||||
let resp = cors.response(&mut req, resp).unwrap().response();
|
let resp = cors.response(&mut req, resp).unwrap().response();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&b"*"[..],
|
&b"*"[..],
|
||||||
resp.headers()
|
resp.headers().get(header::ACCESS_CONTROL_ALLOW_ORIGIN).unwrap().as_bytes()
|
||||||
.get(header::ACCESS_CONTROL_ALLOW_ORIGIN)
|
|
||||||
.unwrap()
|
|
||||||
.as_bytes()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
&b"Origin"[..],
|
|
||||||
resp.headers().get(header::VARY).unwrap().as_bytes()
|
|
||||||
);
|
);
|
||||||
|
assert_eq!(&b"Origin"[..], resp.headers().get(header::VARY).unwrap().as_bytes());
|
||||||
|
|
||||||
let resp: HttpResponse = HttpResponse::Ok()
|
let resp: HttpResponse =
|
||||||
.header(header::VARY, "Accept")
|
HttpResponse::Ok().header(header::VARY, "Accept").finish();
|
||||||
.finish();
|
|
||||||
let resp = cors.response(&mut req, resp).unwrap().response();
|
let resp = cors.response(&mut req, resp).unwrap().response();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&b"Accept, Origin"[..],
|
&b"Accept, Origin"[..],
|
||||||
@ -1101,10 +1066,7 @@ mod tests {
|
|||||||
let resp = cors.response(&mut req, resp).unwrap().response();
|
let resp = cors.response(&mut req, resp).unwrap().response();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&b"https://www.example.com"[..],
|
&b"https://www.example.com"[..],
|
||||||
resp.headers()
|
resp.headers().get(header::ACCESS_CONTROL_ALLOW_ORIGIN).unwrap().as_bytes()
|
||||||
.get(header::ACCESS_CONTROL_ALLOW_ORIGIN)
|
|
||||||
.unwrap()
|
|
||||||
.as_bytes()
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,10 +89,7 @@ fn origin(headers: &HeaderMap) -> Option<Result<Cow<str>, CsrfError>> {
|
|||||||
headers
|
headers
|
||||||
.get(header::ORIGIN)
|
.get(header::ORIGIN)
|
||||||
.map(|origin| {
|
.map(|origin| {
|
||||||
origin
|
origin.to_str().map_err(|_| CsrfError::BadOrigin).map(|o| o.into())
|
||||||
.to_str()
|
|
||||||
.map_err(|_| CsrfError::BadOrigin)
|
|
||||||
.map(|o| o.into())
|
|
||||||
})
|
})
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
headers.get(header::REFERER).map(|referer| {
|
headers.get(header::REFERER).map(|referer| {
|
||||||
@ -261,9 +258,8 @@ mod tests {
|
|||||||
fn test_upgrade() {
|
fn test_upgrade() {
|
||||||
let strict_csrf = CsrfFilter::new().allowed_origin("https://www.example.com");
|
let strict_csrf = CsrfFilter::new().allowed_origin("https://www.example.com");
|
||||||
|
|
||||||
let lax_csrf = CsrfFilter::new()
|
let lax_csrf =
|
||||||
.allowed_origin("https://www.example.com")
|
CsrfFilter::new().allowed_origin("https://www.example.com").allow_upgrade();
|
||||||
.allow_upgrade();
|
|
||||||
|
|
||||||
let mut req = TestRequest::with_header("Origin", "https://cswsh.com")
|
let mut req = TestRequest::with_header("Origin", "https://cswsh.com")
|
||||||
.header("Connection", "Upgrade")
|
.header("Connection", "Upgrade")
|
||||||
|
@ -76,7 +76,7 @@ impl DefaultHeaders {
|
|||||||
|
|
||||||
impl<S> Middleware<S> for DefaultHeaders {
|
impl<S> Middleware<S> for DefaultHeaders {
|
||||||
fn response(
|
fn response(
|
||||||
&self, _: &mut HttpRequest<S>, mut resp: HttpResponse
|
&self, _: &mut HttpRequest<S>, mut resp: HttpResponse,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
for (key, value) in self.headers.iter() {
|
for (key, value) in self.headers.iter() {
|
||||||
if !resp.headers().contains_key(key) {
|
if !resp.headers().contains_key(key) {
|
||||||
@ -112,9 +112,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
|
assert_eq!(resp.headers().get(CONTENT_TYPE).unwrap(), "0001");
|
||||||
|
|
||||||
let resp = HttpResponse::Ok()
|
let resp = HttpResponse::Ok().header(CONTENT_TYPE, "0002").finish();
|
||||||
.header(CONTENT_TYPE, "0002")
|
|
||||||
.finish();
|
|
||||||
let resp = match mw.response(&mut req, resp) {
|
let resp = match mw.response(&mut req, resp) {
|
||||||
Ok(Response::Done(resp)) => resp,
|
Ok(Response::Done(resp)) => resp,
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
|
@ -69,7 +69,7 @@ impl<S> ErrorHandlers<S> {
|
|||||||
|
|
||||||
impl<S: 'static> Middleware<S> for ErrorHandlers<S> {
|
impl<S: 'static> Middleware<S> for ErrorHandlers<S> {
|
||||||
fn response(
|
fn response(
|
||||||
&self, req: &mut HttpRequest<S>, resp: HttpResponse
|
&self, req: &mut HttpRequest<S>, resp: HttpResponse,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
if let Some(handler) = self.handlers.get(&resp.status()) {
|
if let Some(handler) = self.handlers.get(&resp.status()) {
|
||||||
handler(req, resp)
|
handler(req, resp)
|
||||||
@ -82,8 +82,8 @@ impl<S: 'static> Middleware<S> for ErrorHandlers<S> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use http::StatusCode;
|
|
||||||
use http::header::CONTENT_TYPE;
|
use http::header::CONTENT_TYPE;
|
||||||
|
use http::StatusCode;
|
||||||
|
|
||||||
fn render_500<S>(_: &mut HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
|
fn render_500<S>(_: &mut HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
|
||||||
let mut builder = resp.into_builder();
|
let mut builder = resp.into_builder();
|
||||||
|
@ -49,8 +49,8 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use cookie::{Cookie, CookieJar, Key};
|
use cookie::{Cookie, CookieJar, Key};
|
||||||
|
use futures::future::{err as FutErr, ok as FutOk, FutureResult};
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use futures::future::{FutureResult, err as FutErr, ok as FutOk};
|
|
||||||
use time::Duration;
|
use time::Duration;
|
||||||
|
|
||||||
use error::{Error, Result};
|
use error::{Error, Result};
|
||||||
@ -164,7 +164,9 @@ pub struct IdentityService<T> {
|
|||||||
impl<T> IdentityService<T> {
|
impl<T> IdentityService<T> {
|
||||||
/// Create new identity service with specified backend.
|
/// Create new identity service with specified backend.
|
||||||
pub fn new(backend: T) -> Self {
|
pub fn new(backend: T) -> Self {
|
||||||
IdentityService { backend }
|
IdentityService {
|
||||||
|
backend,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,20 +181,18 @@ impl<S: 'static, T: IdentityPolicy<S>> Middleware<S> for IdentityService<T> {
|
|||||||
fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
|
fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
|
||||||
let mut req = req.clone();
|
let mut req = req.clone();
|
||||||
|
|
||||||
let fut = self.backend
|
let fut = self.backend.from_request(&mut req).then(move |res| match res {
|
||||||
.from_request(&mut req)
|
Ok(id) => {
|
||||||
.then(move |res| match res {
|
req.extensions().insert(IdentityBox(Box::new(id)));
|
||||||
Ok(id) => {
|
FutOk(None)
|
||||||
req.extensions().insert(IdentityBox(Box::new(id)));
|
}
|
||||||
FutOk(None)
|
Err(err) => FutErr(err),
|
||||||
}
|
});
|
||||||
Err(err) => FutErr(err),
|
|
||||||
});
|
|
||||||
Ok(Started::Future(Box::new(fut)))
|
Ok(Started::Future(Box::new(fut)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response(
|
fn response(
|
||||||
&self, req: &mut HttpRequest<S>, resp: HttpResponse
|
&self, req: &mut HttpRequest<S>, resp: HttpResponse,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
if let Some(mut id) = req.extensions().remove::<IdentityBox>() {
|
if let Some(mut id) = req.extensions().remove::<IdentityBox>() {
|
||||||
id.0.write(resp)
|
id.0.write(resp)
|
||||||
|
@ -254,10 +254,9 @@ impl FormatText {
|
|||||||
"-".fmt(fmt)
|
"-".fmt(fmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FormatText::RequestTime => entry_time
|
FormatText::RequestTime => {
|
||||||
.strftime("[%d/%b/%Y:%H:%M:%S %z]")
|
entry_time.strftime("[%d/%b/%Y:%H:%M:%S %z]").unwrap().fmt(fmt)
|
||||||
.unwrap()
|
}
|
||||||
.fmt(fmt),
|
|
||||||
FormatText::RequestHeader(ref name) => {
|
FormatText::RequestHeader(ref name) => {
|
||||||
let s = if let Some(val) = req.headers().get(name) {
|
let s = if let Some(val) = req.headers().get(name) {
|
||||||
if let Ok(s) = val.to_str() {
|
if let Ok(s) = val.to_str() {
|
||||||
@ -314,10 +313,8 @@ mod tests {
|
|||||||
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test");
|
let logger = Logger::new("%% %{User-Agent}i %{X-Test}o %{HOME}e %D test");
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers
|
||||||
header::USER_AGENT,
|
.insert(header::USER_AGENT, header::HeaderValue::from_static("ACTIX-WEB"));
|
||||||
header::HeaderValue::from_static("ACTIX-WEB"),
|
|
||||||
);
|
|
||||||
let mut req = HttpRequest::new(
|
let mut req = HttpRequest::new(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
Uri::from_str("/").unwrap(),
|
Uri::from_str("/").unwrap(),
|
||||||
@ -354,10 +351,8 @@ mod tests {
|
|||||||
let format = Format::default();
|
let format = Format::default();
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers
|
||||||
header::USER_AGENT,
|
.insert(header::USER_AGENT, header::HeaderValue::from_static("ACTIX-WEB"));
|
||||||
header::HeaderValue::from_static("ACTIX-WEB"),
|
|
||||||
);
|
|
||||||
let req = HttpRequest::new(
|
let req = HttpRequest::new(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
Uri::from_str("/").unwrap(),
|
Uri::from_str("/").unwrap(),
|
||||||
@ -365,9 +360,7 @@ mod tests {
|
|||||||
headers,
|
headers,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let resp = HttpResponse::build(StatusCode::OK)
|
let resp = HttpResponse::build(StatusCode::OK).force_close().finish();
|
||||||
.force_close()
|
|
||||||
.finish();
|
|
||||||
let entry_time = time::now();
|
let entry_time = time::now();
|
||||||
|
|
||||||
let render = |fmt: &mut Formatter| {
|
let render = |fmt: &mut Formatter| {
|
||||||
@ -388,9 +381,7 @@ mod tests {
|
|||||||
HeaderMap::new(),
|
HeaderMap::new(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
let resp = HttpResponse::build(StatusCode::OK)
|
let resp = HttpResponse::build(StatusCode::OK).force_close().finish();
|
||||||
.force_close()
|
|
||||||
.finish();
|
|
||||||
let entry_time = time::now();
|
let entry_time = time::now();
|
||||||
|
|
||||||
let render = |fmt: &mut Formatter| {
|
let render = |fmt: &mut Formatter| {
|
||||||
|
@ -21,8 +21,9 @@ pub use self::logger::Logger;
|
|||||||
|
|
||||||
#[cfg(feature = "session")]
|
#[cfg(feature = "session")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[deprecated(since = "0.5.4",
|
#[deprecated(
|
||||||
note = "please use `actix_web::middleware::session` instead")]
|
since = "0.5.4", note = "please use `actix_web::middleware::session` instead"
|
||||||
|
)]
|
||||||
pub use self::session::{CookieSessionBackend, CookieSessionError, RequestSession,
|
pub use self::session::{CookieSessionBackend, CookieSessionError, RequestSession,
|
||||||
Session, SessionBackend, SessionImpl, SessionStorage};
|
Session, SessionBackend, SessionImpl, SessionStorage};
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ pub trait Middleware<S>: 'static {
|
|||||||
/// Method is called when handler returns response,
|
/// Method is called when handler returns response,
|
||||||
/// but before sending http message to peer.
|
/// but before sending http message to peer.
|
||||||
fn response(
|
fn response(
|
||||||
&self, req: &mut HttpRequest<S>, resp: HttpResponse
|
&self, req: &mut HttpRequest<S>, resp: HttpResponse,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
Ok(Response::Done(resp))
|
Ok(Response::Done(resp))
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,8 @@ use std::rc::Rc;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cookie::{Cookie, CookieJar, Key};
|
use cookie::{Cookie, CookieJar, Key};
|
||||||
|
use futures::future::{err as FutErr, ok as FutOk, FutureResult};
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use futures::future::{FutureResult, err as FutErr, ok as FutOk};
|
|
||||||
use http::header::{self, HeaderValue};
|
use http::header::{self, HeaderValue};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
@ -202,21 +202,18 @@ impl<S: 'static, T: SessionBackend<S>> Middleware<S> for SessionStorage<T, S> {
|
|||||||
fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
|
fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
|
||||||
let mut req = req.clone();
|
let mut req = req.clone();
|
||||||
|
|
||||||
let fut = self.0
|
let fut = self.0.from_request(&mut req).then(move |res| match res {
|
||||||
.from_request(&mut req)
|
Ok(sess) => {
|
||||||
.then(move |res| match res {
|
req.extensions().insert(Arc::new(SessionImplBox(Box::new(sess))));
|
||||||
Ok(sess) => {
|
FutOk(None)
|
||||||
req.extensions()
|
}
|
||||||
.insert(Arc::new(SessionImplBox(Box::new(sess))));
|
Err(err) => FutErr(err),
|
||||||
FutOk(None)
|
});
|
||||||
}
|
|
||||||
Err(err) => FutErr(err),
|
|
||||||
});
|
|
||||||
Ok(Started::Future(Box::new(fut)))
|
Ok(Started::Future(Box::new(fut)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response(
|
fn response(
|
||||||
&self, req: &mut HttpRequest<S>, resp: HttpResponse
|
&self, req: &mut HttpRequest<S>, resp: HttpResponse,
|
||||||
) -> Result<Response> {
|
) -> Result<Response> {
|
||||||
if let Some(s_box) = req.extensions().remove::<Arc<SessionImplBox>>() {
|
if let Some(s_box) = req.extensions().remove::<Arc<SessionImplBox>>() {
|
||||||
s_box.0.write(resp)
|
s_box.0.write(resp)
|
||||||
@ -349,7 +346,7 @@ impl CookieSessionInner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_cookie(
|
fn set_cookie(
|
||||||
&self, resp: &mut HttpResponse, state: &HashMap<String, String>
|
&self, resp: &mut HttpResponse, state: &HashMap<String, String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let value =
|
let value =
|
||||||
serde_json::to_string(&state).map_err(CookieSessionError::Serialize)?;
|
serde_json::to_string(&state).map_err(CookieSessionError::Serialize)?;
|
||||||
|
@ -7,8 +7,8 @@ use std::{cmp, fmt};
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures::task::{current as current_task, Task};
|
use futures::task::{current as current_task, Task};
|
||||||
use futures::{Async, Poll, Stream};
|
use futures::{Async, Poll, Stream};
|
||||||
use http::HttpTryFrom;
|
|
||||||
use http::header::{self, HeaderMap, HeaderName, HeaderValue};
|
use http::header::{self, HeaderMap, HeaderName, HeaderValue};
|
||||||
|
use http::HttpTryFrom;
|
||||||
use httparse;
|
use httparse;
|
||||||
use mime;
|
use mime;
|
||||||
|
|
||||||
@ -122,11 +122,7 @@ where
|
|||||||
if let Some(err) = self.error.take() {
|
if let Some(err) = self.error.take() {
|
||||||
Err(err)
|
Err(err)
|
||||||
} else if self.safety.current() {
|
} else if self.safety.current() {
|
||||||
self.inner
|
self.inner.as_mut().unwrap().borrow_mut().poll(&self.safety)
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.borrow_mut()
|
|
||||||
.poll(&self.safety)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Async::NotReady)
|
Ok(Async::NotReady)
|
||||||
}
|
}
|
||||||
@ -168,7 +164,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_boundary(
|
fn read_boundary(
|
||||||
payload: &mut PayloadHelper<S>, boundary: &str
|
payload: &mut PayloadHelper<S>, boundary: &str,
|
||||||
) -> Poll<bool, MultipartError> {
|
) -> Poll<bool, MultipartError> {
|
||||||
// TODO: need to read epilogue
|
// TODO: need to read epilogue
|
||||||
match payload.readline()? {
|
match payload.readline()? {
|
||||||
@ -192,7 +188,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn skip_until_boundary(
|
fn skip_until_boundary(
|
||||||
payload: &mut PayloadHelper<S>, boundary: &str
|
payload: &mut PayloadHelper<S>, boundary: &str,
|
||||||
) -> Poll<bool, MultipartError> {
|
) -> Poll<bool, MultipartError> {
|
||||||
let mut eof = false;
|
let mut eof = false;
|
||||||
loop {
|
loop {
|
||||||
@ -230,7 +226,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll(
|
fn poll(
|
||||||
&mut self, safety: &Safety
|
&mut self, safety: &Safety,
|
||||||
) -> Poll<Option<MultipartItem<S>>, MultipartError> {
|
) -> Poll<Option<MultipartItem<S>>, MultipartError> {
|
||||||
if self.state == InnerState::Eof {
|
if self.state == InnerState::Eof {
|
||||||
Ok(Async::Ready(None))
|
Ok(Async::Ready(None))
|
||||||
@ -450,7 +446,7 @@ where
|
|||||||
S: Stream<Item = Bytes, Error = PayloadError>,
|
S: Stream<Item = Bytes, Error = PayloadError>,
|
||||||
{
|
{
|
||||||
fn new(
|
fn new(
|
||||||
payload: PayloadRef<S>, boundary: String, headers: &HeaderMap
|
payload: PayloadRef<S>, boundary: String, headers: &HeaderMap,
|
||||||
) -> Result<InnerField<S>, PayloadError> {
|
) -> Result<InnerField<S>, PayloadError> {
|
||||||
let len = if let Some(len) = headers.get(header::CONTENT_LENGTH) {
|
let len = if let Some(len) = headers.get(header::CONTENT_LENGTH) {
|
||||||
if let Ok(s) = len.to_str() {
|
if let Ok(s) = len.to_str() {
|
||||||
@ -477,7 +473,7 @@ where
|
|||||||
/// Reads body part content chunk of the specified size.
|
/// Reads body part content chunk of the specified size.
|
||||||
/// The body part must has `Content-Length` header with proper value.
|
/// The body part must has `Content-Length` header with proper value.
|
||||||
fn read_len(
|
fn read_len(
|
||||||
payload: &mut PayloadHelper<S>, size: &mut u64
|
payload: &mut PayloadHelper<S>, size: &mut u64,
|
||||||
) -> Poll<Option<Bytes>, MultipartError> {
|
) -> Poll<Option<Bytes>, MultipartError> {
|
||||||
if *size == 0 {
|
if *size == 0 {
|
||||||
Ok(Async::Ready(None))
|
Ok(Async::Ready(None))
|
||||||
@ -502,7 +498,7 @@ where
|
|||||||
/// Reads content chunk of body part with unknown length.
|
/// Reads content chunk of body part with unknown length.
|
||||||
/// The `Content-Length` header for body part is not necessary.
|
/// The `Content-Length` header for body part is not necessary.
|
||||||
fn read_stream(
|
fn read_stream(
|
||||||
payload: &mut PayloadHelper<S>, boundary: &str
|
payload: &mut PayloadHelper<S>, boundary: &str,
|
||||||
) -> Poll<Option<Bytes>, MultipartError> {
|
) -> Poll<Option<Bytes>, MultipartError> {
|
||||||
match payload.read_until(b"\r")? {
|
match payload.read_until(b"\r")? {
|
||||||
Async::NotReady => Ok(Async::NotReady),
|
Async::NotReady => Ok(Async::NotReady),
|
||||||
@ -675,10 +671,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers.insert(header::CONTENT_TYPE, header::HeaderValue::from_static("test"));
|
||||||
header::CONTENT_TYPE,
|
|
||||||
header::HeaderValue::from_static("test"),
|
|
||||||
);
|
|
||||||
|
|
||||||
match Multipart::boundary(&headers) {
|
match Multipart::boundary(&headers) {
|
||||||
Err(MultipartError::ParseContentType) => (),
|
Err(MultipartError::ParseContentType) => (),
|
||||||
|
18
src/param.rs
18
src/param.rs
@ -94,8 +94,7 @@ impl<'a, 'b, 'c: 'a> Index<&'b str> for &'c Params<'a> {
|
|||||||
type Output = str;
|
type Output = str;
|
||||||
|
|
||||||
fn index(&self, name: &'b str) -> &str {
|
fn index(&self, name: &'b str) -> &str {
|
||||||
self.get(name)
|
self.get(name).expect("Value for parameter is not available")
|
||||||
.expect("Value for parameter is not available")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,18 +201,9 @@ mod tests {
|
|||||||
PathBuf::from_param("/test/*tt"),
|
PathBuf::from_param("/test/*tt"),
|
||||||
Err(UriSegmentError::BadStart('*'))
|
Err(UriSegmentError::BadStart('*'))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(PathBuf::from_param("/test/tt:"), Err(UriSegmentError::BadEnd(':')));
|
||||||
PathBuf::from_param("/test/tt:"),
|
assert_eq!(PathBuf::from_param("/test/tt<"), Err(UriSegmentError::BadEnd('<')));
|
||||||
Err(UriSegmentError::BadEnd(':'))
|
assert_eq!(PathBuf::from_param("/test/tt>"), Err(UriSegmentError::BadEnd('>')));
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
PathBuf::from_param("/test/tt<"),
|
|
||||||
Err(UriSegmentError::BadEnd('<'))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
PathBuf::from_param("/test/tt>"),
|
|
||||||
Err(UriSegmentError::BadEnd('>'))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
PathBuf::from_param("/seg1/seg2/"),
|
PathBuf::from_param("/seg1/seg2/"),
|
||||||
Ok(PathBuf::from_iter(vec!["seg1", "seg2"]))
|
Ok(PathBuf::from_iter(vec!["seg1", "seg2"]))
|
||||||
|
@ -47,7 +47,9 @@ impl Payload {
|
|||||||
PayloadSender {
|
PayloadSender {
|
||||||
inner: Rc::downgrade(&shared),
|
inner: Rc::downgrade(&shared),
|
||||||
},
|
},
|
||||||
Payload { inner: shared },
|
Payload {
|
||||||
|
inner: shared,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,10 +536,7 @@ mod tests {
|
|||||||
assert_eq!(format!("{}", err.cause().unwrap()), "ParseError");
|
assert_eq!(format!("{}", err.cause().unwrap()), "ParseError");
|
||||||
|
|
||||||
let err = PayloadError::Incomplete;
|
let err = PayloadError::Incomplete;
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", err), "A payload reached EOF, but is not complete.");
|
||||||
format!("{}", err),
|
|
||||||
"A payload reached EOF, but is not complete."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -671,10 +670,7 @@ mod tests {
|
|||||||
let (mut sender, payload) = Payload::new(false);
|
let (mut sender, payload) = Payload::new(false);
|
||||||
let mut payload = PayloadHelper::new(payload);
|
let mut payload = PayloadHelper::new(payload);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(Async::NotReady, payload.read_until(b"ne").ok().unwrap());
|
||||||
Async::NotReady,
|
|
||||||
payload.read_until(b"ne").ok().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
sender.feed_data(Bytes::from("line1"));
|
sender.feed_data(Bytes::from("line1"));
|
||||||
sender.feed_data(Bytes::from("line2"));
|
sender.feed_data(Bytes::from("line2"));
|
||||||
|
@ -67,7 +67,7 @@ impl<S: 'static, H: PipelineHandler<S>> PipelineState<S, H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct PipelineInfo<S> {
|
struct PipelineInfo<S> {
|
||||||
req: HttpRequest<S>,
|
req: UnsafeCell<HttpRequest<S>>,
|
||||||
count: u16,
|
count: u16,
|
||||||
mws: Rc<Vec<Box<Middleware<S>>>>,
|
mws: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
context: Option<Box<ActorHttpContext>>,
|
context: Option<Box<ActorHttpContext>>,
|
||||||
@ -79,7 +79,7 @@ struct PipelineInfo<S> {
|
|||||||
impl<S> PipelineInfo<S> {
|
impl<S> PipelineInfo<S> {
|
||||||
fn new(req: HttpRequest<S>) -> PipelineInfo<S> {
|
fn new(req: HttpRequest<S>) -> PipelineInfo<S> {
|
||||||
PipelineInfo {
|
PipelineInfo {
|
||||||
req,
|
req: UnsafeCell::new(req),
|
||||||
count: 0,
|
count: 0,
|
||||||
mws: Rc::new(Vec::new()),
|
mws: Rc::new(Vec::new()),
|
||||||
error: None,
|
error: None,
|
||||||
@ -89,11 +89,17 @@ impl<S> PipelineInfo<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn req(&self) -> &HttpRequest<S> {
|
||||||
|
unsafe { &*self.req.get() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
|
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref))]
|
||||||
fn req_mut(&self) -> &mut HttpRequest<S> {
|
fn req_mut(&self) -> &mut HttpRequest<S> {
|
||||||
#[allow(mutable_transmutes)]
|
#[allow(mutable_transmutes)]
|
||||||
unsafe {
|
unsafe {
|
||||||
mem::transmute(&self.req)
|
&mut *self.req.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,8 +122,8 @@ impl<S: 'static, H: PipelineHandler<S>> Pipeline<S, H> {
|
|||||||
handler: Rc<UnsafeCell<H>>, htype: HandlerType,
|
handler: Rc<UnsafeCell<H>>, htype: HandlerType,
|
||||||
) -> Pipeline<S, H> {
|
) -> Pipeline<S, H> {
|
||||||
let mut info = PipelineInfo {
|
let mut info = PipelineInfo {
|
||||||
req,
|
|
||||||
mws,
|
mws,
|
||||||
|
req: UnsafeCell::new(req),
|
||||||
count: 0,
|
count: 0,
|
||||||
error: None,
|
error: None,
|
||||||
context: None,
|
context: None,
|
||||||
@ -159,7 +165,7 @@ impl<S: 'static, H: PipelineHandler<S>> HttpHandlerTask for Pipeline<S, H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
fn poll_io(&mut self, io: &mut Writer) -> Poll<bool, Error> {
|
||||||
let info: &mut PipelineInfo<_> = unsafe { mem::transmute(&mut self.0) };
|
let info: &mut PipelineInfo<_> = unsafe { &mut *(&mut self.0 as *mut _) };
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if self.1.is_response() {
|
if self.1.is_response() {
|
||||||
@ -197,7 +203,7 @@ impl<S: 'static, H: PipelineHandler<S>> HttpHandlerTask for Pipeline<S, H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<(), Error> {
|
fn poll(&mut self) -> Poll<(), Error> {
|
||||||
let info: &mut PipelineInfo<_> = unsafe { mem::transmute(&mut self.0) };
|
let info: &mut PipelineInfo<_> = unsafe { &mut *(&mut self.0 as *mut _) };
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.1 {
|
match self.1 {
|
||||||
@ -228,17 +234,17 @@ struct StartMiddlewares<S, H> {
|
|||||||
|
|
||||||
impl<S: 'static, H: PipelineHandler<S>> StartMiddlewares<S, H> {
|
impl<S: 'static, H: PipelineHandler<S>> StartMiddlewares<S, H> {
|
||||||
fn init(
|
fn init(
|
||||||
info: &mut PipelineInfo<S>, hnd: Rc<UnsafeCell<H>>, htype: HandlerType
|
info: &mut PipelineInfo<S>, hnd: Rc<UnsafeCell<H>>, htype: HandlerType,
|
||||||
) -> PipelineState<S, H> {
|
) -> PipelineState<S, H> {
|
||||||
// execute middlewares, we need this stage because middlewares could be
|
// execute middlewares, we need this stage because middlewares could be
|
||||||
// non-async and we can move to next state immediately
|
// non-async and we can move to next state immediately
|
||||||
let len = info.mws.len() as u16;
|
let len = info.mws.len() as u16;
|
||||||
loop {
|
loop {
|
||||||
if info.count == len {
|
if info.count == len {
|
||||||
let reply = unsafe { &mut *hnd.get() }.handle(info.req.clone(), htype);
|
let reply = unsafe { &mut *hnd.get() }.handle(info.req().clone(), htype);
|
||||||
return WaitingResponse::init(info, reply);
|
return WaitingResponse::init(info, reply);
|
||||||
} else {
|
} else {
|
||||||
match info.mws[info.count as usize].start(&mut info.req) {
|
match info.mws[info.count as usize].start(info.req_mut()) {
|
||||||
Ok(Started::Done) => info.count += 1,
|
Ok(Started::Done) => info.count += 1,
|
||||||
Ok(Started::Response(resp)) => {
|
Ok(Started::Response(resp)) => {
|
||||||
return RunMiddlewares::init(info, resp)
|
return RunMiddlewares::init(info, resp)
|
||||||
@ -278,7 +284,7 @@ impl<S: 'static, H: PipelineHandler<S>> StartMiddlewares<S, H> {
|
|||||||
}
|
}
|
||||||
if info.count == len {
|
if info.count == len {
|
||||||
let reply = unsafe { &mut *self.hnd.get() }
|
let reply = unsafe { &mut *self.hnd.get() }
|
||||||
.handle(info.req.clone(), self.htype);
|
.handle(info.req().clone(), self.htype);
|
||||||
return Some(WaitingResponse::init(info, reply));
|
return Some(WaitingResponse::init(info, reply));
|
||||||
} else {
|
} else {
|
||||||
loop {
|
loop {
|
||||||
@ -462,7 +468,7 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn poll_io(
|
fn poll_io(
|
||||||
mut self, io: &mut Writer, info: &mut PipelineInfo<S>
|
mut self, io: &mut Writer, info: &mut PipelineInfo<S>,
|
||||||
) -> Result<PipelineState<S, H>, PipelineState<S, H>> {
|
) -> Result<PipelineState<S, H>, PipelineState<S, H>> {
|
||||||
loop {
|
loop {
|
||||||
if self.drain.is_none() && self.running != RunningState::Paused {
|
if self.drain.is_none() && self.running != RunningState::Paused {
|
||||||
@ -482,8 +488,7 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
info.error = Some(err.into());
|
info.error = Some(err.into());
|
||||||
return Ok(FinishingMiddlewares::init(
|
return Ok(FinishingMiddlewares::init(
|
||||||
info,
|
info, self.resp,
|
||||||
self.resp,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -525,8 +530,7 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
if let Err(err) = io.write_eof() {
|
if let Err(err) = io.write_eof() {
|
||||||
info.error = Some(err.into());
|
info.error = Some(err.into());
|
||||||
return Ok(FinishingMiddlewares::init(
|
return Ok(FinishingMiddlewares::init(
|
||||||
info,
|
info, self.resp,
|
||||||
self.resp,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -537,8 +541,7 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
info.error = Some(err.into());
|
info.error = Some(err.into());
|
||||||
return Ok(FinishingMiddlewares::init(
|
return Ok(FinishingMiddlewares::init(
|
||||||
info,
|
info, self.resp,
|
||||||
self.resp,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
@ -572,8 +575,7 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
info.error = Some(err.into());
|
info.error = Some(err.into());
|
||||||
return Ok(
|
return Ok(
|
||||||
FinishingMiddlewares::init(
|
FinishingMiddlewares::init(
|
||||||
info,
|
info, self.resp,
|
||||||
self.resp,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -585,8 +587,7 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
info.error = Some(err.into());
|
info.error = Some(err.into());
|
||||||
return Ok(
|
return Ok(
|
||||||
FinishingMiddlewares::init(
|
FinishingMiddlewares::init(
|
||||||
info,
|
info, self.resp,
|
||||||
self.resp,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -611,8 +612,7 @@ impl<S: 'static, H> ProcessResponse<S, H> {
|
|||||||
Err(err) => {
|
Err(err) => {
|
||||||
info.error = Some(err);
|
info.error = Some(err);
|
||||||
return Ok(FinishingMiddlewares::init(
|
return Ok(FinishingMiddlewares::init(
|
||||||
info,
|
info, self.resp,
|
||||||
self.resp,
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -796,18 +796,15 @@ mod tests {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.run(lazy(|| {
|
.run(lazy(|| {
|
||||||
let mut info = PipelineInfo::new(HttpRequest::default());
|
let mut info = PipelineInfo::new(HttpRequest::default());
|
||||||
Completed::<(), Inner<()>>::init(&mut info)
|
Completed::<(), Inner<()>>::init(&mut info).is_none().unwrap();
|
||||||
.is_none()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let req = HttpRequest::default();
|
let req = HttpRequest::default();
|
||||||
let mut ctx = HttpContext::new(req.clone(), MyActor);
|
let mut ctx = HttpContext::new(req.clone(), MyActor);
|
||||||
let addr: Addr<Unsync, _> = ctx.address();
|
let addr: Addr<Unsync, _> = ctx.address();
|
||||||
let mut info = PipelineInfo::new(req);
|
let mut info = PipelineInfo::new(req);
|
||||||
info.context = Some(Box::new(ctx));
|
info.context = Some(Box::new(ctx));
|
||||||
let mut state = Completed::<(), Inner<()>>::init(&mut info)
|
let mut state =
|
||||||
.completed()
|
Completed::<(), Inner<()>>::init(&mut info).completed().unwrap();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert!(state.poll(&mut info).is_none());
|
assert!(state.poll(&mut info).is_none());
|
||||||
let pp = Pipeline(info, PipelineState::Completed(state));
|
let pp = Pipeline(info, PipelineState::Completed(state));
|
||||||
|
@ -171,7 +171,7 @@ pub fn Method<S: 'static>(method: http::Method) -> MethodPredicate<S> {
|
|||||||
/// Return predicate that matches if request contains specified header and
|
/// Return predicate that matches if request contains specified header and
|
||||||
/// value.
|
/// value.
|
||||||
pub fn Header<S: 'static>(
|
pub fn Header<S: 'static>(
|
||||||
name: &'static str, value: &'static str
|
name: &'static str, value: &'static str,
|
||||||
) -> HeaderPredicate<S> {
|
) -> HeaderPredicate<S> {
|
||||||
HeaderPredicate(
|
HeaderPredicate(
|
||||||
header::HeaderName::try_from(name).unwrap(),
|
header::HeaderName::try_from(name).unwrap(),
|
||||||
@ -181,11 +181,7 @@ pub fn Header<S: 'static>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct HeaderPredicate<S>(
|
pub struct HeaderPredicate<S>(header::HeaderName, header::HeaderValue, PhantomData<S>);
|
||||||
header::HeaderName,
|
|
||||||
header::HeaderValue,
|
|
||||||
PhantomData<S>,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<S: 'static> Predicate<S> for HeaderPredicate<S> {
|
impl<S: 'static> Predicate<S> for HeaderPredicate<S> {
|
||||||
fn check(&self, req: &mut HttpRequest<S>) -> bool {
|
fn check(&self, req: &mut HttpRequest<S>) -> bool {
|
||||||
|
@ -132,10 +132,7 @@ impl<S: 'static> ResourceHandler<S> {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn method(&mut self, method: Method) -> &mut Route<S> {
|
pub fn method(&mut self, method: Method) -> &mut Route<S> {
|
||||||
self.routes.push(Route::default());
|
self.routes.push(Route::default());
|
||||||
self.routes
|
self.routes.last_mut().unwrap().filter(pred::Method(method))
|
||||||
.last_mut()
|
|
||||||
.unwrap()
|
|
||||||
.filter(pred::Method(method))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a new route and add handler object.
|
/// Register a new route and add handler object.
|
||||||
@ -188,13 +185,11 @@ impl<S: 'static> ResourceHandler<S> {
|
|||||||
/// This is similar to `App's` middlewares, but
|
/// This is similar to `App's` middlewares, but
|
||||||
/// middlewares get invoked on resource level.
|
/// middlewares get invoked on resource level.
|
||||||
pub fn middleware<M: Middleware<S>>(&mut self, mw: M) {
|
pub fn middleware<M: Middleware<S>>(&mut self, mw: M) {
|
||||||
Rc::get_mut(&mut self.middlewares)
|
Rc::get_mut(&mut self.middlewares).unwrap().push(Box::new(mw));
|
||||||
.unwrap()
|
|
||||||
.push(Box::new(mw));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle(
|
pub(crate) fn handle(
|
||||||
&mut self, mut req: HttpRequest<S>, default: Option<&mut ResourceHandler<S>>
|
&mut self, mut req: HttpRequest<S>, default: Option<&mut ResourceHandler<S>>,
|
||||||
) -> Reply {
|
) -> Reply {
|
||||||
for route in &mut self.routes {
|
for route in &mut self.routes {
|
||||||
if route.check(&mut req) {
|
if route.check(&mut req) {
|
||||||
|
25
src/route.rs
25
src/route.rs
@ -50,7 +50,7 @@ impl<S: 'static> Route<S> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn compose(
|
pub(crate) fn compose(
|
||||||
&mut self, req: HttpRequest<S>, mws: Rc<Vec<Box<Middleware<S>>>>
|
&mut self, req: HttpRequest<S>, mws: Rc<Vec<Box<Middleware<S>>>>,
|
||||||
) -> Reply {
|
) -> Reply {
|
||||||
Reply::async(Compose::new(req, mws, self.handler.clone()))
|
Reply::async(Compose::new(req, mws, self.handler.clone()))
|
||||||
}
|
}
|
||||||
@ -170,7 +170,7 @@ impl<S: 'static> Route<S> {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn with2<T1, T2, F, R>(
|
pub fn with2<T1, T2, F, R>(
|
||||||
&mut self, handler: F
|
&mut self, handler: F,
|
||||||
) -> (ExtractorConfig<S, T1>, ExtractorConfig<S, T2>)
|
) -> (ExtractorConfig<S, T1>, ExtractorConfig<S, T2>)
|
||||||
where
|
where
|
||||||
F: Fn(T1, T2) -> R + 'static,
|
F: Fn(T1, T2) -> R + 'static,
|
||||||
@ -180,22 +180,14 @@ impl<S: 'static> Route<S> {
|
|||||||
{
|
{
|
||||||
let cfg1 = ExtractorConfig::default();
|
let cfg1 = ExtractorConfig::default();
|
||||||
let cfg2 = ExtractorConfig::default();
|
let cfg2 = ExtractorConfig::default();
|
||||||
self.h(With2::new(
|
self.h(With2::new(handler, Clone::clone(&cfg1), Clone::clone(&cfg2)));
|
||||||
handler,
|
|
||||||
Clone::clone(&cfg1),
|
|
||||||
Clone::clone(&cfg2),
|
|
||||||
));
|
|
||||||
(cfg1, cfg2)
|
(cfg1, cfg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set handler function, use request extractor for all paramters.
|
/// Set handler function, use request extractor for all paramters.
|
||||||
pub fn with3<T1, T2, T3, F, R>(
|
pub fn with3<T1, T2, T3, F, R>(
|
||||||
&mut self, handler: F
|
&mut self, handler: F,
|
||||||
) -> (
|
) -> (ExtractorConfig<S, T1>, ExtractorConfig<S, T2>, ExtractorConfig<S, T3>)
|
||||||
ExtractorConfig<S, T1>,
|
|
||||||
ExtractorConfig<S, T2>,
|
|
||||||
ExtractorConfig<S, T3>,
|
|
||||||
)
|
|
||||||
where
|
where
|
||||||
F: Fn(T1, T2, T3) -> R + 'static,
|
F: Fn(T1, T2, T3) -> R + 'static,
|
||||||
R: Responder + 'static,
|
R: Responder + 'static,
|
||||||
@ -288,7 +280,7 @@ impl<S: 'static> ComposeState<S> {
|
|||||||
|
|
||||||
impl<S: 'static> Compose<S> {
|
impl<S: 'static> Compose<S> {
|
||||||
fn new(
|
fn new(
|
||||||
req: HttpRequest<S>, mws: Rc<Vec<Box<Middleware<S>>>>, handler: InnerHandler<S>
|
req: HttpRequest<S>, mws: Rc<Vec<Box<Middleware<S>>>>, handler: InnerHandler<S>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut info = ComposeInfo {
|
let mut info = ComposeInfo {
|
||||||
count: 0,
|
count: 0,
|
||||||
@ -298,7 +290,10 @@ impl<S: 'static> Compose<S> {
|
|||||||
};
|
};
|
||||||
let state = StartMiddlewares::init(&mut info);
|
let state = StartMiddlewares::init(&mut info);
|
||||||
|
|
||||||
Compose { state, info }
|
Compose {
|
||||||
|
state,
|
||||||
|
info,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,11 @@ impl Router {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let path: &str = unsafe { mem::transmute(&req.path()[self.0.prefix_len..]) };
|
let path: &str = unsafe { mem::transmute(&req.path()[self.0.prefix_len..]) };
|
||||||
let route_path = if path.is_empty() { "/" } else { path };
|
let route_path = if path.is_empty() {
|
||||||
|
"/"
|
||||||
|
} else {
|
||||||
|
path
|
||||||
|
};
|
||||||
|
|
||||||
for (idx, pattern) in self.0.patterns.iter().enumerate() {
|
for (idx, pattern) in self.0.patterns.iter().enumerate() {
|
||||||
if pattern.match_with_params(route_path, req.match_info_mut()) {
|
if pattern.match_with_params(route_path, req.match_info_mut()) {
|
||||||
@ -98,7 +102,11 @@ impl Router {
|
|||||||
/// following path would be recognizable `/test/name` but `has_route()` call
|
/// following path would be recognizable `/test/name` but `has_route()` call
|
||||||
/// would return `false`.
|
/// would return `false`.
|
||||||
pub fn has_route(&self, path: &str) -> bool {
|
pub fn has_route(&self, path: &str) -> bool {
|
||||||
let path = if path.is_empty() { "/" } else { path };
|
let path = if path.is_empty() {
|
||||||
|
"/"
|
||||||
|
} else {
|
||||||
|
path
|
||||||
|
};
|
||||||
|
|
||||||
for pattern in &self.0.patterns {
|
for pattern in &self.0.patterns {
|
||||||
if pattern.is_match(path) {
|
if pattern.is_match(path) {
|
||||||
@ -113,7 +121,7 @@ impl Router {
|
|||||||
/// Check [`HttpRequest::url_for()`](../struct.HttpRequest.html#method.
|
/// Check [`HttpRequest::url_for()`](../struct.HttpRequest.html#method.
|
||||||
/// url_for) for detailed information.
|
/// url_for) for detailed information.
|
||||||
pub fn resource_path<U, I>(
|
pub fn resource_path<U, I>(
|
||||||
&self, name: &str, elements: U
|
&self, name: &str, elements: U,
|
||||||
) -> Result<String, UrlGenerationError>
|
) -> Result<String, UrlGenerationError>
|
||||||
where
|
where
|
||||||
U: IntoIterator<Item = I>,
|
U: IntoIterator<Item = I>,
|
||||||
@ -245,7 +253,7 @@ impl Resource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn match_with_params<'a>(
|
pub fn match_with_params<'a>(
|
||||||
&'a self, path: &'a str, params: &'a mut Params<'a>
|
&'a self, path: &'a str, params: &'a mut Params<'a>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
match self.tp {
|
match self.tp {
|
||||||
PatternType::Static(ref s) => s == path,
|
PatternType::Static(ref s) => s == path,
|
||||||
@ -270,7 +278,7 @@ impl Resource {
|
|||||||
|
|
||||||
/// Build reousrce path.
|
/// Build reousrce path.
|
||||||
pub fn resource_path<U, I>(
|
pub fn resource_path<U, I>(
|
||||||
&self, router: &Router, elements: U
|
&self, router: &Router, elements: U,
|
||||||
) -> Result<String, UrlGenerationError>
|
) -> Result<String, UrlGenerationError>
|
||||||
where
|
where
|
||||||
U: IntoIterator<Item = I>,
|
U: IntoIterator<Item = I>,
|
||||||
@ -383,34 +391,19 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer() {
|
fn test_recognizer() {
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(
|
(Resource::new("", "/name"), Some(ResourceHandler::default())),
|
||||||
Resource::new("", "/name"),
|
(Resource::new("", "/name/{val}"), Some(ResourceHandler::default())),
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Resource::new("", "/name/{val}"),
|
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
Resource::new("", "/name/{val}/index.html"),
|
Resource::new("", "/name/{val}/index.html"),
|
||||||
Some(ResourceHandler::default()),
|
Some(ResourceHandler::default()),
|
||||||
),
|
),
|
||||||
(
|
(Resource::new("", "/file/{file}.{ext}"), Some(ResourceHandler::default())),
|
||||||
Resource::new("", "/file/{file}.{ext}"),
|
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
Resource::new("", "/v{val}/{val2}/index.html"),
|
Resource::new("", "/v{val}/{val2}/index.html"),
|
||||||
Some(ResourceHandler::default()),
|
Some(ResourceHandler::default()),
|
||||||
),
|
),
|
||||||
(
|
(Resource::new("", "/v/{tail:.*}"), Some(ResourceHandler::default())),
|
||||||
Resource::new("", "/v/{tail:.*}"),
|
(Resource::new("", "{test}/index.html"), Some(ResourceHandler::default())),
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Resource::new("", "{test}/index.html"),
|
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
@ -439,10 +432,7 @@ mod tests {
|
|||||||
|
|
||||||
let mut req = TestRequest::with_uri("/v/blah-blah/index.html").finish();
|
let mut req = TestRequest::with_uri("/v/blah-blah/index.html").finish();
|
||||||
assert_eq!(rec.recognize(&mut req), Some(5));
|
assert_eq!(rec.recognize(&mut req), Some(5));
|
||||||
assert_eq!(
|
assert_eq!(req.match_info().get("tail").unwrap(), "blah-blah/index.html");
|
||||||
req.match_info().get("tail").unwrap(),
|
|
||||||
"blah-blah/index.html"
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut req = TestRequest::with_uri("/bbb/index.html").finish();
|
let mut req = TestRequest::with_uri("/bbb/index.html").finish();
|
||||||
assert_eq!(rec.recognize(&mut req), Some(6));
|
assert_eq!(rec.recognize(&mut req), Some(6));
|
||||||
@ -452,14 +442,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer_2() {
|
fn test_recognizer_2() {
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(
|
(Resource::new("", "/index.json"), Some(ResourceHandler::default())),
|
||||||
Resource::new("", "/index.json"),
|
(Resource::new("", "/{source}.json"), Some(ResourceHandler::default())),
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Resource::new("", "/{source}.json"),
|
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
@ -473,14 +457,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_recognizer_with_prefix() {
|
fn test_recognizer_with_prefix() {
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(
|
(Resource::new("", "/name"), Some(ResourceHandler::default())),
|
||||||
Resource::new("", "/name"),
|
(Resource::new("", "/name/{val}"), Some(ResourceHandler::default())),
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Resource::new("", "/name/{val}"),
|
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
let (rec, _) = Router::new::<()>("/test", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("/test", ServerSettings::default(), routes);
|
||||||
|
|
||||||
@ -497,14 +475,8 @@ mod tests {
|
|||||||
|
|
||||||
// same patterns
|
// same patterns
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(
|
(Resource::new("", "/name"), Some(ResourceHandler::default())),
|
||||||
Resource::new("", "/name"),
|
(Resource::new("", "/name/{val}"), Some(ResourceHandler::default())),
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Resource::new("", "/name/{val}"),
|
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
let (rec, _) = Router::new::<()>("/test2", ServerSettings::default(), routes);
|
let (rec, _) = Router::new::<()>("/test2", ServerSettings::default(), routes);
|
||||||
|
|
||||||
@ -573,14 +545,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_request_resource() {
|
fn test_request_resource() {
|
||||||
let routes = vec![
|
let routes = vec![
|
||||||
(
|
(Resource::new("r1", "/index.json"), Some(ResourceHandler::default())),
|
||||||
Resource::new("r1", "/index.json"),
|
(Resource::new("r2", "/test.json"), Some(ResourceHandler::default())),
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Resource::new("r2", "/test.json"),
|
|
||||||
Some(ResourceHandler::default()),
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
let (router, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
let (router, _) = Router::new::<()>("", ServerSettings::default(), routes);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use futures::{Async, Future, Poll};
|
|||||||
use tokio_io::{AsyncRead, AsyncWrite};
|
use tokio_io::{AsyncRead, AsyncWrite};
|
||||||
|
|
||||||
use super::settings::WorkerSettings;
|
use super::settings::WorkerSettings;
|
||||||
use super::{utils, HttpHandler, IoStream, h1, h2};
|
use super::{h1, h2, utils, HttpHandler, IoStream};
|
||||||
|
|
||||||
const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0";
|
const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0";
|
||||||
|
|
||||||
@ -93,12 +93,12 @@ where
|
|||||||
let el = self as *mut _;
|
let el = self as *mut _;
|
||||||
self.node = Some(Node::new(el));
|
self.node = Some(Node::new(el));
|
||||||
let _ = match self.proto {
|
let _ = match self.proto {
|
||||||
Some(HttpProtocol::H1(ref mut h1)) => self.node
|
Some(HttpProtocol::H1(ref mut h1)) => {
|
||||||
.as_ref()
|
self.node.as_ref().map(|n| h1.settings().head().insert(n))
|
||||||
.map(|n| h1.settings().head().insert(n)),
|
}
|
||||||
Some(HttpProtocol::H2(ref mut h2)) => self.node
|
Some(HttpProtocol::H2(ref mut h2)) => {
|
||||||
.as_ref()
|
self.node.as_ref().map(|n| h2.settings().head().insert(n))
|
||||||
.map(|n| h2.settings().head().insert(n)),
|
}
|
||||||
Some(HttpProtocol::Unknown(ref mut settings, _, _, _)) => {
|
Some(HttpProtocol::Unknown(ref mut settings, _, _, _)) => {
|
||||||
self.node.as_ref().map(|n| settings.head().insert(n))
|
self.node.as_ref().map(|n| settings.head().insert(n))
|
||||||
}
|
}
|
||||||
@ -112,7 +112,9 @@ where
|
|||||||
match result {
|
match result {
|
||||||
Ok(Async::Ready(())) | Err(_) => {
|
Ok(Async::Ready(())) | Err(_) => {
|
||||||
h1.settings().remove_channel();
|
h1.settings().remove_channel();
|
||||||
self.node.as_mut().map(|n| n.remove());
|
if let Some(n) = self.node.as_mut() {
|
||||||
|
n.remove()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -123,7 +125,9 @@ where
|
|||||||
match result {
|
match result {
|
||||||
Ok(Async::Ready(())) | Err(_) => {
|
Ok(Async::Ready(())) | Err(_) => {
|
||||||
h2.settings().remove_channel();
|
h2.settings().remove_channel();
|
||||||
self.node.as_mut().map(|n| n.remove());
|
if let Some(n) = self.node.as_mut() {
|
||||||
|
n.remove()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -139,7 +143,9 @@ where
|
|||||||
Ok(Async::Ready(0)) | Err(_) => {
|
Ok(Async::Ready(0)) | Err(_) => {
|
||||||
debug!("Ignored premature client disconnection");
|
debug!("Ignored premature client disconnection");
|
||||||
settings.remove_channel();
|
settings.remove_channel();
|
||||||
self.node.as_mut().map(|n| n.remove());
|
if let Some(n) = self.node.as_mut() {
|
||||||
|
n.remove()
|
||||||
|
};
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@ -162,12 +168,8 @@ where
|
|||||||
if let Some(HttpProtocol::Unknown(settings, addr, io, buf)) = self.proto.take() {
|
if let Some(HttpProtocol::Unknown(settings, addr, io, buf)) = self.proto.take() {
|
||||||
match kind {
|
match kind {
|
||||||
ProtocolKind::Http1 => {
|
ProtocolKind::Http1 => {
|
||||||
self.proto = Some(HttpProtocol::H1(h1::Http1::new(
|
self.proto =
|
||||||
settings,
|
Some(HttpProtocol::H1(h1::Http1::new(settings, io, addr, buf)));
|
||||||
io,
|
|
||||||
addr,
|
|
||||||
buf,
|
|
||||||
)));
|
|
||||||
return self.poll();
|
return self.poll();
|
||||||
}
|
}
|
||||||
ProtocolKind::Http2 => {
|
ProtocolKind::Http2 => {
|
||||||
@ -204,7 +206,8 @@ impl<T> Node<T> {
|
|||||||
#[allow(mutable_transmutes)]
|
#[allow(mutable_transmutes)]
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(ref next2) = self.next {
|
if let Some(ref next2) = self.next {
|
||||||
let n: &mut Node<()> = mem::transmute(next2.as_ref().unwrap());
|
let n: &mut Node<()> =
|
||||||
|
&mut *(next2.as_ref().unwrap() as *const _ as *mut _);
|
||||||
n.prev = Some(next as *const _ as *mut _);
|
n.prev = Some(next as *const _ as *mut _);
|
||||||
}
|
}
|
||||||
let slf: &mut Node<T> = mem::transmute(self);
|
let slf: &mut Node<T> = mem::transmute(self);
|
||||||
@ -275,7 +278,9 @@ where
|
|||||||
T: AsyncRead + AsyncWrite + 'static,
|
T: AsyncRead + AsyncWrite + 'static,
|
||||||
{
|
{
|
||||||
pub fn new(io: T) -> Self {
|
pub fn new(io: T) -> Self {
|
||||||
WrapperStream { io }
|
WrapperStream {
|
||||||
|
io,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,8 +763,7 @@ impl TransferEncoding {
|
|||||||
return Ok(*remaining == 0);
|
return Ok(*remaining == 0);
|
||||||
}
|
}
|
||||||
let len = cmp::min(*remaining, msg.len() as u64);
|
let len = cmp::min(*remaining, msg.len() as u64);
|
||||||
self.buffer
|
self.buffer.extend(msg.take().split_to(len as usize).into());
|
||||||
.extend(msg.take().split_to(len as usize).into());
|
|
||||||
|
|
||||||
*remaining -= len as u64;
|
*remaining -= len as u64;
|
||||||
Ok(*remaining == 0)
|
Ok(*remaining == 0)
|
||||||
@ -856,10 +855,8 @@ impl AcceptEncoding {
|
|||||||
|
|
||||||
/// Parse a raw Accept-Encoding header value into an ordered list.
|
/// Parse a raw Accept-Encoding header value into an ordered list.
|
||||||
pub fn parse(raw: &str) -> ContentEncoding {
|
pub fn parse(raw: &str) -> ContentEncoding {
|
||||||
let mut encodings: Vec<_> = raw.replace(' ', "")
|
let mut encodings: Vec<_> =
|
||||||
.split(',')
|
raw.replace(' ', "").split(',').map(|l| AcceptEncoding::new(l)).collect();
|
||||||
.map(|l| AcceptEncoding::new(l))
|
|
||||||
.collect();
|
|
||||||
encodings.sort();
|
encodings.sort();
|
||||||
|
|
||||||
for enc in encodings {
|
for enc in encodings {
|
||||||
@ -879,9 +876,7 @@ mod tests {
|
|||||||
fn test_chunked_te() {
|
fn test_chunked_te() {
|
||||||
let bytes = SharedBytes::default();
|
let bytes = SharedBytes::default();
|
||||||
let mut enc = TransferEncoding::chunked(bytes.clone());
|
let mut enc = TransferEncoding::chunked(bytes.clone());
|
||||||
assert!(!enc.encode(Binary::from(b"test".as_ref()))
|
assert!(!enc.encode(Binary::from(b"test".as_ref())).ok().unwrap());
|
||||||
.ok()
|
|
||||||
.unwrap());
|
|
||||||
assert!(enc.encode(Binary::from(b"".as_ref())).ok().unwrap());
|
assert!(enc.encode(Binary::from(b"".as_ref())).ok().unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bytes.get_mut().take().freeze(),
|
bytes.get_mut().take().freeze(),
|
||||||
|
@ -210,8 +210,7 @@ where
|
|||||||
self.stream.reset();
|
self.stream.reset();
|
||||||
|
|
||||||
if ready {
|
if ready {
|
||||||
item.flags
|
item.flags.insert(EntryFlags::EOF | EntryFlags::FINISHED);
|
||||||
.insert(EntryFlags::EOF | EntryFlags::FINISHED);
|
|
||||||
} else {
|
} else {
|
||||||
item.flags.insert(EntryFlags::FINISHED);
|
item.flags.insert(EntryFlags::FINISHED);
|
||||||
}
|
}
|
||||||
@ -253,10 +252,7 @@ where
|
|||||||
// cleanup finished tasks
|
// cleanup finished tasks
|
||||||
let max = self.tasks.len() >= MAX_PIPELINED_MESSAGES;
|
let max = self.tasks.len() >= MAX_PIPELINED_MESSAGES;
|
||||||
while !self.tasks.is_empty() {
|
while !self.tasks.is_empty() {
|
||||||
if self.tasks[0]
|
if self.tasks[0].flags.contains(EntryFlags::EOF | EntryFlags::FINISHED) {
|
||||||
.flags
|
|
||||||
.contains(EntryFlags::EOF | EntryFlags::FINISHED)
|
|
||||||
{
|
|
||||||
self.tasks.pop_front();
|
self.tasks.pop_front();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -308,7 +304,10 @@ where
|
|||||||
pub fn parse(&mut self) {
|
pub fn parse(&mut self) {
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
match self.decoder.decode(&mut self.buf, &self.settings) {
|
match self.decoder.decode(&mut self.buf, &self.settings) {
|
||||||
Ok(Some(Message::Message { msg, payload })) => {
|
Ok(Some(Message::Message {
|
||||||
|
msg,
|
||||||
|
payload,
|
||||||
|
})) => {
|
||||||
self.flags.insert(Flags::STARTED);
|
self.flags.insert(Flags::STARTED);
|
||||||
|
|
||||||
if payload {
|
if payload {
|
||||||
@ -421,13 +420,19 @@ mod tests {
|
|||||||
impl Message {
|
impl Message {
|
||||||
fn message(self) -> SharedHttpInnerMessage {
|
fn message(self) -> SharedHttpInnerMessage {
|
||||||
match self {
|
match self {
|
||||||
Message::Message { msg, payload: _ } => msg,
|
Message::Message {
|
||||||
|
msg,
|
||||||
|
payload: _,
|
||||||
|
} => msg,
|
||||||
_ => panic!("error"),
|
_ => panic!("error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn is_payload(&self) -> bool {
|
fn is_payload(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Message::Message { msg: _, payload } => payload,
|
Message::Message {
|
||||||
|
msg: _,
|
||||||
|
payload,
|
||||||
|
} => payload,
|
||||||
_ => panic!("error"),
|
_ => panic!("error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -623,10 +628,7 @@ mod tests {
|
|||||||
assert_eq!(req.version(), Version::HTTP_11);
|
assert_eq!(req.version(), Version::HTTP_11);
|
||||||
assert_eq!(*req.method(), Method::GET);
|
assert_eq!(*req.method(), Method::GET);
|
||||||
assert_eq!(req.path(), "/test");
|
assert_eq!(req.path(), "/test");
|
||||||
assert_eq!(
|
assert_eq!(req.headers().get("test").unwrap().as_bytes(), b"value");
|
||||||
req.headers().get("test").unwrap().as_bytes(),
|
|
||||||
b"value"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(_) | Err(_) => unreachable!("Error during parsing http request"),
|
Ok(_) | Err(_) => unreachable!("Error during parsing http request"),
|
||||||
}
|
}
|
||||||
@ -848,12 +850,7 @@ mod tests {
|
|||||||
assert!(!req.keep_alive());
|
assert!(!req.keep_alive());
|
||||||
assert!(req.upgrade());
|
assert!(req.upgrade());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
reader
|
reader.decode(&mut buf, &settings).unwrap().unwrap().chunk().as_ref(),
|
||||||
.decode(&mut buf, &settings)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.chunk()
|
|
||||||
.as_ref(),
|
|
||||||
b"some raw data"
|
b"some raw data"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -910,30 +907,14 @@ mod tests {
|
|||||||
|
|
||||||
buf.extend(b"4\r\ndata\r\n4\r\nline\r\n0\r\n\r\n");
|
buf.extend(b"4\r\ndata\r\n4\r\nline\r\n0\r\n\r\n");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
reader
|
reader.decode(&mut buf, &settings).unwrap().unwrap().chunk().as_ref(),
|
||||||
.decode(&mut buf, &settings)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.chunk()
|
|
||||||
.as_ref(),
|
|
||||||
b"data"
|
b"data"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
reader
|
reader.decode(&mut buf, &settings).unwrap().unwrap().chunk().as_ref(),
|
||||||
.decode(&mut buf, &settings)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.chunk()
|
|
||||||
.as_ref(),
|
|
||||||
b"line"
|
b"line"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(reader.decode(&mut buf, &settings).unwrap().unwrap().eof());
|
||||||
reader
|
|
||||||
.decode(&mut buf, &settings)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.eof()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1014,13 +995,7 @@ mod tests {
|
|||||||
assert!(reader.decode(&mut buf, &settings).unwrap().is_none());
|
assert!(reader.decode(&mut buf, &settings).unwrap().is_none());
|
||||||
|
|
||||||
buf.extend(b"\r\n");
|
buf.extend(b"\r\n");
|
||||||
assert!(
|
assert!(reader.decode(&mut buf, &settings).unwrap().unwrap().eof());
|
||||||
reader
|
|
||||||
.decode(&mut buf, &settings)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.eof()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1038,17 +1013,9 @@ mod tests {
|
|||||||
assert!(req.chunked().unwrap());
|
assert!(req.chunked().unwrap());
|
||||||
|
|
||||||
buf.extend(b"4;test\r\ndata\r\n4\r\nline\r\n0\r\n\r\n"); // test: test\r\n\r\n")
|
buf.extend(b"4;test\r\ndata\r\n4\r\nline\r\n0\r\n\r\n"); // test: test\r\n\r\n")
|
||||||
let chunk = reader
|
let chunk = reader.decode(&mut buf, &settings).unwrap().unwrap().chunk();
|
||||||
.decode(&mut buf, &settings)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.chunk();
|
|
||||||
assert_eq!(chunk, Bytes::from_static(b"data"));
|
assert_eq!(chunk, Bytes::from_static(b"data"));
|
||||||
let chunk = reader
|
let chunk = reader.decode(&mut buf, &settings).unwrap().unwrap().chunk();
|
||||||
.decode(&mut buf, &settings)
|
|
||||||
.unwrap()
|
|
||||||
.unwrap()
|
|
||||||
.chunk();
|
|
||||||
assert_eq!(chunk, Bytes::from_static(b"line"));
|
assert_eq!(chunk, Bytes::from_static(b"line"));
|
||||||
let msg = reader.decode(&mut buf, &settings).unwrap().unwrap();
|
let msg = reader.decode(&mut buf, &settings).unwrap().unwrap();
|
||||||
assert!(msg.eof());
|
assert!(msg.eof());
|
||||||
|
@ -41,7 +41,9 @@ impl From<io::Error> for DecoderError {
|
|||||||
|
|
||||||
impl H1Decoder {
|
impl H1Decoder {
|
||||||
pub fn new() -> H1Decoder {
|
pub fn new() -> H1Decoder {
|
||||||
H1Decoder { decoder: None }
|
H1Decoder {
|
||||||
|
decoder: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode<H>(
|
pub fn decode<H>(
|
||||||
@ -59,9 +61,7 @@ impl H1Decoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.parse_message(src, settings)
|
match self.parse_message(src, settings).map_err(DecoderError::Error)? {
|
||||||
.map_err(DecoderError::Error)?
|
|
||||||
{
|
|
||||||
Async::Ready((msg, decoder)) => {
|
Async::Ready((msg, decoder)) => {
|
||||||
if let Some(decoder) = decoder {
|
if let Some(decoder) = decoder {
|
||||||
self.decoder = Some(decoder);
|
self.decoder = Some(decoder);
|
||||||
@ -103,7 +103,7 @@ impl H1Decoder {
|
|||||||
let (len, method, path, version, headers_len) = {
|
let (len, method, path, version, headers_len) = {
|
||||||
let b = unsafe {
|
let b = unsafe {
|
||||||
let b: &[u8] = buf;
|
let b: &[u8] = buf;
|
||||||
mem::transmute(b)
|
&*(b as *const [u8])
|
||||||
};
|
};
|
||||||
let mut req = httparse::Request::new(&mut headers);
|
let mut req = httparse::Request::new(&mut headers);
|
||||||
match req.parse(b)? {
|
match req.parse(b)? {
|
||||||
@ -415,10 +415,9 @@ impl ChunkedState {
|
|||||||
match byte!(rdr) {
|
match byte!(rdr) {
|
||||||
b'\n' if *size > 0 => Ok(Async::Ready(ChunkedState::Body)),
|
b'\n' if *size > 0 => Ok(Async::Ready(ChunkedState::Body)),
|
||||||
b'\n' if *size == 0 => Ok(Async::Ready(ChunkedState::EndCr)),
|
b'\n' if *size == 0 => Ok(Async::Ready(ChunkedState::EndCr)),
|
||||||
_ => Err(io::Error::new(
|
_ => {
|
||||||
io::ErrorKind::InvalidInput,
|
Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk size LF"))
|
||||||
"Invalid chunk size LF",
|
}
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,37 +450,33 @@ impl ChunkedState {
|
|||||||
fn read_body_cr(rdr: &mut BytesMut) -> Poll<ChunkedState, io::Error> {
|
fn read_body_cr(rdr: &mut BytesMut) -> Poll<ChunkedState, io::Error> {
|
||||||
match byte!(rdr) {
|
match byte!(rdr) {
|
||||||
b'\r' => Ok(Async::Ready(ChunkedState::BodyLf)),
|
b'\r' => Ok(Async::Ready(ChunkedState::BodyLf)),
|
||||||
_ => Err(io::Error::new(
|
_ => {
|
||||||
io::ErrorKind::InvalidInput,
|
Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body CR"))
|
||||||
"Invalid chunk body CR",
|
}
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn read_body_lf(rdr: &mut BytesMut) -> Poll<ChunkedState, io::Error> {
|
fn read_body_lf(rdr: &mut BytesMut) -> Poll<ChunkedState, io::Error> {
|
||||||
match byte!(rdr) {
|
match byte!(rdr) {
|
||||||
b'\n' => Ok(Async::Ready(ChunkedState::Size)),
|
b'\n' => Ok(Async::Ready(ChunkedState::Size)),
|
||||||
_ => Err(io::Error::new(
|
_ => {
|
||||||
io::ErrorKind::InvalidInput,
|
Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk body LF"))
|
||||||
"Invalid chunk body LF",
|
}
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn read_end_cr(rdr: &mut BytesMut) -> Poll<ChunkedState, io::Error> {
|
fn read_end_cr(rdr: &mut BytesMut) -> Poll<ChunkedState, io::Error> {
|
||||||
match byte!(rdr) {
|
match byte!(rdr) {
|
||||||
b'\r' => Ok(Async::Ready(ChunkedState::EndLf)),
|
b'\r' => Ok(Async::Ready(ChunkedState::EndLf)),
|
||||||
_ => Err(io::Error::new(
|
_ => {
|
||||||
io::ErrorKind::InvalidInput,
|
Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end CR"))
|
||||||
"Invalid chunk end CR",
|
}
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn read_end_lf(rdr: &mut BytesMut) -> Poll<ChunkedState, io::Error> {
|
fn read_end_lf(rdr: &mut BytesMut) -> Poll<ChunkedState, io::Error> {
|
||||||
match byte!(rdr) {
|
match byte!(rdr) {
|
||||||
b'\n' => Ok(Async::Ready(ChunkedState::End)),
|
b'\n' => Ok(Async::Ready(ChunkedState::End)),
|
||||||
_ => Err(io::Error::new(
|
_ => {
|
||||||
io::ErrorKind::InvalidInput,
|
Err(io::Error::new(io::ErrorKind::InvalidInput, "Invalid chunk end LF"))
|
||||||
"Invalid chunk end LF",
|
}
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
use bytes::BufMut;
|
use bytes::BufMut;
|
||||||
use futures::{Async, Poll};
|
use futures::{Async, Poll};
|
||||||
|
use std::io;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::{io, mem};
|
|
||||||
use tokio_io::AsyncWrite;
|
use tokio_io::AsyncWrite;
|
||||||
|
|
||||||
use super::encoding::ContentEncoder;
|
use super::encoding::ContentEncoder;
|
||||||
@ -13,10 +13,10 @@ use super::shared::SharedBytes;
|
|||||||
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
|
use super::{Writer, WriterState, MAX_WRITE_BUFFER_SIZE};
|
||||||
use body::{Binary, Body};
|
use body::{Binary, Body};
|
||||||
use header::ContentEncoding;
|
use header::ContentEncoding;
|
||||||
|
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE};
|
||||||
|
use http::{Method, Version};
|
||||||
use httprequest::HttpInnerMessage;
|
use httprequest::HttpInnerMessage;
|
||||||
use httpresponse::HttpResponse;
|
use httpresponse::HttpResponse;
|
||||||
use http::{Method, Version};
|
|
||||||
use http::header::{HeaderValue, CONNECTION, CONTENT_LENGTH, DATE};
|
|
||||||
|
|
||||||
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
const AVERAGE_HEADER_SIZE: usize = 30; // totally scientific
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ pub(crate) struct H1Writer<T: AsyncWrite, H: 'static> {
|
|||||||
|
|
||||||
impl<T: AsyncWrite, H: 'static> H1Writer<T, H> {
|
impl<T: AsyncWrite, H: 'static> H1Writer<T, H> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
stream: T, buf: SharedBytes, settings: Rc<WorkerSettings<H>>
|
stream: T, buf: SharedBytes, settings: Rc<WorkerSettings<H>>,
|
||||||
) -> H1Writer<T, H> {
|
) -> H1Writer<T, H> {
|
||||||
H1Writer {
|
H1Writer {
|
||||||
flags: Flags::empty(),
|
flags: Flags::empty(),
|
||||||
@ -117,8 +117,7 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
|
|||||||
let version = msg.version().unwrap_or_else(|| req.version);
|
let version = msg.version().unwrap_or_else(|| req.version);
|
||||||
if msg.upgrade() {
|
if msg.upgrade() {
|
||||||
self.flags.insert(Flags::UPGRADE);
|
self.flags.insert(Flags::UPGRADE);
|
||||||
msg.headers_mut()
|
msg.headers_mut().insert(CONNECTION, HeaderValue::from_static("upgrade"));
|
||||||
.insert(CONNECTION, HeaderValue::from_static("upgrade"));
|
|
||||||
}
|
}
|
||||||
// keep-alive
|
// keep-alive
|
||||||
else if self.flags.contains(Flags::KEEPALIVE) {
|
else if self.flags.contains(Flags::KEEPALIVE) {
|
||||||
@ -127,8 +126,7 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
|
|||||||
.insert(CONNECTION, HeaderValue::from_static("keep-alive"));
|
.insert(CONNECTION, HeaderValue::from_static("keep-alive"));
|
||||||
}
|
}
|
||||||
} else if version >= Version::HTTP_11 {
|
} else if version >= Version::HTTP_11 {
|
||||||
msg.headers_mut()
|
msg.headers_mut().insert(CONNECTION, HeaderValue::from_static("close"));
|
||||||
.insert(CONNECTION, HeaderValue::from_static("close"));
|
|
||||||
}
|
}
|
||||||
let body = msg.replace_body(Body::Empty);
|
let body = msg.replace_body(Body::Empty);
|
||||||
|
|
||||||
@ -169,7 +167,7 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
|
|||||||
let mut pos = 0;
|
let mut pos = 0;
|
||||||
let mut has_date = false;
|
let mut has_date = false;
|
||||||
let mut remaining = buffer.remaining_mut();
|
let mut remaining = buffer.remaining_mut();
|
||||||
let mut buf: &mut [u8] = unsafe { mem::transmute(buffer.bytes_mut()) };
|
let mut buf = unsafe { &mut *(buffer.bytes_mut() as *mut [u8]) };
|
||||||
for (key, value) in msg.headers() {
|
for (key, value) in msg.headers() {
|
||||||
if is_bin && key == CONTENT_LENGTH {
|
if is_bin && key == CONTENT_LENGTH {
|
||||||
is_bin = false;
|
is_bin = false;
|
||||||
@ -184,7 +182,7 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
|
|||||||
pos = 0;
|
pos = 0;
|
||||||
buffer.reserve(len);
|
buffer.reserve(len);
|
||||||
remaining = buffer.remaining_mut();
|
remaining = buffer.remaining_mut();
|
||||||
buf = unsafe { mem::transmute(buffer.bytes_mut()) };
|
buf = unsafe { &mut *(buffer.bytes_mut() as *mut _) };
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[pos..pos + k.len()].copy_from_slice(k);
|
buf[pos..pos + k.len()].copy_from_slice(k);
|
||||||
@ -272,7 +270,8 @@ impl<T: AsyncWrite, H: 'static> Writer for H1Writer<T, H> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn poll_completed(&mut self, shutdown: bool) -> Poll<(), io::Error> {
|
fn poll_completed(&mut self, shutdown: bool) -> Poll<(), io::Error> {
|
||||||
if !self.buffer.is_empty() {
|
if !self.buffer.is_empty() {
|
||||||
let buf: &[u8] = unsafe { mem::transmute(self.buffer.as_ref()) };
|
let buf: &[u8] =
|
||||||
|
unsafe { &mut *(self.buffer.as_ref() as *const _ as *mut _) };
|
||||||
let written = self.write_data(buf)?;
|
let written = self.write_data(buf)?;
|
||||||
let _ = self.buffer.split_to(written);
|
let _ = self.buffer.split_to(written);
|
||||||
if self.buffer.len() > self.buffer_capacity {
|
if self.buffer.len() > self.buffer_capacity {
|
||||||
|
@ -61,7 +61,7 @@ where
|
|||||||
H: HttpHandler + 'static,
|
H: HttpHandler + 'static,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
settings: Rc<WorkerSettings<H>>, io: T, addr: Option<SocketAddr>, buf: Bytes
|
settings: Rc<WorkerSettings<H>>, io: T, addr: Option<SocketAddr>, buf: Bytes,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Http2 {
|
Http2 {
|
||||||
flags: Flags::empty(),
|
flags: Flags::empty(),
|
||||||
|
@ -45,7 +45,7 @@ pub(crate) struct H2Writer<H: 'static> {
|
|||||||
|
|
||||||
impl<H: 'static> H2Writer<H> {
|
impl<H: 'static> H2Writer<H> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
respond: SendResponse<Bytes>, buf: SharedBytes, settings: Rc<WorkerSettings<H>>
|
respond: SendResponse<Bytes>, buf: SharedBytes, settings: Rc<WorkerSettings<H>>,
|
||||||
) -> H2Writer<H> {
|
) -> H2Writer<H> {
|
||||||
H2Writer {
|
H2Writer {
|
||||||
respond,
|
respond,
|
||||||
@ -107,8 +107,7 @@ impl<H: 'static> Writer for H2Writer<H> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Body::Empty => {
|
Body::Empty => {
|
||||||
msg.headers_mut()
|
msg.headers_mut().insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
|
||||||
.insert(CONTENT_LENGTH, HeaderValue::from_static("0"));
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -120,9 +119,7 @@ impl<H: 'static> Writer for H2Writer<H> {
|
|||||||
resp.headers_mut().insert(key, value.clone());
|
resp.headers_mut().insert(key, value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.respond
|
match self.respond.send_response(resp, self.flags.contains(Flags::EOF)) {
|
||||||
.send_response(resp, self.flags.contains(Flags::EOF))
|
|
||||||
{
|
|
||||||
Ok(stream) => self.stream = Some(stream),
|
Ok(stream) => self.stream = Some(stream),
|
||||||
Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "err")),
|
Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "err")),
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ impl SharedHttpInnerMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
msg: Rc<HttpInnerMessage>, pool: Rc<SharedMessagePool>
|
msg: Rc<HttpInnerMessage>, pool: Rc<SharedMessagePool>,
|
||||||
) -> SharedHttpInnerMessage {
|
) -> SharedHttpInnerMessage {
|
||||||
SharedHttpInnerMessage(Some(msg), Some(pool))
|
SharedHttpInnerMessage(Some(msg), Some(pool))
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ impl SharedHttpInnerMessage {
|
|||||||
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref, inline_always))]
|
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref, inline_always))]
|
||||||
pub fn get_mut(&self) -> &mut HttpInnerMessage {
|
pub fn get_mut(&self) -> &mut HttpInnerMessage {
|
||||||
let r: &HttpInnerMessage = self.0.as_ref().unwrap().as_ref();
|
let r: &HttpInnerMessage = self.0.as_ref().unwrap().as_ref();
|
||||||
unsafe { mem::transmute(r) }
|
unsafe { &mut *(r as *const _ as *mut _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -96,9 +96,8 @@ const DEC_DIGITS_LUT: &[u8] = b"0001020304050607080910111213141516171819\
|
|||||||
8081828384858687888990919293949596979899";
|
8081828384858687888990919293949596979899";
|
||||||
|
|
||||||
pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesMut) {
|
pub(crate) fn write_status_line(version: Version, mut n: u16, bytes: &mut BytesMut) {
|
||||||
let mut buf: [u8; 13] = [
|
let mut buf: [u8; 13] =
|
||||||
b'H', b'T', b'T', b'P', b'/', b'1', b'.', b'1', b' ', b' ', b' ', b' ', b' '
|
[b'H', b'T', b'T', b'P', b'/', b'1', b'.', b'1', b' ', b' ', b' ', b' ', b' '];
|
||||||
];
|
|
||||||
match version {
|
match version {
|
||||||
Version::HTTP_2 => buf[5] = b'2',
|
Version::HTTP_2 => buf[5] = b'2',
|
||||||
Version::HTTP_10 => buf[7] = b'0',
|
Version::HTTP_10 => buf[7] = b'0',
|
||||||
@ -251,63 +250,33 @@ mod tests {
|
|||||||
let mut bytes = BytesMut::new();
|
let mut bytes = BytesMut::new();
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(0, &mut bytes);
|
write_content_length(0, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 0\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 0\r\n"[..]
|
|
||||||
);
|
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(9, &mut bytes);
|
write_content_length(9, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 9\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 9\r\n"[..]
|
|
||||||
);
|
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(10, &mut bytes);
|
write_content_length(10, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 10\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 10\r\n"[..]
|
|
||||||
);
|
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(99, &mut bytes);
|
write_content_length(99, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 99\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 99\r\n"[..]
|
|
||||||
);
|
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(100, &mut bytes);
|
write_content_length(100, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 100\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 100\r\n"[..]
|
|
||||||
);
|
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(101, &mut bytes);
|
write_content_length(101, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 101\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 101\r\n"[..]
|
|
||||||
);
|
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(998, &mut bytes);
|
write_content_length(998, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 998\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 998\r\n"[..]
|
|
||||||
);
|
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(1000, &mut bytes);
|
write_content_length(1000, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 1000\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 1000\r\n"[..]
|
|
||||||
);
|
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(1001, &mut bytes);
|
write_content_length(1001, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 1001\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 1001\r\n"[..]
|
|
||||||
);
|
|
||||||
bytes.reserve(50);
|
bytes.reserve(50);
|
||||||
write_content_length(5909, &mut bytes);
|
write_content_length(5909, &mut bytes);
|
||||||
assert_eq!(
|
assert_eq!(bytes.take().freeze(), b"\r\ncontent-length: 5909\r\n"[..]);
|
||||||
bytes.take().freeze(),
|
|
||||||
b"\r\ncontent-length: 5909\r\n"[..]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,10 @@ use std::sync::Arc;
|
|||||||
use std::{fmt, mem, net};
|
use std::{fmt, mem, net};
|
||||||
use time;
|
use time;
|
||||||
|
|
||||||
use super::KeepAlive;
|
|
||||||
use super::channel::Node;
|
use super::channel::Node;
|
||||||
use super::helpers;
|
use super::helpers;
|
||||||
use super::shared::{SharedBytes, SharedBytesPool};
|
use super::shared::{SharedBytes, SharedBytesPool};
|
||||||
|
use super::KeepAlive;
|
||||||
use body::Body;
|
use body::Body;
|
||||||
use httpresponse::{HttpResponse, HttpResponseBuilder, HttpResponsePool};
|
use httpresponse::{HttpResponse, HttpResponseBuilder, HttpResponsePool};
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ impl Default for ServerSettings {
|
|||||||
impl ServerSettings {
|
impl ServerSettings {
|
||||||
/// Crate server settings instance
|
/// Crate server settings instance
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
addr: Option<net::SocketAddr>, host: &Option<String>, secure: bool
|
addr: Option<net::SocketAddr>, host: &Option<String>, secure: bool,
|
||||||
) -> ServerSettings {
|
) -> ServerSettings {
|
||||||
let host = if let Some(ref host) = *host {
|
let host = if let Some(ref host) = *host {
|
||||||
host.clone()
|
host.clone()
|
||||||
@ -119,7 +119,7 @@ impl ServerSettings {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn get_response_builder(
|
pub(crate) fn get_response_builder(
|
||||||
&self, status: StatusCode
|
&self, status: StatusCode,
|
||||||
) -> HttpResponseBuilder {
|
) -> HttpResponseBuilder {
|
||||||
HttpResponsePool::get_builder(&self.responses, status)
|
HttpResponsePool::get_builder(&self.responses, status)
|
||||||
}
|
}
|
||||||
@ -255,10 +255,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_len() {
|
fn test_date_len() {
|
||||||
assert_eq!(
|
assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
|
||||||
DATE_VALUE_LENGTH,
|
|
||||||
"Sun, 06 Nov 1994 08:49:37 GMT".len()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::io;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::{io, mem};
|
|
||||||
|
|
||||||
use body::Binary;
|
use body::Binary;
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ impl SharedBytes {
|
|||||||
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref, inline_always))]
|
#[cfg_attr(feature = "cargo-clippy", allow(mut_from_ref, inline_always))]
|
||||||
pub(crate) fn get_mut(&self) -> &mut BytesMut {
|
pub(crate) fn get_mut(&self) -> &mut BytesMut {
|
||||||
let r: &BytesMut = self.0.as_ref().unwrap().as_ref();
|
let r: &BytesMut = self.0.as_ref().unwrap().as_ref();
|
||||||
unsafe { mem::transmute(r) }
|
unsafe { &mut *(r as *const _ as *mut _) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -219,10 +219,7 @@ where
|
|||||||
if let Some(e) = err.take() {
|
if let Some(e) = err.take() {
|
||||||
Err(e)
|
Err(e)
|
||||||
} else {
|
} else {
|
||||||
Err(io::Error::new(
|
Err(io::Error::new(io::ErrorKind::Other, "Can not bind to address."))
|
||||||
io::ErrorKind::Other,
|
|
||||||
"Can not bind to address.",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
@ -230,7 +227,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn start_workers(
|
fn start_workers(
|
||||||
&mut self, settings: &ServerSettings, handler: &StreamHandlerType
|
&mut self, settings: &ServerSettings, handler: &StreamHandlerType,
|
||||||
) -> Vec<(usize, mpsc::UnboundedSender<Conn<net::TcpStream>>)> {
|
) -> Vec<(usize, mpsc::UnboundedSender<Conn<net::TcpStream>>)> {
|
||||||
// start workers
|
// start workers
|
||||||
let mut workers = Vec::new();
|
let mut workers = Vec::new();
|
||||||
@ -332,9 +329,9 @@ impl<H: IntoHttpHandler> HttpServer<H> {
|
|||||||
ctx.add_stream(rx);
|
ctx.add_stream(rx);
|
||||||
self
|
self
|
||||||
});
|
});
|
||||||
signals.map(|signals| {
|
if let Some(signals) = signals {
|
||||||
signals.do_send(signal::Subscribe(addr.clone().recipient()))
|
signals.do_send(signal::Subscribe(addr.clone().recipient()))
|
||||||
});
|
}
|
||||||
addr
|
addr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -378,10 +375,7 @@ impl<H: IntoHttpHandler> HttpServer<H> {
|
|||||||
/// Start listening for incoming tls connections.
|
/// Start listening for incoming tls connections.
|
||||||
pub fn start_tls(mut self, acceptor: TlsAcceptor) -> io::Result<Addr<Syn, Self>> {
|
pub fn start_tls(mut self, acceptor: TlsAcceptor) -> io::Result<Addr<Syn, Self>> {
|
||||||
if self.sockets.is_empty() {
|
if self.sockets.is_empty() {
|
||||||
Err(io::Error::new(
|
Err(io::Error::new(io::ErrorKind::Other, "No socket addresses are bound"))
|
||||||
io::ErrorKind::Other,
|
|
||||||
"No socket addresses are bound",
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
let (tx, rx) = mpsc::unbounded();
|
let (tx, rx) = mpsc::unbounded();
|
||||||
let addrs: Vec<(net::SocketAddr, net::TcpListener)> =
|
let addrs: Vec<(net::SocketAddr, net::TcpListener)> =
|
||||||
@ -427,13 +421,10 @@ impl<H: IntoHttpHandler> HttpServer<H> {
|
|||||||
///
|
///
|
||||||
/// This method sets alpn protocols to "h2" and "http/1.1"
|
/// This method sets alpn protocols to "h2" and "http/1.1"
|
||||||
pub fn start_ssl(
|
pub fn start_ssl(
|
||||||
mut self, mut builder: SslAcceptorBuilder
|
mut self, mut builder: SslAcceptorBuilder,
|
||||||
) -> io::Result<Addr<Syn, Self>> {
|
) -> io::Result<Addr<Syn, Self>> {
|
||||||
if self.sockets.is_empty() {
|
if self.sockets.is_empty() {
|
||||||
Err(io::Error::new(
|
Err(io::Error::new(io::ErrorKind::Other, "No socket addresses are bound"))
|
||||||
io::ErrorKind::Other,
|
|
||||||
"No socket addresses are bound",
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
// alpn support
|
// alpn support
|
||||||
if !self.no_http2 {
|
if !self.no_http2 {
|
||||||
@ -545,8 +536,9 @@ impl<H: IntoHttpHandler> HttpServer<H> {
|
|||||||
}));
|
}));
|
||||||
self
|
self
|
||||||
});
|
});
|
||||||
signals
|
if let Some(signals) = signals {
|
||||||
.map(|signals| signals.do_send(signal::Subscribe(addr.clone().recipient())));
|
signals.do_send(signal::Subscribe(addr.clone().recipient()))
|
||||||
|
}
|
||||||
addr
|
addr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -562,17 +554,35 @@ impl<H: IntoHttpHandler> Handler<signal::Signal> for HttpServer<H> {
|
|||||||
signal::SignalType::Int => {
|
signal::SignalType::Int => {
|
||||||
info!("SIGINT received, exiting");
|
info!("SIGINT received, exiting");
|
||||||
self.exit = true;
|
self.exit = true;
|
||||||
Handler::<StopServer>::handle(self, StopServer { graceful: false }, ctx);
|
Handler::<StopServer>::handle(
|
||||||
|
self,
|
||||||
|
StopServer {
|
||||||
|
graceful: false,
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
signal::SignalType::Term => {
|
signal::SignalType::Term => {
|
||||||
info!("SIGTERM received, stopping");
|
info!("SIGTERM received, stopping");
|
||||||
self.exit = true;
|
self.exit = true;
|
||||||
Handler::<StopServer>::handle(self, StopServer { graceful: true }, ctx);
|
Handler::<StopServer>::handle(
|
||||||
|
self,
|
||||||
|
StopServer {
|
||||||
|
graceful: true,
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
signal::SignalType::Quit => {
|
signal::SignalType::Quit => {
|
||||||
info!("SIGQUIT received, exiting");
|
info!("SIGQUIT received, exiting");
|
||||||
self.exit = true;
|
self.exit = true;
|
||||||
Handler::<StopServer>::handle(self, StopServer { graceful: false }, ctx);
|
Handler::<StopServer>::handle(
|
||||||
|
self,
|
||||||
|
StopServer {
|
||||||
|
graceful: false,
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -696,7 +706,9 @@ impl<H: IntoHttpHandler> Handler<StopServer> for HttpServer<H> {
|
|||||||
let tx2 = tx.clone();
|
let tx2 = tx.clone();
|
||||||
worker
|
worker
|
||||||
.1
|
.1
|
||||||
.send(StopWorker { graceful: dur })
|
.send(StopWorker {
|
||||||
|
graceful: dur,
|
||||||
|
})
|
||||||
.into_actor(self)
|
.into_actor(self)
|
||||||
.then(move |_, slf, ctx| {
|
.then(move |_, slf, ctx| {
|
||||||
slf.workers.pop();
|
slf.workers.pop();
|
||||||
@ -746,9 +758,8 @@ fn start_accept_thread(
|
|||||||
|
|
||||||
// start accept thread
|
// start accept thread
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
|
#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
|
||||||
let _ = thread::Builder::new()
|
let _ = thread::Builder::new().name(format!("Accept on {}", addr)).spawn(
|
||||||
.name(format!("Accept on {}", addr))
|
move || {
|
||||||
.spawn(move || {
|
|
||||||
const SRV: mio::Token = mio::Token(0);
|
const SRV: mio::Token = mio::Token(0);
|
||||||
const CMD: mio::Token = mio::Token(1);
|
const CMD: mio::Token = mio::Token(1);
|
||||||
|
|
||||||
@ -773,12 +784,9 @@ fn start_accept_thread(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start listening for incoming commands
|
// Start listening for incoming commands
|
||||||
if let Err(err) = poll.register(
|
if let Err(err) =
|
||||||
®,
|
poll.register(®, CMD, mio::Ready::readable(), mio::PollOpt::edge())
|
||||||
CMD,
|
{
|
||||||
mio::Ready::readable(),
|
|
||||||
mio::PollOpt::edge(),
|
|
||||||
) {
|
|
||||||
panic!("Can not register Registration: {}", err);
|
panic!("Can not register Registration: {}", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -909,13 +917,14 @@ fn start_accept_thread(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
(readiness, tx)
|
(readiness, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_tcp_listener(
|
fn create_tcp_listener(
|
||||||
addr: net::SocketAddr, backlog: i32
|
addr: net::SocketAddr, backlog: i32,
|
||||||
) -> io::Result<net::TcpListener> {
|
) -> io::Result<net::TcpListener> {
|
||||||
let builder = match addr {
|
let builder = match addr {
|
||||||
net::SocketAddr::V4(_) => TcpBuilder::new_v4()?,
|
net::SocketAddr::V4(_) => TcpBuilder::new_v4()?,
|
||||||
|
@ -8,7 +8,7 @@ const LW_BUFFER_SIZE: usize = 4096;
|
|||||||
const HW_BUFFER_SIZE: usize = 32_768;
|
const HW_BUFFER_SIZE: usize = 32_768;
|
||||||
|
|
||||||
pub fn read_from_io<T: IoStream>(
|
pub fn read_from_io<T: IoStream>(
|
||||||
io: &mut T, buf: &mut BytesMut
|
io: &mut T, buf: &mut BytesMut,
|
||||||
) -> Poll<usize, io::Error> {
|
) -> Poll<usize, io::Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if buf.remaining_mut() < LW_BUFFER_SIZE {
|
if buf.remaining_mut() < LW_BUFFER_SIZE {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use futures::Future;
|
|
||||||
use futures::unsync::oneshot;
|
use futures::unsync::oneshot;
|
||||||
|
use futures::Future;
|
||||||
use net2::TcpStreamExt;
|
use net2::TcpStreamExt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::{net, time};
|
use std::{net, time};
|
||||||
@ -59,7 +59,7 @@ where
|
|||||||
|
|
||||||
impl<H: HttpHandler + 'static> Worker<H> {
|
impl<H: HttpHandler + 'static> Worker<H> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
h: Vec<H>, handler: StreamHandlerType, keep_alive: KeepAlive
|
h: Vec<H>, handler: StreamHandlerType, keep_alive: KeepAlive,
|
||||||
) -> Worker<H> {
|
) -> Worker<H> {
|
||||||
let tcp_ka = if let KeepAlive::Tcp(val) = keep_alive {
|
let tcp_ka = if let KeepAlive::Tcp(val) = keep_alive {
|
||||||
Some(time::Duration::new(val as u64, 0))
|
Some(time::Duration::new(val as u64, 0))
|
||||||
@ -77,13 +77,11 @@ impl<H: HttpHandler + 'static> Worker<H> {
|
|||||||
|
|
||||||
fn update_time(&self, ctx: &mut Context<Self>) {
|
fn update_time(&self, ctx: &mut Context<Self>) {
|
||||||
self.settings.update_date();
|
self.settings.update_date();
|
||||||
ctx.run_later(time::Duration::new(1, 0), |slf, ctx| {
|
ctx.run_later(time::Duration::new(1, 0), |slf, ctx| slf.update_time(ctx));
|
||||||
slf.update_time(ctx)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shutdown_timeout(
|
fn shutdown_timeout(
|
||||||
&self, ctx: &mut Context<Self>, tx: oneshot::Sender<bool>, dur: time::Duration
|
&self, ctx: &mut Context<Self>, tx: oneshot::Sender<bool>, dur: time::Duration,
|
||||||
) {
|
) {
|
||||||
// sleep for 1 second and then check again
|
// sleep for 1 second and then check again
|
||||||
ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
|
ctx.run_later(time::Duration::new(1, 0), move |slf, ctx| {
|
||||||
@ -124,8 +122,7 @@ where
|
|||||||
if self.tcp_ka.is_some() && msg.io.set_keepalive(self.tcp_ka).is_err() {
|
if self.tcp_ka.is_some() && msg.io.set_keepalive(self.tcp_ka).is_err() {
|
||||||
error!("Can not set socket keep-alive option");
|
error!("Can not set socket keep-alive option");
|
||||||
}
|
}
|
||||||
self.handler
|
self.handler.handle(Rc::clone(&self.settings), &self.hnd, msg);
|
||||||
.handle(Rc::clone(&self.settings), &self.hnd, msg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +162,7 @@ pub(crate) enum StreamHandlerType {
|
|||||||
|
|
||||||
impl StreamHandlerType {
|
impl StreamHandlerType {
|
||||||
fn handle<H: HttpHandler>(
|
fn handle<H: HttpHandler>(
|
||||||
&mut self, h: Rc<WorkerSettings<H>>, hnd: &Handle, msg: Conn<net::TcpStream>
|
&mut self, h: Rc<WorkerSettings<H>>, hnd: &Handle, msg: Conn<net::TcpStream>,
|
||||||
) {
|
) {
|
||||||
match *self {
|
match *self {
|
||||||
StreamHandlerType::Normal => {
|
StreamHandlerType::Normal => {
|
||||||
@ -177,60 +174,57 @@ impl StreamHandlerType {
|
|||||||
}
|
}
|
||||||
#[cfg(feature = "tls")]
|
#[cfg(feature = "tls")]
|
||||||
StreamHandlerType::Tls(ref acceptor) => {
|
StreamHandlerType::Tls(ref acceptor) => {
|
||||||
let Conn { io, peer, http2 } = msg;
|
let Conn {
|
||||||
|
io,
|
||||||
|
peer,
|
||||||
|
http2,
|
||||||
|
} = msg;
|
||||||
let _ = io.set_nodelay(true);
|
let _ = io.set_nodelay(true);
|
||||||
let io = TcpStream::from_stream(io, hnd)
|
let io = TcpStream::from_stream(io, hnd)
|
||||||
.expect("failed to associate TCP stream");
|
.expect("failed to associate TCP stream");
|
||||||
|
|
||||||
hnd.spawn(
|
hnd.spawn(TlsAcceptorExt::accept_async(acceptor, io).then(move |res| {
|
||||||
TlsAcceptorExt::accept_async(acceptor, io).then(move |res| {
|
match res {
|
||||||
match res {
|
Ok(io) => {
|
||||||
Ok(io) => Arbiter::handle().spawn(HttpChannel::new(
|
Arbiter::handle().spawn(HttpChannel::new(h, io, peer, http2))
|
||||||
h,
|
}
|
||||||
io,
|
Err(err) => {
|
||||||
peer,
|
trace!("Error during handling tls connection: {}", err)
|
||||||
http2,
|
}
|
||||||
)),
|
};
|
||||||
Err(err) => {
|
future::result(Ok(()))
|
||||||
trace!("Error during handling tls connection: {}", err)
|
}));
|
||||||
}
|
|
||||||
};
|
|
||||||
future::result(Ok(()))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "alpn")]
|
#[cfg(feature = "alpn")]
|
||||||
StreamHandlerType::Alpn(ref acceptor) => {
|
StreamHandlerType::Alpn(ref acceptor) => {
|
||||||
let Conn { io, peer, .. } = msg;
|
let Conn {
|
||||||
|
io,
|
||||||
|
peer,
|
||||||
|
..
|
||||||
|
} = msg;
|
||||||
let _ = io.set_nodelay(true);
|
let _ = io.set_nodelay(true);
|
||||||
let io = TcpStream::from_stream(io, hnd)
|
let io = TcpStream::from_stream(io, hnd)
|
||||||
.expect("failed to associate TCP stream");
|
.expect("failed to associate TCP stream");
|
||||||
|
|
||||||
hnd.spawn(
|
hnd.spawn(SslAcceptorExt::accept_async(acceptor, io).then(move |res| {
|
||||||
SslAcceptorExt::accept_async(acceptor, io).then(move |res| {
|
match res {
|
||||||
match res {
|
Ok(io) => {
|
||||||
Ok(io) => {
|
let http2 = if let Some(p) =
|
||||||
let http2 = if let Some(p) =
|
io.get_ref().ssl().selected_alpn_protocol()
|
||||||
io.get_ref().ssl().selected_alpn_protocol()
|
{
|
||||||
{
|
p.len() == 2 && &p == b"h2"
|
||||||
p.len() == 2 && &p == b"h2"
|
} else {
|
||||||
} else {
|
false
|
||||||
false
|
};
|
||||||
};
|
Arbiter::handle()
|
||||||
Arbiter::handle().spawn(HttpChannel::new(
|
.spawn(HttpChannel::new(h, io, peer, http2));
|
||||||
h,
|
}
|
||||||
io,
|
Err(err) => {
|
||||||
peer,
|
trace!("Error during handling tls connection: {}", err)
|
||||||
http2,
|
}
|
||||||
));
|
};
|
||||||
}
|
future::result(Ok(()))
|
||||||
Err(err) => {
|
}));
|
||||||
trace!("Error during handling tls connection: {}", err)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
future::result(Ok(()))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
27
src/test.rs
27
src/test.rs
@ -170,14 +170,22 @@ impl TestServer {
|
|||||||
if uri.starts_with('/') {
|
if uri.starts_with('/') {
|
||||||
format!(
|
format!(
|
||||||
"{}://{}{}",
|
"{}://{}{}",
|
||||||
if self.ssl { "https" } else { "http" },
|
if self.ssl {
|
||||||
|
"https"
|
||||||
|
} else {
|
||||||
|
"http"
|
||||||
|
},
|
||||||
self.addr,
|
self.addr,
|
||||||
uri
|
uri
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
"{}://{}/{}",
|
"{}://{}/{}",
|
||||||
if self.ssl { "https" } else { "http" },
|
if self.ssl {
|
||||||
|
"https"
|
||||||
|
} else {
|
||||||
|
"http"
|
||||||
|
},
|
||||||
self.addr,
|
self.addr,
|
||||||
uri
|
uri
|
||||||
)
|
)
|
||||||
@ -202,7 +210,7 @@ impl TestServer {
|
|||||||
|
|
||||||
/// Connect to websocket server
|
/// Connect to websocket server
|
||||||
pub fn ws(
|
pub fn ws(
|
||||||
&mut self
|
&mut self,
|
||||||
) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> {
|
) -> Result<(ws::ClientReader, ws::ClientWriter), ws::ClientError> {
|
||||||
let url = self.url("/");
|
let url = self.url("/");
|
||||||
self.system.run_until_complete(
|
self.system.run_until_complete(
|
||||||
@ -350,17 +358,14 @@ pub struct TestApp<S = ()> {
|
|||||||
impl<S: 'static> TestApp<S> {
|
impl<S: 'static> TestApp<S> {
|
||||||
fn new(state: S) -> TestApp<S> {
|
fn new(state: S) -> TestApp<S> {
|
||||||
let app = App::with_state(state);
|
let app = App::with_state(state);
|
||||||
TestApp { app: Some(app) }
|
TestApp {
|
||||||
|
app: Some(app),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register handler for "/"
|
/// Register handler for "/"
|
||||||
pub fn handler<H: Handler<S>>(&mut self, handler: H) {
|
pub fn handler<H: Handler<S>>(&mut self, handler: H) {
|
||||||
self.app = Some(
|
self.app = Some(self.app.take().unwrap().resource("/", |r| r.h(handler)));
|
||||||
self.app
|
|
||||||
.take()
|
|
||||||
.unwrap()
|
|
||||||
.resource("/", |r| r.h(handler)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register middleware
|
/// Register middleware
|
||||||
@ -594,7 +599,7 @@ impl<S> TestRequest<S> {
|
|||||||
///
|
///
|
||||||
/// This method panics is handler returns actor or async result.
|
/// This method panics is handler returns actor or async result.
|
||||||
pub fn run<H: Handler<S>>(
|
pub fn run<H: Handler<S>>(
|
||||||
self, mut h: H
|
self, mut h: H,
|
||||||
) -> Result<HttpResponse, <<H as Handler<S>>::Result as Responder>::Error> {
|
) -> Result<HttpResponse, <<H as Handler<S>>::Result as Responder>::Error> {
|
||||||
let req = self.finish();
|
let req = self.finish();
|
||||||
let resp = h.handle(req.clone());
|
let resp = h.handle(req.clone());
|
||||||
|
@ -44,7 +44,10 @@ impl Url {
|
|||||||
pub fn new(uri: Uri) -> Url {
|
pub fn new(uri: Uri) -> Url {
|
||||||
let path = DEFAULT_QUOTER.requote(uri.path().as_bytes());
|
let path = DEFAULT_QUOTER.requote(uri.path().as_bytes());
|
||||||
|
|
||||||
Url { uri, path }
|
Url {
|
||||||
|
uri,
|
||||||
|
path,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uri(&self) -> &Uri {
|
pub fn uri(&self) -> &Uri {
|
||||||
|
36
src/with.rs
36
src/with.rs
@ -187,7 +187,7 @@ where
|
|||||||
S: 'static,
|
S: 'static,
|
||||||
{
|
{
|
||||||
pub fn new(
|
pub fn new(
|
||||||
f: F, cfg1: ExtractorConfig<S, T1>, cfg2: ExtractorConfig<S, T2>
|
f: F, cfg1: ExtractorConfig<S, T1>, cfg2: ExtractorConfig<S, T2>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
With2 {
|
With2 {
|
||||||
hnd: Rc::new(UnsafeCell::new(f)),
|
hnd: Rc::new(UnsafeCell::new(f)),
|
||||||
@ -307,10 +307,8 @@ where
|
|||||||
Async::Ready(item) => {
|
Async::Ready(item) => {
|
||||||
self.item = Some(item);
|
self.item = Some(item);
|
||||||
self.fut1.take();
|
self.fut1.take();
|
||||||
self.fut2 = Some(Box::new(T2::from_request(
|
self.fut2 =
|
||||||
&self.req,
|
Some(Box::new(T2::from_request(&self.req, self.cfg2.as_ref())));
|
||||||
self.cfg2.as_ref(),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
Async::NotReady => return Ok(Async::NotReady),
|
Async::NotReady => return Ok(Async::NotReady),
|
||||||
}
|
}
|
||||||
@ -510,10 +508,8 @@ where
|
|||||||
Async::Ready(item) => {
|
Async::Ready(item) => {
|
||||||
self.item1 = Some(item);
|
self.item1 = Some(item);
|
||||||
self.fut1.take();
|
self.fut1.take();
|
||||||
self.fut2 = Some(Box::new(T2::from_request(
|
self.fut2 =
|
||||||
&self.req,
|
Some(Box::new(T2::from_request(&self.req, self.cfg2.as_ref())));
|
||||||
self.cfg2.as_ref(),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
Async::NotReady => return Ok(Async::NotReady),
|
Async::NotReady => return Ok(Async::NotReady),
|
||||||
}
|
}
|
||||||
@ -524,10 +520,8 @@ where
|
|||||||
Async::Ready(item) => {
|
Async::Ready(item) => {
|
||||||
self.item2 = Some(item);
|
self.item2 = Some(item);
|
||||||
self.fut2.take();
|
self.fut2.take();
|
||||||
self.fut3 = Some(Box::new(T3::from_request(
|
self.fut3 =
|
||||||
&self.req,
|
Some(Box::new(T3::from_request(&self.req, self.cfg3.as_ref())));
|
||||||
self.cfg3.as_ref(),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
Async::NotReady => return Ok(Async::NotReady),
|
Async::NotReady => return Ok(Async::NotReady),
|
||||||
}
|
}
|
||||||
@ -539,15 +533,13 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
let hnd: &mut F = unsafe { &mut *self.hnd.get() };
|
let hnd: &mut F = unsafe { &mut *self.hnd.get() };
|
||||||
let item = match (*hnd)(
|
let item =
|
||||||
self.item1.take().unwrap(),
|
match (*hnd)(self.item1.take().unwrap(), self.item2.take().unwrap(), item)
|
||||||
self.item2.take().unwrap(),
|
.respond_to(self.req.drop_state())
|
||||||
item,
|
{
|
||||||
).respond_to(self.req.drop_state())
|
Ok(item) => item.into(),
|
||||||
{
|
Err(err) => return Err(err.into()),
|
||||||
Ok(item) => item.into(),
|
};
|
||||||
Err(err) => return Err(err.into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
match item.into() {
|
match item.into() {
|
||||||
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)),
|
ReplyItem::Message(resp) => return Ok(Async::Ready(resp)),
|
||||||
|
@ -121,7 +121,7 @@ impl Client {
|
|||||||
|
|
||||||
/// Create new websocket connection with custom `ClientConnector`
|
/// Create new websocket connection with custom `ClientConnector`
|
||||||
pub fn with_connector<S: AsRef<str>>(
|
pub fn with_connector<S: AsRef<str>>(
|
||||||
uri: S, conn: Addr<Unsync, ClientConnector>
|
uri: S, conn: Addr<Unsync, ClientConnector>,
|
||||||
) -> Client {
|
) -> Client {
|
||||||
let mut cl = Client {
|
let mut cl = Client {
|
||||||
request: ClientRequest::build(),
|
request: ClientRequest::build(),
|
||||||
@ -142,9 +142,8 @@ impl Client {
|
|||||||
U: IntoIterator<Item = V> + 'static,
|
U: IntoIterator<Item = V> + 'static,
|
||||||
V: AsRef<str>,
|
V: AsRef<str>,
|
||||||
{
|
{
|
||||||
let mut protos = protos
|
let mut protos =
|
||||||
.into_iter()
|
protos.into_iter().fold(String::new(), |acc, s| acc + s.as_ref() + ",");
|
||||||
.fold(String::new(), |acc, s| acc + s.as_ref() + ",");
|
|
||||||
protos.pop();
|
protos.pop();
|
||||||
self.protocols = Some(protos);
|
self.protocols = Some(protos);
|
||||||
self
|
self
|
||||||
@ -218,8 +217,7 @@ impl Client {
|
|||||||
self.request.upgrade();
|
self.request.upgrade();
|
||||||
self.request.set_header(header::UPGRADE, "websocket");
|
self.request.set_header(header::UPGRADE, "websocket");
|
||||||
self.request.set_header(header::CONNECTION, "upgrade");
|
self.request.set_header(header::CONNECTION, "upgrade");
|
||||||
self.request
|
self.request.set_header(header::SEC_WEBSOCKET_VERSION, "13");
|
||||||
.set_header(header::SEC_WEBSOCKET_VERSION, "13");
|
|
||||||
self.request.with_connector(self.conn.clone());
|
self.request.with_connector(self.conn.clone());
|
||||||
|
|
||||||
if let Some(protocols) = self.protocols.take() {
|
if let Some(protocols) = self.protocols.take() {
|
||||||
@ -394,10 +392,7 @@ impl Future for ClientHandshake {
|
|||||||
encoded,
|
encoded,
|
||||||
key
|
key
|
||||||
);
|
);
|
||||||
return Err(ClientError::InvalidChallengeResponse(
|
return Err(ClientError::InvalidChallengeResponse(encoded, key.clone()));
|
||||||
encoded,
|
|
||||||
key.clone(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
trace!("Missing SEC-WEBSOCKET-ACCEPT header");
|
trace!("Missing SEC-WEBSOCKET-ACCEPT header");
|
||||||
@ -416,7 +411,9 @@ impl Future for ClientHandshake {
|
|||||||
inner: Rc::clone(&inner),
|
inner: Rc::clone(&inner),
|
||||||
max_size: self.max_size,
|
max_size: self.max_size,
|
||||||
},
|
},
|
||||||
ClientWriter { inner },
|
ClientWriter {
|
||||||
|
inner,
|
||||||
|
},
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -536,23 +533,13 @@ impl ClientWriter {
|
|||||||
/// Send ping frame
|
/// Send ping frame
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ping(&mut self, message: &str) {
|
pub fn ping(&mut self, message: &str) {
|
||||||
self.write(Frame::message(
|
self.write(Frame::message(Vec::from(message), OpCode::Ping, true, true));
|
||||||
Vec::from(message),
|
|
||||||
OpCode::Ping,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send pong frame
|
/// Send pong frame
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pong(&mut self, message: &str) {
|
pub fn pong(&mut self, message: &str) {
|
||||||
self.write(Frame::message(
|
self.write(Frame::message(Vec::from(message), OpCode::Pong, true, true));
|
||||||
Vec::from(message),
|
|
||||||
OpCode::Pong,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send close frame
|
/// Send close frame
|
||||||
|
@ -156,23 +156,13 @@ where
|
|||||||
/// Send ping frame
|
/// Send ping frame
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ping(&mut self, message: &str) {
|
pub fn ping(&mut self, message: &str) {
|
||||||
self.write(Frame::message(
|
self.write(Frame::message(Vec::from(message), OpCode::Ping, true, false));
|
||||||
Vec::from(message),
|
|
||||||
OpCode::Ping,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send pong frame
|
/// Send pong frame
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pong(&mut self, message: &str) {
|
pub fn pong(&mut self, message: &str) {
|
||||||
self.write(Frame::message(
|
self.write(Frame::message(Vec::from(message), OpCode::Pong, true, false));
|
||||||
Vec::from(message),
|
|
||||||
OpCode::Pong,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send close frame
|
/// Send close frame
|
||||||
|
@ -8,9 +8,9 @@ use body::Binary;
|
|||||||
use error::PayloadError;
|
use error::PayloadError;
|
||||||
use payload::PayloadHelper;
|
use payload::PayloadHelper;
|
||||||
|
|
||||||
use ws::ProtocolError;
|
|
||||||
use ws::mask::apply_mask;
|
use ws::mask::apply_mask;
|
||||||
use ws::proto::{CloseCode, CloseReason, OpCode};
|
use ws::proto::{CloseCode, CloseReason, OpCode};
|
||||||
|
use ws::ProtocolError;
|
||||||
|
|
||||||
/// A struct representing a `WebSocket` frame.
|
/// A struct representing a `WebSocket` frame.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -36,7 +36,7 @@ impl Frame {
|
|||||||
NetworkEndian::write_u16(&mut code_bytes, reason.code.into());
|
NetworkEndian::write_u16(&mut code_bytes, reason.code.into());
|
||||||
|
|
||||||
let mut payload = Vec::from(&code_bytes[..]);
|
let mut payload = Vec::from(&code_bytes[..]);
|
||||||
if let Some(description) = reason.description{
|
if let Some(description) = reason.description {
|
||||||
payload.extend(description.as_bytes());
|
payload.extend(description.as_bytes());
|
||||||
}
|
}
|
||||||
payload
|
payload
|
||||||
@ -48,7 +48,7 @@ impl Frame {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
|
#[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
|
||||||
fn read_copy_md<S>(
|
fn read_copy_md<S>(
|
||||||
pl: &mut PayloadHelper<S>, server: bool, max_size: usize
|
pl: &mut PayloadHelper<S>, server: bool, max_size: usize,
|
||||||
) -> Poll<Option<(usize, bool, OpCode, usize, Option<u32>)>, ProtocolError>
|
) -> Poll<Option<(usize, bool, OpCode, usize, Option<u32>)>, ProtocolError>
|
||||||
where
|
where
|
||||||
S: Stream<Item = Bytes, Error = PayloadError>,
|
S: Stream<Item = Bytes, Error = PayloadError>,
|
||||||
@ -122,17 +122,11 @@ impl Frame {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Async::Ready(Some((
|
Ok(Async::Ready(Some((idx, finished, opcode, length, mask))))
|
||||||
idx,
|
|
||||||
finished,
|
|
||||||
opcode,
|
|
||||||
length,
|
|
||||||
mask,
|
|
||||||
))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_chunk_md(
|
fn read_chunk_md(
|
||||||
chunk: &[u8], server: bool, max_size: usize
|
chunk: &[u8], server: bool, max_size: usize,
|
||||||
) -> Poll<(usize, bool, OpCode, usize, Option<u32>), ProtocolError> {
|
) -> Poll<(usize, bool, OpCode, usize, Option<u32>), ProtocolError> {
|
||||||
let chunk_len = chunk.len();
|
let chunk_len = chunk.len();
|
||||||
|
|
||||||
@ -203,7 +197,7 @@ impl Frame {
|
|||||||
|
|
||||||
/// Parse the input stream into a frame.
|
/// Parse the input stream into a frame.
|
||||||
pub fn parse<S>(
|
pub fn parse<S>(
|
||||||
pl: &mut PayloadHelper<S>, server: bool, max_size: usize
|
pl: &mut PayloadHelper<S>, server: bool, max_size: usize,
|
||||||
) -> Poll<Option<Frame>, ProtocolError>
|
) -> Poll<Option<Frame>, ProtocolError>
|
||||||
where
|
where
|
||||||
S: Stream<Item = Bytes, Error = PayloadError>,
|
S: Stream<Item = Bytes, Error = PayloadError>,
|
||||||
@ -288,7 +282,10 @@ impl Frame {
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
Some(CloseReason { code, description })
|
Some(CloseReason {
|
||||||
|
code,
|
||||||
|
description,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -296,7 +293,7 @@ impl Frame {
|
|||||||
|
|
||||||
/// Generate binary representation
|
/// Generate binary representation
|
||||||
pub fn message<B: Into<Binary>>(
|
pub fn message<B: Into<Binary>>(
|
||||||
data: B, code: OpCode, finished: bool, genmask: bool
|
data: B, code: OpCode, finished: bool, genmask: bool,
|
||||||
) -> Binary {
|
) -> Binary {
|
||||||
let payload = data.into();
|
let payload = data.into();
|
||||||
let one: u8 = if finished {
|
let one: u8 = if finished {
|
||||||
|
@ -28,7 +28,11 @@ fn apply_mask_fast32(buf: &mut [u8], mask_u32: u32) {
|
|||||||
// Possible first unaligned block.
|
// Possible first unaligned block.
|
||||||
let head = min(len, (8 - (ptr as usize & 0x7)) & 0x3);
|
let head = min(len, (8 - (ptr as usize & 0x7)) & 0x3);
|
||||||
let mask_u32 = if head > 0 {
|
let mask_u32 = if head > 0 {
|
||||||
let n = if head > 4 { head - 4 } else { head };
|
let n = if head > 4 {
|
||||||
|
head - 4
|
||||||
|
} else {
|
||||||
|
head
|
||||||
|
};
|
||||||
|
|
||||||
let mask_u32 = if n > 0 {
|
let mask_u32 = if n > 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
121
src/ws/mod.rs
121
src/ws/mod.rs
@ -133,24 +133,24 @@ pub enum HandshakeError {
|
|||||||
impl ResponseError for HandshakeError {
|
impl ResponseError for HandshakeError {
|
||||||
fn error_response(&self) -> HttpResponse {
|
fn error_response(&self) -> HttpResponse {
|
||||||
match *self {
|
match *self {
|
||||||
HandshakeError::GetMethodRequired => HttpResponse::MethodNotAllowed()
|
HandshakeError::GetMethodRequired => {
|
||||||
.header(header::ALLOW, "GET")
|
HttpResponse::MethodNotAllowed().header(header::ALLOW, "GET").finish()
|
||||||
.finish(),
|
}
|
||||||
HandshakeError::NoWebsocketUpgrade => HttpResponse::BadRequest()
|
HandshakeError::NoWebsocketUpgrade => HttpResponse::BadRequest()
|
||||||
.reason("No WebSocket UPGRADE header found")
|
.reason("No WebSocket UPGRADE header found")
|
||||||
.finish(),
|
.finish(),
|
||||||
HandshakeError::NoConnectionUpgrade => HttpResponse::BadRequest()
|
HandshakeError::NoConnectionUpgrade => {
|
||||||
.reason("No CONNECTION upgrade")
|
HttpResponse::BadRequest().reason("No CONNECTION upgrade").finish()
|
||||||
.finish(),
|
}
|
||||||
HandshakeError::NoVersionHeader => HttpResponse::BadRequest()
|
HandshakeError::NoVersionHeader => HttpResponse::BadRequest()
|
||||||
.reason("Websocket version header is required")
|
.reason("Websocket version header is required")
|
||||||
.finish(),
|
.finish(),
|
||||||
HandshakeError::UnsupportedVersion => HttpResponse::BadRequest()
|
HandshakeError::UnsupportedVersion => {
|
||||||
.reason("Unsupported version")
|
HttpResponse::BadRequest().reason("Unsupported version").finish()
|
||||||
.finish(),
|
}
|
||||||
HandshakeError::BadWebsocketKey => HttpResponse::BadRequest()
|
HandshakeError::BadWebsocketKey => {
|
||||||
.reason("Handshake error")
|
HttpResponse::BadRequest().reason("Handshake error").finish()
|
||||||
.finish(),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,7 +189,7 @@ where
|
|||||||
// /// the returned response headers contain the first protocol in this list
|
// /// the returned response headers contain the first protocol in this list
|
||||||
// /// which the server also knows.
|
// /// which the server also knows.
|
||||||
pub fn handshake<S>(
|
pub fn handshake<S>(
|
||||||
req: &HttpRequest<S>
|
req: &HttpRequest<S>,
|
||||||
) -> Result<HttpResponseBuilder, HandshakeError> {
|
) -> Result<HttpResponseBuilder, HandshakeError> {
|
||||||
// WebSocket accepts only GET
|
// WebSocket accepts only GET
|
||||||
if *req.method() != Method::GET {
|
if *req.method() != Method::GET {
|
||||||
@ -216,9 +216,7 @@ pub fn handshake<S>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check supported version
|
// check supported version
|
||||||
if !req.headers()
|
if !req.headers().contains_key(header::SEC_WEBSOCKET_VERSION) {
|
||||||
.contains_key(header::SEC_WEBSOCKET_VERSION)
|
|
||||||
{
|
|
||||||
return Err(HandshakeError::NoVersionHeader);
|
return Err(HandshakeError::NoVersionHeader);
|
||||||
}
|
}
|
||||||
let supported_ver = {
|
let supported_ver = {
|
||||||
@ -355,10 +353,7 @@ mod tests {
|
|||||||
HeaderMap::new(),
|
HeaderMap::new(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(HandshakeError::GetMethodRequired, handshake(&req).err().unwrap());
|
||||||
HandshakeError::GetMethodRequired,
|
|
||||||
handshake(&req).err().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let req = HttpRequest::new(
|
let req = HttpRequest::new(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
@ -367,16 +362,10 @@ mod tests {
|
|||||||
HeaderMap::new(),
|
HeaderMap::new(),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(HandshakeError::NoWebsocketUpgrade, handshake(&req).err().unwrap());
|
||||||
HandshakeError::NoWebsocketUpgrade,
|
|
||||||
handshake(&req).err().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers.insert(header::UPGRADE, header::HeaderValue::from_static("test"));
|
||||||
header::UPGRADE,
|
|
||||||
header::HeaderValue::from_static("test"),
|
|
||||||
);
|
|
||||||
let req = HttpRequest::new(
|
let req = HttpRequest::new(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
Uri::from_str("/").unwrap(),
|
Uri::from_str("/").unwrap(),
|
||||||
@ -384,16 +373,10 @@ mod tests {
|
|||||||
headers,
|
headers,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(HandshakeError::NoWebsocketUpgrade, handshake(&req).err().unwrap());
|
||||||
HandshakeError::NoWebsocketUpgrade,
|
|
||||||
handshake(&req).err().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers.insert(header::UPGRADE, header::HeaderValue::from_static("websocket"));
|
||||||
header::UPGRADE,
|
|
||||||
header::HeaderValue::from_static("websocket"),
|
|
||||||
);
|
|
||||||
let req = HttpRequest::new(
|
let req = HttpRequest::new(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
Uri::from_str("/").unwrap(),
|
Uri::from_str("/").unwrap(),
|
||||||
@ -401,20 +384,11 @@ mod tests {
|
|||||||
headers,
|
headers,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(HandshakeError::NoConnectionUpgrade, handshake(&req).err().unwrap());
|
||||||
HandshakeError::NoConnectionUpgrade,
|
|
||||||
handshake(&req).err().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers.insert(header::UPGRADE, header::HeaderValue::from_static("websocket"));
|
||||||
header::UPGRADE,
|
headers.insert(header::CONNECTION, header::HeaderValue::from_static("upgrade"));
|
||||||
header::HeaderValue::from_static("websocket"),
|
|
||||||
);
|
|
||||||
headers.insert(
|
|
||||||
header::CONNECTION,
|
|
||||||
header::HeaderValue::from_static("upgrade"),
|
|
||||||
);
|
|
||||||
let req = HttpRequest::new(
|
let req = HttpRequest::new(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
Uri::from_str("/").unwrap(),
|
Uri::from_str("/").unwrap(),
|
||||||
@ -422,20 +396,11 @@ mod tests {
|
|||||||
headers,
|
headers,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(HandshakeError::NoVersionHeader, handshake(&req).err().unwrap());
|
||||||
HandshakeError::NoVersionHeader,
|
|
||||||
handshake(&req).err().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers.insert(header::UPGRADE, header::HeaderValue::from_static("websocket"));
|
||||||
header::UPGRADE,
|
headers.insert(header::CONNECTION, header::HeaderValue::from_static("upgrade"));
|
||||||
header::HeaderValue::from_static("websocket"),
|
|
||||||
);
|
|
||||||
headers.insert(
|
|
||||||
header::CONNECTION,
|
|
||||||
header::HeaderValue::from_static("upgrade"),
|
|
||||||
);
|
|
||||||
headers.insert(
|
headers.insert(
|
||||||
header::SEC_WEBSOCKET_VERSION,
|
header::SEC_WEBSOCKET_VERSION,
|
||||||
header::HeaderValue::from_static("5"),
|
header::HeaderValue::from_static("5"),
|
||||||
@ -447,20 +412,11 @@ mod tests {
|
|||||||
headers,
|
headers,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(HandshakeError::UnsupportedVersion, handshake(&req).err().unwrap());
|
||||||
HandshakeError::UnsupportedVersion,
|
|
||||||
handshake(&req).err().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers.insert(header::UPGRADE, header::HeaderValue::from_static("websocket"));
|
||||||
header::UPGRADE,
|
headers.insert(header::CONNECTION, header::HeaderValue::from_static("upgrade"));
|
||||||
header::HeaderValue::from_static("websocket"),
|
|
||||||
);
|
|
||||||
headers.insert(
|
|
||||||
header::CONNECTION,
|
|
||||||
header::HeaderValue::from_static("upgrade"),
|
|
||||||
);
|
|
||||||
headers.insert(
|
headers.insert(
|
||||||
header::SEC_WEBSOCKET_VERSION,
|
header::SEC_WEBSOCKET_VERSION,
|
||||||
header::HeaderValue::from_static("13"),
|
header::HeaderValue::from_static("13"),
|
||||||
@ -472,28 +428,17 @@ mod tests {
|
|||||||
headers,
|
headers,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(HandshakeError::BadWebsocketKey, handshake(&req).err().unwrap());
|
||||||
HandshakeError::BadWebsocketKey,
|
|
||||||
handshake(&req).err().unwrap()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
headers.insert(
|
headers.insert(header::UPGRADE, header::HeaderValue::from_static("websocket"));
|
||||||
header::UPGRADE,
|
headers.insert(header::CONNECTION, header::HeaderValue::from_static("upgrade"));
|
||||||
header::HeaderValue::from_static("websocket"),
|
|
||||||
);
|
|
||||||
headers.insert(
|
|
||||||
header::CONNECTION,
|
|
||||||
header::HeaderValue::from_static("upgrade"),
|
|
||||||
);
|
|
||||||
headers.insert(
|
headers.insert(
|
||||||
header::SEC_WEBSOCKET_VERSION,
|
header::SEC_WEBSOCKET_VERSION,
|
||||||
header::HeaderValue::from_static("13"),
|
header::HeaderValue::from_static("13"),
|
||||||
);
|
);
|
||||||
headers.insert(
|
headers
|
||||||
header::SEC_WEBSOCKET_KEY,
|
.insert(header::SEC_WEBSOCKET_KEY, header::HeaderValue::from_static("13"));
|
||||||
header::HeaderValue::from_static("13"),
|
|
||||||
);
|
|
||||||
let req = HttpRequest::new(
|
let req = HttpRequest::new(
|
||||||
Method::GET,
|
Method::GET,
|
||||||
Uri::from_str("/").unwrap(),
|
Uri::from_str("/").unwrap(),
|
||||||
|
@ -194,11 +194,11 @@ impl From<CloseCode> for CloseReason {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <T: Into<String>> From<(CloseCode, T)> for CloseReason {
|
impl<T: Into<String>> From<(CloseCode, T)> for CloseReason {
|
||||||
fn from(info: (CloseCode, T)) -> Self {
|
fn from(info: (CloseCode, T)) -> Self {
|
||||||
CloseReason{
|
CloseReason {
|
||||||
code: info.0,
|
code: info.0,
|
||||||
description: Some(info.1.into())
|
description: Some(info.1.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ use std::io::Read;
|
|||||||
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use flate2::read::GzDecoder;
|
use flate2::read::GzDecoder;
|
||||||
use futures::Future;
|
|
||||||
use futures::stream::once;
|
use futures::stream::once;
|
||||||
|
use futures::Future;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use actix_web::*;
|
use actix_web::*;
|
||||||
@ -72,10 +72,7 @@ fn test_with_query_parameter() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let request = srv.get()
|
let request = srv.get().uri(srv.url("/?qp=5").as_str()).finish().unwrap();
|
||||||
.uri(srv.url("/?qp=5").as_str())
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
@ -124,10 +121,8 @@ fn test_client_gzip_encoding() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.post()
|
let request =
|
||||||
.content_encoding(http::ContentEncoding::Gzip)
|
srv.post().content_encoding(http::ContentEncoding::Gzip).body(STR).unwrap();
|
||||||
.body(STR)
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -167,10 +162,7 @@ fn test_client_gzip_encoding_large() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_client_gzip_encoding_large_random() {
|
fn test_client_gzip_encoding_large_random() {
|
||||||
let data = rand::thread_rng()
|
let data = rand::thread_rng().gen_ascii_chars().take(100_000).collect::<String>();
|
||||||
.gen_ascii_chars()
|
|
||||||
.take(100_000)
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.handler(|req: HttpRequest| {
|
app.handler(|req: HttpRequest| {
|
||||||
@ -228,10 +220,7 @@ fn test_client_brotli_encoding() {
|
|||||||
#[cfg(feature = "brotli")]
|
#[cfg(feature = "brotli")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_client_brotli_encoding_large_random() {
|
fn test_client_brotli_encoding_large_random() {
|
||||||
let data = rand::thread_rng()
|
let data = rand::thread_rng().gen_ascii_chars().take(70_000).collect::<String>();
|
||||||
.gen_ascii_chars()
|
|
||||||
.take(70_000)
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.handler(|req: HttpRequest| {
|
app.handler(|req: HttpRequest| {
|
||||||
@ -275,10 +264,8 @@ fn test_client_deflate_encoding() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.post()
|
let request =
|
||||||
.content_encoding(http::ContentEncoding::Deflate)
|
srv.post().content_encoding(http::ContentEncoding::Deflate).body(STR).unwrap();
|
||||||
.body(STR)
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -290,10 +277,7 @@ fn test_client_deflate_encoding() {
|
|||||||
#[cfg(feature = "brotli")]
|
#[cfg(feature = "brotli")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_client_deflate_encoding_large_random() {
|
fn test_client_deflate_encoding_large_random() {
|
||||||
let data = rand::thread_rng()
|
let data = rand::thread_rng().gen_ascii_chars().take(70_000).collect::<String>();
|
||||||
.gen_ascii_chars()
|
|
||||||
.take(70_000)
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.handler(|req: HttpRequest| {
|
app.handler(|req: HttpRequest| {
|
||||||
@ -338,9 +322,7 @@ fn test_client_streaming_explicit() {
|
|||||||
|
|
||||||
let body = once(Ok(Bytes::from_static(STR.as_ref())));
|
let body = once(Ok(Bytes::from_static(STR.as_ref())));
|
||||||
|
|
||||||
let request = srv.get()
|
let request = srv.get().body(Body::Streaming(Box::new(body))).unwrap();
|
||||||
.body(Body::Streaming(Box::new(body)))
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -413,11 +395,8 @@ fn test_client_cookie_handling() {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let request = srv.get()
|
let request =
|
||||||
.cookie(cookie1.clone())
|
srv.get().cookie(cookie1.clone()).cookie(cookie2.clone()).finish().unwrap();
|
||||||
.cookie(cookie2.clone())
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
let c1 = response.cookie("cookie1").expect("Missing cookie1");
|
let c1 = response.cookie("cookie1").expect("Missing cookie1");
|
||||||
|
@ -26,10 +26,7 @@ fn test_path_extractor() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.get()
|
let request = srv.get().uri(srv.url("/test/index.html")).finish().unwrap();
|
||||||
.uri(srv.url("/test/index.html"))
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -47,10 +44,7 @@ fn test_query_extractor() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.get()
|
let request = srv.get().uri(srv.url("/index.html?username=test")).finish().unwrap();
|
||||||
.uri(srv.url("/index.html?username=test"))
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -59,10 +53,7 @@ fn test_query_extractor() {
|
|||||||
assert_eq!(bytes, Bytes::from_static(b"Welcome test!"));
|
assert_eq!(bytes, Bytes::from_static(b"Welcome test!"));
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.get()
|
let request = srv.get().uri(srv.url("/index.html")).finish().unwrap();
|
||||||
.uri(srv.url("/index.html"))
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
||||||
}
|
}
|
||||||
@ -78,10 +69,8 @@ fn test_path_and_query_extractor() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.get()
|
let request =
|
||||||
.uri(srv.url("/test1/index.html?username=test2"))
|
srv.get().uri(srv.url("/test1/index.html?username=test2")).finish().unwrap();
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -90,10 +79,7 @@ fn test_path_and_query_extractor() {
|
|||||||
assert_eq!(bytes, Bytes::from_static(b"Welcome test1 - test2!"));
|
assert_eq!(bytes, Bytes::from_static(b"Welcome test1 - test2!"));
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.get()
|
let request = srv.get().uri(srv.url("/test1/index.html")).finish().unwrap();
|
||||||
.uri(srv.url("/test1/index.html"))
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
||||||
}
|
}
|
||||||
@ -102,18 +88,15 @@ fn test_path_and_query_extractor() {
|
|||||||
fn test_path_and_query_extractor2() {
|
fn test_path_and_query_extractor2() {
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.resource("/{username}/index.html", |r| {
|
app.resource("/{username}/index.html", |r| {
|
||||||
r.route()
|
r.route().with3(|_: HttpRequest, p: Path<PParam>, q: Query<PParam>| {
|
||||||
.with3(|_: HttpRequest, p: Path<PParam>, q: Query<PParam>| {
|
format!("Welcome {} - {}!", p.username, q.username)
|
||||||
format!("Welcome {} - {}!", p.username, q.username)
|
})
|
||||||
})
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.get()
|
let request =
|
||||||
.uri(srv.url("/test1/index.html?username=test2"))
|
srv.get().uri(srv.url("/test1/index.html?username=test2")).finish().unwrap();
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -122,10 +105,7 @@ fn test_path_and_query_extractor2() {
|
|||||||
assert_eq!(bytes, Bytes::from_static(b"Welcome test1 - test2!"));
|
assert_eq!(bytes, Bytes::from_static(b"Welcome test1 - test2!"));
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.get()
|
let request = srv.get().uri(srv.url("/test1/index.html")).finish().unwrap();
|
||||||
.uri(srv.url("/test1/index.html"))
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
||||||
}
|
}
|
||||||
@ -137,10 +117,7 @@ fn test_non_ascii_route() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.get()
|
let request = srv.get().uri(srv.url("/中文/index.html")).finish().unwrap();
|
||||||
.uri(srv.url("/中文/index.html"))
|
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -158,17 +135,12 @@ fn test_unsafe_path_route() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.get()
|
let request =
|
||||||
.uri(srv.url("/test/http%3A%2F%2Fexample.com"))
|
srv.get().uri(srv.url("/test/http%3A%2F%2Fexample.com")).finish().unwrap();
|
||||||
.finish()
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
let bytes = srv.execute(response.body()).unwrap();
|
let bytes = srv.execute(response.body()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(bytes, Bytes::from_static(b"success: http:%2F%2Fexample.com"));
|
||||||
bytes,
|
|
||||||
Bytes::from_static(b"success: http:%2F%2Fexample.com")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,9 @@ extern crate brotli2;
|
|||||||
#[cfg(feature = "brotli")]
|
#[cfg(feature = "brotli")]
|
||||||
use brotli2::write::{BrotliDecoder, BrotliEncoder};
|
use brotli2::write::{BrotliDecoder, BrotliEncoder};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::{Bytes, BytesMut};
|
||||||
use flate2::Compression;
|
|
||||||
use flate2::read::GzDecoder;
|
use flate2::read::GzDecoder;
|
||||||
use flate2::write::{DeflateDecoder, DeflateEncoder, GzEncoder};
|
use flate2::write::{DeflateDecoder, DeflateEncoder, GzEncoder};
|
||||||
|
use flate2::Compression;
|
||||||
use futures::stream::once;
|
use futures::stream::once;
|
||||||
use futures::{future, Future, Stream};
|
use futures::{future, Future, Stream};
|
||||||
use h2::client as h2client;
|
use h2::client as h2client;
|
||||||
@ -62,11 +62,9 @@ fn test_start() {
|
|||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let sys = System::new("test");
|
let sys = System::new("test");
|
||||||
let srv = server::new(|| {
|
let srv = server::new(|| {
|
||||||
vec![
|
vec![App::new().resource("/", |r| {
|
||||||
App::new().resource("/", |r| {
|
r.method(http::Method::GET).f(|_| HttpResponse::Ok())
|
||||||
r.method(http::Method::GET).f(|_| HttpResponse::Ok())
|
})]
|
||||||
}),
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let srv = srv.bind("127.0.0.1:0").unwrap();
|
let srv = srv.bind("127.0.0.1:0").unwrap();
|
||||||
@ -113,11 +111,9 @@ fn test_shutdown() {
|
|||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let sys = System::new("test");
|
let sys = System::new("test");
|
||||||
let srv = server::new(|| {
|
let srv = server::new(|| {
|
||||||
vec![
|
vec![App::new().resource("/", |r| {
|
||||||
App::new().resource("/", |r| {
|
r.method(http::Method::GET).f(|_| HttpResponse::Ok())
|
||||||
r.method(http::Method::GET).f(|_| HttpResponse::Ok())
|
})]
|
||||||
}),
|
|
||||||
]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let srv = srv.bind("127.0.0.1:0").unwrap();
|
let srv = srv.bind("127.0.0.1:0").unwrap();
|
||||||
@ -135,7 +131,9 @@ fn test_shutdown() {
|
|||||||
.finish()
|
.finish()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let response = sys.run_until_complete(req.send()).unwrap();
|
let response = sys.run_until_complete(req.send()).unwrap();
|
||||||
srv_addr.do_send(server::StopServer { graceful: true });
|
srv_addr.do_send(server::StopServer {
|
||||||
|
graceful: true,
|
||||||
|
});
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,9 +206,7 @@ fn test_body() {
|
|||||||
fn test_body_gzip() {
|
fn test_body_gzip() {
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.handler(|_| {
|
app.handler(|_| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().content_encoding(http::ContentEncoding::Gzip).body(STR)
|
||||||
.content_encoding(http::ContentEncoding::Gzip)
|
|
||||||
.body(STR)
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -258,10 +254,7 @@ fn test_body_gzip_large() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_body_gzip_large_random() {
|
fn test_body_gzip_large_random() {
|
||||||
let data = rand::thread_rng()
|
let data = rand::thread_rng().gen_ascii_chars().take(70_000).collect::<String>();
|
||||||
.gen_ascii_chars()
|
|
||||||
.take(70_000)
|
|
||||||
.collect::<String>();
|
|
||||||
let srv_data = Arc::new(data.clone());
|
let srv_data = Arc::new(data.clone());
|
||||||
|
|
||||||
let mut srv = test::TestServer::new(move |app| {
|
let mut srv = test::TestServer::new(move |app| {
|
||||||
@ -342,11 +335,7 @@ fn test_body_br_streaming() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_head_empty() {
|
fn test_head_empty() {
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.handler(|_| {
|
app.handler(|_| HttpResponse::Ok().content_length(STR.len() as u64).finish())
|
||||||
HttpResponse::Ok()
|
|
||||||
.content_length(STR.len() as u64)
|
|
||||||
.finish()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let request = srv.head().finish().unwrap();
|
let request = srv.head().finish().unwrap();
|
||||||
@ -354,10 +343,7 @@ fn test_head_empty() {
|
|||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
{
|
{
|
||||||
let len = response
|
let len = response.headers().get(http::header::CONTENT_LENGTH).unwrap();
|
||||||
.headers()
|
|
||||||
.get(http::header::CONTENT_LENGTH)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,10 +368,7 @@ fn test_head_binary() {
|
|||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
{
|
{
|
||||||
let len = response
|
let len = response.headers().get(http::header::CONTENT_LENGTH).unwrap();
|
||||||
.headers()
|
|
||||||
.get(http::header::CONTENT_LENGTH)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,10 +392,7 @@ fn test_head_binary2() {
|
|||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
{
|
{
|
||||||
let len = response
|
let len = response.headers().get(http::header::CONTENT_LENGTH).unwrap();
|
||||||
.headers()
|
|
||||||
.get(http::header::CONTENT_LENGTH)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
assert_eq!(format!("{}", STR.len()), len.to_str().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -468,9 +448,7 @@ fn test_body_chunked_explicit() {
|
|||||||
fn test_body_deflate() {
|
fn test_body_deflate() {
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.handler(|_| {
|
app.handler(|_| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().content_encoding(http::ContentEncoding::Deflate).body(STR)
|
||||||
.content_encoding(http::ContentEncoding::Deflate)
|
|
||||||
.body(STR)
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -494,9 +472,7 @@ fn test_body_deflate() {
|
|||||||
fn test_body_brotli() {
|
fn test_body_brotli() {
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.handler(|_| {
|
app.handler(|_| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().content_encoding(http::ContentEncoding::Br).body(STR)
|
||||||
.content_encoding(http::ContentEncoding::Br)
|
|
||||||
.body(STR)
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -580,10 +556,7 @@ fn test_gzip_encoding_large() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_reading_gzip_encoding_large_random() {
|
fn test_reading_gzip_encoding_large_random() {
|
||||||
let data = rand::thread_rng()
|
let data = rand::thread_rng().gen_ascii_chars().take(60_000).collect::<String>();
|
||||||
.gen_ascii_chars()
|
|
||||||
.take(60_000)
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.handler(|req: HttpRequest| {
|
app.handler(|req: HttpRequest| {
|
||||||
@ -634,10 +607,8 @@ fn test_reading_deflate_encoding() {
|
|||||||
let enc = e.finish().unwrap();
|
let enc = e.finish().unwrap();
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.post()
|
let request =
|
||||||
.header(http::header::CONTENT_ENCODING, "deflate")
|
srv.post().header(http::header::CONTENT_ENCODING, "deflate").body(enc).unwrap();
|
||||||
.body(enc)
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -666,10 +637,8 @@ fn test_reading_deflate_encoding_large() {
|
|||||||
let enc = e.finish().unwrap();
|
let enc = e.finish().unwrap();
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.post()
|
let request =
|
||||||
.header(http::header::CONTENT_ENCODING, "deflate")
|
srv.post().header(http::header::CONTENT_ENCODING, "deflate").body(enc).unwrap();
|
||||||
.body(enc)
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -680,10 +649,7 @@ fn test_reading_deflate_encoding_large() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_reading_deflate_encoding_large_random() {
|
fn test_reading_deflate_encoding_large_random() {
|
||||||
let data = rand::thread_rng()
|
let data = rand::thread_rng().gen_ascii_chars().take(160_000).collect::<String>();
|
||||||
.gen_ascii_chars()
|
|
||||||
.take(160_000)
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let mut srv = test::TestServer::new(|app| {
|
let mut srv = test::TestServer::new(|app| {
|
||||||
app.handler(|req: HttpRequest| {
|
app.handler(|req: HttpRequest| {
|
||||||
@ -702,10 +668,8 @@ fn test_reading_deflate_encoding_large_random() {
|
|||||||
let enc = e.finish().unwrap();
|
let enc = e.finish().unwrap();
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.post()
|
let request =
|
||||||
.header(http::header::CONTENT_ENCODING, "deflate")
|
srv.post().header(http::header::CONTENT_ENCODING, "deflate").body(enc).unwrap();
|
||||||
.body(enc)
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -735,10 +699,8 @@ fn test_brotli_encoding() {
|
|||||||
let enc = e.finish().unwrap();
|
let enc = e.finish().unwrap();
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.post()
|
let request =
|
||||||
.header(http::header::CONTENT_ENCODING, "br")
|
srv.post().header(http::header::CONTENT_ENCODING, "br").body(enc).unwrap();
|
||||||
.body(enc)
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -768,10 +730,8 @@ fn test_brotli_encoding_large() {
|
|||||||
let enc = e.finish().unwrap();
|
let enc = e.finish().unwrap();
|
||||||
|
|
||||||
// client request
|
// client request
|
||||||
let request = srv.post()
|
let request =
|
||||||
.header(http::header::CONTENT_ENCODING, "br")
|
srv.post().header(http::header::CONTENT_ENCODING, "br").body(enc).unwrap();
|
||||||
.body(enc)
|
|
||||||
.unwrap();
|
|
||||||
let response = srv.execute(request.send()).unwrap();
|
let response = srv.execute(request.send()).unwrap();
|
||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
@ -789,30 +749,29 @@ fn test_h2() {
|
|||||||
let handle = core.handle();
|
let handle = core.handle();
|
||||||
let tcp = TcpStream::connect(&addr, &handle);
|
let tcp = TcpStream::connect(&addr, &handle);
|
||||||
|
|
||||||
let tcp = tcp.then(|res| h2client::handshake(res.unwrap()))
|
let tcp = tcp.then(|res| h2client::handshake(res.unwrap())).then(move |res| {
|
||||||
.then(move |res| {
|
let (mut client, h2) = res.unwrap();
|
||||||
let (mut client, h2) = res.unwrap();
|
|
||||||
|
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.uri(format!("https://{}/", addr).as_str())
|
.uri(format!("https://{}/", addr).as_str())
|
||||||
.body(())
|
.body(())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (response, _) = client.send_request(request, false).unwrap();
|
let (response, _) = client.send_request(request, false).unwrap();
|
||||||
|
|
||||||
// Spawn a task to run the conn...
|
// Spawn a task to run the conn...
|
||||||
handle.spawn(h2.map_err(|e| println!("GOT ERR={:?}", e)));
|
handle.spawn(h2.map_err(|e| println!("GOT ERR={:?}", e)));
|
||||||
|
|
||||||
response.and_then(|response| {
|
response.and_then(|response| {
|
||||||
assert_eq!(response.status(), http::StatusCode::OK);
|
assert_eq!(response.status(), http::StatusCode::OK);
|
||||||
|
|
||||||
let (_, body) = response.into_parts();
|
let (_, body) = response.into_parts();
|
||||||
|
|
||||||
body.fold(BytesMut::new(), |mut b, c| -> Result<_, h2::Error> {
|
body.fold(BytesMut::new(), |mut b, c| -> Result<_, h2::Error> {
|
||||||
b.extend(c);
|
b.extend(c);
|
||||||
Ok(b)
|
Ok(b)
|
||||||
})
|
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
|
});
|
||||||
let _res = core.run(tcp);
|
let _res = core.run(tcp);
|
||||||
// assert_eq!(res.unwrap(), Bytes::from_static(STR.as_ref()));
|
// assert_eq!(res.unwrap(), Bytes::from_static(STR.as_ref()));
|
||||||
}
|
}
|
||||||
@ -836,28 +795,20 @@ struct MiddlewareTest {
|
|||||||
|
|
||||||
impl<S> middleware::Middleware<S> for MiddlewareTest {
|
impl<S> middleware::Middleware<S> for MiddlewareTest {
|
||||||
fn start(&self, _: &mut HttpRequest<S>) -> Result<middleware::Started> {
|
fn start(&self, _: &mut HttpRequest<S>) -> Result<middleware::Started> {
|
||||||
self.start.store(
|
self.start.store(self.start.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
||||||
self.start.load(Ordering::Relaxed) + 1,
|
|
||||||
Ordering::Relaxed,
|
|
||||||
);
|
|
||||||
Ok(middleware::Started::Done)
|
Ok(middleware::Started::Done)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response(
|
fn response(
|
||||||
&self, _: &mut HttpRequest<S>, resp: HttpResponse
|
&self, _: &mut HttpRequest<S>, resp: HttpResponse,
|
||||||
) -> Result<middleware::Response> {
|
) -> Result<middleware::Response> {
|
||||||
self.response.store(
|
self.response
|
||||||
self.response.load(Ordering::Relaxed) + 1,
|
.store(self.response.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
||||||
Ordering::Relaxed,
|
|
||||||
);
|
|
||||||
Ok(middleware::Response::Done(resp))
|
Ok(middleware::Response::Done(resp))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(&self, _: &mut HttpRequest<S>, _: &HttpResponse) -> middleware::Finished {
|
fn finish(&self, _: &mut HttpRequest<S>, _: &HttpResponse) -> middleware::Finished {
|
||||||
self.finish.store(
|
self.finish.store(self.finish.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
|
||||||
self.finish.load(Ordering::Relaxed) + 1,
|
|
||||||
Ordering::Relaxed,
|
|
||||||
);
|
|
||||||
middleware::Finished::Done
|
middleware::Finished::Done
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,12 +44,7 @@ fn test_simple() {
|
|||||||
|
|
||||||
writer.binary(b"text".as_ref());
|
writer.binary(b"text".as_ref());
|
||||||
let (item, reader) = srv.execute(reader.into_future()).unwrap();
|
let (item, reader) = srv.execute(reader.into_future()).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(item, Some(ws::Message::Binary(Bytes::from_static(b"text").into())));
|
||||||
item,
|
|
||||||
Some(ws::Message::Binary(
|
|
||||||
Bytes::from_static(b"text").into()
|
|
||||||
))
|
|
||||||
);
|
|
||||||
|
|
||||||
writer.ping("ping");
|
writer.ping("ping");
|
||||||
let (item, reader) = srv.execute(reader.into_future()).unwrap();
|
let (item, reader) = srv.execute(reader.into_future()).unwrap();
|
||||||
@ -75,7 +70,8 @@ fn test_close_description() {
|
|||||||
let mut srv = test::TestServer::new(|app| app.handler(|req| ws::start(req, Ws)));
|
let mut srv = test::TestServer::new(|app| app.handler(|req| ws::start(req, Ws)));
|
||||||
let (reader, mut writer) = srv.ws().unwrap();
|
let (reader, mut writer) = srv.ws().unwrap();
|
||||||
|
|
||||||
let close_reason:ws::CloseReason = (ws::CloseCode::Normal, "close description").into();
|
let close_reason: ws::CloseReason =
|
||||||
|
(ws::CloseCode::Normal, "close description").into();
|
||||||
writer.close(Some(close_reason.clone()));
|
writer.close(Some(close_reason.clone()));
|
||||||
let (item, _) = srv.execute(reader.into_future()).unwrap();
|
let (item, _) = srv.execute(reader.into_future()).unwrap();
|
||||||
assert_eq!(item, Some(ws::Message::Close(Some(close_reason))));
|
assert_eq!(item, Some(ws::Message::Close(Some(close_reason))));
|
||||||
@ -83,10 +79,7 @@ fn test_close_description() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_large_text() {
|
fn test_large_text() {
|
||||||
let data = rand::thread_rng()
|
let data = rand::thread_rng().gen_ascii_chars().take(65_536).collect::<String>();
|
||||||
.gen_ascii_chars()
|
|
||||||
.take(65_536)
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let mut srv = test::TestServer::new(|app| app.handler(|req| ws::start(req, Ws)));
|
let mut srv = test::TestServer::new(|app| app.handler(|req| ws::start(req, Ws)));
|
||||||
let (mut reader, mut writer) = srv.ws().unwrap();
|
let (mut reader, mut writer) = srv.ws().unwrap();
|
||||||
@ -101,10 +94,7 @@ fn test_large_text() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_large_bin() {
|
fn test_large_bin() {
|
||||||
let data = rand::thread_rng()
|
let data = rand::thread_rng().gen_ascii_chars().take(65_536).collect::<String>();
|
||||||
.gen_ascii_chars()
|
|
||||||
.take(65_536)
|
|
||||||
.collect::<String>();
|
|
||||||
|
|
||||||
let mut srv = test::TestServer::new(|app| app.handler(|req| ws::start(req, Ws)));
|
let mut srv = test::TestServer::new(|app| app.handler(|req| ws::start(req, Ws)));
|
||||||
let (mut reader, mut writer) = srv.ws().unwrap();
|
let (mut reader, mut writer) = srv.ws().unwrap();
|
||||||
@ -113,10 +103,7 @@ fn test_large_bin() {
|
|||||||
writer.binary(data.clone());
|
writer.binary(data.clone());
|
||||||
let (item, r) = srv.execute(reader.into_future()).unwrap();
|
let (item, r) = srv.execute(reader.into_future()).unwrap();
|
||||||
reader = r;
|
reader = r;
|
||||||
assert_eq!(
|
assert_eq!(item, Some(ws::Message::Binary(Binary::from(data.clone()))));
|
||||||
item,
|
|
||||||
Some(ws::Message::Binary(Binary::from(data.clone())))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,26 +207,20 @@ fn test_ws_server_ssl() {
|
|||||||
|
|
||||||
// load ssl keys
|
// load ssl keys
|
||||||
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
|
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
|
||||||
builder
|
builder.set_private_key_file("tests/key.pem", SslFiletype::PEM).unwrap();
|
||||||
.set_private_key_file("tests/key.pem", SslFiletype::PEM)
|
builder.set_certificate_chain_file("tests/cert.pem").unwrap();
|
||||||
.unwrap();
|
|
||||||
builder
|
|
||||||
.set_certificate_chain_file("tests/cert.pem")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut srv = test::TestServer::build()
|
let mut srv = test::TestServer::build().ssl(builder.build()).start(|app| {
|
||||||
.ssl(builder.build())
|
app.handler(|req| {
|
||||||
.start(|app| {
|
ws::start(
|
||||||
app.handler(|req| {
|
req,
|
||||||
ws::start(
|
Ws2 {
|
||||||
req,
|
count: 0,
|
||||||
Ws2 {
|
bin: false,
|
||||||
count: 0,
|
},
|
||||||
bin: false,
|
)
|
||||||
},
|
})
|
||||||
)
|
});
|
||||||
})
|
|
||||||
});
|
|
||||||
let (mut reader, _writer) = srv.ws().unwrap();
|
let (mut reader, _writer) = srv.ws().unwrap();
|
||||||
|
|
||||||
let data = Some(ws::Message::Text("0".repeat(65_536)));
|
let data = Some(ws::Message::Text("0".repeat(65_536)));
|
||||||
|
@ -14,8 +14,8 @@ extern crate url;
|
|||||||
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
@ -61,12 +61,8 @@ fn main() {
|
|||||||
let sample_rate = parse_u64_default(matches.value_of("sample-rate"), 1) as usize;
|
let sample_rate = parse_u64_default(matches.value_of("sample-rate"), 1) as usize;
|
||||||
|
|
||||||
let perf_counters = Arc::new(PerfCounters::new());
|
let perf_counters = Arc::new(PerfCounters::new());
|
||||||
let payload = Arc::new(
|
let payload =
|
||||||
thread_rng()
|
Arc::new(thread_rng().gen_ascii_chars().take(payload_size).collect::<String>());
|
||||||
.gen_ascii_chars()
|
|
||||||
.take(payload_size)
|
|
||||||
.collect::<String>(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let sys = actix::System::new("ws-client");
|
let sys = actix::System::new("ws-client");
|
||||||
|
|
||||||
@ -82,43 +78,40 @@ fn main() {
|
|||||||
let perf = perf_counters.clone();
|
let perf = perf_counters.clone();
|
||||||
let addr = Arbiter::new(format!("test {}", t));
|
let addr = Arbiter::new(format!("test {}", t));
|
||||||
|
|
||||||
addr.do_send(actix::msgs::Execute::new(
|
addr.do_send(actix::msgs::Execute::new(move || -> Result<(), ()> {
|
||||||
move || -> Result<(), ()> {
|
for _ in 0..concurrency {
|
||||||
for _ in 0..concurrency {
|
let pl2 = pl.clone();
|
||||||
let pl2 = pl.clone();
|
let perf2 = perf.clone();
|
||||||
let perf2 = perf.clone();
|
let ws2 = ws.clone();
|
||||||
let ws2 = ws.clone();
|
|
||||||
|
|
||||||
Arbiter::handle().spawn(
|
Arbiter::handle().spawn(
|
||||||
ws::Client::new(&ws)
|
ws::Client::new(&ws)
|
||||||
.write_buffer_capacity(0)
|
.write_buffer_capacity(0)
|
||||||
.connect()
|
.connect()
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
println!("Error: {}", e);
|
println!("Error: {}", e);
|
||||||
//Arbiter::system().do_send(actix::msgs::SystemExit(0));
|
//Arbiter::system().do_send(actix::msgs::SystemExit(0));
|
||||||
()
|
()
|
||||||
})
|
})
|
||||||
.map(move |(reader, writer)| {
|
.map(move |(reader, writer)| {
|
||||||
let addr: Addr<Syn, _> =
|
let addr: Addr<Syn, _> = ChatClient::create(move |ctx| {
|
||||||
ChatClient::create(move |ctx| {
|
ChatClient::add_stream(reader, ctx);
|
||||||
ChatClient::add_stream(reader, ctx);
|
ChatClient {
|
||||||
ChatClient {
|
url: ws2,
|
||||||
url: ws2,
|
conn: writer,
|
||||||
conn: writer,
|
payload: pl2,
|
||||||
payload: pl2,
|
bin: bin,
|
||||||
bin: bin,
|
ts: time::precise_time_ns(),
|
||||||
ts: time::precise_time_ns(),
|
perf_counters: perf2,
|
||||||
perf_counters: perf2,
|
sent: 0,
|
||||||
sent: 0,
|
max_payload_size: max_payload_size,
|
||||||
max_payload_size: max_payload_size,
|
}
|
||||||
}
|
});
|
||||||
});
|
}),
|
||||||
}),
|
);
|
||||||
);
|
}
|
||||||
}
|
Ok(())
|
||||||
Ok(())
|
}));
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = sys.run();
|
let res = sys.run();
|
||||||
@ -126,10 +119,7 @@ fn main() {
|
|||||||
|
|
||||||
fn parse_u64_default(input: Option<&str>, default: u64) -> u64 {
|
fn parse_u64_default(input: Option<&str>, default: u64) -> u64 {
|
||||||
input
|
input
|
||||||
.map(|v| {
|
.map(|v| v.parse().expect(&format!("not a valid number: {}", v)))
|
||||||
v.parse()
|
|
||||||
.expect(&format!("not a valid number: {}", v))
|
|
||||||
})
|
|
||||||
.unwrap_or(default)
|
.unwrap_or(default)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,15 +139,13 @@ impl Actor for Perf {
|
|||||||
|
|
||||||
impl Perf {
|
impl Perf {
|
||||||
fn sample_rate(&self, ctx: &mut Context<Self>) {
|
fn sample_rate(&self, ctx: &mut Context<Self>) {
|
||||||
ctx.run_later(
|
ctx.run_later(Duration::new(self.sample_rate_secs as u64, 0), |act, ctx| {
|
||||||
Duration::new(self.sample_rate_secs as u64, 0),
|
let req_count = act.counters.pull_request_count();
|
||||||
|act, ctx| {
|
if req_count != 0 {
|
||||||
let req_count = act.counters.pull_request_count();
|
let conns = act.counters.pull_connections_count();
|
||||||
if req_count != 0 {
|
let latency = act.counters.pull_latency_ns();
|
||||||
let conns = act.counters.pull_connections_count();
|
let latency_max = act.counters.pull_latency_max_ns();
|
||||||
let latency = act.counters.pull_latency_ns();
|
println!(
|
||||||
let latency_max = act.counters.pull_latency_max_ns();
|
|
||||||
println!(
|
|
||||||
"rate: {}, conns: {}, throughput: {:?} kb, latency: {}, latency max: {}",
|
"rate: {}, conns: {}, throughput: {:?} kb, latency: {}, latency max: {}",
|
||||||
req_count / act.sample_rate_secs,
|
req_count / act.sample_rate_secs,
|
||||||
conns / act.sample_rate_secs,
|
conns / act.sample_rate_secs,
|
||||||
@ -166,11 +154,10 @@ impl Perf {
|
|||||||
time::Duration::nanoseconds((latency / req_count as u64) as i64),
|
time::Duration::nanoseconds((latency / req_count as u64) as i64),
|
||||||
time::Duration::nanoseconds(latency_max as i64)
|
time::Duration::nanoseconds(latency_max as i64)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
act.sample_rate(ctx);
|
act.sample_rate(ctx);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,8 +301,7 @@ impl PerfCounters {
|
|||||||
loop {
|
loop {
|
||||||
let current = self.lat_max.load(Ordering::SeqCst);
|
let current = self.lat_max.load(Ordering::SeqCst);
|
||||||
if current >= nanos
|
if current >= nanos
|
||||||
|| self.lat_max
|
|| self.lat_max.compare_and_swap(current, nanos, Ordering::SeqCst)
|
||||||
.compare_and_swap(current, nanos, Ordering::SeqCst)
|
|
||||||
== current
|
== current
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user