Skip to main content

Sites

Struct Sites 

Source
pub struct Sites<G: Gate = Open, E: Render = NoRender> { /* private fields */ }
Expand description

A table of applications, chosen per request by host and base path: an application that lists the request’s host (or an alias of it) wins over one that answers any host, and among those, the longest base path that holds the request’s path. A request no application claims goes to the first one added, which answers it by its own rules (421 for a host it does not serve, 404 outside its base).

use web_net::{App, Sites, get};

let blog = App::builder()
    .host("example.com")
    .base("/blog")
    .route(get("/", |cx| cx.text(200, "blog")))
    .build()?;
let shop = App::builder()
    .host("shop.example.com")
    .route(get("/", |cx| cx.text(200, "shop")))
    .build()?;
let main = App::builder()
    .host("example.com")
    .route(get("/", |cx| cx.text(200, "home")))
    .build()?;
let sites = Sites::new().site(main).site(blog).site(shop);

use serve_net::testing::respond;
assert_eq!(respond(&sites, b"GET /blog/ HTTP/1.1\r\nHost: example.com\r\n\r\n").text(), "blog");
assert_eq!(respond(&sites, b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n").text(), "home");
assert_eq!(respond(&sites, b"GET / HTTP/1.1\r\nHost: shop.example.com\r\n\r\n").text(), "shop");
assert_eq!(respond(&sites, b"GET / HTTP/1.1\r\nHost: other.example\r\n\r\n").status, 421);

Implementations§

Source§

impl<G: Gate, E: Render> Sites<G, E>

Source

pub fn new() -> Self

An empty table.

use web_net::Sites;

// With no application, every request is answered with 421.
let sites: Sites = Sites::new();
let r = serve_net::testing::respond(&sites, b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n");
assert_eq!(r.status, 421);
Source

pub fn site(self, app: App<G, E>) -> Self

Adds an application. The first one added answers what no other claims.

use serve_net::testing::respond;
use web_net::{App, Sites, get};

let main = App::builder().host("example.com").route(get("/", |cx| cx.text(200, "home"))).build()?;
let shop = App::builder().host("shop.example.com").route(get("/", |cx| cx.text(200, "shop"))).build()?;
let sites = Sites::new().site(main).site(shop);
assert_eq!(respond(&sites, b"GET / HTTP/1.1\r\nHost: shop.example.com\r\n\r\n").text(), "shop");
assert_eq!(respond(&sites, b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n").text(), "home");
Source

pub fn pick(&self, req: &HttpRequest<'_>) -> Option<&App<G, E>>

The application for a request, if the table has any.

use serve_net::{Envelope, HttpReply, HttpRequest, HttpService, Outcome};
use web_net::{App, Sites, get};

// A front that picks the application itself before it answers.
struct Front(Sites);
impl HttpService for Front {
    fn call(&self, req: &HttpRequest<'_>, env: &Envelope, reply: &mut HttpReply) -> Outcome {
        let app = self.0.pick(req).expect("one site is configured");
        app.respond(req, env, None, reply).outcome
    }
}

let shop = App::builder().host("shop.example.com").route(get("/", |cx| cx.text(200, "shop"))).build()?;
let front = Front(Sites::new().site(shop));
let r = serve_net::testing::respond(&front, b"GET / HTTP/1.1\r\nHost: shop.example.com\r\n\r\n");
assert_eq!(r.text(), "shop");
Source

pub fn listen(self, addr: impl ToSocketAddrs) -> Result<Running, ServeError>

Serves every site on addr, as App::listen does for one.

§Errors

As App::listen.

use web_net::{App, Sites, get};

let main = App::builder().host("example.com").route(get("/", |cx| cx.text(200, "home"))).build()?;
let shop = App::builder().host("shop.example.com").route(get("/", |cx| cx.text(200, "shop"))).build()?;
Sites::new().site(main).site(shop).listen("127.0.0.1:8080")?.wait();
Source

pub fn respond( &self, req: &HttpRequest<'_>, env: &Envelope, who: Option<&G::Identity>, reply: &mut HttpReply, ) -> Served

As App::respond on the chosen application.

use serve_net::{Envelope, HttpReply, HttpRequest, HttpService, Outcome};
use web_net::{App, Guest, Sites, get};

// A front that authenticated every request already.
struct Front(Sites);
impl HttpService for Front {
    fn call(&self, req: &HttpRequest<'_>, env: &Envelope, reply: &mut HttpReply) -> Outcome {
        self.0.respond(req, env, Some(&Guest), reply).outcome
    }
}

let app = App::builder().route(get("/", |cx| cx.text(200, "hi"))).build()?;
let r = serve_net::testing::respond(&Front(Sites::new().site(app)), b"GET / HTTP/1.1\r\nHost: localhost\r\n\r\n");
assert_eq!(r.text(), "hi");

Trait Implementations§

Source§

impl<G: Gate, E: Render> Debug for Sites<G, E>

Source§

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

Formats the value using the given formatter. Read more
Source§

impl<G: Gate, E: Render> Default for Sites<G, E>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<G: Gate, E: Render> HttpService for Sites<G, E>

Source§

fn call( &self, request: &HttpRequest<'_>, env: &Envelope, reply: &mut HttpReply, ) -> Outcome

The request is complete.
Source§

fn done(&self, env: &Envelope, _finished: &Finished)

Exactly once per request that reached head, on every path.
Source§

const WORK: WorkClass = WorkClass::Quick

How the service behaves.
Source§

fn head(&self, head: &HttpHead<'_>, env: &mut Envelope) -> HeadAction

The head is complete; before admission and before any body byte.
Source§

fn upgraded(&self, env: &Envelope, conn: UpgradedConn)

After the 101 for an upgrade this service asked for in head left, and after done for that request. The conversation itself belongs to the upgrade target (a WebSocketService, feature ws).

Auto Trait Implementations§

§

impl<G = Open, E = NoRender> !RefUnwindSafe for Sites<G, E>

§

impl<G = Open, E = NoRender> !UnwindSafe for Sites<G, E>

§

impl<G, E> Forget for Sites<G, E>

§

impl<G, E> Freeze for Sites<G, E>
where Vec<App<G, E>>: Freeze,

§

impl<G, E> Move for Sites<G, E>

§

impl<G, E> Send for Sites<G, E>
where Vec<App<G, E>>: Send,

§

impl<G, E> Sync for Sites<G, E>
where Vec<App<G, E>>: Sync,

§

impl<G, E> Unpin for Sites<G, E>
where Vec<App<G, E>>: Unpin,

§

impl<G, E> UnsafeUnpin for Sites<G, E>
where Vec<App<G, E>>: UnsafeUnpin,

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<S> Service<HttpFamily> for S
where S: HttpService,

Source§

const WORK: WorkClass = <S as HttpService>::WORK

How the service behaves.
Source§

fn head(&self, head: &HttpHead<'_>, env: &mut Envelope) -> HeadAction

The head is complete; before admission and any body byte.
Source§

fn call( &self, request: &HttpRequest<'_>, env: &Envelope, reply: &mut Reply<HttpFamily>, ) -> Outcome

The request is complete.
Source§

fn upgraded(&self, env: &Envelope, conn: UpgradedConn)

After a switch response the service asked for left.
Source§

fn done(&self, env: &Envelope, finished: &Finished)

Exactly once per request that reached head.
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.