use std::{env::var, time::Instant};
use actix_web::{Error, HttpResponse};
use crate::url::make as make_url;
#[allow(clippy::unused_async, clippy::future_not_send, clippy::too_many_lines)]
pub async fn default(
req: actix_web::HttpRequest,
) -> Result<HttpResponse, Error> {
let mut is_proxy = false;
let mut is_raw = false;
let mut is_nocss = false;
let url = match make_url(
&format!("{}{}", req.path(), {
if !req.query_string().is_empty() || req.uri().to_string().ends_with('?')
{
format!("?{}", req.query_string())
} else {
"".to_string()
}
}),
false,
&mut is_proxy,
&mut is_raw,
&mut is_nocss,
) {
Ok(url) => url,
Err(e) => {
return Ok(
HttpResponse::BadRequest()
.content_type("text/plain")
.body(format!("{}", e)),
);
}
};
let mut timer = Instant::now();
let mut response = match gmi::request::make_request(&url) {
Ok(response) => response,
Err(e) => {
return Ok(HttpResponse::Ok().body(e.to_string()));
}
};
if response.data.is_empty() {
response = match gmi::request::make_request(&match make_url(
req.path(),
true,
&mut is_proxy,
&mut is_raw,
&mut is_nocss,
) {
Ok(url) => url,
Err(e) => {
return Ok(
HttpResponse::BadRequest()
.content_type("text/plain")
.body(format!("{}", e)),
);
}
}) {
Ok(response) => response,
Err(e) => {
return Ok(HttpResponse::Ok().body(e.to_string()));
}
};
}
let response_time_taken = timer.elapsed();
let meta = germ::meta::Meta::from_string(&response.meta);
let charset = meta
.parameters()
.get("charset")
.map_or_else(|| "utf-8".to_string(), ToString::to_string);
let language = meta
.parameters()
.get("lang")
.map_or_else(|| "".to_string(), ToString::to_string);
timer = Instant::now();
let mut html_context = if is_raw {
String::new()
} else {
format!(
"<!DOCTYPE html><html{}><head>",
if language.is_empty() {
"".to_string()
} else {
format!(" lang=\"{}\"", language)
}
)
};
let gemini_html =
crate::gemini_to_html::gemini_to_html(&response, &url, is_proxy);
let gemini_title = gemini_html.0;
let convert_time_taken = timer.elapsed();
if is_raw {
html_context.push_str(&String::from_utf8_lossy(&response.data));
return Ok(
HttpResponse::Ok()
.content_type(format!("{}; charset={}", meta.mime(), charset))
.body(html_context),
);
}
if is_nocss {
html_context.push_str(&gemini_html.1);
return Ok(
HttpResponse::Ok()
.content_type(format!("text/html; charset={}", meta.mime()))
.body(html_context),
);
}
if let Ok(css) = var("CSS_EXTERNAL") {
html_context.push_str(&format!(
"<link rel=\"stylesheet\" type=\"text/css\" href=\"{}\">",
css
));
}
if let Ok(favicon) = var("FAVICON_EXTERNAL") {
html_context.push_str(&format!(
"<link rel=\"icon\" type=\"image/x-icon\" href=\"{}\">",
favicon
));
}
html_context.push_str(&format!("<title>{}</title>", gemini_title));
html_context.push_str("</head><body>");
match response.status {
gmi::protocol::StatusCode::Success(_) =>
html_context.push_str(&gemini_html.1),
_ => html_context.push_str(&format!("<p>{}</p>", response.meta)),
}
html_context.push_str(&format!(
"<details>\n<summary>Proxy information</summary>
<dl>
<dt>Original URL</dt><dd><a href=\"{}\">{0}</a></dd>
<dt>Status code</dt>
<dd>{:?}</dd>
<dt>Meta</dt><dd>{}</dd>
<dt>Capsule response time</dt>
<dd>{} milliseconds</dd>
<dt>Gemini-to-HTML time</dt>
<dd>{} milliseconds</dd>
</dl>
<p>This content has been proxied by \
<a href=\"https://github.com/gemrest/september{}\">September ({})</a>.</p>
</details></body></html>",
url,
response.status,
response.meta,
response_time_taken.as_nanos() as f64 / 1_000_000.0,
convert_time_taken.as_nanos() as f64 / 1_000_000.0,
format_args!("/tree/{}", env!("VERGEN_GIT_SHA")),
env!("VERGEN_GIT_SHA").get(0..5).unwrap_or("UNKNOWN"),
));
if let Ok(plain_texts) = var("PLAIN_TEXT_ROUTE") {
if plain_texts.split(',').any(|r| r == req.path()) {
return Ok(
HttpResponse::Ok()
.body(String::from_utf8_lossy(&response.data).to_string()),
);
}
}
Ok(
HttpResponse::Ok()
.content_type(format!("text/html; charset={}", charset))
.body(html_context),
)
}