create a http server and parse cookies in rust

To create a HTTP server in Rust, we can use the hyper library. We can also use the cookie library to parse cookies. Here is an example of how to use these libraries to create a HTTP server that can parse cookies:

main.rs
use hyper::{Body, Request, Response, Server};
use hyper::header::{COOKIE, SET_COOKIE};
use hyper::http::{Error, StatusCode};
use std::collections::HashMap;
use cookie::{Cookie, CookieJar};

type GenericError = Box<dyn std::error::Error + Send + Sync>;

async fn handle_request(req: Request<Body>) -> Result<Response<Body>, GenericError> {
    if req.method() == hyper::Method::POST && req.uri().path() == "/login" {
        let (parts, body) = req.into_parts();
        let whole_body = hyper::body::to_bytes(body).await?;
        let body_str = String::from_utf8(whole_body.to_vec())?;
        let body_params = body_str.split("&").map(|s| s.split("=")).collect::<Vec<_>>();

        let mut form_params = HashMap::new();
        for entry in body_params {
            let key = entry.clone().nth(0).unwrap().to_string();
            let value = entry.clone().nth(1).unwrap().to_string();
            form_params.insert(key, value);
        }

        let username = form_params.get("username").cloned().unwrap_or_else(String::new);
        let password = form_params.get("password").cloned().unwrap_or_else(String::new);

        let mut cookie_jar = CookieJar::new();
        cookie_jar.add(Cookie::new("username", username));
        cookie_jar.add(Cookie::new("password", password));

        let mut resp = Response::new(Body::empty());
        let headers = resp.headers_mut();
        for cookie in cookie_jar.delta() {
            let cookie_string = cookie.to_string();
            headers.append(SET_COOKIE, cookie_string.parse().unwrap());
        }

        *resp.body_mut() = Body::from(format!("Welcome {}! You have logged in successfully!", username));
        *resp.status_mut() = StatusCode::OK;
        return Ok(resp);
    }

    if let Some(cookie_header) = req.headers().get(COOKIE) {
        let cookies_str = cookie_header.to_str()?;
        let cookie_jar = cookies_str.parse::<CookieJar>()?;
        let username_cookie = cookie_jar.get("username");
        let password_cookie = cookie_jar.get("password");

        if let (Some(username_cookie), Some(password_cookie)) = (username_cookie, password_cookie) {
            let username = username_cookie.value().to_string();
            let password = password_cookie.value().to_string();
            let message = format!("Welcome back {}! Your password is {}", username, password);
            let mut resp = Response::new(Body::empty());
            *resp.body_mut() = Body::from(message);
            *resp.status_mut() = StatusCode::OK;
            return Ok(resp);
        }
    }

    let mut resp = Response::new(Body::empty());
    *resp.body_mut() = Body::from("Welcome! Please log in.");
    *resp.status_mut() = StatusCode::OK;
    Ok(resp)
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let addr = "127.0.0.1:3000".parse()?;
    let server = Server::bind(&addr).serve(|| hyper::service::make_service_fn(|_| {
        async { Ok::<_, GenericError>(hyper::service::service_fn(handle_request)) }
    }));

    println!("Listening on http://{}", addr);
    server.await?;
    Ok(())
}

3084 chars
77 lines

In this example, we define a handle_request() function that handles incoming HTTP requests. When a POST request is received with /login as the path, we parse the request body to extract the username and password form fields, store them in cookies, and return a message indicating a successful login.

When a subsequent request is received with valid cookies containing username and password, we retrieve the values and generate a response indicating a successful login. If no valid cookies are present, we return a default message prompting the user to log in.

The main function uses hyper to bind the server to an address and start serving requests.

gistlibby LogSnag