mirror of
https://github.com/fafhrd91/actix-web
synced 2025-01-18 05:41:50 +01:00
simplify Application creation; update url dispatch guide section
This commit is contained in:
parent
caca907c23
commit
0f75d066f2
@ -57,7 +57,7 @@ fn main() {
|
|||||||
let sys = actix::System::new("ws-example");
|
let sys = actix::System::new("ws-example");
|
||||||
|
|
||||||
HttpServer::new(
|
HttpServer::new(
|
||||||
Application::new("/")
|
Application::new()
|
||||||
// enable logger
|
// enable logger
|
||||||
.middleware(middlewares::Logger::default())
|
.middleware(middlewares::Logger::default())
|
||||||
// cookie session middleware
|
// cookie session middleware
|
||||||
|
@ -60,7 +60,7 @@ fn main() {
|
|||||||
let sys = actix::System::new("ws-example");
|
let sys = actix::System::new("ws-example");
|
||||||
|
|
||||||
HttpServer::new(
|
HttpServer::new(
|
||||||
Application::with_state("/", AppState{counter: Cell::new(0)})
|
Application::with_state(AppState{counter: Cell::new(0)})
|
||||||
// enable logger
|
// enable logger
|
||||||
.middleware(middlewares::Logger::default())
|
.middleware(middlewares::Logger::default())
|
||||||
// websocket route
|
// websocket route
|
||||||
|
@ -61,7 +61,7 @@ fn main() {
|
|||||||
let sys = actix::System::new("ws-example");
|
let sys = actix::System::new("ws-example");
|
||||||
|
|
||||||
HttpServer::new(
|
HttpServer::new(
|
||||||
Application::new("/")
|
Application::new()
|
||||||
// enable logger
|
// enable logger
|
||||||
.middleware(middlewares::Logger::default())
|
.middleware(middlewares::Logger::default())
|
||||||
// websocket route
|
// websocket route
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
- [Handler](./qs_4.md)
|
- [Handler](./qs_4.md)
|
||||||
- [Errors](./qs_4_5.md)
|
- [Errors](./qs_4_5.md)
|
||||||
- [State](./qs_6.md)
|
- [State](./qs_6.md)
|
||||||
- [Resources and Routes](./qs_5.md)
|
- [URL Dispatch](./qs_5.md)
|
||||||
- [Request & Response](./qs_7.md)
|
- [Request & Response](./qs_7.md)
|
||||||
- [WebSockets](./qs_9.md)
|
- [WebSockets](./qs_9.md)
|
||||||
- [Middlewares](./qs_10.md)
|
- [Middlewares](./qs_10.md)
|
||||||
|
@ -20,7 +20,7 @@ use actix_web::Application;
|
|||||||
use actix_web::middlewares::Logger;
|
use actix_web::middlewares::Logger;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.middleware(Logger::default())
|
.middleware(Logger::default())
|
||||||
.middleware(Logger::new("%a %{User-Agent}i"))
|
.middleware(Logger::new("%a %{User-Agent}i"))
|
||||||
.finish();
|
.finish();
|
||||||
@ -71,7 +71,7 @@ Tto set default response headers `DefaultHeaders` middleware could be used.
|
|||||||
use actix_web::*;
|
use actix_web::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.middleware(
|
.middleware(
|
||||||
middlewares::DefaultHeaders::build()
|
middlewares::DefaultHeaders::build()
|
||||||
.header("X-Version", "0.2")
|
.header("X-Version", "0.2")
|
||||||
|
@ -16,7 +16,7 @@ fn index(req: HttpRequest) -> Result<fs::NamedFile> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index))
|
.resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ And this name has to be used in `StaticFile` constructor.
|
|||||||
use actix_web::*;
|
use actix_web::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource("/static/{tail:.*}", |r| r.h(fs::StaticFiles::new("tail", ".", true)))
|
.resource("/static/{tail:.*}", |r| r.h(fs::StaticFiles::new("tail", ".", true)))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ request handler with the application's `resource` on a particular *HTTP method*
|
|||||||
# "Hello world!"
|
# "Hello world!"
|
||||||
# }
|
# }
|
||||||
# fn main() {
|
# fn main() {
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.resource("/", |r| r.method(Method::GET).f(index))
|
.resource("/", |r| r.method(Method::GET).f(index))
|
||||||
.finish();
|
.finish();
|
||||||
# }
|
# }
|
||||||
@ -79,7 +79,7 @@ fn main() {
|
|||||||
let sys = actix::System::new("example");
|
let sys = actix::System::new("example");
|
||||||
|
|
||||||
HttpServer::new(
|
HttpServer::new(
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource("/", |r| r.f(index)))
|
.resource("/", |r| r.f(index)))
|
||||||
.serve::<_, ()>("127.0.0.1:8088").unwrap();
|
.serve::<_, ()>("127.0.0.1:8088").unwrap();
|
||||||
|
|
||||||
|
@ -5,8 +5,8 @@ It provides routing, middlewares, pre-processing of requests, and post-processin
|
|||||||
websocket protcol handling, multipart streams, etc.
|
websocket protcol handling, multipart streams, etc.
|
||||||
|
|
||||||
All actix web server is built around `Application` instance.
|
All actix web server is built around `Application` instance.
|
||||||
It is used for registering handlers for routes and resources, middlewares.
|
It is used for registering routes for resources, middlewares.
|
||||||
Also it stores applicationspecific state that is shared accross all handlers
|
Also it stores application specific state that is shared accross all handlers
|
||||||
within same application.
|
within same application.
|
||||||
|
|
||||||
Application acts as namespace for all routes, i.e all routes for specific application
|
Application acts as namespace for all routes, i.e all routes for specific application
|
||||||
@ -20,7 +20,8 @@ has same url path prefix:
|
|||||||
# "Hello world!"
|
# "Hello world!"
|
||||||
# }
|
# }
|
||||||
# fn main() {
|
# fn main() {
|
||||||
let app = Application::new("/prefix")
|
let app = Application::new()
|
||||||
|
.prefix("/prefix")
|
||||||
.resource("/index.html", |r| r.method(Method::GET).f(index))
|
.resource("/index.html", |r| r.method(Method::GET).f(index))
|
||||||
.finish()
|
.finish()
|
||||||
# }
|
# }
|
||||||
@ -28,23 +29,27 @@ has same url path prefix:
|
|||||||
|
|
||||||
In this example application with `/prefix` prefix and `index.html` resource
|
In this example application with `/prefix` prefix and `index.html` resource
|
||||||
get created. This resource is available as on `/prefix/index.html` url.
|
get created. This resource is available as on `/prefix/index.html` url.
|
||||||
|
For more information check
|
||||||
|
[*URL Matching*](./qs_5.html#using-a-application-prefix-to-compose-applications) section.
|
||||||
|
|
||||||
Multiple applications could be served with one server:
|
Multiple applications could be served with one server:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# extern crate actix_web;
|
# extern crate actix_web;
|
||||||
# extern crate tokio_core;
|
# extern crate tokio_core;
|
||||||
use std::net::SocketAddr;
|
# use tokio_core::net::TcpStream;
|
||||||
|
# use std::net::SocketAddr;
|
||||||
use actix_web::*;
|
use actix_web::*;
|
||||||
use tokio_core::net::TcpStream;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
HttpServer::<TcpStream, SocketAddr, _>::new(vec![
|
HttpServer::<TcpStream, SocketAddr, _>::new(vec![
|
||||||
Application::new("/app1")
|
Application::new()
|
||||||
|
.prefix("/app1")
|
||||||
.resource("/", |r| r.f(|r| httpcodes::HTTPOk)),
|
.resource("/", |r| r.f(|r| httpcodes::HTTPOk)),
|
||||||
Application::new("/app2")
|
Application::new()
|
||||||
|
.prefix("/app2")
|
||||||
.resource("/", |r| r.f(|r| httpcodes::HTTPOk)),
|
.resource("/", |r| r.f(|r| httpcodes::HTTPOk)),
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource("/", |r| r.f(|r| httpcodes::HTTPOk)),
|
.resource("/", |r| r.f(|r| httpcodes::HTTPOk)),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ fn main() {
|
|||||||
let sys = actix::System::new("example");
|
let sys = actix::System::new("example");
|
||||||
|
|
||||||
HttpServer::new(
|
HttpServer::new(
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource("/", |r| r.method(Method::GET).f(index)))
|
.resource("/", |r| r.method(Method::GET).f(index)))
|
||||||
.serve::<_, ()>("127.0.0.1:8088").unwrap();
|
.serve::<_, ()>("127.0.0.1:8088").unwrap();
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ fn index(req: HttpRequest) -> FutureResult<HttpResponse, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource("/async", |r| r.route().a(index))
|
.resource("/async", |r| r.route().a(index))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ fn index(req: HttpRequest) -> HttpResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource("/async", |r| r.f(index))
|
.resource("/async", |r| r.f(index))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ fn index(req: HttpRequest) -> io::Result<fs::NamedFile> {
|
|||||||
}
|
}
|
||||||
#
|
#
|
||||||
# fn main() {
|
# fn main() {
|
||||||
# Application::new("/")
|
# Application::new()
|
||||||
# .resource(r"/a/index.html", |r| r.f(index))
|
# .resource(r"/a/index.html", |r| r.f(index))
|
||||||
# .finish();
|
# .finish();
|
||||||
# }
|
# }
|
||||||
@ -57,7 +57,7 @@ fn index(req: HttpRequest) -> Result<&'static str, MyError> {
|
|||||||
}
|
}
|
||||||
#
|
#
|
||||||
# fn main() {
|
# fn main() {
|
||||||
# Application::new("/")
|
# Application::new()
|
||||||
# .resource(r"/a/index.html", |r| r.f(index))
|
# .resource(r"/a/index.html", |r| r.f(index))
|
||||||
# .finish();
|
# .finish();
|
||||||
# }
|
# }
|
||||||
@ -99,7 +99,7 @@ fn index(req: HttpRequest) -> Result<&'static str, MyError> {
|
|||||||
}
|
}
|
||||||
#
|
#
|
||||||
# fn main() {
|
# fn main() {
|
||||||
# Application::new("/")
|
# Application::new()
|
||||||
# .resource(r"/a/index.html", |r| r.f(index))
|
# .resource(r"/a/index.html", |r| r.f(index))
|
||||||
# .finish();
|
# .finish();
|
||||||
# }
|
# }
|
||||||
@ -126,7 +126,7 @@ fn index(req: HttpRequest) -> Result<&'static str> {
|
|||||||
Ok(result.map_err(error::ErrorBadRequest)?)
|
Ok(result.map_err(error::ErrorBadRequest)?)
|
||||||
}
|
}
|
||||||
# fn main() {
|
# fn main() {
|
||||||
# Application::new("/")
|
# Application::new()
|
||||||
# .resource(r"/a/index.html", |r| r.f(index))
|
# .resource(r"/a/index.html", |r| r.f(index))
|
||||||
# .finish();
|
# .finish();
|
||||||
# }
|
# }
|
||||||
|
@ -1,115 +1,251 @@
|
|||||||
# Resources and Routes
|
# URL Dispatch
|
||||||
|
|
||||||
All resources and routes register for specific application.
|
URL dispatch provides a simple way to map URLs to `Handler` code using a simple pattern matching
|
||||||
Application routes incoming requests based on route criteria which is defined during
|
language. *Regex* crate and it's
|
||||||
resource registration or path prefix for simple handlers.
|
[*RegexSet*](https://doc.rust-lang.org/regex/regex/struct.RegexSet.html) is beeing used for
|
||||||
Internally *router* is a list of *resources*. Resource is an entry in *route table*
|
pattern matching. If one of the patterns matches the path information associated with a request,
|
||||||
which corresponds to requested URL.
|
a particular handler object is invoked. A handler is a specific object that implements
|
||||||
|
`Handler` trait, defined in your application, that receives the request and returns
|
||||||
|
a response object. More informatin is available in [handler section](../qs_4.html).
|
||||||
|
|
||||||
Prefix handler:
|
## Resource configuration
|
||||||
|
|
||||||
|
Resource configuraiton is the act of adding a new resource to an application.
|
||||||
|
A resource has a name, which acts as an identifier to be used for URL generation.
|
||||||
|
The name also allows developers to add routes to existing resources.
|
||||||
|
A resource also has a pattern, meant to match against the *PATH* portion of a *URL*
|
||||||
|
(the portion following the scheme and port, e.g., */foo/bar* in the
|
||||||
|
*URL* *http://localhost:8080/foo/bar*).
|
||||||
|
|
||||||
|
The [Application::resource](../actix_web/struct.Application.html#method.resource) methods
|
||||||
|
add a single resource to application routing table. This method accepts *path pattern*
|
||||||
|
and resource configuration funnction.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# extern crate actix_web;
|
# extern crate actix_web;
|
||||||
# use actix_web::*;
|
# use actix_web::*;
|
||||||
|
# use actix_web::httpcodes::*;
|
||||||
#
|
#
|
||||||
fn index(req: HttpRequest) -> HttpResponse {
|
# fn index(req: HttpRequest) -> HttpResponse {
|
||||||
unimplemented!()
|
# unimplemented!()
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
Application::new("/")
|
|
||||||
.resource("/prefix", |r| r.f(index))
|
|
||||||
.finish();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example `index` get called for any url which starts with `/prefix`.
|
|
||||||
|
|
||||||
Application prefix combines with handler prefix i.e
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# extern crate actix_web;
|
|
||||||
# use actix_web::*;
|
|
||||||
#
|
|
||||||
fn index(req: HttpRequest) -> HttpResponse {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
Application::new("/app")
|
|
||||||
.resource("/prefix", |r| r.f(index))
|
|
||||||
.finish();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example `index` get called for any url which starts with`/app/prefix`.
|
|
||||||
|
|
||||||
Resource contains set of route for same endpoint. Route corresponds to handling
|
|
||||||
*HTTP method* by calling *web handler*. Resource select route based on *http method*,
|
|
||||||
if no route could be matched default response `HTTPMethodNotAllowed` get resturned.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# extern crate actix_web;
|
|
||||||
# use actix_web::*;
|
|
||||||
#
|
|
||||||
fn main() {
|
|
||||||
Application::new("/")
|
|
||||||
.resource("/prefix", |r| {
|
|
||||||
r.method(Method::GET).h(httpcodes::HTTPOk);
|
|
||||||
r.method(Method::POST).h(httpcodes::HTTPForbidden);
|
|
||||||
})
|
|
||||||
.finish();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
[`ApplicationBuilder::resource()` method](../actix_web/dev/struct.ApplicationBuilder.html#method.resource)
|
|
||||||
accepts configuration function, resource could be configured at once.
|
|
||||||
Check [`Resource`](../actix-web/target/doc/actix_web/struct.Resource.html) documentation
|
|
||||||
for more information.
|
|
||||||
|
|
||||||
## Variable resources
|
|
||||||
|
|
||||||
Resource may have *variable path*also. For instance, a resource with the
|
|
||||||
path '/a/{name}/c' would match all incoming requests with paths such
|
|
||||||
as '/a/b/c', '/a/1/c', and '/a/etc/c'.
|
|
||||||
|
|
||||||
A *variable part* is specified in the form {identifier}, where the identifier can be
|
|
||||||
used later in a request handler to access the matched value for that part. This is
|
|
||||||
done by looking up the identifier in the `HttpRequest.match_info` object:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# extern crate actix_web;
|
|
||||||
use actix_web::*;
|
|
||||||
|
|
||||||
fn index(req: HttpRequest) -> String {
|
|
||||||
format!("Hello, {}", &req.match_info()["name"])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
Application::new("/")
|
|
||||||
.resource("/{name}", |r| r.method(Method::GET).f(index))
|
|
||||||
.finish();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
By default, each part matches the regular expression `[^{}/]+`.
|
|
||||||
|
|
||||||
You can also specify a custom regex in the form `{identifier:regex}`:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# extern crate actix_web;
|
|
||||||
# use actix_web::*;
|
|
||||||
# fn index(req: HttpRequest) -> String {
|
|
||||||
# format!("Hello, {}", &req.match_info()["name"])
|
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource(r"{name:\d+}", |r| r.method(Method::GET).f(index))
|
.resource("/prefix", |r| r.f(index))
|
||||||
|
.resource("/user/{name}",
|
||||||
|
|r| r.method(Method::GET).f(|req| HTTPOk))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
*Configuraiton function* has following type:
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
FnOnce(&mut Resource<_>) -> ()
|
||||||
|
```
|
||||||
|
|
||||||
|
*Configration function* can set name and register specific routes.
|
||||||
|
If resource does not contain any route or does not have any matching routes it
|
||||||
|
returns *NOT FOUND* http resources.
|
||||||
|
|
||||||
|
## Configuring a Route
|
||||||
|
|
||||||
|
Resource contains set of routes. Each route in turn has set of predicates and handler.
|
||||||
|
New route could be crearted with `Resource::route()` method which returns reference
|
||||||
|
to new *Route* instance. By default *route* does not contain any predicates, so matches
|
||||||
|
all requests and default handler is `HTTPNotFound`.
|
||||||
|
|
||||||
|
Application routes incoming requests based on route criteria which is defined during
|
||||||
|
resource registration and route registration. Resource matches all routes it contains in
|
||||||
|
the order that the routes were registered via `Resource::route()`. *Route* can contain
|
||||||
|
any number of *predicates* but only one handler.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# extern crate actix_web;
|
||||||
|
# use actix_web::*;
|
||||||
|
# use actix_web::httpcodes::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Application::new()
|
||||||
|
.resource("/path", |resource|
|
||||||
|
resource.route()
|
||||||
|
.p(pred::Get())
|
||||||
|
.p(pred::Header("content-type", "text/plain"))
|
||||||
|
.f(|req| HTTPOk)
|
||||||
|
)
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example `index` get called for *GET* request,
|
||||||
|
if request contains `Content-Type` header and value of this header is *text/plain*
|
||||||
|
and path equals to `/test`. Resource calls handle of the first matches route.
|
||||||
|
If resource can not match any route "NOT FOUND" response get returned.
|
||||||
|
|
||||||
|
## Route matching
|
||||||
|
|
||||||
|
The main purpose of route configuration is to match (or not match) the request's `path`
|
||||||
|
against a URL path pattern. `path` represents the path portion of the URL that was requested.
|
||||||
|
|
||||||
|
The way that *actix* does this is very simple. When a request enters the system,
|
||||||
|
for each resource configuration registration present in the system, actix checks
|
||||||
|
the request's path against the pattern declared. *Regex* crate and it's
|
||||||
|
[*RegexSet*](https://doc.rust-lang.org/regex/regex/struct.RegexSet.html) is beeing used for
|
||||||
|
pattern matching. If resource could not be found, *default resource* get used as matched
|
||||||
|
resource.
|
||||||
|
|
||||||
|
When a route configuration is declared, it may contain route predicate arguments. All route
|
||||||
|
predicates associated with a route declaration must be `true` for the route configuration to
|
||||||
|
be used for a given request during a check. If any predicate in the set of route predicate
|
||||||
|
arguments provided to a route configuration returns `false` during a check, that route is
|
||||||
|
skipped and route matching continues through the ordered set of routes.
|
||||||
|
|
||||||
|
If any route matches, the route matching process stops and the handler associated with
|
||||||
|
route get invoked.
|
||||||
|
|
||||||
|
If no route matches after all route patterns are exhausted, *NOT FOUND* response get returned.
|
||||||
|
|
||||||
|
## Resource pattern syntax
|
||||||
|
|
||||||
|
The syntax of the pattern matching language used by the actix in the pattern
|
||||||
|
argument is straightforward.
|
||||||
|
|
||||||
|
The pattern used in route configuration may start with a slash character. If the pattern
|
||||||
|
does not start with a slash character, an implicit slash will be prepended
|
||||||
|
to it at matching time. For example, the following patterns are equivalent:
|
||||||
|
|
||||||
|
```
|
||||||
|
{foo}/bar/baz
|
||||||
|
```
|
||||||
|
|
||||||
|
and:
|
||||||
|
|
||||||
|
```
|
||||||
|
/{foo}/bar/baz
|
||||||
|
```
|
||||||
|
|
||||||
|
A *variable part*(replacement marker) is specified in the form *{identifier}*,
|
||||||
|
where this means "accept any characters up to the next slash character and use this
|
||||||
|
as the name in the `HttpRequest.match_info` object".
|
||||||
|
|
||||||
|
A replacement marker in a pattern matches the regular expression `[^{}/]+`.
|
||||||
|
|
||||||
|
A match_info is the `Params` object representing the dynamic parts extracted from a
|
||||||
|
*URL* based on the routing pattern. It is available as *request.match_info*. For example, the
|
||||||
|
following pattern defines one literal segment (foo) and two replacement markers (baz, and bar):
|
||||||
|
|
||||||
|
```
|
||||||
|
foo/{baz}/{bar}
|
||||||
|
```
|
||||||
|
|
||||||
|
The above pattern will match these URLs, generating the following match information:
|
||||||
|
|
||||||
|
```
|
||||||
|
foo/1/2 -> Params {'baz':'1', 'bar':'2'}
|
||||||
|
foo/abc/def -> Params {'baz':'abc', 'bar':'def'}
|
||||||
|
```
|
||||||
|
|
||||||
|
It will not match the following patterns however:
|
||||||
|
|
||||||
|
```
|
||||||
|
foo/1/2/ -> No match (trailing slash)
|
||||||
|
bar/abc/def -> First segment literal mismatch
|
||||||
|
```
|
||||||
|
|
||||||
|
The match for a segment replacement marker in a segment will be done only up to
|
||||||
|
the first non-alphanumeric character in the segment in the pattern. So, for instance,
|
||||||
|
if this route pattern was used:
|
||||||
|
|
||||||
|
```
|
||||||
|
foo/{name}.html
|
||||||
|
```
|
||||||
|
|
||||||
|
The literal path */foo/biz.html* will match the above route pattern, and the match result
|
||||||
|
will be `Params{'name': 'biz'}`. However, the literal path */foo/biz* will not match,
|
||||||
|
because it does not contain a literal *.html* at the end of the segment represented
|
||||||
|
by *{name}.html* (it only contains biz, not biz.html).
|
||||||
|
|
||||||
|
To capture both segments, two replacement markers can be used:
|
||||||
|
|
||||||
|
```
|
||||||
|
foo/{name}.{ext}
|
||||||
|
```
|
||||||
|
|
||||||
|
The literal path */foo/biz.html* will match the above route pattern, and the match
|
||||||
|
result will be *Params{'name': 'biz', 'ext': 'html'}*. This occurs because there is a
|
||||||
|
literal part of *.* (period) between the two replacement markers *{name}* and *{ext}*.
|
||||||
|
|
||||||
|
Replacement markers can optionally specify a regular expression which will be used to decide
|
||||||
|
whether a path segment should match the marker. To specify that a replacement marker should
|
||||||
|
match only a specific set of characters as defined by a regular expression, you must use a
|
||||||
|
slightly extended form of replacement marker syntax. Within braces, the replacement marker
|
||||||
|
name must be followed by a colon, then directly thereafter, the regular expression. The default
|
||||||
|
regular expression associated with a replacement marker *[^/]+* matches one or more characters
|
||||||
|
which are not a slash. For example, under the hood, the replacement marker *{foo}* can more
|
||||||
|
verbosely be spelled as *{foo:[^/]+}*. You can change this to be an arbitrary regular expression
|
||||||
|
to match an arbitrary sequence of characters, such as *{foo:\d+}* to match only digits.
|
||||||
|
|
||||||
|
Segments must contain at least one character in order to match a segment replacement marker.
|
||||||
|
For example, for the URL */abc/*:
|
||||||
|
|
||||||
|
* */abc/{foo}* will not match.
|
||||||
|
* */{foo}/* will match.
|
||||||
|
|
||||||
|
Note that path will be URL-unquoted and decoded into valid unicode string before
|
||||||
|
matching pattern and values representing matched path segments will be URL-unquoted too.
|
||||||
|
So for instance, the following pattern:
|
||||||
|
|
||||||
|
```
|
||||||
|
foo/{bar}
|
||||||
|
```
|
||||||
|
|
||||||
|
When matching the following URL:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://example.com/foo/La%20Pe%C3%B1a
|
||||||
|
```
|
||||||
|
|
||||||
|
The matchdict will look like so (the value is URL-decoded):
|
||||||
|
|
||||||
|
```
|
||||||
|
Params{'bar': 'La Pe\xf1a'}
|
||||||
|
```
|
||||||
|
|
||||||
|
Literal strings in the path segment should represent the decoded value of the
|
||||||
|
path provided to actix. You don't want to use a URL-encoded value in the pattern.
|
||||||
|
For example, rather than this:
|
||||||
|
|
||||||
|
```
|
||||||
|
/Foo%20Bar/{baz}
|
||||||
|
```
|
||||||
|
|
||||||
|
You'll want to use something like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
/Foo Bar/{baz}
|
||||||
|
```
|
||||||
|
|
||||||
|
It is possible to get "tail match". For this purpose custom regex has to be used.
|
||||||
|
|
||||||
|
```
|
||||||
|
foo/{bar}/{tail:.*}
|
||||||
|
```
|
||||||
|
|
||||||
|
The above pattern will match these URLs, generating the following match information:
|
||||||
|
|
||||||
|
```
|
||||||
|
foo/1/2/ -> Params{'bar':'1', 'tail': '2/'}
|
||||||
|
foo/abc/def/a/b/c -> Params{'bar':u'abc', 'tail': 'def/a/b/c'}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Match information
|
||||||
|
|
||||||
|
All values representing matched path segments are available in
|
||||||
|
[`HttpRequest::match_info`](../actix_web/struct.HttpRequest.html#method.match_info).
|
||||||
|
Specific value can be received with
|
||||||
|
[`Params::get()`](../actix_web/dev/struct.Params.html#method.get) method.
|
||||||
|
|
||||||
Any matched parameter can be deserialized into specific type if this type
|
Any matched parameter can be deserialized into specific type if this type
|
||||||
implements `FromParam` trait. For example most of standard integer types
|
implements `FromParam` trait. For example most of standard integer types
|
||||||
implements `FromParam` trait. i.e.:
|
implements `FromParam` trait. i.e.:
|
||||||
@ -125,7 +261,7 @@ fn index(req: HttpRequest) -> Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource(r"/a/{v1}/{v2}/", |r| r.f(index))
|
.resource(r"/a/{v1}/{v2}/", |r| r.f(index))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
@ -133,25 +269,6 @@ fn main() {
|
|||||||
|
|
||||||
For this example for path '/a/1/2/', values v1 and v2 will resolve to "1" and "2".
|
For this example for path '/a/1/2/', values v1 and v2 will resolve to "1" and "2".
|
||||||
|
|
||||||
It is possible to match path tail with custom `.*` regex.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# extern crate actix_web;
|
|
||||||
# use actix_web::*;
|
|
||||||
#
|
|
||||||
# fn index(req: HttpRequest) -> HttpResponse {
|
|
||||||
# unimplemented!()
|
|
||||||
# }
|
|
||||||
fn main() {
|
|
||||||
Application::new("/")
|
|
||||||
.resource(r"/test/{tail:.*}", |r| r.method(Method::GET).f(index))
|
|
||||||
.finish();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Above example would match all incoming requests with path such as
|
|
||||||
'/test/b/c', '/test/index.html', and '/test/etc/test'.
|
|
||||||
|
|
||||||
It is possible to create a `PathBuf` from a tail path parameter. The returned `PathBuf` is
|
It is possible to create a `PathBuf` from a tail path parameter. The returned `PathBuf` is
|
||||||
percent-decoded. If a segment is equal to "..", the previous segment (if
|
percent-decoded. If a segment is equal to "..", the previous segment (if
|
||||||
any) is skipped.
|
any) is skipped.
|
||||||
@ -179,13 +296,63 @@ fn index(req: HttpRequest) -> Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index))
|
.resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Path normalization
|
List of `FromParam` implementation could be found in
|
||||||
|
[api docs](../actix_web/dev/trait.FromParam.html#foreign-impls)
|
||||||
|
|
||||||
|
## Generating resource URLs
|
||||||
|
|
||||||
|
Use the [HttpRequest.url_for()](../actix_web/struct.HttpRequest.html#method.url_for)
|
||||||
|
method to generate URLs based on resource patterns. For example, if you've configured a
|
||||||
|
resource with the name "foo" and the pattern "{a}/{b}/{c}", you might do this.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# extern crate actix_web;
|
||||||
|
# use actix_web::*;
|
||||||
|
# use actix_web::httpcodes::*;
|
||||||
|
#
|
||||||
|
fn index(req: HttpRequest) -> HttpResponse {
|
||||||
|
let url = req.url_for("foo", &["1", "2", "3"]);
|
||||||
|
HTTPOk.into()
|
||||||
|
}
|
||||||
|
# fn main() {}
|
||||||
|
```
|
||||||
|
|
||||||
|
This would return something like the string *http://example.com/1/2/3* (at least if
|
||||||
|
the current protocol and hostname implied http://example.com).
|
||||||
|
`url_for()` method return [*Url object*](https://docs.rs/url/1.6.0/url/struct.Url.html) so you
|
||||||
|
can modify this url (add query parameters, anchor, etc).
|
||||||
|
`url_for()` could be called only for *named* resources otherwise error get returned.
|
||||||
|
|
||||||
|
## External resources
|
||||||
|
|
||||||
|
Resources that are valid URLs, could be registered as external resources. They are useful
|
||||||
|
for URL generation purposes only and are never considered for matching at request time.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# extern crate actix_web;
|
||||||
|
use actix_web::*;
|
||||||
|
|
||||||
|
fn index(mut req: HttpRequest) -> Result<HttpResponse> {
|
||||||
|
let url = req.url_for("youtube", &["oHg5SJYRHA0"])?;
|
||||||
|
assert_eq!(url.as_str(), "https://youtube.com/watch/oHg5SJYRHA0");
|
||||||
|
Ok(httpcodes::HTTPOk.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let app = Application::new()
|
||||||
|
.resource("/index.html", |r| r.f(index))
|
||||||
|
.external_resource("youtube", "https://youtube.com/watch/{video_id}")
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Path normalization and redirecting to slash-appended routes
|
||||||
|
|
||||||
By normalizing it means:
|
By normalizing it means:
|
||||||
|
|
||||||
@ -214,7 +381,7 @@ This handler designed to be use as a handler for application's *default resource
|
|||||||
# httpcodes::HTTPOk
|
# httpcodes::HTTPOk
|
||||||
# }
|
# }
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.resource("/resource/", |r| r.f(index))
|
.resource("/resource/", |r| r.f(index))
|
||||||
.default_resource(|r| r.h(NormalizePath::default()))
|
.default_resource(|r| r.h(NormalizePath::default()))
|
||||||
.finish();
|
.finish();
|
||||||
@ -239,9 +406,123 @@ It is possible to register path normalization only for *GET* requests only
|
|||||||
# httpcodes::HTTPOk
|
# httpcodes::HTTPOk
|
||||||
# }
|
# }
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.resource("/resource/", |r| r.f(index))
|
.resource("/resource/", |r| r.f(index))
|
||||||
.default_resource(|r| r.method(Method::GET).h(NormalizePath::default()))
|
.default_resource(|r| r.method(Method::GET).h(NormalizePath::default()))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Using a Application Prefix to Compose Applications
|
||||||
|
|
||||||
|
The `Applicaiton::prefix()`" method allows to set specific application prefix.
|
||||||
|
If route_prefix is supplied to the include method, it must be a string.
|
||||||
|
This prefix represents a resource prefix that will be prepended to all resource patterns added
|
||||||
|
by the resource configuration. This can be used to help mount a set of routes at a different
|
||||||
|
location than the included callable's author intended while still maintaining the same
|
||||||
|
resource names.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# extern crate actix_web;
|
||||||
|
# use actix_web::*;
|
||||||
|
#
|
||||||
|
fn show_users(req: HttpRequest) -> HttpResponse {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Application::new()
|
||||||
|
.prefix("/users")
|
||||||
|
.resource("/show", |r| r.f(show_users))
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above example, the *show_users* route will have an effective route pattern of
|
||||||
|
*/users/show* instead of */show* because the application's prefix argument will be prepended
|
||||||
|
to the pattern. The route will then only match if the URL path is /users/show,
|
||||||
|
and when the `HttpRequest.url_for()` function is called with the route name show_users,
|
||||||
|
it will generate a URL with that same path.
|
||||||
|
|
||||||
|
## Custom route predicates
|
||||||
|
|
||||||
|
You can think of predicate as simple function that accept *request* object reference
|
||||||
|
and returns *true* or *false*. Formally predicate is any object that implements
|
||||||
|
[`Predicate`](../actix_web/pred/trait.Predicate.html) trait. Actix provides
|
||||||
|
several predicates, you can check [functions section](../actix_web/pred/index.html#functions)
|
||||||
|
of api docs.
|
||||||
|
|
||||||
|
Here is simple predicates that check that request contains specific *header* and predicate
|
||||||
|
usage:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# extern crate actix_web;
|
||||||
|
# extern crate http;
|
||||||
|
# use actix_web::*;
|
||||||
|
# use actix_web::httpcodes::*;
|
||||||
|
use http::header::CONTENT_TYPE;
|
||||||
|
use actix_web::pred::Predicate;
|
||||||
|
|
||||||
|
struct ContentTypeHeader;
|
||||||
|
|
||||||
|
impl<S: 'static> Predicate<S> for ContentTypeHeader {
|
||||||
|
|
||||||
|
fn check(&self, req: &mut HttpRequest<S>) -> bool {
|
||||||
|
req.headers().contains_key(CONTENT_TYPE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Application::new()
|
||||||
|
.resource("/index.html", |r|
|
||||||
|
r.route()
|
||||||
|
.p(Box::new(ContentTypeHeader))
|
||||||
|
.f(|req| HTTPOk))
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example *index* handler will be called only if request contains *CONTENT-TYPE* header.
|
||||||
|
|
||||||
|
Predicates can have access to application's state via `HttpRequest::state()` method.
|
||||||
|
Also predicates can store extra information in
|
||||||
|
[requests`s extensions](../actix_web/struct.HttpRequest.html#method.extensions).
|
||||||
|
|
||||||
|
### Modifing predicate values
|
||||||
|
|
||||||
|
You can invert the meaning of any predicate value by wrapping it in a `Not` predicate.
|
||||||
|
For example if you want to return "METHOD NOT ALLOWED" response for all methods
|
||||||
|
except "GET":
|
||||||
|
|
||||||
|
```rust
|
||||||
|
# extern crate actix_web;
|
||||||
|
# extern crate http;
|
||||||
|
# use actix_web::*;
|
||||||
|
# use actix_web::httpcodes::*;
|
||||||
|
use actix_web::pred;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Application::new()
|
||||||
|
.resource("/index.html", |r|
|
||||||
|
r.route()
|
||||||
|
.p(pred::Not(pred::Get()))
|
||||||
|
.f(|req| HTTPMethodNotAllowed))
|
||||||
|
.finish();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`Any` predicate accept list of predicates and matches if any of the supplied
|
||||||
|
predicates match. i.e:
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
pred::Any(vec![pred::Get(), pred::Post()])
|
||||||
|
```
|
||||||
|
|
||||||
|
`All` predicate accept list of predicates and matches if all of the supplied
|
||||||
|
predicates match. i.e:
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
pred::All(vec![pred::Get(), pred::Header("content-type", "plain/text")])
|
||||||
|
```
|
||||||
|
@ -30,7 +30,7 @@ fn index(req: HttpRequest<AppState>) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::with_state("/", AppState{counter: Cell::new(0)})
|
Application::with_state(AppState{counter: Cell::new(0)})
|
||||||
.resource("/", |r| r.method(Method::GET).f(index))
|
.resource("/", |r| r.method(Method::GET).f(index))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# HttpRequest & HttpResponse
|
# Request & Response
|
||||||
|
|
||||||
## Response
|
## Response
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ fn index(req: HttpRequest) -> Result<Json<MyObj>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource(r"/a/{name}", |r| r.method(Method::GET).f(index))
|
.resource(r"/a/{name}", |r| r.method(Method::GET).f(index))
|
||||||
.finish();
|
.finish();
|
||||||
}
|
}
|
||||||
|
@ -69,13 +69,11 @@ impl Application<()> {
|
|||||||
|
|
||||||
/// Create application with empty state. Application can
|
/// Create application with empty state. Application can
|
||||||
/// be configured with builder-like pattern.
|
/// be configured with builder-like pattern.
|
||||||
///
|
pub fn new() -> Application<()> {
|
||||||
/// This method accepts path prefix for which it should serve requests.
|
|
||||||
pub fn new<T: Into<String>>(prefix: T) -> Application<()> {
|
|
||||||
Application {
|
Application {
|
||||||
parts: Some(ApplicationParts {
|
parts: Some(ApplicationParts {
|
||||||
state: (),
|
state: (),
|
||||||
prefix: prefix.into(),
|
prefix: "/".to_owned(),
|
||||||
default: Resource::default_not_found(),
|
default: Resource::default_not_found(),
|
||||||
resources: HashMap::new(),
|
resources: HashMap::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
@ -85,6 +83,12 @@ impl Application<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Application<()> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Application::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S> Application<S> where S: 'static {
|
impl<S> Application<S> where S: 'static {
|
||||||
|
|
||||||
/// Create application with specific state. Application can be
|
/// Create application with specific state. Application can be
|
||||||
@ -92,11 +96,11 @@ impl<S> Application<S> where S: 'static {
|
|||||||
///
|
///
|
||||||
/// State is shared with all reousrces within same application and could be
|
/// State is shared with all reousrces within same application and could be
|
||||||
/// accessed with `HttpRequest::state()` method.
|
/// accessed with `HttpRequest::state()` method.
|
||||||
pub fn with_state<T: Into<String>>(prefix: T, state: S) -> Application<S> {
|
pub fn with_state(state: S) -> Application<S> {
|
||||||
Application {
|
Application {
|
||||||
parts: Some(ApplicationParts {
|
parts: Some(ApplicationParts {
|
||||||
state: state,
|
state: state,
|
||||||
prefix: prefix.into(),
|
prefix: "/".to_owned(),
|
||||||
default: Resource::default_not_found(),
|
default: Resource::default_not_found(),
|
||||||
resources: HashMap::new(),
|
resources: HashMap::new(),
|
||||||
external: HashMap::new(),
|
external: HashMap::new(),
|
||||||
@ -105,6 +109,42 @@ impl<S> Application<S> where S: 'static {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set application prefix.
|
||||||
|
///
|
||||||
|
/// Only requests that matches application's prefix get processed by this application.
|
||||||
|
/// Application prefix always contains laading "/" slash. If supplied prefix
|
||||||
|
/// does not contain leading slash, it get inserted.
|
||||||
|
///
|
||||||
|
/// Inthe following example only requests with "/app/" path prefix
|
||||||
|
/// get handled. Request with path "/app/test/" will be handled,
|
||||||
|
/// but request with path "/other/..." will return *NOT FOUND*
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # extern crate actix_web;
|
||||||
|
/// use actix_web::*;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let app = Application::new()
|
||||||
|
/// .prefix("/app")
|
||||||
|
/// .resource("/test", |r| {
|
||||||
|
/// r.method(Method::GET).f(|_| httpcodes::HTTPOk);
|
||||||
|
/// r.method(Method::HEAD).f(|_| httpcodes::HTTPMethodNotAllowed);
|
||||||
|
/// })
|
||||||
|
/// .finish();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn prefix<P: Into<String>>(&mut self, prefix: P) -> &mut Self {
|
||||||
|
{
|
||||||
|
let parts = self.parts.as_mut().expect("Use after finish");
|
||||||
|
let mut prefix = prefix.into();
|
||||||
|
if !prefix.starts_with('/') {
|
||||||
|
prefix.insert(0, '/')
|
||||||
|
}
|
||||||
|
parts.prefix = prefix;
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Configure resource for specific path.
|
/// Configure resource for specific path.
|
||||||
///
|
///
|
||||||
/// Resource may have variable path also. For instance, a resource with
|
/// Resource may have variable path also. For instance, a resource with
|
||||||
@ -128,7 +168,7 @@ impl<S> Application<S> where S: 'static {
|
|||||||
/// use actix_web::*;
|
/// use actix_web::*;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::new("/")
|
/// let app = Application::new()
|
||||||
/// .resource("/test", |r| {
|
/// .resource("/test", |r| {
|
||||||
/// r.method(Method::GET).f(|_| httpcodes::HTTPOk);
|
/// r.method(Method::GET).f(|_| httpcodes::HTTPOk);
|
||||||
/// r.method(Method::HEAD).f(|_| httpcodes::HTTPMethodNotAllowed);
|
/// r.method(Method::HEAD).f(|_| httpcodes::HTTPMethodNotAllowed);
|
||||||
@ -184,7 +224,7 @@ impl<S> Application<S> where S: 'static {
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::new("/")
|
/// let app = Application::new()
|
||||||
/// .resource("/index.html", |r| r.f(index))
|
/// .resource("/index.html", |r| r.f(index))
|
||||||
/// .external_resource("youtube", "https://youtube.com/watch/{video_id}")
|
/// .external_resource("youtube", "https://youtube.com/watch/{video_id}")
|
||||||
/// .finish();
|
/// .finish();
|
||||||
@ -275,7 +315,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_resource() {
|
fn test_default_resource() {
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.resource("/test", |r| r.h(httpcodes::HTTPOk))
|
.resource("/test", |r| r.h(httpcodes::HTTPOk))
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
@ -291,7 +331,7 @@ mod tests {
|
|||||||
let resp = app.run(req);
|
let resp = app.run(req);
|
||||||
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
assert_eq!(resp.as_response().unwrap().status(), StatusCode::NOT_FOUND);
|
||||||
|
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.default_resource(|r| r.h(httpcodes::HTTPMethodNotAllowed))
|
.default_resource(|r| r.h(httpcodes::HTTPMethodNotAllowed))
|
||||||
.finish();
|
.finish();
|
||||||
let req = HttpRequest::new(
|
let req = HttpRequest::new(
|
||||||
@ -303,7 +343,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_unhandled_prefix() {
|
fn test_unhandled_prefix() {
|
||||||
let app = Application::new("/test")
|
let app = Application::new()
|
||||||
|
.prefix("/test")
|
||||||
.resource("/test", |r| r.h(httpcodes::HTTPOk))
|
.resource("/test", |r| r.h(httpcodes::HTTPOk))
|
||||||
.finish();
|
.finish();
|
||||||
assert!(app.handle(HttpRequest::default()).is_err());
|
assert!(app.handle(HttpRequest::default()).is_err());
|
||||||
@ -311,7 +352,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_state() {
|
fn test_state() {
|
||||||
let app = Application::with_state("/", 10)
|
let app = Application::with_state(10)
|
||||||
.resource("/", |r| r.h(httpcodes::HTTPOk))
|
.resource("/", |r| r.h(httpcodes::HTTPOk))
|
||||||
.finish();
|
.finish();
|
||||||
let req = HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone());
|
let req = HttpRequest::default().with_state(Rc::clone(&app.state), app.router.clone());
|
||||||
|
@ -199,7 +199,7 @@ impl FromRequest for FilesystemElement {
|
|||||||
/// use actix_web::{fs, Application};
|
/// use actix_web::{fs, Application};
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::new("/")
|
/// let app = Application::new()
|
||||||
/// .resource("/static/{tail:.*}", |r| r.h(fs::StaticFiles::new("tail", ".", true)))
|
/// .resource("/static/{tail:.*}", |r| r.h(fs::StaticFiles::new("tail", ".", true)))
|
||||||
/// .finish();
|
/// .finish();
|
||||||
/// }
|
/// }
|
||||||
|
@ -303,7 +303,7 @@ impl<T: Serialize> FromRequest for Json<T> {
|
|||||||
/// # httpcodes::HTTPOk
|
/// # httpcodes::HTTPOk
|
||||||
/// # }
|
/// # }
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::new("/")
|
/// let app = Application::new()
|
||||||
/// .resource("/test/", |r| r.f(index))
|
/// .resource("/test/", |r| r.f(index))
|
||||||
/// .default_resource(|r| r.h(NormalizePath::default()))
|
/// .default_resource(|r| r.h(NormalizePath::default()))
|
||||||
/// .finish();
|
/// .finish();
|
||||||
@ -412,7 +412,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_normalize_path_trailing_slashes() {
|
fn test_normalize_path_trailing_slashes() {
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.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| r.h(NormalizePath::default()))
|
.default_resource(|r| r.h(NormalizePath::default()))
|
||||||
@ -444,7 +444,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_normalize_path_trailing_slashes_disabled() {
|
fn test_normalize_path_trailing_slashes_disabled() {
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.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| r.h(
|
.default_resource(|r| r.h(
|
||||||
@ -471,7 +471,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_normalize_path_merge_slashes() {
|
fn test_normalize_path_merge_slashes() {
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.resource("/resource1", |r| r.method(Method::GET).f(index))
|
.resource("/resource1", |r| r.method(Method::GET).f(index))
|
||||||
.resource("/resource1/a/b", |r| r.method(Method::GET).f(index))
|
.resource("/resource1/a/b", |r| r.method(Method::GET).f(index))
|
||||||
.default_resource(|r| r.h(NormalizePath::default()))
|
.default_resource(|r| r.h(NormalizePath::default()))
|
||||||
@ -507,7 +507,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_normalize_path_merge_and_append_slashes() {
|
fn test_normalize_path_merge_and_append_slashes() {
|
||||||
let app = Application::new("/")
|
let app = Application::new()
|
||||||
.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))
|
||||||
.resource("/resource1/a/b", |r| r.method(Method::GET).f(index))
|
.resource("/resource1/a/b", |r| r.method(Method::GET).f(index))
|
||||||
|
@ -21,6 +21,7 @@ pub struct ConnectionInfo<'a> {
|
|||||||
impl<'a> ConnectionInfo<'a> {
|
impl<'a> ConnectionInfo<'a> {
|
||||||
|
|
||||||
/// Create *ConnectionInfo* instance for a request.
|
/// Create *ConnectionInfo* instance for a request.
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
|
||||||
pub fn new<S>(req: &'a HttpRequest<S>) -> ConnectionInfo<'a> {
|
pub fn new<S>(req: &'a HttpRequest<S>) -> ConnectionInfo<'a> {
|
||||||
let mut host = None;
|
let mut host = None;
|
||||||
let mut scheme = None;
|
let mut scheme = None;
|
||||||
|
@ -15,7 +15,7 @@ use middlewares::{Response, Middleware};
|
|||||||
/// use actix_web::*;
|
/// use actix_web::*;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::new("/")
|
/// let app = Application::new()
|
||||||
/// .middleware(
|
/// .middleware(
|
||||||
/// middlewares::DefaultHeaders::build()
|
/// middlewares::DefaultHeaders::build()
|
||||||
/// .header("X-Version", "0.2")
|
/// .header("X-Version", "0.2")
|
||||||
|
@ -27,7 +27,7 @@ use middlewares::{Middleware, Started, Finished};
|
|||||||
/// use actix_web::middlewares::Logger;
|
/// use actix_web::middlewares::Logger;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::new("/")
|
/// let app = Application::new()
|
||||||
/// .middleware(Logger::default())
|
/// .middleware(Logger::default())
|
||||||
/// .middleware(Logger::new("%a %{User-Agent}i"))
|
/// .middleware(Logger::new("%a %{User-Agent}i"))
|
||||||
/// .finish();
|
/// .finish();
|
||||||
|
@ -170,7 +170,7 @@ mod tests {
|
|||||||
let pred = Header("transfer-encoding", "other");
|
let pred = Header("transfer-encoding", "other");
|
||||||
assert!(!pred.check(&mut req));
|
assert!(!pred.check(&mut req));
|
||||||
|
|
||||||
let pred = Header("content-tye", "other");
|
let pred = Header("content-type", "other");
|
||||||
assert!(!pred.check(&mut req));
|
assert!(!pred.check(&mut req));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,9 @@ use std::marker::PhantomData;
|
|||||||
|
|
||||||
use http::Method;
|
use http::Method;
|
||||||
|
|
||||||
|
use pred;
|
||||||
use route::Route;
|
use route::Route;
|
||||||
use handler::{Reply, Handler, FromRequest, RouteHandler, WrapHandler};
|
use handler::{Reply, Handler, FromRequest, RouteHandler};
|
||||||
use httpcodes::HTTPNotFound;
|
use httpcodes::HTTPNotFound;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ use httprequest::HttpRequest;
|
|||||||
/// use actix_web::*;
|
/// use actix_web::*;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::new("/")
|
/// let app = Application::new()
|
||||||
/// .resource(
|
/// .resource(
|
||||||
/// "/", |r| r.method(Method::GET).f(|r| HttpResponse::Ok()))
|
/// "/", |r| r.method(Method::GET).f(|r| HttpResponse::Ok()))
|
||||||
/// .finish();
|
/// .finish();
|
||||||
@ -31,7 +32,6 @@ pub struct Resource<S=()> {
|
|||||||
name: String,
|
name: String,
|
||||||
state: PhantomData<S>,
|
state: PhantomData<S>,
|
||||||
routes: Vec<Route<S>>,
|
routes: Vec<Route<S>>,
|
||||||
default: Box<RouteHandler<S>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Default for Resource<S> {
|
impl<S> Default for Resource<S> {
|
||||||
@ -39,8 +39,7 @@ impl<S> Default for Resource<S> {
|
|||||||
Resource {
|
Resource {
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
state: PhantomData,
|
state: PhantomData,
|
||||||
routes: Vec::new(),
|
routes: Vec::new() }
|
||||||
default: Box::new(HTTPNotFound)}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,8 +49,7 @@ impl<S> Resource<S> {
|
|||||||
Resource {
|
Resource {
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
state: PhantomData,
|
state: PhantomData,
|
||||||
routes: Vec::new(),
|
routes: Vec::new() }
|
||||||
default: Box::new(HTTPNotFound)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set resource name
|
/// Set resource name
|
||||||
@ -74,7 +72,7 @@ impl<S: 'static> Resource<S> {
|
|||||||
/// use actix_web::*;
|
/// use actix_web::*;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let app = Application::new("/")
|
/// let app = Application::new()
|
||||||
/// .resource(
|
/// .resource(
|
||||||
/// "/", |r| r.route()
|
/// "/", |r| r.route()
|
||||||
/// .p(pred::Any(vec![pred::Get(), pred::Put()]))
|
/// .p(pred::Any(vec![pred::Get(), pred::Put()]))
|
||||||
@ -97,7 +95,7 @@ impl<S: 'static> Resource<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.last_mut().unwrap().method(method)
|
self.routes.last_mut().unwrap().p(pred::Method(method))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a new route and add handler object.
|
/// Register a new route and add handler object.
|
||||||
@ -126,12 +124,6 @@ impl<S: 'static> Resource<S> {
|
|||||||
self.routes.push(Route::default());
|
self.routes.push(Route::default());
|
||||||
self.routes.last_mut().unwrap().f(handler)
|
self.routes.last_mut().unwrap().f(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default handler is used if no matched route found.
|
|
||||||
/// By default `HTTPNotFound` is used.
|
|
||||||
pub fn default_handler<H>(&mut self, handler: H) where H: Handler<S> {
|
|
||||||
self.default = Box::new(WrapHandler::new(handler));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> RouteHandler<S> for Resource<S> {
|
impl<S: 'static> RouteHandler<S> for Resource<S> {
|
||||||
@ -142,6 +134,6 @@ impl<S: 'static> RouteHandler<S> for Resource<S> {
|
|||||||
return route.handle(req)
|
return route.handle(req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.default.handle(req)
|
Reply::response(HTTPNotFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
src/route.rs
17
src/route.rs
@ -1,8 +1,7 @@
|
|||||||
use http::Method;
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
use pred::{self, Predicate};
|
use pred::Predicate;
|
||||||
use handler::{Reply, Handler, FromRequest, RouteHandler, AsyncHandler, WrapHandler};
|
use handler::{Reply, Handler, FromRequest, RouteHandler, AsyncHandler, WrapHandler};
|
||||||
use httpcodes::HTTPNotFound;
|
use httpcodes::HTTPNotFound;
|
||||||
use httprequest::HttpRequest;
|
use httprequest::HttpRequest;
|
||||||
@ -43,20 +42,6 @@ impl<S: 'static> Route<S> {
|
|||||||
self.handler.handle(req)
|
self.handler.handle(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add method check to route. This method could be called multiple times.
|
|
||||||
pub fn method(&mut self, method: Method) -> &mut Self {
|
|
||||||
self.preds.push(pred::Method(method));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add predicates to route.
|
|
||||||
pub fn predicates<P>(&mut self, preds: P) -> &mut Self
|
|
||||||
where P: IntoIterator<Item=Box<Predicate<S>>>
|
|
||||||
{
|
|
||||||
self.preds.extend(preds.into_iter());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add match predicate to route.
|
/// Add match predicate to route.
|
||||||
pub fn p(&mut self, p: Box<Predicate<S>>) -> &mut Self {
|
pub fn p(&mut self, p: Box<Predicate<S>>) -> &mut Self {
|
||||||
self.preds.push(p);
|
self.preds.push(p);
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! Application::new("/")
|
//! Application::new()
|
||||||
//! .resource("/ws/", |r| r.method(Method::GET).f(ws_index)) // <- register websocket route
|
//! .resource("/ws/", |r| r.method(Method::GET).f(ws_index)) // <- register websocket route
|
||||||
//! .finish();
|
//! .finish();
|
||||||
//! }
|
//! }
|
||||||
|
@ -16,7 +16,7 @@ fn test_serve() {
|
|||||||
thread::spawn(|| {
|
thread::spawn(|| {
|
||||||
let sys = System::new("test");
|
let sys = System::new("test");
|
||||||
let srv = HttpServer::new(
|
let srv = HttpServer::new(
|
||||||
vec![Application::new("/")
|
vec![Application::new()
|
||||||
.resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk))]);
|
.resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk))]);
|
||||||
srv.serve::<_, ()>("127.0.0.1:58902").unwrap();
|
srv.serve::<_, ()>("127.0.0.1:58902").unwrap();
|
||||||
sys.run();
|
sys.run();
|
||||||
@ -36,7 +36,7 @@ fn test_serve_incoming() {
|
|||||||
let sys = System::new("test");
|
let sys = System::new("test");
|
||||||
|
|
||||||
let srv = HttpServer::new(
|
let srv = HttpServer::new(
|
||||||
Application::new("/")
|
Application::new()
|
||||||
.resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk)));
|
.resource("/", |r| r.method(Method::GET).h(httpcodes::HTTPOk)));
|
||||||
let tcp = TcpListener::from_listener(tcp, &addr2, Arbiter::handle()).unwrap();
|
let tcp = TcpListener::from_listener(tcp, &addr2, Arbiter::handle()).unwrap();
|
||||||
srv.serve_incoming::<_, ()>(tcp.incoming(), false).unwrap();
|
srv.serve_incoming::<_, ()>(tcp.incoming(), false).unwrap();
|
||||||
@ -84,7 +84,7 @@ fn test_middlewares() {
|
|||||||
let sys = System::new("test");
|
let sys = System::new("test");
|
||||||
|
|
||||||
HttpServer::new(
|
HttpServer::new(
|
||||||
vec![Application::new("/")
|
vec![Application::new()
|
||||||
.middleware(MiddlewareTest{start: act_num1,
|
.middleware(MiddlewareTest{start: act_num1,
|
||||||
response: act_num2,
|
response: act_num2,
|
||||||
finish: act_num3})
|
finish: act_num3})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user