1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 07:53:00 +01:00

refactor Handler trait, use mut self

This commit is contained in:
Nikolay Kim 2017-12-26 09:00:45 -08:00
parent b61a07a320
commit cf8c2ca95e
14 changed files with 138 additions and 59 deletions

View File

@ -39,6 +39,81 @@ fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
} }
``` ```
Some notes on shared application state and handler state. If you noticed
*Handler* trait is generic over *S*, which defines application state type. So
application state is accessible from handler with `HttpRequest::state()` method.
But state is accessible as a read-only reference, if you need mutable access to state
you have to implement it yourself. On other hand handler can mutable access it's own state
as `handle` method takes mutable reference to *self*. Beware, actix creates multiple copies
of application state and handlers, unique for each thread, so if you run your
application in several threads actix will create same amount as number of threads
of application state objects and handler objects.
Here is example of handler that stores number of processed requests:
```rust
# extern crate actix;
# extern crate actix_web;
use actix_web::*;
use actix_web::dev::Handler;
struct MyHandler(usize);
impl<S> Handler<S> for MyHandler {
type Result = HttpResponse;
/// Handle request
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
self.0 += 1;
httpcodes::HTTPOk.response()
}
}
# fn main() {}
```
This handler will work, but `self.0` value will be different depends on number of threads and
number of requests processed per thread. Proper implementation would use `Arc` and `AtomicUsize`
```rust
# extern crate actix;
# extern crate actix_web;
use actix_web::*;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
struct MyHandler(Arc<AtomicUsize>);
impl<S> Handler<S> for MyHandler {
type Result = HttpResponse;
/// Handle request
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
let num = self.0.load(Ordering::Relaxed) + 1;
self.0.store(num, Ordering::Relaxed);
httpcodes::HTTPOk.response()
}
}
fn main() {
let sys = actix::System::new("example");
let inc = Arc::new(AtomicUsize::new(0));
HttpServer::new(
move || {
let cloned = inc.clone();
Application::new()
.resource("/", move |r| r.h(MyHandler(cloned)))
})
.bind("127.0.0.1:8088").unwrap()
.start();
println!("Started http server: 127.0.0.1:8088");
# actix::Arbiter::system().send(actix::msgs::SystemExit(0));
let _ = sys.run();
}
```
## Response with custom type ## Response with custom type
To return custom type directly from handler function type needs to implement `Responder` trait. To return custom type directly from handler function type needs to implement `Responder` trait.

View File

@ -15,7 +15,8 @@ pub struct HttpApplication<S=()> {
state: Rc<S>, state: Rc<S>,
prefix: String, prefix: String,
default: Resource<S>, default: Resource<S>,
router: Router<S>, router: Router,
resources: Vec<Resource<S>>,
middlewares: Rc<Vec<Box<Middleware<S>>>>, middlewares: Rc<Vec<Box<Middleware<S>>>>,
} }
@ -25,9 +26,9 @@ impl<S: 'static> HttpApplication<S> {
req.with_state(Rc::clone(&self.state), self.router.clone()) req.with_state(Rc::clone(&self.state), self.router.clone())
} }
pub(crate) fn run(&self, mut req: HttpRequest<S>) -> Reply { pub(crate) fn run(&mut self, mut req: HttpRequest<S>) -> Reply {
if let Some(h) = self.router.recognize(&mut req) { if let Some(idx) = self.router.recognize(&mut req) {
h.handle(req.clone(), Some(&self.default)) self.resources[idx].handle(req.clone(), Some(&mut self.default))
} else { } else {
self.default.handle(req, None) self.default.handle(req, None)
} }
@ -36,11 +37,12 @@ impl<S: 'static> HttpApplication<S> {
impl<S: 'static> HttpHandler for HttpApplication<S> { impl<S: 'static> HttpHandler for HttpApplication<S> {
fn handle(&self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest> { fn handle(&mut self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest> {
if req.path().starts_with(&self.prefix) { if req.path().starts_with(&self.prefix) {
let req = self.prepare_request(req); let req = self.prepare_request(req);
// TODO: redesign run callback
Ok(Box::new(Pipeline::new(req, Rc::clone(&self.middlewares), Ok(Box::new(Pipeline::new(req, Rc::clone(&self.middlewares),
&|req: HttpRequest<S>| self.run(req)))) &mut |req: HttpRequest<S>| self.run(req))))
} else { } else {
Err(req) Err(req)
} }
@ -264,11 +266,13 @@ impl<S> Application<S> where S: 'static {
resources.insert(pattern, None); resources.insert(pattern, None);
} }
let (router, resources) = Router::new(prefix, resources);
HttpApplication { HttpApplication {
state: Rc::new(parts.state), state: Rc::new(parts.state),
prefix: prefix.to_owned(), prefix: prefix.to_owned(),
default: parts.default, default: parts.default,
router: Router::new(prefix, resources), router: router,
resources: resources,
middlewares: Rc::new(parts.middlewares), middlewares: Rc::new(parts.middlewares),
} }
} }
@ -314,7 +318,7 @@ mod tests {
#[test] #[test]
fn test_default_resource() { fn test_default_resource() {
let app = Application::new() let mut app = Application::new()
.resource("/test", |r| r.h(httpcodes::HTTPOk)) .resource("/test", |r| r.h(httpcodes::HTTPOk))
.finish(); .finish();
@ -330,7 +334,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 mut 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(
@ -342,7 +346,7 @@ mod tests {
#[test] #[test]
fn test_unhandled_prefix() { fn test_unhandled_prefix() {
let app = Application::new() let mut app = Application::new()
.prefix("/test") .prefix("/test")
.resource("/test", |r| r.h(httpcodes::HTTPOk)) .resource("/test", |r| r.h(httpcodes::HTTPOk))
.finish(); .finish();
@ -351,7 +355,7 @@ mod tests {
#[test] #[test]
fn test_state() { fn test_state() {
let app = Application::with_state(10) let mut 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());

View File

@ -18,7 +18,7 @@ use server::{ServerSettings, WorkerSettings};
pub trait HttpHandler: 'static { pub trait HttpHandler: 'static {
/// Handle request /// Handle request
fn handle(&self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest>; fn handle(&mut self, req: HttpRequest) -> Result<Box<HttpHandlerTask>, HttpRequest>;
/// Set server settings /// Set server settings
fn server_settings(&mut self, settings: ServerSettings) {} fn server_settings(&mut self, settings: ServerSettings) {}

View File

@ -252,7 +252,7 @@ impl StaticFiles {
impl<S> Handler<S> for StaticFiles { impl<S> Handler<S> for StaticFiles {
type Result = Result<FilesystemElement, io::Error>; type Result = Result<FilesystemElement, io::Error>;
fn handle(&self, req: HttpRequest<S>) -> Self::Result { fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
if !self.accessible { if !self.accessible {
Err(io::Error::new(io::ErrorKind::NotFound, "not found")) Err(io::Error::new(io::ErrorKind::NotFound, "not found"))
} else { } else {

View File

@ -231,7 +231,7 @@ impl<T, H> Http1<T, H>
// start request processing // start request processing
let mut pipe = None; let mut pipe = None;
for h in self.settings.handlers().iter() { for h in self.settings.handlers().iter_mut() {
req = match h.handle(req) { req = match h.handle(req) {
Ok(t) => { Ok(t) => {
pipe = Some(t); pipe = Some(t);

View File

@ -261,7 +261,7 @@ impl Entry {
// start request processing // start request processing
let mut task = None; let mut task = None;
for h in settings.handlers().iter() { for h in settings.handlers().iter_mut() {
req = match h.handle(req) { req = match h.handle(req) {
Ok(t) => { Ok(t) => {
task = Some(t); task = Some(t);

View File

@ -19,7 +19,7 @@ pub trait Handler<S>: 'static {
type Result: Responder; type Result: Responder;
/// Handle request /// Handle request
fn handle(&self, req: HttpRequest<S>) -> Self::Result; fn handle(&mut self, req: HttpRequest<S>) -> Self::Result;
} }
/// Trait implemented by types that generate responses for clients. /// Trait implemented by types that generate responses for clients.
@ -59,7 +59,7 @@ impl<F, R, S> Handler<S> for F
{ {
type Result = R; type Result = R;
fn handle(&self, req: HttpRequest<S>) -> R { fn handle(&mut self, req: HttpRequest<S>) -> R {
(self)(req) (self)(req)
} }
} }
@ -207,7 +207,7 @@ impl<I, E> Responder for Box<Future<Item=I, Error=E>>
/// Trait defines object that could be regestered as resource route /// Trait defines object that could be regestered as resource route
pub(crate) trait RouteHandler<S>: 'static { pub(crate) trait RouteHandler<S>: 'static {
fn handle(&self, req: HttpRequest<S>) -> Reply; fn handle(&mut self, req: HttpRequest<S>) -> Reply;
} }
/// Route handler wrapper for Handler /// Route handler wrapper for Handler
@ -236,7 +236,7 @@ impl<S, H, R> RouteHandler<S> for WrapHandler<S, H, R>
R: Responder + 'static, R: Responder + 'static,
S: 'static, S: 'static,
{ {
fn handle(&self, req: HttpRequest<S>) -> Reply { fn handle(&mut self, req: HttpRequest<S>) -> Reply {
let req2 = req.clone_without_state(); let req2 = req.clone_without_state();
match self.h.handle(req).respond_to(req2) { match self.h.handle(req).respond_to(req2) {
Ok(reply) => reply.into(), Ok(reply) => reply.into(),
@ -277,7 +277,7 @@ impl<S, H, F, R, E> RouteHandler<S> for AsyncHandler<S, H, F, R, E>
E: Into<Error> + 'static, E: Into<Error> + 'static,
S: 'static, S: 'static,
{ {
fn handle(&self, req: HttpRequest<S>) -> Reply { fn handle(&mut self, req: HttpRequest<S>) -> Reply {
let req2 = req.clone_without_state(); let req2 = req.clone_without_state();
let fut = (self.h)(req) let fut = (self.h)(req)
.map_err(|e| e.into()) .map_err(|e| e.into())
@ -368,7 +368,7 @@ impl NormalizePath {
impl<S> Handler<S> for NormalizePath { impl<S> Handler<S> for NormalizePath {
type Result = Result<HttpResponse, HttpError>; type Result = Result<HttpResponse, HttpError>;
fn handle(&self, req: HttpRequest<S>) -> Self::Result { fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
if let Some(router) = req.router() { if let Some(router) = req.router() {
let query = req.query_string(); let query = req.query_string();
if self.merge { if self.merge {
@ -420,7 +420,7 @@ mod tests {
#[test] #[test]
fn test_normalize_path_trailing_slashes() { fn test_normalize_path_trailing_slashes() {
let app = Application::new() let mut 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()))
@ -452,7 +452,7 @@ mod tests {
#[test] #[test]
fn test_normalize_path_trailing_slashes_disabled() { fn test_normalize_path_trailing_slashes_disabled() {
let app = Application::new() let mut 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(
@ -479,7 +479,7 @@ mod tests {
#[test] #[test]
fn test_normalize_path_merge_slashes() { fn test_normalize_path_merge_slashes() {
let app = Application::new() let mut 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()))
@ -515,7 +515,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 mut 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))

View File

@ -70,13 +70,13 @@ impl StaticResponse {
impl<S> Handler<S> for StaticResponse { impl<S> Handler<S> for StaticResponse {
type Result = HttpResponse; type Result = HttpResponse;
fn handle(&self, _: HttpRequest<S>) -> HttpResponse { fn handle(&mut self, _: HttpRequest<S>) -> HttpResponse {
HttpResponse::new(self.0, Body::Empty) HttpResponse::new(self.0, Body::Empty)
} }
} }
impl<S> RouteHandler<S> for StaticResponse { impl<S> RouteHandler<S> for StaticResponse {
fn handle(&self, _: HttpRequest<S>) -> Reply { fn handle(&mut self, _: HttpRequest<S>) -> Reply {
Reply::response(HttpResponse::new(self.0, Body::Empty)) Reply::response(HttpResponse::new(self.0, Body::Empty))
} }
} }

View File

@ -87,7 +87,7 @@ impl HttpMessage {
} }
/// An HTTP Request /// An HTTP Request
pub struct HttpRequest<S=()>(SharedHttpMessage, Option<Rc<S>>, Option<Router<S>>); pub struct HttpRequest<S=()>(SharedHttpMessage, Option<Rc<S>>, Option<Router>);
impl HttpRequest<()> { impl HttpRequest<()> {
/// Construct a new Request. /// Construct a new Request.
@ -146,7 +146,7 @@ impl HttpRequest<()> {
#[inline] #[inline]
/// Construct new http request with state. /// Construct new http request with state.
pub fn with_state<S>(self, state: Rc<S>, router: Router<S>) -> HttpRequest<S> { pub fn with_state<S>(self, state: Rc<S>, router: Router) -> HttpRequest<S> {
HttpRequest(self.0, Some(state), Some(router)) HttpRequest(self.0, Some(state), Some(router))
} }
} }
@ -277,7 +277,7 @@ impl<S> HttpRequest<S> {
/// This method returns reference to current `Router` object. /// This method returns reference to current `Router` object.
#[inline] #[inline]
pub fn router(&self) -> Option<&Router<S>> { pub fn router(&self) -> Option<&Router> {
self.2.as_ref() self.2.as_ref()
} }
@ -736,11 +736,11 @@ mod tests {
let mut req = HttpRequest::new(Method::GET, Uri::from_str("/value/?id=test").unwrap(), let mut req = HttpRequest::new(Method::GET, Uri::from_str("/value/?id=test").unwrap(),
Version::HTTP_11, HeaderMap::new(), None); Version::HTTP_11, HeaderMap::new(), None);
let mut resource = Resource::default(); let mut resource = Resource::<()>::default();
resource.name("index"); resource.name("index");
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert(Pattern::new("index", "/{key}/"), Some(resource)); map.insert(Pattern::new("index", "/{key}/"), Some(resource));
let router = Router::new("", map); let (router, _) = Router::new("", map);
assert!(router.recognize(&mut req).is_some()); assert!(router.recognize(&mut req).is_some());
assert_eq!(req.match_info().get("key"), Some("value")); assert_eq!(req.match_info().get("key"), Some("value"));
@ -843,11 +843,11 @@ mod tests {
let req = HttpRequest::new( let req = HttpRequest::new(
Method::GET, Uri::from_str("/").unwrap(), Version::HTTP_11, headers, None); Method::GET, Uri::from_str("/").unwrap(), Version::HTTP_11, headers, None);
let mut resource = Resource::default(); let mut resource = Resource::<()>::default();
resource.name("index"); resource.name("index");
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert(Pattern::new("index", "/user/{name}.{ext}"), Some(resource)); map.insert(Pattern::new("index", "/user/{name}.{ext}"), Some(resource));
let router = Router::new("", map); let (router, _) = Router::new("", map);
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"));
@ -874,7 +874,7 @@ mod tests {
resource.name("index"); resource.name("index");
let mut map = HashMap::new(); let mut map = HashMap::new();
map.insert(Pattern::new("youtube", "https://youtube.com/watch/{video_id}"), None); map.insert(Pattern::new("youtube", "https://youtube.com/watch/{video_id}"), None);
let router = Router::new("", map); let (router, _) = Router::new::<()>("", map);
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);

View File

@ -15,8 +15,8 @@ use httprequest::HttpRequest;
use httpresponse::HttpResponse; use httpresponse::HttpResponse;
use middlewares::{Middleware, Finished, Started, Response}; use middlewares::{Middleware, Finished, Started, Response};
type Handler<S> = Fn(HttpRequest<S>) -> Reply; type Handler<S> = FnMut(HttpRequest<S>) -> Reply;
pub(crate) type PipelineHandler<'a, S> = &'a Fn(HttpRequest<S>) -> Reply; pub(crate) type PipelineHandler<'a, S> = &'a mut FnMut(HttpRequest<S>) -> Reply;
pub struct Pipeline<S>(PipelineInfo<S>, PipelineState<S>); pub struct Pipeline<S>(PipelineInfo<S>, PipelineState<S>);
@ -287,7 +287,7 @@ impl<S> StartMiddlewares<S> {
let len = info.mws.len(); let len = info.mws.len();
loop { loop {
if info.count == len { if info.count == len {
let reply = (&*handler)(info.req.clone()); let reply = (&mut *handler)(info.req.clone());
return WaitingResponse::init(info, reply) return WaitingResponse::init(info, reply)
} else { } else {
match info.mws[info.count].start(&mut info.req) { match info.mws[info.count].start(&mut info.req) {
@ -329,7 +329,7 @@ impl<S> StartMiddlewares<S> {
return Ok(RunMiddlewares::init(info, resp)); return Ok(RunMiddlewares::init(info, resp));
} }
if info.count == len { if info.count == len {
let reply = (unsafe{&*self.hnd})(info.req.clone()); let reply = (unsafe{&mut *self.hnd})(info.req.clone());
return Ok(WaitingResponse::init(info, reply)); return Ok(WaitingResponse::init(info, reply));
} else { } else {
loop { loop {

View File

@ -126,10 +126,10 @@ impl<S: 'static> Resource<S> {
self.routes.last_mut().unwrap().f(handler) self.routes.last_mut().unwrap().f(handler)
} }
pub(crate) fn handle(&self, mut req: HttpRequest<S>, default: Option<&Resource<S>>) pub(crate) fn handle(&mut self, mut req: HttpRequest<S>, default: Option<&mut Resource<S>>)
-> Reply -> Reply
{ {
for route in &self.routes { for route in &mut self.routes {
if route.check(&mut req) { if route.check(&mut req) {
return route.handle(req) return route.handle(req)
} }

View File

@ -36,7 +36,7 @@ impl<S: 'static> Route<S> {
true true
} }
pub(crate) fn handle(&self, req: HttpRequest<S>) -> Reply { pub(crate) fn handle(&mut self, req: HttpRequest<S>) -> Reply {
self.handler.handle(req) self.handler.handle(req)
} }

View File

@ -12,20 +12,20 @@ use server::ServerSettings;
/// Interface for application router. /// Interface for application router.
pub struct Router<S>(Rc<Inner<S>>); pub struct Router(Rc<Inner>);
struct Inner<S> { struct Inner {
prefix: String, prefix: String,
regset: RegexSet, regset: RegexSet,
named: HashMap<String, (Pattern, bool)>, named: HashMap<String, (Pattern, bool)>,
patterns: Vec<Pattern>, patterns: Vec<Pattern>,
resources: Vec<Resource<S>>,
srv: ServerSettings, srv: ServerSettings,
} }
impl<S> Router<S> { impl Router {
/// Create new router /// Create new router
pub fn new(prefix: &str, map: HashMap<Pattern, Option<Resource<S>>>) -> Router<S> pub fn new<S>(prefix: &str, map: HashMap<Pattern, Option<Resource<S>>>)
-> (Router, Vec<Resource<S>>)
{ {
let prefix = prefix.trim().trim_right_matches('/').to_owned(); let prefix = prefix.trim().trim_right_matches('/').to_owned();
let mut named = HashMap::new(); let mut named = HashMap::new();
@ -46,13 +46,12 @@ impl<S> Router<S> {
} }
} }
Router(Rc::new( (Router(Rc::new(
Inner{ prefix: prefix, Inner{ prefix: prefix,
regset: RegexSet::new(&paths).unwrap(), regset: RegexSet::new(&paths).unwrap(),
named: named, named: named,
patterns: patterns, patterns: patterns,
resources: resources, srv: ServerSettings::default() })), resources)
srv: ServerSettings::default() }))
} }
pub(crate) fn set_server_settings(&mut self, settings: ServerSettings) { pub(crate) fn set_server_settings(&mut self, settings: ServerSettings) {
@ -72,7 +71,7 @@ impl<S> Router<S> {
} }
/// Query for matched resource /// Query for matched resource
pub fn recognize(&self, req: &mut HttpRequest<S>) -> Option<&Resource<S>> { pub fn recognize<S>(&self, req: &mut HttpRequest<S>) -> Option<usize> {
let mut idx = None; let mut idx = None;
{ {
let path = &req.path()[self.0.prefix.len()..]; let path = &req.path()[self.0.prefix.len()..];
@ -88,7 +87,7 @@ impl<S> Router<S> {
if let Some(idx) = idx { if let Some(idx) = idx {
let path: &str = unsafe{ mem::transmute(&req.path()[self.0.prefix.len()..]) }; let path: &str = unsafe{ mem::transmute(&req.path()[self.0.prefix.len()..]) };
self.0.patterns[idx].update_match_info(path, req); self.0.patterns[idx].update_match_info(path, req);
return Some(&self.0.resources[idx]) return Some(idx)
} else { } else {
None None
} }
@ -128,8 +127,8 @@ impl<S> Router<S> {
} }
} }
impl<S: 'static> Clone for Router<S> { impl Clone for Router {
fn clone(&self) -> Router<S> { fn clone(&self) -> Router {
Router(Rc::clone(&self.0)) Router(Rc::clone(&self.0))
} }
} }
@ -315,7 +314,7 @@ mod tests {
routes.insert(Pattern::new("", "/v{val}/{val2}/index.html"), Some(Resource::default())); routes.insert(Pattern::new("", "/v{val}/{val2}/index.html"), Some(Resource::default()));
routes.insert(Pattern::new("", "/v/{tail:.*}"), Some(Resource::default())); routes.insert(Pattern::new("", "/v/{tail:.*}"), Some(Resource::default()));
routes.insert(Pattern::new("", "{test}/index.html"), Some(Resource::default())); routes.insert(Pattern::new("", "{test}/index.html"), Some(Resource::default()));
let rec = Router::new("", routes); let (rec, _) = Router::new::<()>("", routes);
let mut req = HttpRequest::new( let mut req = HttpRequest::new(
Method::GET, Uri::from_str("/name").unwrap(), Method::GET, Uri::from_str("/name").unwrap(),

View File

@ -1,5 +1,6 @@
use std::{io, net, thread}; use std::{io, net, thread};
use std::rc::Rc; use std::rc::Rc;
use std::cell::{RefCell, RefMut};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -447,7 +448,7 @@ struct Worker<H> {
} }
pub(crate) struct WorkerSettings<H> { pub(crate) struct WorkerSettings<H> {
h: Vec<H>, h: RefCell<Vec<H>>,
enabled: bool, enabled: bool,
keep_alive: u64, keep_alive: u64,
bytes: Rc<helpers::SharedBytesPool>, bytes: Rc<helpers::SharedBytesPool>,
@ -457,7 +458,7 @@ pub(crate) struct WorkerSettings<H> {
impl<H> WorkerSettings<H> { impl<H> WorkerSettings<H> {
pub(crate) fn new(h: Vec<H>, keep_alive: Option<u64>) -> WorkerSettings<H> { pub(crate) fn new(h: Vec<H>, keep_alive: Option<u64>) -> WorkerSettings<H> {
WorkerSettings { WorkerSettings {
h: h, h: RefCell::new(h),
enabled: if let Some(ka) = keep_alive { ka > 0 } else { false }, enabled: if let Some(ka) = keep_alive { ka > 0 } else { false },
keep_alive: keep_alive.unwrap_or(0), keep_alive: keep_alive.unwrap_or(0),
bytes: Rc::new(helpers::SharedBytesPool::new()), bytes: Rc::new(helpers::SharedBytesPool::new()),
@ -465,8 +466,8 @@ impl<H> WorkerSettings<H> {
} }
} }
pub fn handlers(&self) -> &Vec<H> { pub fn handlers(&self) -> RefMut<Vec<H>> {
&self.h self.h.borrow_mut()
} }
pub fn keep_alive(&self) -> u64 { pub fn keep_alive(&self) -> u64 {
self.keep_alive self.keep_alive