♻️ Simple & Efficient Gemini-to-HTTP Proxy fuwn.net
proxy gemini-protocol protocol gemini http rust
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(src): Remove unnecessary allocations

Fuwn 0fd7b223 48a8799d

+87 -50
+31 -22
src/html.rs
··· 1 - use {germ::ast::Node, std::env::var, url::Url}; 1 + use {germ::ast::Node, std::env::var, std::fmt::Write, url::Url}; 2 2 3 3 fn link_from_host_href(url: &Url, href: &str) -> Option<String> { 4 4 Some(format!( ··· 98 98 } 99 99 100 100 match node { 101 - Node::Text(text) => html.push_str(&format!("<p>{}</p>", safe(text))), 101 + Node::Text(text) => { 102 + let _ = write!(&mut html, "<p>{}</p>", safe(text)); 103 + } 102 104 Node::Link { to, text } => { 103 105 let mut href = to.to_string(); 104 106 let mut surface = false; ··· 202 204 || extension == "svg" 203 205 { 204 206 if embed_images == "1" { 205 - html.push_str(&format!( 206 - "<p><a href=\"{}\">{}</a> <i>Embedded below</i></p>\n", 207 + let _ = writeln!( 208 + &mut html, 209 + "<p><a href=\"{}\">{}</a> <i>Embedded below</i></p>", 207 210 href, 208 211 safe(text.as_ref().unwrap_or(to)), 209 - )); 212 + ); 210 213 } 211 214 212 - html.push_str(&format!( 213 - "<p><img src=\"{}\" alt=\"{}\" /></p>\n", 215 + let _ = writeln!( 216 + &mut html, 217 + "<p><img src=\"{}\" alt=\"{}\" /></p>", 214 218 safe(&href), 215 219 safe(text.as_ref().unwrap_or(to)), 216 - )); 220 + ); 217 221 218 222 continue; 219 223 } ··· 222 226 223 227 previous_link = true; 224 228 225 - html.push_str(&format!( 229 + let _ = write!( 230 + &mut html, 226 231 r#"{}<a href="{}">{}</a>"#, 227 232 if condense_links { "" } else { GEMINI_FRAGMENT }, 228 233 href, 229 234 safe(text.as_ref().unwrap_or(to)).trim(), 230 - )); 235 + ); 231 236 } 232 237 Node::Heading { level, text } => { 233 238 if !condensible_headings.contains(&node.to_gemtext().as_str()) { ··· 238 243 title = safe(text).to_string(); 239 244 } 240 245 241 - html.push_str(&format!( 246 + let _ = write!( 247 + &mut html, 242 248 "<{}>{}</{0}>", 243 249 match level { 244 250 1 => "h1", ··· 247 253 _ => "p", 248 254 }, 249 255 safe(text), 250 - )); 256 + ); 251 257 } 252 - Node::List(items) => html.push_str(&format!( 253 - "<ul>{}</ul>", 254 - items 255 - .iter() 256 - .map(|i| format!("<li>{}</li>", safe(i))) 257 - .collect::<Vec<String>>() 258 - .join("\n") 259 - )), 258 + Node::List(items) => { 259 + let _ = write!( 260 + &mut html, 261 + "<ul>{}</ul>", 262 + items 263 + .iter() 264 + .map(|i| format!("<li>{}</li>", safe(i))) 265 + .collect::<Vec<String>>() 266 + .join("\n") 267 + ); 268 + } 260 269 Node::Blockquote(text) => { 261 - html.push_str(&format!("<blockquote>{}</blockquote>", safe(text))); 270 + let _ = write!(&mut html, "<blockquote>{}</blockquote>", safe(text)); 262 271 } 263 272 Node::PreformattedText { text, .. } => { 264 273 let mut new_text = text.to_string(); 265 274 266 275 new_text.pop(); 267 276 268 - html.push_str(&format!("<pre>{new_text}</pre>")); 277 + let _ = write!(&mut html, "<pre>{new_text}</pre>"); 269 278 } 270 279 Node::Whitespace => {} 271 280 }
+2 -1
src/main.rs
··· 14 14 mod response; 15 15 mod url; 16 16 17 - #[macro_use] extern crate log; 17 + #[macro_use] 18 + extern crate log; 18 19 19 20 use {actix_web::web, response::default, std::env::var}; 20 21
+34 -19
src/response.rs
··· 3 3 use { 4 4 crate::url::from_path as url_from_path, 5 5 actix_web::{Error, HttpResponse}, 6 - std::{env::var, time::Instant}, 6 + std::{env::var, fmt::Write, time::Instant}, 7 7 }; 8 8 9 9 const CSS: &str = include_str!("../default.css"); ··· 137 137 css.split(',').filter(|s| !s.is_empty()).collect::<Vec<_>>(); 138 138 139 139 for stylesheet in stylesheets { 140 - html_context.push_str(&format!( 140 + let _ = write!( 141 + &mut html_context, 141 142 "<link rel=\"stylesheet\" type=\"text/css\" href=\"{stylesheet}\">", 142 - )); 143 + ); 143 144 } 144 145 } else if !configuration.is_no_css() { 145 - html_context.push_str(&format!(r#"<link rel="stylesheet" href="https://latex.vercel.app/style.css"><style>{CSS}</style>"#)); 146 + let _ = write!( 147 + &mut html_context, 148 + r#"<link rel="stylesheet" href="https://latex.vercel.app/style.css"><style>{CSS}</style>"# 149 + ); 146 150 147 151 if let Ok(primary) = var("PRIMARY_COLOUR") { 148 - html_context 149 - .push_str(&format!("<style>:root {{ --primary: {primary} }}</style>")); 152 + let _ = write!( 153 + &mut html_context, 154 + "<style>:root {{ --primary: {primary} }}</style>" 155 + ); 150 156 } else { 151 - html_context 152 - .push_str("<style>:root { --primary: var(--base0D); }</style>"); 157 + let _ = write!( 158 + &mut html_context, 159 + "<style>:root {{ --primary: var(--base0D); }}</style>" 160 + ); 153 161 } 154 162 } 155 163 156 164 if let Ok(favicon) = var("FAVICON_EXTERNAL") { 157 - html_context.push_str(&format!( 165 + let _ = write!( 166 + &mut html_context, 158 167 "<link rel=\"icon\" type=\"image/x-icon\" href=\"{favicon}\">", 159 - )); 168 + ); 160 169 } 161 170 162 171 if var("MATHJAX").unwrap_or_else(|_| "true".to_string()).to_lowercase() ··· 173 182 html_context.push_str(&head); 174 183 } 175 184 176 - html_context.push_str(&format!("<title>{gemini_title}</title>")); 177 - html_context.push_str("</head><body>"); 185 + let _ = write!(&mut html_context, "<title>{gemini_title}</title>"); 186 + let _ = write!(&mut html_context, "</head><body>"); 178 187 179 188 if !http_request.path().starts_with("/proxy") { 180 189 if let Ok(header) = var("HEADER") { 181 - html_context 182 - .push_str(&format!("<big><blockquote>{header}</blockquote></big>")); 190 + let _ = write!( 191 + &mut html_context, 192 + "<big><blockquote>{header}</blockquote></big>" 193 + ); 183 194 } 184 195 } 185 196 ··· 188 199 if let (Some(status), Some(url)) = 189 200 (redirect_response_status, redirect_url) 190 201 { 191 - html_context.push_str(&format!( 202 + let _ = write!( 203 + &mut html_context, 192 204 "<blockquote>This page {} redirects to <a \ 193 205 href=\"{}\">{}</a>.</blockquote>", 194 206 if status == germ::request::Status::PermanentRedirect { ··· 198 210 }, 199 211 url, 200 212 url 201 - )); 213 + ); 202 214 } 203 215 204 216 html_context.push_str(&gemini_html.1); 205 217 } 206 - _ => html_context.push_str(&format!("<p>{}</p>", response.meta())), 218 + _ => { 219 + let _ = write!(&mut html_context, "<p>{}</p>", response.meta()); 220 + } 207 221 } 208 222 209 - html_context.push_str(&format!( 223 + let _ = write!( 224 + &mut html_context, 210 225 "<details>\n<summary>Proxy Information</summary> 211 226 <dl> 212 227 <dt>Original URL</dt><dd><a \ ··· 233 248 convert_time_taken.as_nanos() as f64 / 1_000_000.0, 234 249 format_args!("/tree/{}", env!("VERGEN_GIT_SHA")), 235 250 env!("VERGEN_GIT_SHA").get(0..5).unwrap_or("UNKNOWN"), 236 - )); 251 + ); 237 252 238 253 if let Ok(plain_texts) = var("PLAIN_TEXT_ROUTE") { 239 254 if plain_texts.split(',').any(|r| {
+20 -8
src/response/configuration.rs
··· 1 1 pub struct Configuration { 2 - is_proxy: bool, 3 - is_raw: bool, 2 + is_proxy: bool, 3 + is_raw: bool, 4 4 is_no_css: bool, 5 5 } 6 6 ··· 9 9 Self { is_proxy: false, is_raw: false, is_no_css: false } 10 10 } 11 11 12 - pub const fn is_proxy(&self) -> bool { self.is_proxy } 12 + pub const fn is_proxy(&self) -> bool { 13 + self.is_proxy 14 + } 13 15 14 - pub const fn is_raw(&self) -> bool { self.is_raw } 16 + pub const fn is_raw(&self) -> bool { 17 + self.is_raw 18 + } 15 19 16 - pub const fn is_no_css(&self) -> bool { self.is_no_css } 20 + pub const fn is_no_css(&self) -> bool { 21 + self.is_no_css 22 + } 17 23 18 - pub fn set_proxy(&mut self, is_proxy: bool) { self.is_proxy = is_proxy; } 24 + pub fn set_proxy(&mut self, is_proxy: bool) { 25 + self.is_proxy = is_proxy; 26 + } 19 27 20 - pub fn set_raw(&mut self, is_raw: bool) { self.is_raw = is_raw; } 28 + pub fn set_raw(&mut self, is_raw: bool) { 29 + self.is_raw = is_raw; 30 + } 21 31 22 - pub fn set_no_css(&mut self, is_no_css: bool) { self.is_no_css = is_no_css; } 32 + pub fn set_no_css(&mut self, is_no_css: bool) { 33 + self.is_no_css = is_no_css; 34 + } 23 35 }