Use tracing; use cow for hop redirects

This commit is contained in:
Edward Shen 2022-06-02 23:22:53 -07:00
parent 72e672bc73
commit 0144cf5f50
Signed by: edward
GPG key ID: 19182661E818369F

View file

@ -1,7 +1,7 @@
use crate::config::{Route as ConfigRoute, RouteType}; use crate::config::{Route as ConfigRoute, RouteType};
use crate::{template_args, BunBunError, Route, State}; use crate::{template_args, BunBunError, Route, State};
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use axum::body::{boxed, Bytes, Full}; use axum::body::{boxed, Bytes, Empty, Full};
use axum::extract::Query; use axum::extract::Query;
use axum::http::{header, StatusCode}; use axum::http::{header, StatusCode};
use axum::response::{Html, IntoResponse, Response}; use axum::response::{Html, IntoResponse, Response};
@ -9,6 +9,7 @@ use axum::Extension;
use handlebars::Handlebars; use handlebars::Handlebars;
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
use serde::Deserialize; use serde::Deserialize;
use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
@ -88,7 +89,7 @@ pub async fn hop(
) -> impl IntoResponse { ) -> impl IntoResponse {
let data = data.load(); let data = data.load();
match resolve_hop(&query.to, &data.routes, &data.default_route) { match resolve_hop(&query.to, &data.routes, data.default_route.as_deref()) {
RouteResolution::Resolved { route: path, args } => { RouteResolution::Resolved { route: path, args } => {
let resolved_template = match path { let resolved_template = match path {
ConfigRoute { ConfigRoute {
@ -100,7 +101,7 @@ pub async fn hop(
route_type: RouteType::External, route_type: RouteType::External,
path, path,
.. ..
} => Ok(HopAction::Redirect(path.clone())), } => Ok(HopAction::Redirect(Cow::Borrowed(path))),
}; };
match resolved_template { match resolved_template {
@ -113,8 +114,8 @@ pub async fn hop(
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Response::builder() Response::builder()
.status(StatusCode::FOUND) .status(StatusCode::FOUND)
.header(header::LOCATION, &path) .header(header::LOCATION, rendered)
.body(boxed(Full::from(rendered))) .body(boxed(Empty::new()))
} }
Ok(HopAction::Body(body)) => Response::builder() Ok(HopAction::Body(body)) => Response::builder()
.status(StatusCode::OK) .status(StatusCode::OK)
@ -149,7 +150,7 @@ enum RouteResolution<'a> {
fn resolve_hop<'a>( fn resolve_hop<'a>(
query: &str, query: &str,
routes: &'a HashMap<String, Route>, routes: &'a HashMap<String, Route>,
default_route: &Option<String>, default_route: Option<&str>,
) -> RouteResolution<'a> { ) -> RouteResolution<'a> {
let mut split_args = query.split_ascii_whitespace().peekable(); let mut split_args = query.split_ascii_whitespace().peekable();
let maybe_route = { let maybe_route = {
@ -209,8 +210,8 @@ const fn check_route(route: &Route, arg_count: usize) -> bool {
#[derive(Deserialize, Debug, PartialEq, Eq)] #[derive(Deserialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
enum HopAction { enum HopAction<'a> {
Redirect(String), Redirect(Cow<'a, str>),
Body(String), Body(String),
} }
@ -218,13 +219,13 @@ enum HopAction {
/// so long as the executable was successfully executed. Returns an Error if the /// so long as the executable was successfully executed. Returns an Error if the
/// file doesn't exist or bunbun did not have permission to read and execute the /// file doesn't exist or bunbun did not have permission to read and execute the
/// file. /// file.
fn resolve_path(path: &Path, args: &str) -> Result<HopAction, BunBunError> { fn resolve_path(path: &Path, args: &str) -> Result<HopAction<'static>, BunBunError> {
let output = Command::new(path.canonicalize()?) let output = Command::new(path.canonicalize()?)
.args(args.split(' ')) .args(args.split(' '))
.output()?; .output()?;
if output.status.success() { if output.status.success() {
Ok(serde_json::from_slice(&output.stdout[..])?) Ok(serde_json::from_slice(&output.stdout)?)
} else { } else {
error!( error!(
"Program exit code for {} was not 0! Dumping standard error!", "Program exit code for {} was not 0! Dumping standard error!",
@ -250,7 +251,7 @@ mod resolve_hop {
#[test] #[test]
fn empty_routes_no_default_yields_failed_hop() { fn empty_routes_no_default_yields_failed_hop() {
assert_eq!( assert_eq!(
resolve_hop("hello world", &HashMap::new(), &None), resolve_hop("hello world", &HashMap::new(), None),
RouteResolution::Unresolved RouteResolution::Unresolved
); );
} }
@ -258,11 +259,7 @@ mod resolve_hop {
#[test] #[test]
fn empty_routes_some_default_yields_failed_hop() { fn empty_routes_some_default_yields_failed_hop() {
assert_eq!( assert_eq!(
resolve_hop( resolve_hop("hello world", &HashMap::new(), Some(&"google")),
"hello world",
&HashMap::new(),
&Some(String::from("google"))
),
RouteResolution::Unresolved RouteResolution::Unresolved
); );
} }
@ -272,7 +269,7 @@ mod resolve_hop {
let mut map: HashMap<String, Route> = HashMap::new(); let mut map: HashMap<String, Route> = HashMap::new();
map.insert("google".into(), Route::from("https://example.com")); map.insert("google".into(), Route::from("https://example.com"));
assert_eq!( assert_eq!(
resolve_hop("hello world", &map, &Some(String::from("google"))), resolve_hop("hello world", &map, Some("google")),
generate_route_result(&Route::from("https://example.com"), "hello world"), generate_route_result(&Route::from("https://example.com"), "hello world"),
); );
Ok(()) Ok(())
@ -283,7 +280,7 @@ mod resolve_hop {
let mut map: HashMap<String, Route> = HashMap::new(); let mut map: HashMap<String, Route> = HashMap::new();
map.insert("google".into(), Route::from("https://example.com")); map.insert("google".into(), Route::from("https://example.com"));
assert_eq!( assert_eq!(
resolve_hop("google hello world", &map, &Some(String::from("a"))), resolve_hop("google hello world", &map, Some("a")),
generate_route_result(&Route::from("https://example.com"), "hello world"), generate_route_result(&Route::from("https://example.com"), "hello world"),
); );
Ok(()) Ok(())
@ -294,7 +291,7 @@ mod resolve_hop {
let mut map: HashMap<String, Route> = HashMap::new(); let mut map: HashMap<String, Route> = HashMap::new();
map.insert("google".into(), Route::from("https://example.com")); map.insert("google".into(), Route::from("https://example.com"));
assert_eq!( assert_eq!(
resolve_hop("google hello world", &map, &None), resolve_hop("google hello world", &map, None),
generate_route_result(&Route::from("https://example.com"), "hello world"), generate_route_result(&Route::from("https://example.com"), "hello world"),
); );
Ok(()) Ok(())
@ -358,6 +355,7 @@ mod resolve_path {
use super::{resolve_path, HopAction}; use super::{resolve_path, HopAction};
use anyhow::Result; use anyhow::Result;
use std::borrow::Cow;
use std::env::current_dir; use std::env::current_dir;
use std::io::ErrorKind; use std::io::ErrorKind;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -401,7 +399,7 @@ mod resolve_path {
fn return_body() -> Result<()> { fn return_body() -> Result<()> {
assert_eq!( assert_eq!(
resolve_path(&Path::new("/bin/echo"), r#"{"body": "a"}"#)?, resolve_path(&Path::new("/bin/echo"), r#"{"body": "a"}"#)?,
HopAction::Body("a".to_string()) HopAction::Body("a".to_owned())
); );
Ok(()) Ok(())
@ -411,7 +409,7 @@ mod resolve_path {
fn return_redirect() -> Result<()> { fn return_redirect() -> Result<()> {
assert_eq!( assert_eq!(
resolve_path(&Path::new("/bin/echo"), r#"{"redirect": "a"}"#)?, resolve_path(&Path::new("/bin/echo"), r#"{"redirect": "a"}"#)?,
HopAction::Redirect("a".to_string()) HopAction::Redirect(Cow::Borrowed("a"))
); );
Ok(()) Ok(())
} }