pub struct Cx<'r, I> { /* private fields */ }Expand description
The context a handler receives: proof that the request passed its route’s access check, the identity it carries, and the reply.
There is no public way to make one: web-net builds it only after the gate cleared the request.
Implementations§
Source§impl<'r, I> Cx<'r, I>
impl<'r, I> Cx<'r, I>
Sourcepub fn param(&self, name: &str) -> Option<Cow<'r, str>>
pub fn param(&self, name: &str) -> Option<Cow<'r, str>>
A route parameter (:id or *rest), percent-decoded.
Sourcepub fn param_as<T: FromStr>(&self, name: &str) -> Result<T>
pub fn param_as<T: FromStr>(&self, name: &str) -> Result<T>
A route parameter parsed as T. A value that does not parse means
the page does not exist (/users/abc for a numeric id): 404.
§Errors
404 route.param when the parameter is missing or does not parse.
Examples found in repository?
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15 let app = App::builder()
16 .host("127.0.0.1:8091")
17 .development()
18 .base("/app")
19 .route(
20 get("/", |cx| {
21 let users = cx.url("/users/7");
22 cx.html(
23 200,
24 &format!("<h1>Hello</h1><a href=\"{users}\">user 7</a>"),
25 );
26 Ok(())
27 })
28 .public(),
29 )
30 .route(
31 get("/users/:id", |cx| {
32 let id: u64 = cx.param_as("id")?;
33 cx.text(200, &format!("user {id}"));
34 Ok(())
35 })
36 .public(),
37 )
38 .route(
39 Route::at("/contact")
40 .get(|cx| {
41 cx.html(200, "<form method=post><button>Send</button></form>");
42 Ok(())
43 })
44 .post(|cx| cx.see_other("/"))
45 .public(),
46 )
47 .build()?;
48
49 let server = serve_net::Server::builder()
50 .listener(serve_net::ListenerSpec::tcp("web", "127.0.0.1:8091"))
51 .serve(app)?;
52 println!("listening on http://127.0.0.1:8091/app/");
53 server.wait();
54 Ok(())
55}Sourcepub fn query(&self, name: &str) -> Result<Option<Cow<'r, str>>>
pub fn query(&self, name: &str) -> Result<Option<Cow<'r, str>>>
The first value of a query parameter, decoded (+ is a space).
§Errors
400 query.duplicate when the name appears twice (parameter
pollution is refused, never resolved by picking one), 400
query.invalid when the value does not decode to UTF-8.
Sourcepub fn body(&self) -> Result<&'r [u8]>
pub fn body(&self) -> Result<&'r [u8]>
The request body.
§Errors
None today; reading the body is fallible so CSRF and body inspection can refuse it in later versions without changing handlers.
Sourcepub fn set_header(&mut self, name: &str, value: impl AsRef<[u8]>) -> &mut Self
pub fn set_header(&mut self, name: &str, value: impl AsRef<[u8]>) -> &mut Self
Adds a reply field. A name that is not a token, a value with a
control character, or a framing field (content-length, …) turns
the reply into a 500 when the handler returns.
Sourcepub fn body_bytes(&mut self, bytes: &[u8]) -> &mut Self
pub fn body_bytes(&mut self, bytes: &[u8]) -> &mut Self
Sets the body.
Sourcepub fn html(&mut self, status: u16, html: &str) -> &mut Self
pub fn html(&mut self, status: u16, html: &str) -> &mut Self
Status, content-type: text/html; charset=utf-8, and the HTML.
Examples found in repository?
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15 let app = App::builder()
16 .host("127.0.0.1:8091")
17 .development()
18 .base("/app")
19 .route(
20 get("/", |cx| {
21 let users = cx.url("/users/7");
22 cx.html(
23 200,
24 &format!("<h1>Hello</h1><a href=\"{users}\">user 7</a>"),
25 );
26 Ok(())
27 })
28 .public(),
29 )
30 .route(
31 get("/users/:id", |cx| {
32 let id: u64 = cx.param_as("id")?;
33 cx.text(200, &format!("user {id}"));
34 Ok(())
35 })
36 .public(),
37 )
38 .route(
39 Route::at("/contact")
40 .get(|cx| {
41 cx.html(200, "<form method=post><button>Send</button></form>");
42 Ok(())
43 })
44 .post(|cx| cx.see_other("/"))
45 .public(),
46 )
47 .build()?;
48
49 let server = serve_net::Server::builder()
50 .listener(serve_net::ListenerSpec::tcp("web", "127.0.0.1:8091"))
51 .serve(app)?;
52 println!("listening on http://127.0.0.1:8091/app/");
53 server.wait();
54 Ok(())
55}Sourcepub fn text(&mut self, status: u16, text: &str) -> &mut Self
pub fn text(&mut self, status: u16, text: &str) -> &mut Self
Status, content-type: text/plain; charset=utf-8, and the text.
Examples found in repository?
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15 let app = App::builder()
16 .host("127.0.0.1:8091")
17 .development()
18 .base("/app")
19 .route(
20 get("/", |cx| {
21 let users = cx.url("/users/7");
22 cx.html(
23 200,
24 &format!("<h1>Hello</h1><a href=\"{users}\">user 7</a>"),
25 );
26 Ok(())
27 })
28 .public(),
29 )
30 .route(
31 get("/users/:id", |cx| {
32 let id: u64 = cx.param_as("id")?;
33 cx.text(200, &format!("user {id}"));
34 Ok(())
35 })
36 .public(),
37 )
38 .route(
39 Route::at("/contact")
40 .get(|cx| {
41 cx.html(200, "<form method=post><button>Send</button></form>");
42 Ok(())
43 })
44 .post(|cx| cx.see_other("/"))
45 .public(),
46 )
47 .build()?;
48
49 let server = serve_net::Server::builder()
50 .listener(serve_net::ListenerSpec::tcp("web", "127.0.0.1:8091"))
51 .serve(app)?;
52 println!("listening on http://127.0.0.1:8091/app/");
53 server.wait();
54 Ok(())
55}Adds a Set-Cookie field built with cookie-net (re-exported as
web_net::cookie_net).
use web_net::{App, get, cookie_net::SetCookie};
let app = App::builder()
.route(get("/", |cx| {
cx.set_cookie(&SetCookie::new("theme", "dark").map_err(|_| web_net::Error::internal("cookie"))?);
cx.text(200, "ok");
Ok(())
}).public())
.build()?;
let r = serve_net::testing::respond(&app, b"GET / HTTP/1.1\r\nHost: a\r\n\r\n");
assert!(r.header("set-cookie").is_some());Sourcepub fn not_modified(&mut self, tag: &str) -> bool
pub fn not_modified(&mut self, tag: &str) -> bool
The conditional fast path for a page: sets ETag: "<tag>" and, when
the request’s If-None-Match matches it (a GET or HEAD), turns the
reply into 304 Not Modified and returns true, so the handler
returns before building the page.
tag is the opaque part (letters, digits, and -._~ are safe), for
example a revision number. An unusable tag sets nothing and returns
false.
use web_net::{App, get};
let app = App::builder()
.route(get("/", |cx| {
if cx.not_modified("rev-7") {
return Ok(());
}
cx.html(200, "<h1>page</h1>");
Ok(())
}).public())
.build()?;
let r = serve_net::testing::respond(&app, b"GET / HTTP/1.1\r\nHost: a\r\nIf-None-Match: \"rev-7\"\r\n\r\n");
assert_eq!(r.status, 304);Sourcepub fn url(&self, path: &str) -> String
pub fn url(&self, path: &str) -> String
The site-relative path as a URL path: the site’s base path in
front (/blog + /posts/1). Every link a page writes goes through
this, so the site works installed in a folder.
Examples found in repository?
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15 let app = App::builder()
16 .host("127.0.0.1:8091")
17 .development()
18 .base("/app")
19 .route(
20 get("/", |cx| {
21 let users = cx.url("/users/7");
22 cx.html(
23 200,
24 &format!("<h1>Hello</h1><a href=\"{users}\">user 7</a>"),
25 );
26 Ok(())
27 })
28 .public(),
29 )
30 .route(
31 get("/users/:id", |cx| {
32 let id: u64 = cx.param_as("id")?;
33 cx.text(200, &format!("user {id}"));
34 Ok(())
35 })
36 .public(),
37 )
38 .route(
39 Route::at("/contact")
40 .get(|cx| {
41 cx.html(200, "<form method=post><button>Send</button></form>");
42 Ok(())
43 })
44 .post(|cx| cx.see_other("/"))
45 .public(),
46 )
47 .build()?;
48
49 let server = serve_net::Server::builder()
50 .listener(serve_net::ListenerSpec::tcp("web", "127.0.0.1:8091"))
51 .serve(app)?;
52 println!("listening on http://127.0.0.1:8091/app/");
53 server.wait();
54 Ok(())
55}Sourcepub fn see_other(&mut self, path: &str) -> Result
pub fn see_other(&mut self, path: &str) -> Result
303 See Other to a site-relative path: the answer to a form that
was accepted, so a reload does not post it again.
§Errors
500 redirect.not_local when path is not a local path (it must
start with one /): redirects to other hosts are never built from a
string a handler passes along.
Examples found in repository?
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15 let app = App::builder()
16 .host("127.0.0.1:8091")
17 .development()
18 .base("/app")
19 .route(
20 get("/", |cx| {
21 let users = cx.url("/users/7");
22 cx.html(
23 200,
24 &format!("<h1>Hello</h1><a href=\"{users}\">user 7</a>"),
25 );
26 Ok(())
27 })
28 .public(),
29 )
30 .route(
31 get("/users/:id", |cx| {
32 let id: u64 = cx.param_as("id")?;
33 cx.text(200, &format!("user {id}"));
34 Ok(())
35 })
36 .public(),
37 )
38 .route(
39 Route::at("/contact")
40 .get(|cx| {
41 cx.html(200, "<form method=post><button>Send</button></form>");
42 Ok(())
43 })
44 .post(|cx| cx.see_other("/"))
45 .public(),
46 )
47 .build()?;
48
49 let server = serve_net::Server::builder()
50 .listener(serve_net::ListenerSpec::tcp("web", "127.0.0.1:8091"))
51 .serve(app)?;
52 println!("listening on http://127.0.0.1:8091/app/");
53 server.wait();
54 Ok(())
55}Sourcepub fn render(&mut self, view: &dyn View) -> Result
pub fn render(&mut self, view: &dyn View) -> Result
Renders the route’s template (declared with
Route::template) against view into the
body. The status stays as set (200 by default); content-type is
HTML unless the handler set one.
§Errors
500 render.no_engine or render.no_template when nothing can
render; the engine’s own RenderError as a 500;
a checkpoint’s denial.