pub struct Request {
pub method: Method,
pub path: String,
pub version: String,
pub query: Query,
pub headers: Headers,
pub cookies: CookieJar,
pub body: Arc<Vec<u8>>,
pub address: SocketAddr,
pub socket: Arc<Mutex<TcpStream>>,
/* private fields */
}
Expand description
Http Request
Fieldsยง
ยงmethod: Method
Request method.
path: String
Request path (not tokenized).
The query string is not included, its in the query
field.
version: String
HTTP version string. Should usually be โHTTP/1.1โ.
query: Query
Request Query.
headers: Headers
Request headers.
Will not include cookies, which are in the cookies
field.
Request Cookies.
body: Arc<Vec<u8>>
Request body, as a static byte vec.
address: SocketAddr
Client socket address. If you are using a reverse proxy, this will be the address of the proxy (often localhost).
socket: Arc<Mutex<TcpStream>>
The raw tcp socket
Implementationsยง
Sourceยงimpl Request
impl Request
Sourcepub fn param(&self, name: impl AsRef<str>) -> Option<String>
pub fn param(&self, name: impl AsRef<str>) -> Option<String>
Get a path parameter by its name.
ยงExample
server.route(Method::GET, "/greet/{name}", |req| {
// Get name Path param
// This is safe to unwrap because the router will only call this handler if the path param exists
let name = req.param("name").unwrap();
// Format a nice message
let message = format!("Hello, {}", name);
// Send Response
Response::new()
.text(message)
.content(Content::TXT)
});
Examples found in repository?
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 }
More examples
18 fn exec(&self) {
19 // Create a new Server instance on localhost port 8080
20 let mut server = Server::<()>::new(Ipv4Addr::LOCALHOST, 8080);
21
22 // Define a route to handel query string
23 // This will try to find a name value pair in the query string
24 server.route(Method::GET, "/", |req| {
25 // Format the response text
26 let text = format!(
27 "<h1>Hello, {}!</h1>",
28 // Get the query value of name and default to "Nobody" if not found
29 req.query.get("name").unwrap_or("Nobody")
30 );
31
32 Response::new().text(text).content(Content::HTML)
33 });
34
35 // Define another route
36 // This time to handle form data
37 server.route(Method::POST, "/form", |req| {
38 // The body of requests is not part of the req.query
39 // Instead it is part of the req.body but as a string
40 // We will need to parse it get it as a query
41 let body_data = Query::from_body(&String::from_utf8_lossy(&req.body));
42
43 let name = body_data.get("name").unwrap_or("Nobody");
44 let text = format!("<h1>Hello, {}</h1>", name);
45
46 // Create a new response, with the following default data
47 // - Status: 200
48 // - Data: OK
49 // - Headers: []
50 Response::new()
51 // Set the response body to be text
52 .text(text)
53 // Set the `Content-Type` header to be `text/html`
54 // Note: This could also be set with the Response::content method
55 .header(HeaderType::ContentType, "text/html")
56 });
57
58 // Define webpage with form
59 // The form data will be post to /form on submit
60 server.route(Method::GET, "/form", |_req| {
61 let page = r#"<form method="post">
62 <label for="name">Name:</label>
63 <input type="text" id="name" name="name"><br><br>
64 <input type="submit" value="Submit">
65 </form>"#;
66
67 Response::new().text(page).content(Content::HTML)
68 });
69
70 // Define a page with path params
71 server.route(Method::GET, "/greet/{name}", |req| {
72 // As this route would ever run without all the path params being filled
73 // It is safe to unwrap if the name is in the path
74 let data = format!("<h1>Hello, {}</h1>", req.param("name").unwrap());
75
76 Response::new().text(data).content(Content::HTML)
77 });
78
79 // You can now goto http://localhost:8080?name=John and should see "Hello, John"
80 // If you goto http://localhost:8080/form and submit the form you should see "Hello, {NAME}"
81 // Also goto http://localhost:8080/greet/John and you should see "Hello, John"
82
83 // Start the server
84 // This will block the current thread
85 server.start().unwrap();
86 }
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 body_str(&self) -> Cow<'_, str>
pub fn body_str(&self) -> Cow<'_, str>
Gets the body of the request as a string.
This uses the String::from_utf8_lossy
method, so it will replace invalid UTF-8 characters with the unicode replacement character (๏ฟฝ).
If you want to use a different encoding or handle invalid characters, use a string method on the body field.
Trait Implementationsยง
Sourceยงimpl RealIp for Request
impl RealIp for Request
Sourceยงfn real_ip_header(&self, header: impl Into<HeaderType>) -> IpAddr
fn real_ip_header(&self, header: impl Into<HeaderType>) -> IpAddr
header
into an IpAddr.
If the connection is not coming from localhost, the header isnโt found or the header contains an invalid IP address, the raw socket address will be returned. Read more