diff --git a/Cargo.toml b/Cargo.toml index 0860f5aaf..a85a971fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,13 +25,15 @@ path = "src/main.rs" time = "0.1" http = "0.1" httparse = "0.1" -hyper = "0.11" -unicase = "2.0" slab = "0.4" sha1 = "0.2" rand = "0.3" +url = "1.5" route-recognizer = "0.1" +hyper = "0.11" +unicase = "2.0" + # tokio bytes = "0.4" futures = "0.1" diff --git a/README.md b/README.md index 7e65960dc..23d8203c5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Actix Http [![Build Status](https://travis-ci.org/fafhrd91/actix-http.svg?branch=master)](https://travis-ci.org/fafhrd91/actix-http) +# Actix http [![Build Status](https://travis-ci.org/fafhrd91/actix-http.svg?branch=master)](https://travis-ci.org/fafhrd91/actix-http) Actix http is a server http framework for Actix framework. @@ -8,7 +8,7 @@ Actix http is a server http framework for Actix framework. --- -Actix Http is licensed under the [Apache-2.0 license](http://opensource.org/licenses/APACHE-2.0). +Actix http is licensed under the [Apache-2.0 license](http://opensource.org/licenses/APACHE-2.0). ## Features @@ -49,9 +49,9 @@ impl Route for MyRoute { type State = (); fn request(req: HttpRequest, payload: Option, - ctx: &mut HttpContext) -> HttpMessage + ctx: &mut HttpContext) -> Reply { - HttpMessage::reply_with(req, httpcodes::HTTPOk) + Reply::with(req, httpcodes::HTTPOk) } } diff --git a/src/application.rs b/src/application.rs index 904384dc7..61628ec30 100644 --- a/src/application.rs +++ b/src/application.rs @@ -6,21 +6,21 @@ use route_recognizer::Router; use task::Task; use route::{Payload, RouteHandler}; -use router::HttpHandler; -use resource::HttpResource; +use router::Handler; +use resource::Resource; use httpmessage::HttpRequest; /// Application -pub struct HttpApplication { +pub struct Application { state: S, - default: HttpResource, - resources: HashMap>, + default: Resource, + resources: HashMap>, } -impl HttpApplication where S: 'static +impl Application where S: 'static { - pub(crate) fn prepare(self, prefix: String) -> Box { + pub(crate) fn prepare(self, prefix: String) -> Box { let mut router = Router::new(); let prefix = if prefix.ends_with('/') {prefix } else { prefix + "/" }; @@ -38,46 +38,46 @@ impl HttpApplication where S: 'static } } -impl HttpApplication<()> { +impl Default for Application<()> { - /// Create `HttpApplication` with no state - pub fn no_state() -> Self { - HttpApplication { + /// Create default `Application` with no state + fn default() -> Self { + Application { state: (), - default: HttpResource::default(), + default: Resource::default(), resources: HashMap::new(), } } } -impl HttpApplication where S: 'static { +impl Application where S: 'static { /// Create http application with specific state. State is shared with all /// routes within same application and could be /// accessed with `HttpContext::state()` method. - pub fn new(state: S) -> HttpApplication { - HttpApplication { + pub fn new(state: S) -> Application { + Application { state: state, - default: HttpResource::default(), + default: Resource::default(), resources: HashMap::new(), } } /// Add resource by path. - pub fn add(&mut self, path: P) -> &mut HttpResource + pub fn add(&mut self, path: P) -> &mut Resource { let path = path.to_string(); // add resource if !self.resources.contains_key(&path) { - self.resources.insert(path.clone(), HttpResource::default()); + self.resources.insert(path.clone(), Resource::default()); } self.resources.get_mut(&path).unwrap() } - /// Default resource is used if no matched route could be found. - pub fn default(&mut self) -> &mut HttpResource { + /// Default resource is used if no matches route could be found. + pub fn default_resource(&mut self) -> &mut Resource { &mut self.default } } @@ -86,12 +86,12 @@ impl HttpApplication where S: 'static { pub(crate) struct InnerApplication { state: Rc, - default: HttpResource, - router: Router>, + default: Resource, + router: Router>, } -impl HttpHandler for InnerApplication { +impl Handler for InnerApplication { fn handle(&self, req: HttpRequest, payload: Option) -> Task { if let Ok(h) = self.router.recognize(req.path()) { diff --git a/src/httpmessage.rs b/src/httpmessage.rs index 1843c911d..754ad5e1c 100644 --- a/src/httpmessage.rs +++ b/src/httpmessage.rs @@ -164,6 +164,21 @@ impl HttpRequest { } } + /// Is keepalive enabled by client? + pub fn keep_alive(&self) -> bool { + let ret = match (self.version(), self.headers().get::()) { + (Version::HTTP_10, None) => false, + (Version::HTTP_10, Some(conn)) + if !conn.contains(&ConnectionOption::KeepAlive) => false, + (Version::HTTP_11, Some(conn)) + if conn.contains(&ConnectionOption::Close) => false, + _ => true + }; + trace!("should_keep_alive(version={:?}, header={:?}) = {:?}", + self.version(), self.headers().get::(), ret); + ret + } + pub(crate) fn is_upgrade(&self) -> bool { if let Some(&Connection(ref conn)) = self.headers().get() { conn.contains(&ConnectionOption::from_str("upgrade").unwrap()) @@ -199,7 +214,7 @@ impl Body { } } -/// Implements by something that can be converted to `HttpMessage` +/// Implements by something that can be converted to `HttpResponse` pub trait IntoHttpResponse { /// Convert into response. fn response(self, req: HttpRequest) -> HttpResponse; diff --git a/src/lib.rs b/src/lib.rs index d8c42835f..fbe93b3ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ extern crate time; extern crate bytes; extern crate rand; extern crate sha1; +extern crate url; #[macro_use] extern crate futures; extern crate tokio_core; @@ -14,6 +15,7 @@ extern crate tokio_proto; #[macro_use] extern crate hyper; extern crate unicase; + extern crate http; extern crate httparse; extern crate route_recognizer; @@ -37,11 +39,11 @@ mod wsframe; mod wsproto; pub mod httpcodes; -pub use application::HttpApplication; +pub use application::Application; +pub use httpmessage::{HttpRequest, HttpResponse, IntoHttpResponse}; +pub use router::RoutingMap; +pub use resource::{Reply, Resource}; pub use route::{Route, RouteFactory, RouteHandler, Payload, PayloadItem}; -pub use resource::{HttpMessage, HttpResource}; pub use server::HttpServer; pub use context::HttpContext; -pub use router::RoutingMap; -pub use httpmessage::{HttpRequest, HttpResponse, IntoHttpResponse}; pub use route_recognizer::Params; diff --git a/src/main.rs b/src/main.rs index f95f80b1d..417cf9e45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,13 +21,13 @@ impl Route for MyRoute { fn request(req: HttpRequest, payload: Option, - ctx: &mut HttpContext) -> HttpMessage + ctx: &mut HttpContext) -> Reply { if let Some(pl) = payload { ctx.add_stream(pl); - HttpMessage::stream(MyRoute{req: Some(req)}) + Reply::stream(MyRoute{req: Some(req)}) } else { - HttpMessage::reply_with(req, httpcodes::HTTPOk) + Reply::with(req, httpcodes::HTTPOk) } } } @@ -64,20 +64,20 @@ impl Route for MyWS { fn request(req: HttpRequest, payload: Option, - ctx: &mut HttpContext) -> HttpMessage + ctx: &mut HttpContext) -> Reply { if let Some(payload) = payload { match ws::handshake(req) { Ok(resp) => { ctx.start(resp); ctx.add_stream(ws::WsStream::new(payload)); - HttpMessage::stream(MyWS{}) + Reply::stream(MyWS{}) }, Err(err) => - HttpMessage::reply(err) + Reply::reply(err) } } else { - HttpMessage::reply_with(req, httpcodes::HTTPBadRequest) + Reply::with(req, httpcodes::HTTPBadRequest) } } } @@ -112,7 +112,7 @@ fn main() { let mut routes = RoutingMap::default(); - let mut app = HttpApplication::no_state(); + let mut app = Application::default(); app.add("/test") .get::() .post::(); diff --git a/src/resource.rs b/src/resource.rs index eb8a6d327..4c5802924 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -13,7 +13,7 @@ use httpmessage::{HttpRequest, HttpResponse, IntoHttpResponse}; /// Http resource /// -/// `HttpResource` is an entry in route table which corresponds to requested URL. +/// `Resource` is an entry in route table which corresponds to requested URL. /// /// Resource in turn has at least one route. /// Route corresponds to handling HTTP method by calling route handler. @@ -29,15 +29,15 @@ use httpmessage::{HttpRequest, HttpResponse, IntoHttpResponse}; /// .add_resource("/") /// .post::(); /// } -pub struct HttpResource { +pub struct Resource { state: PhantomData, routes: HashMap>>, default: Box>, } -impl Default for HttpResource { +impl Default for Resource { fn default() -> Self { - HttpResource { + Resource { state: PhantomData, routes: HashMap::new(), default: Box::new(HTTPMethodNotAllowed)} @@ -45,7 +45,7 @@ impl Default for HttpResource { } -impl HttpResource where S: 'static { +impl Resource where S: 'static { /// Register handler for specified method. pub fn handler(&mut self, method: Method, handler: H) -> &mut Self @@ -90,7 +90,7 @@ impl HttpResource where S: 'static { } -impl RouteHandler for HttpResource { +impl RouteHandler for Resource { fn handle(&self, req: HttpRequest, payload: Option, state: Rc) -> Task { if let Some(handler) = self.routes.get(req.method()) { @@ -103,37 +103,37 @@ impl RouteHandler for HttpResource { #[cfg_attr(feature="cargo-clippy", allow(large_enum_variant))] -enum HttpMessageItem where A: Actor> + Route { +enum ReplyItem where A: Actor> + Route { Message(HttpResponse), Actor(A), } /// Represents response process. -pub struct HttpMessage> + Route> (HttpMessageItem); +pub struct Reply> + Route> (ReplyItem); -impl HttpMessage where A: Actor> + Route +impl Reply where A: Actor> + Route { /// Create async response pub fn stream(act: A) -> Self { - HttpMessage(HttpMessageItem::Actor(act)) + Reply(ReplyItem::Actor(act)) } /// Send response pub fn reply(msg: HttpResponse) -> Self { - HttpMessage(HttpMessageItem::Message(msg)) + Reply(ReplyItem::Message(msg)) } /// Send response - pub fn reply_with(req: HttpRequest, msg: I) -> Self { - HttpMessage(HttpMessageItem::Message(msg.response(req))) + pub fn with(req: HttpRequest, msg: I) -> Self { + Reply(ReplyItem::Message(msg.response(req))) } pub(crate) fn into(self, mut ctx: HttpContext) -> Task { match self.0 { - HttpMessageItem::Message(msg) => { + ReplyItem::Message(msg) => { Task::reply(msg) }, - HttpMessageItem::Actor(act) => { + ReplyItem::Actor(act) => { ctx.set_actor(act); Task::with_stream(ctx) } diff --git a/src/route.rs b/src/route.rs index c0aa0ac29..25667055c 100644 --- a/src/route.rs +++ b/src/route.rs @@ -7,7 +7,7 @@ use futures::unsync::mpsc::Receiver; use task::Task; use context::HttpContext; -use resource::HttpMessage; +use resource::Reply; use httpmessage::{HttpRequest, HttpResponse}; /// Stream of `PayloadItem`'s @@ -45,7 +45,7 @@ pub enum Frame { Payload(Option), } -/// Trait defines object that could be regestered as resource route. +/// Trait defines object that could be regestered as resource route pub trait RouteHandler: 'static { fn handle(&self, req: HttpRequest, payload: Option, state: Rc) -> Task; } @@ -57,12 +57,12 @@ pub trait Route: Actor> { type State; /// Handle incoming request. Route actor can return - /// result immediately with `HttpMessage::reply` or `HttpMessage::error`. + /// result immediately with `Reply::reply` or `Reply::with`. /// Actor itself could be returned for handling streaming request/response. - /// In that case `HttpContext::start` and `HttpContext::write` hs to be used. + /// In that case `HttpContext::start` and `HttpContext::write` has to be used. fn request(req: HttpRequest, payload: Option, - ctx: &mut HttpContext) -> HttpMessage; + ctx: &mut HttpContext) -> Reply; /// This method creates `RouteFactory` for this actor. fn factory() -> RouteFactory { @@ -70,7 +70,7 @@ pub trait Route: Actor> { } } -/// This is used for routes registration within `HttpResource`. +/// This is used for routes registration within `Resource` pub struct RouteFactory, S>(PhantomData); impl RouteHandler for RouteFactory diff --git a/src/router.rs b/src/router.rs index d1d519b42..1bf38744e 100644 --- a/src/router.rs +++ b/src/router.rs @@ -5,12 +5,12 @@ use route_recognizer::{Router as Recognizer}; use task::Task; use route::{Payload, RouteHandler}; -use resource::HttpResource; -use application::HttpApplication; +use resource::Resource; +use application::Application; use httpcodes::HTTPNotFound; use httpmessage::{HttpRequest, IntoHttpResponse}; -pub trait HttpHandler: 'static { +pub(crate) trait Handler: 'static { fn handle(&self, req: HttpRequest, payload: Option) -> Task; } @@ -29,8 +29,8 @@ pub trait HttpHandler: 'static { /// router.add_resource("/users/:userid/:friendid").get::(); /// ``` pub struct RoutingMap { - apps: HashMap>, - resources: HashMap, + apps: HashMap>, + resources: HashMap, } impl Default for RoutingMap { @@ -44,7 +44,7 @@ impl Default for RoutingMap { impl RoutingMap { - /// Add `HttpApplication` object with specific prefix. + /// Add `Application` object with specific prefix. /// Application prefixes all registered resources with specified prefix. /// /// ```rust,ignore @@ -52,7 +52,7 @@ impl RoutingMap { /// struct MyRoute; /// /// fn main() { - /// let mut app = HttpApplication::no_state(); + /// let mut app = Application::default(); /// app.add("/test") /// .get::() /// .post::(); @@ -62,7 +62,7 @@ impl RoutingMap { /// } /// ``` /// In this example, `MyRoute` route is available as `http://.../pre/test` url. - pub fn add(&mut self, prefix: P, app: HttpApplication) + pub fn add(&mut self, prefix: P, app: Application) where P: ToString { let prefix = prefix.to_string(); @@ -76,7 +76,7 @@ impl RoutingMap { self.apps.insert(prefix.clone(), app.prepare(prefix)); } - /// This method creates `HttpResource` for specified path + /// This method creates `Resource` for specified path /// or returns mutable reference to resource object. /// /// ```rust,ignore @@ -91,14 +91,14 @@ impl RoutingMap { /// } /// ``` /// In this example, `MyRoute` route is available as `http://.../test` url. - pub fn add_resource

(&mut self, path: P) -> &mut HttpResource + pub fn add_resource

(&mut self, path: P) -> &mut Resource where P: ToString { let path = path.to_string(); // add resource if !self.resources.contains_key(&path) { - self.resources.insert(path.clone(), HttpResource::default()); + self.resources.insert(path.clone(), Resource::default()); } self.resources.get_mut(&path).unwrap() @@ -121,8 +121,8 @@ impl RoutingMap { pub(crate) struct Router { - apps: HashMap>, - resources: Recognizer, + apps: HashMap>, + resources: Recognizer, } impl Router { diff --git a/src/server.rs b/src/server.rs index ae190c4ec..8e1e3c78f 100644 --- a/src/server.rs +++ b/src/server.rs @@ -10,7 +10,7 @@ use task::Task; use reader::Reader; use router::{Router, RoutingMap}; -/// An HTTP Server. +/// An HTTP Server pub struct HttpServer { router: Rc, } diff --git a/src/ws.rs b/src/ws.rs index 85a04a493..8d367f1f5 100644 --- a/src/ws.rs +++ b/src/ws.rs @@ -22,7 +22,7 @@ //! type State = (); //! //! fn request(req: HttpRequest, payload: Option, -//! ctx: &mut HttpContext) -> HttpMessage +//! ctx: &mut HttpContext) -> Reply //! { //! if let Some(payload) = payload { //! // WebSocket handshake @@ -33,13 +33,13 @@ //! // Map Payload into WsStream //! ctx.add_stream(ws::WsStream::new(payload)); //! // Start ws messages processing -//! HttpMessage::stream(WsRoute) +//! Reply::stream(WsRoute) //! }, //! Err(err) => -//! HttpMessage::reply(err) +//! Reply::reply(err) //! } //! } else { -//! HttpMessage::reply_with(req, httpcodes::HTTPBadRequest) +//! Reply::with(req, httpcodes::HTTPBadRequest) //! } //! } //! }