Tiny HTTP redirect URL

tiny_http web Header HeaderField AsciiString Request Response

Part of the Tiny HTTP series.

Sometimes you'd like to have a URL that, instead of showing content would redirect the browser to some other page on the same web site or on a different web site. For example I have a path on the Code Maven web site that will redirect the users to my YouTube channel: https://code-maven.com/youtube. I created this redirection so it will be easy for me to link to the channel and even to type it in when I need to do that.

I often need redirection behind a login page, so when someone visits a page and then wants to login to the website I can send the person back to the same page after s/he logged in. This can be implemented in the front-end without redirection, but if I'd like to do it in the back-end then redirection can be useful.

In technical terms a redirection is created by setting the status code to one of the appropriate numbers in the 300-399 range and adding a field called Location to the header with the target URL as the value.

There is a page listing all the HTTP response status codes and a separate page describing Redirections in HTTP in more details.

Rust code to redirect URL in Tiny HTTP

This is the core of the solution.

First we create a Header with a field called Location and a value supplied by the caller that is the target URL where w would like to redirect the user to.

Then we create a response. The content of the response can be an empty string. The status code must be set correctly and we need to add the header.

fn redirect(request: tiny_http::Request, site: &str, status_code: u16) {
    let header = Header {
        field: HeaderField::from_str("Location").unwrap(),
        value: AsciiString::from_ascii(site).unwrap(),
    };
    request
        .respond(
            Response::from_string("")
                .with_status_code(StatusCode::from(status_code))
                .with_header(header),
        )
        .unwrap();
}

This is how we would call it:

redirect(request, "https://rust.code-maven.com/", 302);

Where 302 means "temporary redirect".

full source code

examples/tiny-http/redirect/Cargo.toml

[package]
name = "redirect"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ascii = "1.1"
tiny_http = "0.12"

examples/tiny-http/redirect/src/main.rs

use ascii::AsciiString;
use std::str::FromStr;
use tiny_http::{Header, HeaderField, Response, Server, StatusCode};

fn main() {
    let host = "127.0.0.1";
    let port = "5000";

    let server_str = format!("{}:{}", host, port);

    let server = Server::http(&server_str).expect("Failed to start demo server.");
    println!("Visit http://{}", server_str);

    for request in server.incoming_requests() {
        let path = if let Some((path, _)) = request.url().split_once('?') {
            path
        } else {
            request.url()
        };

        println!("path: {}", path);

        let (html, status_code) = match path {
            "/" => root_page(&request),
            "/hello" => hello(&request),
            "/redir" => {
                redirect(request, "https://rust.code-maven.com/", 302);
                continue;
            }
            _ => default(&request),
        };

        let header = Header {
            field: HeaderField::from_str("Content-type").unwrap(),
            value: AsciiString::from_ascii("text/html").unwrap(),
        };

        request
            .respond(
                Response::from_string(html)
                    .with_status_code(StatusCode::from(status_code))
                    .with_header(header),
            )
            .unwrap();
    }
}

fn default(_request: &tiny_http::Request) -> (String, u32) {
    (String::from("Page not found"), 404)
}

fn redirect(request: tiny_http::Request, site: &str, status_code: u16) {
    let header = Header {
        field: HeaderField::from_str("Location").unwrap(),
        value: AsciiString::from_ascii(site).unwrap(),
    };
    request
        .respond(
            Response::from_string("")
                .with_status_code(StatusCode::from(status_code))
                .with_header(header),
        )
        .unwrap();
}

fn root_page(_request: &tiny_http::Request) -> (String, u32) {
    (
        String::from(
            r#"Welcome! Try <a href="/hello">this</a> page.  This is a <a href="/redir">redirect</a>"#,
        ),
        200,
    )
}

fn hello(_request: &tiny_http::Request) -> (String, u32) {
    (
        String::from(r#"Hello World! <a href="/">home</a> page."#),
        200,
    )
}

Related Pages

Getting started with Tiny HTTP building a web application in Rust

Author

Gabor Szabo (szabgab)

Gabor Szabo, the author of the Rust Maven web site maintains several Open source projects in Rust and while he still feels he has tons of new things to learn about Rust he already offers training courses in Rust and still teaches Python, Perl, git, GitHub, GitLab, CI, and testing.

Gabor Szabo