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>
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?
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
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();
}
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();
}
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
}
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
}
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
- 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?
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
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();
}
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();
}
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
}
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();
}
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();
}
- 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 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
}
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 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();
}
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 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
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
+ "E
.replace("{QUOTE}", "e.value)
.replace("{AUTHOR}", "e.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();
}
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();
}
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 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();
}
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?
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
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();
}
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();
}
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
}
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();
}
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();
}
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 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
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
+ "E
.replace("{QUOTE}", "e.value)
.replace("{AUTHOR}", "e.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();
}
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();
}
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);