Struct afire::Request

source ยท
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.

ยงcookies: CookieJar

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

source

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?
examples/basic/path_prams.rs (line 25)
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();
    }
More examples
Hide additional examples
examples/basic/data.rs (line 74)
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
76
77
78
79
80
81
82
83
84
85
86
    fn exec(&self) {
        // Create a new Server instance on localhost port 8080
        let mut server = Server::<()>::new(Ipv4Addr::LOCALHOST, 8080);

        // Define a route to handel query string
        // This will try to find a name value pair in the query string
        server.route(Method::GET, "/", |req| {
            // Format the response text
            let text = format!(
                "<h1>Hello, {}!</h1>",
                // Get the query value of name and default to "Nobody" if not found
                req.query.get("name").unwrap_or("Nobody")
            );

            Response::new().text(text).content(Content::HTML)
        });

        // Define another route
        // This time to handle form data
        server.route(Method::POST, "/form", |req| {
            // The body of requests is not part of the req.query
            // Instead it is part of the req.body but as a string
            // We will need to parse it get it as a query
            let body_data = Query::from_body(&String::from_utf8_lossy(&req.body));

            let name = body_data.get("name").unwrap_or("Nobody");
            let text = format!("<h1>Hello, {}</h1>", name);

            // Create a new response, with the following default data
            // - Status: 200
            // - Data: OK
            // - Headers: []
            Response::new()
                // Set the response body to be text
                .text(text)
                // Set the `Content-Type` header to be `text/html`
                // Note: This could also be set with the Response::content method
                .header(HeaderType::ContentType, "text/html")
        });

        // Define webpage with form
        // The form data will be post to /form on submit
        server.route(Method::GET, "/form", |_req| {
            let page = r#"<form method="post">
            <label for="name">Name:</label>
            <input type="text" id="name" name="name"><br><br>
            <input type="submit" value="Submit">
      </form>"#;

            Response::new().text(page).content(Content::HTML)
        });

        // Define a page with path params
        server.route(Method::GET, "/greet/{name}", |req| {
            // As this route would ever run without all the path params being filled
            // It is safe to unwrap if the name is in the path
            let data = format!("<h1>Hello, {}</h1>", req.param("name").unwrap());

            Response::new().text(data).content(Content::HTML)
        });

        // You can now goto http://localhost:8080?name=John and should see "Hello, John"
        // If you goto http://localhost:8080/form and submit the form you should see "Hello, {NAME}"
        // Also goto http://localhost:8080/greet/John and you should see "Hello, John"

        // Start the server
        // This will block the current thread
        server.start().unwrap();
    }
examples/application_quote_book.rs (line 76)
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 108)
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 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 Debug for Request

sourceยง

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

Formats the value using the given formatter. Read more
sourceยง

impl RealIp for Request

sourceยง

fn real_ip_header(&self, header: impl Into<HeaderType>) -> IpAddr

Gets the โ€˜real IPโ€™ of a client by parsing the value of 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
sourceยง

fn real_ip(&self) -> IpAddr

sourceยง

impl ServerSentEventsExt for Request

sourceยง

fn sse(&self) -> Result<ServerSentEventStream>

Initiates a SSE connection on the request.
sourceยง

impl<'a> TryFrom<&'a Request> for MultipartData<'a>

ยง

type Error = MultipartError

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

fn try_from(req: &'a Request) -> Result<Self, Self::Error>

Performs the conversion.

Auto Trait Implementationsยง

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.