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,
)
}