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
impl<State: Send + Sync> Server<State>
Implementations for Server
Sourcepub fn new(raw_ip: impl ToHostAddress, port: u16) -> Self
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?
23fn main() {
24 set_log_level(Level::Debug);
25 let mut server = Server::<()>::new([127, 0, 0, 1], 8080);
26 server.route(Method::ANY, "**", |_req| Response::new());
27
28 Middleware1.attach(&mut server);
29 Middleware2.attach(&mut server);
30 Middleware3.attach(&mut server);
31 Middleware4.attach(&mut server);
32 Middleware5.attach(&mut server);
33
34 server.start().unwrap();
35}
More examples
41 fn exec(&self) {
42 // Set the log level to Trace (shows some helpful information during startup)
43 // The default is Level::Error
44 set_log_level(Level::Trace);
45 trace!(Level::Trace, "Setting log level to Trace");
46 trace!(Level::Error, "Example error message");
47
48 // Create a new Server instance on localhost port 8080
49 let mut server = Server::<()>::new("localhost", 8080);
50
51 server.route(Method::GET, "/", |req| {
52 // The default log level is Level::Trace so this will be logged
53 trace!("Request from {}", req.address.ip());
54 Response::new()
55 });
56
57 server.start().unwrap();
58 }
54 fn exec(&self) {
55 // Create a new Server instance on localhost port 8080
56 let mut server = Server::<()>::new("localhost", 8080);
57
58 // Define a basic route
59 server.route(Method::GET, "/", |_req| {
60 Response::new().text("Hello World!").content(Content::TXT)
61 });
62
63 // Here is where we will attach our Middleware to the Server
64 // This is super easy
65 Log.attach(&mut server);
66
67 // You can now goto http://localhost:8080 you should see that the request is printed to the console
68 // It should look something like this: `[127.0.0.1] GET `
69
70 // Start the server
71 // This will block the current thread
72 server.start().unwrap();
73 }
24 fn exec(&self) {
25 // Create a server on localhost port 8080 with a state of App
26 let mut server = Server::<App>::new("localhost", 8080).state(App::default());
27
28 // Add catch all route that takes in state and the request
29 server.stateful_route(Method::ANY, "**", |sta, _req| {
30 // Respond with and increment request count
31 Response::new().text(sta.count.fetch_add(1, Ordering::Relaxed))
32 });
33
34 // Start the server
35 // This will block the current thread
36 // Because there is a stateful route, this will panic if no state is set
37 server.start().unwrap();
38
39 // Now go to http://localhost:8080
40 // You should see the request count increment each time you refresh
41 }
24 fn exec(&self) {
25 // Create a new Server instance on localhost port 8080
26 let mut server = Server::<()>::new("localhost", 8080);
27
28 // Define a handler for GET "/"
29 server.route(Method::GET, "/", |_req| {
30 Response::new()
31 // hopefully the ThreadId.as_u64 method will become stable
32 // until then im stuck with this mess for the example
33 // It just gets the thread ID to show the user what thread is handling the request
34 .text(format!(
35 "Hello from thread number {:#?}!",
36 unsafe { std::mem::transmute::<_, NonZeroU64>(thread::current().id()) }.get()
37 - 1
38 ))
39 .content(Content::TXT)
40 });
41
42 // Start the server with 8 threads
43 // This will block the current thread
44 server.start_threaded(8).unwrap();
45
46 // If you go to http://localhost:8080 you should see the thread ID change with each refresh
47 }
16 fn exec(&self) {
17 // Create a new Server instance on localhost port 8080
18 let mut server: Server = Server::<()>::new("localhost", 8081);
19
20 // Define a handler for GET "/greet/{name}"
21 // This will handel requests with anything where the {name} is
22 // This includes "/greet/bob", "/greet/fin"
23 server.route(Method::GET, "/greet/{name}", |req| {
24 // Get name path param
25 let name = req.param("name").unwrap();
26
27 // Make a nice Message to send
28 let message = format!("Hello, {}", name);
29
30 // Send Response
31 Response::new().text(message).content(Content::TXT)
32 });
33
34 // Define a greet route for Darren because he is very cool
35 // This will take priority over the other route as it is defined after
36 server.route(Method::GET, "/greet/Darren/", |_req| {
37 Response::new().text("Hello, Darren. You are very cool")
38 });
39
40 // Start the server
41 // This will block the current thread
42 server.start().unwrap();
43 }
- examples/basic/serve_file.rs
- examples/basic/routing.rs
- examples/basic/rate_limit.rs
- examples/basic/error_handling.rs
- examples/basic/serve_static.rs
- examples/basic/basic.rs
- examples/basic/logging.rs
- examples/basic/cookie.rs
- examples/basic/data.rs
- examples/application_quote_book.rs
- examples/basic/header.rs
- examples/application_paste_bin.rs
Sourcepub fn start(&self) -> Result<()>
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?
23fn main() {
24 set_log_level(Level::Debug);
25 let mut server = Server::<()>::new([127, 0, 0, 1], 8080);
26 server.route(Method::ANY, "**", |_req| Response::new());
27
28 Middleware1.attach(&mut server);
29 Middleware2.attach(&mut server);
30 Middleware3.attach(&mut server);
31 Middleware4.attach(&mut server);
32 Middleware5.attach(&mut server);
33
34 server.start().unwrap();
35}
More examples
41 fn exec(&self) {
42 // Set the log level to Trace (shows some helpful information during startup)
43 // The default is Level::Error
44 set_log_level(Level::Trace);
45 trace!(Level::Trace, "Setting log level to Trace");
46 trace!(Level::Error, "Example error message");
47
48 // Create a new Server instance on localhost port 8080
49 let mut server = Server::<()>::new("localhost", 8080);
50
51 server.route(Method::GET, "/", |req| {
52 // The default log level is Level::Trace so this will be logged
53 trace!("Request from {}", req.address.ip());
54 Response::new()
55 });
56
57 server.start().unwrap();
58 }
54 fn exec(&self) {
55 // Create a new Server instance on localhost port 8080
56 let mut server = Server::<()>::new("localhost", 8080);
57
58 // Define a basic route
59 server.route(Method::GET, "/", |_req| {
60 Response::new().text("Hello World!").content(Content::TXT)
61 });
62
63 // Here is where we will attach our Middleware to the Server
64 // This is super easy
65 Log.attach(&mut server);
66
67 // You can now goto http://localhost:8080 you should see that the request is printed to the console
68 // It should look something like this: `[127.0.0.1] GET `
69
70 // Start the server
71 // This will block the current thread
72 server.start().unwrap();
73 }
24 fn exec(&self) {
25 // Create a server on localhost port 8080 with a state of App
26 let mut server = Server::<App>::new("localhost", 8080).state(App::default());
27
28 // Add catch all route that takes in state and the request
29 server.stateful_route(Method::ANY, "**", |sta, _req| {
30 // Respond with and increment request count
31 Response::new().text(sta.count.fetch_add(1, Ordering::Relaxed))
32 });
33
34 // Start the server
35 // This will block the current thread
36 // Because there is a stateful route, this will panic if no state is set
37 server.start().unwrap();
38
39 // Now go to http://localhost:8080
40 // You should see the request count increment each time you refresh
41 }
16 fn exec(&self) {
17 // Create a new Server instance on localhost port 8080
18 let mut server: Server = Server::<()>::new("localhost", 8081);
19
20 // Define a handler for GET "/greet/{name}"
21 // This will handel requests with anything where the {name} is
22 // This includes "/greet/bob", "/greet/fin"
23 server.route(Method::GET, "/greet/{name}", |req| {
24 // Get name path param
25 let name = req.param("name").unwrap();
26
27 // Make a nice Message to send
28 let message = format!("Hello, {}", name);
29
30 // Send Response
31 Response::new().text(message).content(Content::TXT)
32 });
33
34 // Define a greet route for Darren because he is very cool
35 // This will take priority over the other route as it is defined after
36 server.route(Method::GET, "/greet/Darren/", |_req| {
37 Response::new().text("Hello, Darren. You are very cool")
38 });
39
40 // Start the server
41 // This will block the current thread
42 server.start().unwrap();
43 }
19 fn exec(&self) {
20 // Create a new Server instance on localhost port 8080
21 let mut server = Server::<()>::new("localhost", 8080);
22
23 // Define a handler for GET "/"
24 server.route(Method::GET, "/", |_req| {
25 // Try to open a file
26 match File::open("examples/basic/data/index.html") {
27 // If its found send it as response
28 // Because we used File::open and not fs::read, we can use the stream method to send the file in chunks
29 // This is more efficient than reading the whole file into memory and then sending it
30 Ok(content) => Response::new().stream(content).content(Content::HTML),
31
32 // If the file is not found, send a 404 response
33 Err(_) => Response::new()
34 .status(Status::NotFound)
35 .text("Not Found :/")
36 .content(Content::TXT),
37 }
38 });
39
40 // View the file at http://localhost:8080
41
42 // Start the server
43 // This will block the current thread
44 server.start().unwrap();
45 }
- examples/basic/routing.rs
- examples/basic/rate_limit.rs
- examples/basic/error_handling.rs
- examples/basic/serve_static.rs
- examples/basic/basic.rs
- examples/basic/logging.rs
- examples/basic/cookie.rs
- examples/basic/data.rs
- examples/application_quote_book.rs
- examples/basic/header.rs
- examples/application_paste_bin.rs
Sourcepub fn start_threaded(self, threads: usize) -> Result<()>
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?
24 fn exec(&self) {
25 // Create a new Server instance on localhost port 8080
26 let mut server = Server::<()>::new("localhost", 8080);
27
28 // Define a handler for GET "/"
29 server.route(Method::GET, "/", |_req| {
30 Response::new()
31 // hopefully the ThreadId.as_u64 method will become stable
32 // until then im stuck with this mess for the example
33 // It just gets the thread ID to show the user what thread is handling the request
34 .text(format!(
35 "Hello from thread number {:#?}!",
36 unsafe { std::mem::transmute::<_, NonZeroU64>(thread::current().id()) }.get()
37 - 1
38 ))
39 .content(Content::TXT)
40 });
41
42 // Start the server with 8 threads
43 // This will block the current thread
44 server.start_threaded(8).unwrap();
45
46 // If you go to http://localhost:8080 you should see the thread ID change with each refresh
47 }
Sourcepub fn default_header(
self,
key: impl Into<HeaderType>,
value: impl AsRef<str>,
) -> Self
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?
14 fn exec(&self) {
15 // Create a new Server instance on localhost port 8080
16 let mut server = Server::<()>::new("localhost", 8080)
17 // Define server wide default headers
18 // These will be send with every response
19 // If the same header is defined in the route it will be put before the default header
20 // Although it is not guaranteed to be the one picked by the client it usually is
21 // At the bottom of this file is a representation of the order of the headers
22 .default_header("X-Server-Header", "This is a server wide header")
23 // You can also use the HeaderType enum to define a header type
24 // This is also true with the .header method on the Response struct
25 .default_header(HeaderType::Server, "afire");
26
27 // Define a route to redirect to another website
28 server.route(Method::GET, "/", |_req| {
29 // Because this is all bout headers I have put the header vector here
30 let headers = vec![
31 // Tell the client what type of data we are sending
32 afire::Header::new(HeaderType::ContentType, "text/html"),
33 // Tell the client to redirect to another website
34 afire::Header::new(HeaderType::Location, "https://connorcode.com"),
35 // Custom header
36 afire::Header::new("X-Custom-Header", "This is a custom header"),
37 ];
38
39 // Define response body
40 // In this case this should only be seen if the client doesn't support redirects for some reason
41 let text = "<a href=\"https://connorcode.com\">connorcode</a>";
42
43 // The response code of 308 tells the client to redirect to the location specified in the header
44 // There are other response codes you can use too
45 // 301 -> Moved Permanently
46 // 302 -> Found
47 // 303 -> See Other
48 // 307 -> Temporary Redirect
49 // 308 -> Permanent Redirect
50 Response::new()
51 .status(Status::PermanentRedirect)
52 .text(text)
53 .headers(&headers)
54 });
55
56 // Now to define a route to handle client headers
57 // This will just echo the headers back to the client
58 server.route(Method::GET, "/headers", |req| {
59 // Get the headers from the request and make a html string
60 let body = req
61 .headers
62 .iter()
63 .fold(String::new(), |old, new| old + &format!("{:?}<br />", new));
64
65 // Create a response with the headers
66 Response::new().text(body).content(Content::HTML)
67 });
68
69 // You can now goto http://localhost:8080 you should see a redirect to https://connorcode.com
70 // And you can goto http://localhost:8080/headers to see the headers your client sent to the server
71
72 // Start the server
73 // This will block the current thread
74 server.start().unwrap();
75 }
Sourcepub fn socket_timeout(self, socket_timeout: Duration) -> Self
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));
Sourcepub fn keep_alive(self, keep_alive: bool) -> Self
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);
Sourcepub fn state(self, state: State) -> Self
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?
24 fn exec(&self) {
25 // Create a server on localhost port 8080 with a state of App
26 let mut server = Server::<App>::new("localhost", 8080).state(App::default());
27
28 // Add catch all route that takes in state and the request
29 server.stateful_route(Method::ANY, "**", |sta, _req| {
30 // Respond with and increment request count
31 Response::new().text(sta.count.fetch_add(1, Ordering::Relaxed))
32 });
33
34 // Start the server
35 // This will block the current thread
36 // Because there is a stateful route, this will panic if no state is set
37 server.start().unwrap();
38
39 // Now go to http://localhost:8080
40 // You should see the request count increment each time you refresh
41 }
More examples
34fn main() {
35 set_log_level(Level::Trace);
36 let app = App::new(PathBuf::from("quotes.txt"));
37 app.load();
38
39 let mut server = Server::new(Ipv4Addr::LOCALHOST, 8080).state(app);
40
41 // Route to serve the homepage (page that has add quote form)
42 server.route(Method::GET, "/", |_| {
43 Response::new()
44 .text(String::new() + HEADER + HOME)
45 .content(Content::HTML)
46 });
47
48 // Route to handle creating new quotes.
49 // After successful creation the user will be redirected to the new quotes page.
50 server.stateful_route(Method::POST, "/api/new", |app, req| {
51 let form = Query::from_body(&String::from_utf8_lossy(&req.body));
52 let name =
53 url::decode(form.get("author").expect("No author supplied")).expect("Invalid author");
54 let body =
55 url::decode(form.get("quote").expect("No quote supplied")).expect("Invalid quote");
56
57 let quote = Quote {
58 name,
59 value: body,
60 date: now(),
61 };
62 let mut quotes = app.quotes.write().unwrap();
63 let id = quotes.len();
64 quotes.insert(id.to_string(), quote);
65 drop(quotes);
66 trace!(Level::Trace, "Added new quote #{id}");
67
68 app.save();
69 Response::new()
70 .status(Status::SeeOther)
71 .header(HeaderType::Location, format!("/quote/{id}"))
72 .text("Redirecting to quote page.")
73 });
74
75 server.stateful_route(Method::GET, "/quote/{id}", |app, req| {
76 let id = req.param("id").unwrap();
77 if id == "undefined" {
78 return Response::new();
79 }
80
81 let id = id.parse::<usize>().expect("ID is not a valid integer");
82 let quotes = app.quotes.read().unwrap();
83 if id >= quotes.len() {
84 return Response::new()
85 .status(Status::NotFound)
86 .text(format!("No quote with the id {id} was found."));
87 }
88
89 let quote = quotes.get(&id.to_string()).unwrap();
90 Response::new().content(Content::HTML).text(
91 String::new()
92 + HEADER
93 + "E
94 .replace("{QUOTE}", "e.value)
95 .replace("{AUTHOR}", "e.name)
96 .replace("{TIME}", &imp_date(quote.date)),
97 )
98 });
99
100 server.stateful_route(Method::GET, "/quotes", |app, _req| {
101 let mut out = String::from(HEADER);
102 out.push_str("<ul>");
103 for i in app.quotes.read().unwrap().iter() {
104 out.push_str(&format!(
105 "<li><a href=\"/quote/{}\">\"{}\" - {}</a></li>\n",
106 i.0, i.1.name, i.1.value
107 ));
108 }
109
110 Response::new().text(out + "</ul>").content(Content::HTML)
111 });
112
113 // Note: In a production application you may want to multithread the server with the Server::start_threaded method.
114 server.start().unwrap();
115}
21fn main() {
22 // Create Server
23 let mut server = Server::new("localhost", 8080).state(RwLock::new(Vec::new()));
24
25 // New paste interface
26 server.route(Method::GET, "/", |_req| {
27 Response::new().content(Content::HTML).text(
28 r#"
29 <form action="/new-form" method="post">
30 <input type="text" name="name" id="name" placeholder="Title">
31
32 <br />
33 <textarea id="body" name="body" rows="5" cols="33"></textarea>
34 <input type="submit" value="Submit" />
35 </form>
36 "#,
37 )
38 });
39
40 // New paste API handler
41 server.stateful_route(Method::POST, "/new", move |app, req| {
42 // Make sure paste data isn't too long
43 if req.body.len() > DATA_LIMIT {
44 return Response::new()
45 .status(Status::NotFound)
46 .text("Data too big!");
47 }
48
49 // Get the data as string
50 let body_str = String::from_utf8_lossy(&req.body).to_string();
51
52 // Get the name from the Name header
53 let name = req.headers.get("Name").unwrap_or("Untitled");
54
55 let paste = Paste {
56 name: name.to_owned(),
57 body: body_str,
58 time: Instant::now(),
59 };
60
61 // Push this paste to the pastes vector
62 let mut pastes = app.write().unwrap();
63 let id = pastes.len();
64 pastes.push(paste);
65
66 // Send Redirect response
67 Response::new()
68 .status(Status::MovedPermanently)
69 .header(HeaderType::Location, format!("/p/{id}"))
70 .text(format!("Redirecting to /p/{id}."))
71 });
72
73 // New paste form handler
74 server.stateful_route(Method::POST, "/new-form", |app, req| {
75 // Get data from response
76 let query = Query::from_body(String::from_utf8_lossy(&req.body).borrow());
77 let name = url::decode(query.get("name").unwrap_or("Untitled")).expect("Invalid name");
78 let body = url::decode(query.get("body").expect("No body supplied")).expect("Invalid body");
79
80 // Make sure paste data isn't too long
81 if body.len() > DATA_LIMIT {
82 return Response::new()
83 .status(Status::NotFound)
84 .text("Data too big!");
85 }
86
87 let paste = Paste {
88 name,
89 body,
90 time: Instant::now(),
91 };
92
93 // Push this paste to the pastes vector
94 let mut pastes = app.write().unwrap();
95 let id = pastes.len();
96 pastes.push(paste);
97
98 // Send Redirect response
99 Response::new()
100 .status(Status::MovedPermanently)
101 .text("Ok")
102 .header(HeaderType::Location, format!("/p/{}", id))
103 });
104
105 // Get pate handler
106 server.stateful_route(Method::GET, "/p/{id}", move |app, req| {
107 // Get is from path param
108 let id = req.param("id").unwrap().parse::<usize>().unwrap();
109
110 // Get the paste by id
111 let paste = &app.read().unwrap()[id];
112
113 // Send paste
114 Response::new().text(&paste.body)
115 });
116
117 // View all pastes
118 server.stateful_route(Method::GET, "/pastes", move |app, _req| {
119 // Starter HTML
120 let mut out = String::from(
121 r#"<a href="/">New Paste</a><meta charset="UTF-8"><table><tr><th>Name</th><th>Date</th><th>Link</th></tr>"#,
122 );
123
124 // Add a table row for each paste
125 for (i, e) in app.read().unwrap().iter().enumerate() {
126 out.push_str(&format!(
127 "<tr><td>{}</td><td>{}</td><td><a href=\"/p/{}\">๐</a></td></tr>",
128 e.name,
129 fmt_relative_time(e.time.elapsed().as_secs()),
130 i
131 ));
132 }
133
134 // Send HTML
135 Response::new()
136 .text(format!("{}</table>", out))
137 .content(Content::HTML)
138 });
139
140 server.start().unwrap();
141}
Sourcepub fn error_handler(
&mut self,
res: impl Fn(Option<Arc<State>>, &Box<Result<Rc<Request>>>, String) -> Response + Send + Sync + 'static,
)
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?
20 fn exec(&self) {
21 // Create a new Server instance on localhost port 8080
22 let mut server = Server::<()>::new("localhost", 8080);
23
24 // Define a route that will panic
25 server.route(Method::GET, "/panic", |_req| panic!("This is a panic!"));
26
27 // Give the server a main page
28 server.route(Method::GET, "/", |_req| {
29 Response::new()
30 .text(r#"<a href="/panic">PANIC</a>"#)
31 .content(Content::HTML)
32 });
33
34 // You can optionally define a custom error handler
35 // This can be defined anywhere in the server and will take affect for all routes
36 // Its like a normal route, but it will only be called if the route panics
37 let errors = AtomicUsize::new(1);
38 server.error_handler(move |_state, _req, err| {
39 Response::new()
40 .status(Status::InternalServerError)
41 .text(format!(
42 "<h1>Internal Server Error #{}</h1><br>Panicked at '{}'",
43 errors.fetch_add(1, Ordering::Relaxed),
44 err
45 ))
46 .content(Content::HTML)
47 });
48
49 // You can now goto http://localhost:8080/panic
50 // This will cause the route to panic and return a 500 error
51
52 // Start the server
53 // This will block the current thread
54 server.start().unwrap();
55 }
Sourcepub fn route(
&mut self,
method: Method,
path: impl AsRef<str>,
handler: impl Fn(&Request) -> Response + Send + Sync + 'static,
) -> &mut Self
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?
23fn main() {
24 set_log_level(Level::Debug);
25 let mut server = Server::<()>::new([127, 0, 0, 1], 8080);
26 server.route(Method::ANY, "**", |_req| Response::new());
27
28 Middleware1.attach(&mut server);
29 Middleware2.attach(&mut server);
30 Middleware3.attach(&mut server);
31 Middleware4.attach(&mut server);
32 Middleware5.attach(&mut server);
33
34 server.start().unwrap();
35}
More examples
41 fn exec(&self) {
42 // Set the log level to Trace (shows some helpful information during startup)
43 // The default is Level::Error
44 set_log_level(Level::Trace);
45 trace!(Level::Trace, "Setting log level to Trace");
46 trace!(Level::Error, "Example error message");
47
48 // Create a new Server instance on localhost port 8080
49 let mut server = Server::<()>::new("localhost", 8080);
50
51 server.route(Method::GET, "/", |req| {
52 // The default log level is Level::Trace so this will be logged
53 trace!("Request from {}", req.address.ip());
54 Response::new()
55 });
56
57 server.start().unwrap();
58 }
54 fn exec(&self) {
55 // Create a new Server instance on localhost port 8080
56 let mut server = Server::<()>::new("localhost", 8080);
57
58 // Define a basic route
59 server.route(Method::GET, "/", |_req| {
60 Response::new().text("Hello World!").content(Content::TXT)
61 });
62
63 // Here is where we will attach our Middleware to the Server
64 // This is super easy
65 Log.attach(&mut server);
66
67 // You can now goto http://localhost:8080 you should see that the request is printed to the console
68 // It should look something like this: `[127.0.0.1] GET `
69
70 // Start the server
71 // This will block the current thread
72 server.start().unwrap();
73 }
24 fn exec(&self) {
25 // Create a new Server instance on localhost port 8080
26 let mut server = Server::<()>::new("localhost", 8080);
27
28 // Define a handler for GET "/"
29 server.route(Method::GET, "/", |_req| {
30 Response::new()
31 // hopefully the ThreadId.as_u64 method will become stable
32 // until then im stuck with this mess for the example
33 // It just gets the thread ID to show the user what thread is handling the request
34 .text(format!(
35 "Hello from thread number {:#?}!",
36 unsafe { std::mem::transmute::<_, NonZeroU64>(thread::current().id()) }.get()
37 - 1
38 ))
39 .content(Content::TXT)
40 });
41
42 // Start the server with 8 threads
43 // This will block the current thread
44 server.start_threaded(8).unwrap();
45
46 // If you go to http://localhost:8080 you should see the thread ID change with each refresh
47 }
16 fn exec(&self) {
17 // Create a new Server instance on localhost port 8080
18 let mut server: Server = Server::<()>::new("localhost", 8081);
19
20 // Define a handler for GET "/greet/{name}"
21 // This will handel requests with anything where the {name} is
22 // This includes "/greet/bob", "/greet/fin"
23 server.route(Method::GET, "/greet/{name}", |req| {
24 // Get name path param
25 let name = req.param("name").unwrap();
26
27 // Make a nice Message to send
28 let message = format!("Hello, {}", name);
29
30 // Send Response
31 Response::new().text(message).content(Content::TXT)
32 });
33
34 // Define a greet route for Darren because he is very cool
35 // This will take priority over the other route as it is defined after
36 server.route(Method::GET, "/greet/Darren/", |_req| {
37 Response::new().text("Hello, Darren. You are very cool")
38 });
39
40 // Start the server
41 // This will block the current thread
42 server.start().unwrap();
43 }
19 fn exec(&self) {
20 // Create a new Server instance on localhost port 8080
21 let mut server = Server::<()>::new("localhost", 8080);
22
23 // Define a handler for GET "/"
24 server.route(Method::GET, "/", |_req| {
25 // Try to open a file
26 match File::open("examples/basic/data/index.html") {
27 // If its found send it as response
28 // Because we used File::open and not fs::read, we can use the stream method to send the file in chunks
29 // This is more efficient than reading the whole file into memory and then sending it
30 Ok(content) => Response::new().stream(content).content(Content::HTML),
31
32 // If the file is not found, send a 404 response
33 Err(_) => Response::new()
34 .status(Status::NotFound)
35 .text("Not Found :/")
36 .content(Content::TXT),
37 }
38 });
39
40 // View the file at http://localhost:8080
41
42 // Start the server
43 // This will block the current thread
44 server.start().unwrap();
45 }
Sourcepub fn stateful_route(
&mut self,
method: Method,
path: impl AsRef<str>,
handler: impl Fn(Arc<State>, &Request) -> Response + Send + Sync + 'static,
) -> &mut Self
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?
24 fn exec(&self) {
25 // Create a server on localhost port 8080 with a state of App
26 let mut server = Server::<App>::new("localhost", 8080).state(App::default());
27
28 // Add catch all route that takes in state and the request
29 server.stateful_route(Method::ANY, "**", |sta, _req| {
30 // Respond with and increment request count
31 Response::new().text(sta.count.fetch_add(1, Ordering::Relaxed))
32 });
33
34 // Start the server
35 // This will block the current thread
36 // Because there is a stateful route, this will panic if no state is set
37 server.start().unwrap();
38
39 // Now go to http://localhost:8080
40 // You should see the request count increment each time you refresh
41 }
More examples
34fn main() {
35 set_log_level(Level::Trace);
36 let app = App::new(PathBuf::from("quotes.txt"));
37 app.load();
38
39 let mut server = Server::new(Ipv4Addr::LOCALHOST, 8080).state(app);
40
41 // Route to serve the homepage (page that has add quote form)
42 server.route(Method::GET, "/", |_| {
43 Response::new()
44 .text(String::new() + HEADER + HOME)
45 .content(Content::HTML)
46 });
47
48 // Route to handle creating new quotes.
49 // After successful creation the user will be redirected to the new quotes page.
50 server.stateful_route(Method::POST, "/api/new", |app, req| {
51 let form = Query::from_body(&String::from_utf8_lossy(&req.body));
52 let name =
53 url::decode(form.get("author").expect("No author supplied")).expect("Invalid author");
54 let body =
55 url::decode(form.get("quote").expect("No quote supplied")).expect("Invalid quote");
56
57 let quote = Quote {
58 name,
59 value: body,
60 date: now(),
61 };
62 let mut quotes = app.quotes.write().unwrap();
63 let id = quotes.len();
64 quotes.insert(id.to_string(), quote);
65 drop(quotes);
66 trace!(Level::Trace, "Added new quote #{id}");
67
68 app.save();
69 Response::new()
70 .status(Status::SeeOther)
71 .header(HeaderType::Location, format!("/quote/{id}"))
72 .text("Redirecting to quote page.")
73 });
74
75 server.stateful_route(Method::GET, "/quote/{id}", |app, req| {
76 let id = req.param("id").unwrap();
77 if id == "undefined" {
78 return Response::new();
79 }
80
81 let id = id.parse::<usize>().expect("ID is not a valid integer");
82 let quotes = app.quotes.read().unwrap();
83 if id >= quotes.len() {
84 return Response::new()
85 .status(Status::NotFound)
86 .text(format!("No quote with the id {id} was found."));
87 }
88
89 let quote = quotes.get(&id.to_string()).unwrap();
90 Response::new().content(Content::HTML).text(
91 String::new()
92 + HEADER
93 + "E
94 .replace("{QUOTE}", "e.value)
95 .replace("{AUTHOR}", "e.name)
96 .replace("{TIME}", &imp_date(quote.date)),
97 )
98 });
99
100 server.stateful_route(Method::GET, "/quotes", |app, _req| {
101 let mut out = String::from(HEADER);
102 out.push_str("<ul>");
103 for i in app.quotes.read().unwrap().iter() {
104 out.push_str(&format!(
105 "<li><a href=\"/quote/{}\">\"{}\" - {}</a></li>\n",
106 i.0, i.1.name, i.1.value
107 ));
108 }
109
110 Response::new().text(out + "</ul>").content(Content::HTML)
111 });
112
113 // Note: In a production application you may want to multithread the server with the Server::start_threaded method.
114 server.start().unwrap();
115}
21fn main() {
22 // Create Server
23 let mut server = Server::new("localhost", 8080).state(RwLock::new(Vec::new()));
24
25 // New paste interface
26 server.route(Method::GET, "/", |_req| {
27 Response::new().content(Content::HTML).text(
28 r#"
29 <form action="/new-form" method="post">
30 <input type="text" name="name" id="name" placeholder="Title">
31
32 <br />
33 <textarea id="body" name="body" rows="5" cols="33"></textarea>
34 <input type="submit" value="Submit" />
35 </form>
36 "#,
37 )
38 });
39
40 // New paste API handler
41 server.stateful_route(Method::POST, "/new", move |app, req| {
42 // Make sure paste data isn't too long
43 if req.body.len() > DATA_LIMIT {
44 return Response::new()
45 .status(Status::NotFound)
46 .text("Data too big!");
47 }
48
49 // Get the data as string
50 let body_str = String::from_utf8_lossy(&req.body).to_string();
51
52 // Get the name from the Name header
53 let name = req.headers.get("Name").unwrap_or("Untitled");
54
55 let paste = Paste {
56 name: name.to_owned(),
57 body: body_str,
58 time: Instant::now(),
59 };
60
61 // Push this paste to the pastes vector
62 let mut pastes = app.write().unwrap();
63 let id = pastes.len();
64 pastes.push(paste);
65
66 // Send Redirect response
67 Response::new()
68 .status(Status::MovedPermanently)
69 .header(HeaderType::Location, format!("/p/{id}"))
70 .text(format!("Redirecting to /p/{id}."))
71 });
72
73 // New paste form handler
74 server.stateful_route(Method::POST, "/new-form", |app, req| {
75 // Get data from response
76 let query = Query::from_body(String::from_utf8_lossy(&req.body).borrow());
77 let name = url::decode(query.get("name").unwrap_or("Untitled")).expect("Invalid name");
78 let body = url::decode(query.get("body").expect("No body supplied")).expect("Invalid body");
79
80 // Make sure paste data isn't too long
81 if body.len() > DATA_LIMIT {
82 return Response::new()
83 .status(Status::NotFound)
84 .text("Data too big!");
85 }
86
87 let paste = Paste {
88 name,
89 body,
90 time: Instant::now(),
91 };
92
93 // Push this paste to the pastes vector
94 let mut pastes = app.write().unwrap();
95 let id = pastes.len();
96 pastes.push(paste);
97
98 // Send Redirect response
99 Response::new()
100 .status(Status::MovedPermanently)
101 .text("Ok")
102 .header(HeaderType::Location, format!("/p/{}", id))
103 });
104
105 // Get pate handler
106 server.stateful_route(Method::GET, "/p/{id}", move |app, req| {
107 // Get is from path param
108 let id = req.param("id").unwrap().parse::<usize>().unwrap();
109
110 // Get the paste by id
111 let paste = &app.read().unwrap()[id];
112
113 // Send paste
114 Response::new().text(&paste.body)
115 });
116
117 // View all pastes
118 server.stateful_route(Method::GET, "/pastes", move |app, _req| {
119 // Starter HTML
120 let mut out = String::from(
121 r#"<a href="/">New Paste</a><meta charset="UTF-8"><table><tr><th>Name</th><th>Date</th><th>Link</th></tr>"#,
122 );
123
124 // Add a table row for each paste
125 for (i, e) in app.read().unwrap().iter().enumerate() {
126 out.push_str(&format!(
127 "<tr><td>{}</td><td>{}</td><td><a href=\"/p/{}\">๐</a></td></tr>",
128 e.name,
129 fmt_relative_time(e.time.elapsed().as_secs()),
130 i
131 ));
132 }
133
134 // Send HTML
135 Response::new()
136 .text(format!("{}</table>", out))
137 .content(Content::HTML)
138 });
139
140 server.start().unwrap();
141}
Sourcepub fn app(&self) -> Arc<State>
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);