Skip to main content

Cx

Struct Cx 

Source
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>

Source

pub fn request(&self) -> &Request<'r>

The request.

Source

pub fn method(&self) -> Method

The method.

Source

pub fn path(&self) -> &'r str

The canonical path inside the site.

Source

pub fn header(&self, name: &str) -> Option<&'r [u8]>

The first value of a request field.

Source

pub fn identity(&self) -> &'r I

Who the request comes from: always present, possibly a guest.

Source

pub fn id(&self) -> RequestId

The request’s reference, as shown on error pages.

Source

pub fn param(&self, name: &str) -> Option<Cow<'r, str>>

A route parameter (:id or *rest), percent-decoded.

Source

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?
examples/hello.rs (line 32)
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}
Source

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.

Source

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.

Source

pub fn status(&mut self, status: u16) -> &mut Self

Sets the status (default 200).

Source

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.

Source

pub fn body_bytes(&mut self, bytes: &[u8]) -> &mut Self

Sets the body.

Source

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?
examples/hello.rs (lines 22-25)
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}
Source

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?
examples/hello.rs (line 33)
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());
Source

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);
Source

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?
examples/hello.rs (line 21)
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}
Source

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?
examples/hello.rs (line 44)
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}
Source

pub fn redirect(&mut self, status: u16, path: &str) -> Result

A redirect with status (301, 302, 303, 307, 308) to a site-relative path.

§Errors

As see_other; 500 redirect.status for a status that is not a redirect.

Source

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.

Source

pub fn render_named(&mut self, name: &str, view: &dyn View) -> Result

Renders the template name against view. The name is resolved by the engine on every call; prefer render with a template declared on the route, resolved once at build.

§Errors

As render.

Trait Implementations§

Source§

impl<I> Debug for Cx<'_, I>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'r, I> !RefUnwindSafe for Cx<'r, I>

§

impl<'r, I> !UnwindSafe for Cx<'r, I>

§

impl<'r, I> Forget for Cx<'r, I>

§

impl<'r, I> Freeze for Cx<'r, I>
where &'r I: Freeze,

§

impl<'r, I> Send for Cx<'r, I>
where &'r I: Send,

§

impl<'r, I> Sync for Cx<'r, I>
where &'r I: Sync,

§

impl<'r, I> Unpin for Cx<'r, I>
where &'r I: Unpin,

§

impl<'r, I> UnsafeUnpin for Cx<'r, I>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.