Struct afire::Server

source ·
pub struct Server<State: 'static + Send + Sync = ()> {
    pub port: u16,
    pub ip: IpAddr,
    pub routes: Vec<Route<State>>,
    pub middleware: Vec<Box<dyn Middleware + Send + Sync>>,
    pub state: Option<Arc<State>>,
    pub error_handler: Box<dyn Fn(Option<Arc<State>>, &Box<Result<Rc<Request>>>, String) -> Response + Send + Sync>,
    pub default_headers: Headers,
    pub keep_alive: bool,
    pub socket_timeout: Option<Duration>,
}
Expand description

Defines a server.

Fields§

§port: u16

Port to listen on.

§ip: IpAddr

Ip address to listen on.

§routes: Vec<Route<State>>

Routes to handle.

§middleware: Vec<Box<dyn Middleware + Send + Sync>>

Middleware

§state: Option<Arc<State>>

Server wide App State

§error_handler: Box<dyn Fn(Option<Arc<State>>, &Box<Result<Rc<Request>>>, String) -> Response + Send + Sync>

Default response for internal server errors

§default_headers: Headers

Headers automatically added to every response.

§keep_alive: bool

Weather to allow keep-alive connections. If this is set to false, the server will close the connection after every request. This is enabled by default.

§socket_timeout: Option<Duration>

Socket Timeout

Implementations§

source§

impl<State: Send + Sync> Server<State>

Implementations for Server

source

pub fn new(raw_ip: impl ToHostAddress, port: u16) -> Self

Creates a new server on the specified address and port. raw_ip can be either an IP address or ‘localhost’, which expands to 127.0.0.1.

Example
// Create a server for localhost on port 8080
// Note: The server has not been started yet
let mut server = Server::<()>::new("localhost", 8080);
Examples found in repository?
examples/middle_bench.rs (line 25)
23
24
25
26
27
28
29
30
31
32
33
34
35
fn main() {
    set_log_level(Level::Debug);
    let mut server = Server::<()>::new([127, 0, 0, 1], 8080);
    server.route(Method::ANY, "**", |_req| Response::new());

    Middleware1.attach(&mut server);
    Middleware2.attach(&mut server);
    Middleware3.attach(&mut server);
    Middleware4.attach(&mut server);
    Middleware5.attach(&mut server);

    server.start().unwrap();
}
More examples
Hide additional examples
examples/basic/trace.rs (line 49)
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    fn exec(&self) {
        // Set the log level to Trace (shows some helpful information during startup)
        // The default is Level::Error
        set_log_level(Level::Trace);
        trace!(Level::Trace, "Setting log level to Trace");
        trace!(Level::Error, "Example error message");

        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        server.route(Method::GET, "/", |req| {
            // The default log level is Level::Trace so this will be logged
            trace!("Request from {}", req.address.ip());
            Response::new()
        });

        server.start().unwrap();
    }
examples/basic/middleware.rs (line 56)
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        // Define a basic route
        server.route(Method::GET, "/", |_req| {
            Response::new().text("Hello World!").content(Content::TXT)
        });

        // Here is where we will attach our Middleware to the Server
        // This is super easy
        Log.attach(&mut server);

        // You can now goto http://localhost:8080 you should see that the request is printed to the console
        // It should look something like this: `[127.0.0.1] GET `

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
examples/basic/state.rs (line 26)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    fn exec(&self) {
        // Create a server on localhost port 8080 with a state of App
        let mut server = Server::<App>::new("localhost", 8080).state(App::default());

        // Add catch all route that takes in state and the request
        server.stateful_route(Method::ANY, "**", |sta, _req| {
            // Respond with and increment request count
            Response::new().text(sta.count.fetch_add(1, Ordering::Relaxed))
        });

        // Start the server
        // This will block the current thread
        // Because there is a stateful route, this will panic if no state is set
        server.start().unwrap();

        // Now go to http://localhost:8080
        // You should see the request count increment each time you refresh
    }
examples/basic/threading.rs (line 26)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        // Define a handler for GET "/"
        server.route(Method::GET, "/", |_req| {
            Response::new()
                // hopefully the ThreadId.as_u64 method will become stable
                // until then im stuck with this mess for the example
                // It just gets the thread ID to show the user what thread is handling the request
                .text(format!(
                    "Hello from thread number {:#?}!",
                    unsafe { std::mem::transmute::<_, NonZeroU64>(thread::current().id()) }.get()
                        - 1
                ))
                .content(Content::TXT)
        });

        // Start the server with 8 threads
        // This will block the current thread
        server.start_threaded(8).unwrap();

        // If you go to http://localhost:8080 you should see the thread ID change with each refresh
    }
examples/basic/path_prams.rs (line 18)
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server: Server = Server::<()>::new("localhost", 8081);

        // Define a handler for GET "/greet/{name}"
        // This will handel requests with anything where the {name} is
        // This includes "/greet/bob", "/greet/fin"
        server.route(Method::GET, "/greet/{name}", |req| {
            // Get name path param
            let name = req.param("name").unwrap();

            // Make a nice Message to send
            let message = format!("Hello, {}", name);

            // Send Response
            Response::new().text(message).content(Content::TXT)
        });

        // Define a greet route for Darren because he is very cool
        // This will take priority over the other route as it is defined after
        server.route(Method::GET, "/greet/Darren/", |_req| {
            Response::new().text("Hello, Darren. You are very cool")
        });

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
source

pub fn start(&self) -> Result<()>

Starts the server without a threadpool. This is blocking. Will return an error if the server cant bind to the specified address, or of you are using stateful routes and have not set the state. (See Server::state)

Example
// Creates a server on localhost (127.0.0.1) port 8080
let mut server = Server::<()>::new("localhost", 8080);

/* Define Routes, Attach Middleware, etc. */

// Starts the server
// This is blocking
server.start().unwrap();
Examples found in repository?
examples/middle_bench.rs (line 34)
23
24
25
26
27
28
29
30
31
32
33
34
35
fn main() {
    set_log_level(Level::Debug);
    let mut server = Server::<()>::new([127, 0, 0, 1], 8080);
    server.route(Method::ANY, "**", |_req| Response::new());

    Middleware1.attach(&mut server);
    Middleware2.attach(&mut server);
    Middleware3.attach(&mut server);
    Middleware4.attach(&mut server);
    Middleware5.attach(&mut server);

    server.start().unwrap();
}
More examples
Hide additional examples
examples/basic/trace.rs (line 57)
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    fn exec(&self) {
        // Set the log level to Trace (shows some helpful information during startup)
        // The default is Level::Error
        set_log_level(Level::Trace);
        trace!(Level::Trace, "Setting log level to Trace");
        trace!(Level::Error, "Example error message");

        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        server.route(Method::GET, "/", |req| {
            // The default log level is Level::Trace so this will be logged
            trace!("Request from {}", req.address.ip());
            Response::new()
        });

        server.start().unwrap();
    }
examples/basic/middleware.rs (line 72)
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        // Define a basic route
        server.route(Method::GET, "/", |_req| {
            Response::new().text("Hello World!").content(Content::TXT)
        });

        // Here is where we will attach our Middleware to the Server
        // This is super easy
        Log.attach(&mut server);

        // You can now goto http://localhost:8080 you should see that the request is printed to the console
        // It should look something like this: `[127.0.0.1] GET `

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
examples/basic/state.rs (line 37)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    fn exec(&self) {
        // Create a server on localhost port 8080 with a state of App
        let mut server = Server::<App>::new("localhost", 8080).state(App::default());

        // Add catch all route that takes in state and the request
        server.stateful_route(Method::ANY, "**", |sta, _req| {
            // Respond with and increment request count
            Response::new().text(sta.count.fetch_add(1, Ordering::Relaxed))
        });

        // Start the server
        // This will block the current thread
        // Because there is a stateful route, this will panic if no state is set
        server.start().unwrap();

        // Now go to http://localhost:8080
        // You should see the request count increment each time you refresh
    }
examples/basic/path_prams.rs (line 42)
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server: Server = Server::<()>::new("localhost", 8081);

        // Define a handler for GET "/greet/{name}"
        // This will handel requests with anything where the {name} is
        // This includes "/greet/bob", "/greet/fin"
        server.route(Method::GET, "/greet/{name}", |req| {
            // Get name path param
            let name = req.param("name").unwrap();

            // Make a nice Message to send
            let message = format!("Hello, {}", name);

            // Send Response
            Response::new().text(message).content(Content::TXT)
        });

        // Define a greet route for Darren because he is very cool
        // This will take priority over the other route as it is defined after
        server.route(Method::GET, "/greet/Darren/", |_req| {
            Response::new().text("Hello, Darren. You are very cool")
        });

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
examples/basic/serve_file.rs (line 44)
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        // Define a handler for GET "/"
        server.route(Method::GET, "/", |_req| {
            // Try to open a file
            match File::open("examples/basic/data/index.html") {
                // If its found send it as response
                // Because we used File::open and not fs::read, we can use the stream method to send the file in chunks
                // This is more efficient than reading the whole file into memory and then sending it
                Ok(content) => Response::new().stream(content).content(Content::HTML),

                // If the file is not found, send a 404 response
                Err(_) => Response::new()
                    .status(Status::NotFound)
                    .text("Not Found :/")
                    .content(Content::TXT),
            }
        });

        // View the file at http://localhost:8080

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
source

pub fn start_threaded(self, threads: usize) -> Result<()>

Start the server with a threadpool of threads threads. Just like Server::start, this is blocking. Will return an error if the server cant bind to the specified address, or of you are using stateful routes and have not set the state. (See Server::state)

Example
// Import Library
use afire::{Server, Response, Header, Method};

// Creates a server on localhost (127.0.0.1) port 8080
let mut server = Server::<()>::new("localhost", 8080);

/* Define Routes, Attach Middleware, etc. */

// Starts the server with 4 threads
// This is blocking
server.start_threaded(4).unwrap();
Examples found in repository?
examples/basic/threading.rs (line 44)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        // Define a handler for GET "/"
        server.route(Method::GET, "/", |_req| {
            Response::new()
                // hopefully the ThreadId.as_u64 method will become stable
                // until then im stuck with this mess for the example
                // It just gets the thread ID to show the user what thread is handling the request
                .text(format!(
                    "Hello from thread number {:#?}!",
                    unsafe { std::mem::transmute::<_, NonZeroU64>(thread::current().id()) }.get()
                        - 1
                ))
                .content(Content::TXT)
        });

        // Start the server with 8 threads
        // This will block the current thread
        server.start_threaded(8).unwrap();

        // If you go to http://localhost:8080 you should see the thread ID change with each refresh
    }
source

pub fn default_header( self, key: impl Into<HeaderType>, value: impl AsRef<str> ) -> Self

Add a new default header to the server. This will be added to every response if it is not already present.

This will be added to every response

Example
// Create a server for localhost on port 8080
let mut server = Server::<()>::new("localhost", 8080)
    // Add a default header to the response
    .default_header("X-Server", "afire");
Examples found in repository?
examples/basic/header.rs (line 22)
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080)
            // Define server wide default headers
            // These will be send with every response
            // If the same header is defined in the route it will be put before the default header
            // Although it is not guaranteed to be the one picked by the client it usually is
            // At the bottom of this file is a representation of the order of the headers
            .default_header("X-Server-Header", "This is a server wide header")
            // You can also use the HeaderType enum to define a header type
            // This is also true with the .header method on the Response struct
            .default_header(HeaderType::Server, "afire");

        // Define a route to redirect to another website
        server.route(Method::GET, "/", |_req| {
            // Because this is all bout headers I have put the header vector here
            let headers = vec![
                // Tell the client what type of data we are sending
                afire::Header::new(HeaderType::ContentType, "text/html"),
                // Tell the client to redirect to another website
                afire::Header::new(HeaderType::Location, "https://connorcode.com"),
                // Custom header
                afire::Header::new("X-Custom-Header", "This is a custom header"),
            ];

            // Define response body
            // In this case this should only be seen if the client doesn't support redirects for some reason
            let text = "<a href=\"https://connorcode.com\">connorcode</a>";

            // The response code of 308 tells the client to redirect to the location specified in the header
            // There are other response codes you can use too
            // 301 -> Moved Permanently
            // 302 -> Found
            // 303 -> See Other
            // 307 -> Temporary Redirect
            // 308 -> Permanent Redirect
            Response::new()
                .status(Status::PermanentRedirect)
                .text(text)
                .headers(&headers)
        });

        // Now to define a route to handle client headers
        // This will just echo the headers back to the client
        server.route(Method::GET, "/headers", |req| {
            // Get the headers from the request and make a html string
            let body = req
                .headers
                .iter()
                .fold(String::new(), |old, new| old + &format!("{:?}<br />", new));

            // Create a response with the headers
            Response::new().text(body).content(Content::HTML)
        });

        // You can now goto http://localhost:8080 you should see a redirect to https://connorcode.com
        // And you can goto http://localhost:8080/headers to see the headers your client sent to the server

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
source

pub fn socket_timeout(self, socket_timeout: Duration) -> Self

Set the timeout for the socket. This will ensure that the server will not hang on a request for too long. By default there is no timeout.

Example
// Create a server for localhost on port 8080
let mut server = Server::<()>::new("localhost", 8080)
    // Set socket timeout
    .socket_timeout(Duration::from_secs(5));
source

pub fn keep_alive(self, keep_alive: bool) -> Self

Set the keep alive state of the server. This will determine if the server will keep the connection alive after a request. By default this is true. If you aren’t using a threadpool, you may want to set this to false.

Example
// Create a server for localhost on port 8080
let mut server = Server::<()>::new("localhost", 8080)
    // Disable Keep Alive
    .keep_alive(false);
source

pub fn state(self, state: State) -> Self

Set the state of a server. The state will be available to stateful routes (Server::stateful_route) and middleware. It is not mutable, so you will need to use an atomic or sync type to mutate it.

Example
// Create a server for localhost on port 8080
// Note: We can omit the type parameter here because we are setting the state
let mut server = Server::new("localhost", 8080)
    // Set server wide state
    .state(AtomicU32::new(0));

// Add a stateful route to increment the state
server.stateful_route(Method::GET, "/", |state, _req| {
    Response::new().text(state.fetch_add(1, Ordering::Relaxed))
});
Examples found in repository?
examples/basic/state.rs (line 26)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    fn exec(&self) {
        // Create a server on localhost port 8080 with a state of App
        let mut server = Server::<App>::new("localhost", 8080).state(App::default());

        // Add catch all route that takes in state and the request
        server.stateful_route(Method::ANY, "**", |sta, _req| {
            // Respond with and increment request count
            Response::new().text(sta.count.fetch_add(1, Ordering::Relaxed))
        });

        // Start the server
        // This will block the current thread
        // Because there is a stateful route, this will panic if no state is set
        server.start().unwrap();

        // Now go to http://localhost:8080
        // You should see the request count increment each time you refresh
    }
More examples
Hide additional examples
examples/application_quote_book.rs (line 39)
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
fn main() {
    set_log_level(Level::Trace);
    let app = App::new(PathBuf::from("quotes.txt"));
    app.load();

    let mut server = Server::new(Ipv4Addr::LOCALHOST, 8080).state(app);

    // Route to serve the homepage (page that has add quote form)
    server.route(Method::GET, "/", |_| {
        Response::new()
            .text(String::new() + HEADER + HOME)
            .content(Content::HTML)
    });

    // Route to handle creating new quotes.
    // After successful creation the user will be redirected to the new quotes page.
    server.stateful_route(Method::POST, "/api/new", |app, req| {
        let form = Query::from_body(&String::from_utf8_lossy(&req.body));
        let name =
            url::decode(form.get("author").expect("No author supplied")).expect("Invalid author");
        let body =
            url::decode(form.get("quote").expect("No quote supplied")).expect("Invalid quote");

        let quote = Quote {
            name,
            value: body,
            date: now(),
        };
        let mut quotes = app.quotes.write().unwrap();
        let id = quotes.len();
        quotes.insert(id.to_string(), quote);
        drop(quotes);
        trace!(Level::Trace, "Added new quote #{id}");

        app.save();
        Response::new()
            .status(Status::SeeOther)
            .header(HeaderType::Location, format!("/quote/{id}"))
            .text("Redirecting to quote page.")
    });

    server.stateful_route(Method::GET, "/quote/{id}", |app, req| {
        let id = req.param("id").unwrap();
        if id == "undefined" {
            return Response::new();
        }

        let id = id.parse::<usize>().expect("ID is not a valid integer");
        let quotes = app.quotes.read().unwrap();
        if id >= quotes.len() {
            return Response::new()
                .status(Status::NotFound)
                .text(format!("No quote with the id {id} was found."));
        }

        let quote = quotes.get(&id.to_string()).unwrap();
        Response::new().content(Content::HTML).text(
            String::new()
                + HEADER
                + &QUOTE
                    .replace("{QUOTE}", &quote.value)
                    .replace("{AUTHOR}", &quote.name)
                    .replace("{TIME}", &imp_date(quote.date)),
        )
    });

    server.stateful_route(Method::GET, "/quotes", |app, _req| {
        let mut out = String::from(HEADER);
        out.push_str("<ul>");
        for i in app.quotes.read().unwrap().iter() {
            out.push_str(&format!(
                "<li><a href=\"/quote/{}\">\"{}\" - {}</a></li>\n",
                i.0, i.1.name, i.1.value
            ));
        }

        Response::new().text(out + "</ul>").content(Content::HTML)
    });

    // Note: In a production application you may want to multithread the server with the Server::start_threaded method.
    server.start().unwrap();
}
examples/application_paste_bin.rs (line 23)
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
fn main() {
    // Create Server
    let mut server = Server::new("localhost", 8080).state(RwLock::new(Vec::new()));

    // New paste interface
    server.route(Method::GET, "/", |_req| {
        Response::new().content(Content::HTML).text(
            r#"
        <form action="/new-form" method="post">
        <input type="text" name="name" id="name" placeholder="Title">
        
        <br />
        <textarea id="body" name="body" rows="5" cols="33"></textarea>
        <input type="submit" value="Submit" />
    </form>
    "#,
        )
    });

    // New paste API handler
    server.stateful_route(Method::POST, "/new", move |app, req| {
        // Make sure paste data isn't too long
        if req.body.len() > DATA_LIMIT {
            return Response::new()
                .status(Status::NotFound)
                .text("Data too big!");
        }

        // Get the data as string
        let body_str = String::from_utf8_lossy(&req.body).to_string();

        // Get the name from the Name header
        let name = req.headers.get("Name").unwrap_or("Untitled");

        let paste = Paste {
            name: name.to_owned(),
            body: body_str,
            time: Instant::now(),
        };

        // Push this paste to the pastes vector
        let mut pastes = app.write().unwrap();
        let id = pastes.len();
        pastes.push(paste);

        // Send Redirect response
        Response::new()
            .status(Status::MovedPermanently)
            .header(HeaderType::Location, format!("/p/{id}"))
            .text(format!("Redirecting to /p/{id}."))
    });

    // New paste form handler
    server.stateful_route(Method::POST, "/new-form", |app, req| {
        // Get data from response
        let query = Query::from_body(String::from_utf8_lossy(&req.body).borrow());
        let name = url::decode(query.get("name").unwrap_or("Untitled")).expect("Invalid name");
        let body = url::decode(query.get("body").expect("No body supplied")).expect("Invalid body");

        // Make sure paste data isn't too long
        if body.len() > DATA_LIMIT {
            return Response::new()
                .status(Status::NotFound)
                .text("Data too big!");
        }

        let paste = Paste {
            name,
            body,
            time: Instant::now(),
        };

        // Push this paste to the pastes vector
        let mut pastes = app.write().unwrap();
        let id = pastes.len();
        pastes.push(paste);

        // Send Redirect response
        Response::new()
            .status(Status::MovedPermanently)
            .text("Ok")
            .header(HeaderType::Location, format!("/p/{}", id))
    });

    // Get pate handler
    server.stateful_route(Method::GET, "/p/{id}", move |app, req| {
        // Get is from path param
        let id = req.param("id").unwrap().parse::<usize>().unwrap();

        // Get the paste by id
        let paste = &app.read().unwrap()[id];

        // Send paste
        Response::new().text(&paste.body)
    });

    // View all pastes
    server.stateful_route(Method::GET, "/pastes", move |app, _req| {
        // Starter HTML
        let mut out = String::from(
            r#"<a href="/">New Paste</a><meta charset="UTF-8"><table><tr><th>Name</th><th>Date</th><th>Link</th></tr>"#,
        );

        // Add a table row for each paste
        for (i, e) in app.read().unwrap().iter().enumerate() {
            out.push_str(&format!(
                "<tr><td>{}</td><td>{}</td><td><a href=\"/p/{}\">🔗</a></td></tr>",
                e.name,
                fmt_relative_time(e.time.elapsed().as_secs()),
                i
            ));
        }

        // Send HTML
        Response::new()
            .text(format!("{}</table>", out))
            .content(Content::HTML)
    });

    server.start().unwrap();
}
source

pub fn error_handler( &mut self, res: impl Fn(Option<Arc<State>>, &Box<Result<Rc<Request>>>, String) -> Response + Send + Sync + 'static )

Set the panic handler, which is called if a route or middleware panics. This is only available if the panic_handler feature is enabled. If you don’t set it, the default response is 500 “Internal Server Error :/”. Be sure that your panic handler wont panic, because that will just panic the whole application.

Example
// Set the panic handler response
server.error_handler(|_state, _req, err| {
    Response::new()
        .status(Status::InternalServerError)
        .text(format!("Internal Server Error: {}", err))
});
Examples found in repository?
examples/basic/error_handling.rs (lines 38-47)
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        // Define a route that will panic
        server.route(Method::GET, "/panic", |_req| panic!("This is a panic!"));

        // Give the server a main page
        server.route(Method::GET, "/", |_req| {
            Response::new()
                .text(r#"<a href="/panic">PANIC</a>"#)
                .content(Content::HTML)
        });

        // You can optionally define a custom error handler
        // This can be defined anywhere in the server and will take affect for all routes
        // Its like a normal route, but it will only be called if the route panics
        let errors = AtomicUsize::new(1);
        server.error_handler(move |_state, _req, err| {
            Response::new()
                .status(Status::InternalServerError)
                .text(format!(
                    "<h1>Internal Server Error #{}</h1><br>Panicked at '{}'",
                    errors.fetch_add(1, Ordering::Relaxed),
                    err
                ))
                .content(Content::HTML)
        });

        // You can now goto http://localhost:8080/panic
        // This will cause the route to panic and return a 500 error

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
source

pub fn route( &mut self, method: Method, path: impl AsRef<str>, handler: impl Fn(&Request) -> Response + Send + Sync + 'static ) -> &mut Self

Create a new route. The path can contain parameters, which are defined with {...}, as well as wildcards, which are defined with *. (** lets you math anything after the wildcard, including /)

Example
// Define a route
server.route(Method::GET, "/greet/{name}", |req| {
    let name = req.param("name").unwrap();

    Response::new()
        .text(format!("Hello, {}!", name))
        .content(Content::TXT)
});
Examples found in repository?
examples/middle_bench.rs (line 26)
23
24
25
26
27
28
29
30
31
32
33
34
35
fn main() {
    set_log_level(Level::Debug);
    let mut server = Server::<()>::new([127, 0, 0, 1], 8080);
    server.route(Method::ANY, "**", |_req| Response::new());

    Middleware1.attach(&mut server);
    Middleware2.attach(&mut server);
    Middleware3.attach(&mut server);
    Middleware4.attach(&mut server);
    Middleware5.attach(&mut server);

    server.start().unwrap();
}
More examples
Hide additional examples
examples/basic/trace.rs (lines 51-55)
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    fn exec(&self) {
        // Set the log level to Trace (shows some helpful information during startup)
        // The default is Level::Error
        set_log_level(Level::Trace);
        trace!(Level::Trace, "Setting log level to Trace");
        trace!(Level::Error, "Example error message");

        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        server.route(Method::GET, "/", |req| {
            // The default log level is Level::Trace so this will be logged
            trace!("Request from {}", req.address.ip());
            Response::new()
        });

        server.start().unwrap();
    }
examples/basic/middleware.rs (lines 59-61)
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        // Define a basic route
        server.route(Method::GET, "/", |_req| {
            Response::new().text("Hello World!").content(Content::TXT)
        });

        // Here is where we will attach our Middleware to the Server
        // This is super easy
        Log.attach(&mut server);

        // You can now goto http://localhost:8080 you should see that the request is printed to the console
        // It should look something like this: `[127.0.0.1] GET `

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
examples/basic/threading.rs (lines 29-40)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        // Define a handler for GET "/"
        server.route(Method::GET, "/", |_req| {
            Response::new()
                // hopefully the ThreadId.as_u64 method will become stable
                // until then im stuck with this mess for the example
                // It just gets the thread ID to show the user what thread is handling the request
                .text(format!(
                    "Hello from thread number {:#?}!",
                    unsafe { std::mem::transmute::<_, NonZeroU64>(thread::current().id()) }.get()
                        - 1
                ))
                .content(Content::TXT)
        });

        // Start the server with 8 threads
        // This will block the current thread
        server.start_threaded(8).unwrap();

        // If you go to http://localhost:8080 you should see the thread ID change with each refresh
    }
examples/basic/path_prams.rs (lines 23-32)
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server: Server = Server::<()>::new("localhost", 8081);

        // Define a handler for GET "/greet/{name}"
        // This will handel requests with anything where the {name} is
        // This includes "/greet/bob", "/greet/fin"
        server.route(Method::GET, "/greet/{name}", |req| {
            // Get name path param
            let name = req.param("name").unwrap();

            // Make a nice Message to send
            let message = format!("Hello, {}", name);

            // Send Response
            Response::new().text(message).content(Content::TXT)
        });

        // Define a greet route for Darren because he is very cool
        // This will take priority over the other route as it is defined after
        server.route(Method::GET, "/greet/Darren/", |_req| {
            Response::new().text("Hello, Darren. You are very cool")
        });

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
examples/basic/serve_file.rs (lines 24-38)
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new("localhost", 8080);

        // Define a handler for GET "/"
        server.route(Method::GET, "/", |_req| {
            // Try to open a file
            match File::open("examples/basic/data/index.html") {
                // If its found send it as response
                // Because we used File::open and not fs::read, we can use the stream method to send the file in chunks
                // This is more efficient than reading the whole file into memory and then sending it
                Ok(content) => Response::new().stream(content).content(Content::HTML),

                // If the file is not found, send a 404 response
                Err(_) => Response::new()
                    .status(Status::NotFound)
                    .text("Not Found :/")
                    .content(Content::TXT),
            }
        });

        // View the file at http://localhost:8080

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
source

pub fn stateful_route( &mut self, method: Method, path: impl AsRef<str>, handler: impl Fn(Arc<State>, &Request) -> Response + Send + Sync + 'static ) -> &mut Self

Create a new stateful route. Is the same as Server::route, but the state is passed as the first parameter. (See Server::state)

Note: If you add a stateful route, you must also set the state or starting the sever will return an error.

Example
// Create a server for localhost on port 8080
let mut server = Server::<u32>::new("localhost", 8080)
   .state(101);

// Define a route
server.stateful_route(Method::GET, "/nose", |sta, req| {
    Response::new().text(sta.to_string())
});
Examples found in repository?
examples/basic/state.rs (lines 29-32)
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    fn exec(&self) {
        // Create a server on localhost port 8080 with a state of App
        let mut server = Server::<App>::new("localhost", 8080).state(App::default());

        // Add catch all route that takes in state and the request
        server.stateful_route(Method::ANY, "**", |sta, _req| {
            // Respond with and increment request count
            Response::new().text(sta.count.fetch_add(1, Ordering::Relaxed))
        });

        // Start the server
        // This will block the current thread
        // Because there is a stateful route, this will panic if no state is set
        server.start().unwrap();

        // Now go to http://localhost:8080
        // You should see the request count increment each time you refresh
    }
More examples
Hide additional examples
examples/application_quote_book.rs (lines 50-73)
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
fn main() {
    set_log_level(Level::Trace);
    let app = App::new(PathBuf::from("quotes.txt"));
    app.load();

    let mut server = Server::new(Ipv4Addr::LOCALHOST, 8080).state(app);

    // Route to serve the homepage (page that has add quote form)
    server.route(Method::GET, "/", |_| {
        Response::new()
            .text(String::new() + HEADER + HOME)
            .content(Content::HTML)
    });

    // Route to handle creating new quotes.
    // After successful creation the user will be redirected to the new quotes page.
    server.stateful_route(Method::POST, "/api/new", |app, req| {
        let form = Query::from_body(&String::from_utf8_lossy(&req.body));
        let name =
            url::decode(form.get("author").expect("No author supplied")).expect("Invalid author");
        let body =
            url::decode(form.get("quote").expect("No quote supplied")).expect("Invalid quote");

        let quote = Quote {
            name,
            value: body,
            date: now(),
        };
        let mut quotes = app.quotes.write().unwrap();
        let id = quotes.len();
        quotes.insert(id.to_string(), quote);
        drop(quotes);
        trace!(Level::Trace, "Added new quote #{id}");

        app.save();
        Response::new()
            .status(Status::SeeOther)
            .header(HeaderType::Location, format!("/quote/{id}"))
            .text("Redirecting to quote page.")
    });

    server.stateful_route(Method::GET, "/quote/{id}", |app, req| {
        let id = req.param("id").unwrap();
        if id == "undefined" {
            return Response::new();
        }

        let id = id.parse::<usize>().expect("ID is not a valid integer");
        let quotes = app.quotes.read().unwrap();
        if id >= quotes.len() {
            return Response::new()
                .status(Status::NotFound)
                .text(format!("No quote with the id {id} was found."));
        }

        let quote = quotes.get(&id.to_string()).unwrap();
        Response::new().content(Content::HTML).text(
            String::new()
                + HEADER
                + &QUOTE
                    .replace("{QUOTE}", &quote.value)
                    .replace("{AUTHOR}", &quote.name)
                    .replace("{TIME}", &imp_date(quote.date)),
        )
    });

    server.stateful_route(Method::GET, "/quotes", |app, _req| {
        let mut out = String::from(HEADER);
        out.push_str("<ul>");
        for i in app.quotes.read().unwrap().iter() {
            out.push_str(&format!(
                "<li><a href=\"/quote/{}\">\"{}\" - {}</a></li>\n",
                i.0, i.1.name, i.1.value
            ));
        }

        Response::new().text(out + "</ul>").content(Content::HTML)
    });

    // Note: In a production application you may want to multithread the server with the Server::start_threaded method.
    server.start().unwrap();
}
examples/application_paste_bin.rs (lines 41-71)
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
fn main() {
    // Create Server
    let mut server = Server::new("localhost", 8080).state(RwLock::new(Vec::new()));

    // New paste interface
    server.route(Method::GET, "/", |_req| {
        Response::new().content(Content::HTML).text(
            r#"
        <form action="/new-form" method="post">
        <input type="text" name="name" id="name" placeholder="Title">
        
        <br />
        <textarea id="body" name="body" rows="5" cols="33"></textarea>
        <input type="submit" value="Submit" />
    </form>
    "#,
        )
    });

    // New paste API handler
    server.stateful_route(Method::POST, "/new", move |app, req| {
        // Make sure paste data isn't too long
        if req.body.len() > DATA_LIMIT {
            return Response::new()
                .status(Status::NotFound)
                .text("Data too big!");
        }

        // Get the data as string
        let body_str = String::from_utf8_lossy(&req.body).to_string();

        // Get the name from the Name header
        let name = req.headers.get("Name").unwrap_or("Untitled");

        let paste = Paste {
            name: name.to_owned(),
            body: body_str,
            time: Instant::now(),
        };

        // Push this paste to the pastes vector
        let mut pastes = app.write().unwrap();
        let id = pastes.len();
        pastes.push(paste);

        // Send Redirect response
        Response::new()
            .status(Status::MovedPermanently)
            .header(HeaderType::Location, format!("/p/{id}"))
            .text(format!("Redirecting to /p/{id}."))
    });

    // New paste form handler
    server.stateful_route(Method::POST, "/new-form", |app, req| {
        // Get data from response
        let query = Query::from_body(String::from_utf8_lossy(&req.body).borrow());
        let name = url::decode(query.get("name").unwrap_or("Untitled")).expect("Invalid name");
        let body = url::decode(query.get("body").expect("No body supplied")).expect("Invalid body");

        // Make sure paste data isn't too long
        if body.len() > DATA_LIMIT {
            return Response::new()
                .status(Status::NotFound)
                .text("Data too big!");
        }

        let paste = Paste {
            name,
            body,
            time: Instant::now(),
        };

        // Push this paste to the pastes vector
        let mut pastes = app.write().unwrap();
        let id = pastes.len();
        pastes.push(paste);

        // Send Redirect response
        Response::new()
            .status(Status::MovedPermanently)
            .text("Ok")
            .header(HeaderType::Location, format!("/p/{}", id))
    });

    // Get pate handler
    server.stateful_route(Method::GET, "/p/{id}", move |app, req| {
        // Get is from path param
        let id = req.param("id").unwrap().parse::<usize>().unwrap();

        // Get the paste by id
        let paste = &app.read().unwrap()[id];

        // Send paste
        Response::new().text(&paste.body)
    });

    // View all pastes
    server.stateful_route(Method::GET, "/pastes", move |app, _req| {
        // Starter HTML
        let mut out = String::from(
            r#"<a href="/">New Paste</a><meta charset="UTF-8"><table><tr><th>Name</th><th>Date</th><th>Link</th></tr>"#,
        );

        // Add a table row for each paste
        for (i, e) in app.read().unwrap().iter().enumerate() {
            out.push_str(&format!(
                "<tr><td>{}</td><td>{}</td><td><a href=\"/p/{}\">🔗</a></td></tr>",
                e.name,
                fmt_relative_time(e.time.elapsed().as_secs()),
                i
            ));
        }

        // Send HTML
        Response::new()
            .text(format!("{}</table>", out))
            .content(Content::HTML)
    });

    server.start().unwrap();
}
source

pub fn app(&self) -> Arc<State>

Gets a reference to the current server state set outside of stateful routes. Will panic if the server has no state.

Example
// Create a server for localhost on port 8080
let mut server = Server::<u32>::new("localhost", 8080).state(101);

// Get its state and assert it is 101
assert_eq!(*server.app(), 101);

Auto Trait Implementations§

§

impl<State = ()> !RefUnwindSafe for Server<State>

§

impl<State> Send for Server<State>

§

impl<State> Sync for Server<State>

§

impl<State> Unpin for Server<State>

§

impl<State = ()> !UnwindSafe for Server<State>

Blanket Implementations§

source§

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

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere 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 Twhere 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 Twhere U: Into<T>,

§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

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

§

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.