Proper MimeType handling with mycelium

This commit is contained in:
Slatian 2023-10-29 16:51:43 +01:00
parent bfa383ddbe
commit de179ea7fa
4 changed files with 30 additions and 19 deletions

1
Cargo.lock generated
View File

@ -493,6 +493,7 @@ dependencies = [
"idna 0.3.0", "idna 0.3.0",
"lazy_static", "lazy_static",
"maxminddb", "maxminddb",
"mime",
"parking_lot", "parking_lot",
"regex", "regex",
"serde", "serde",

View File

@ -25,3 +25,4 @@ tower-http = { version = "0.4", features = ["fs"] }
trust-dns-proto = "0.22" trust-dns-proto = "0.22"
trust-dns-resolver = { version = "0.22", features = ["dns-over-rustls","dns-over-https","dns-over-quic"] } trust-dns-resolver = { version = "0.22", features = ["dns-over-rustls","dns-over-https","dns-over-quic"] }
maxminddb = "0.23" maxminddb = "0.23"
mime = "0.3"

View File

@ -1,6 +1,7 @@
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use mime::Mime;
/// Defines how the response should be rendered. /// Defines how the response should be rendered.
pub enum MycFormatFamily { pub enum MycFormatFamily {
@ -14,7 +15,7 @@ pub enum MycFormatFamily {
/// Implement on a type that is able to describe a response format. /// Implement on a type that is able to describe a response format.
/// ///
/// It is best implemented on an enum. /// It is best implemented on an enum.
pub trait MycFormat: ToString+Clone+Default { pub trait MycFormat: ToString+Clone+Default+Send {
// Return the format family this // Return the format family this
fn get_family(&self) -> MycFormatFamily { fn get_family(&self) -> MycFormatFamily {
@ -48,7 +49,7 @@ pub trait MycFormat: ToString+Clone+Default {
/// ///
/// Implementing get_mime_type() properly is recommended /// Implementing get_mime_type() properly is recommended
/// for production use. /// for production use.
fn get_less_well_known_mimetype(&self) -> Option<&'static str> { fn get_less_well_known_mimetype(&self) -> Option<Mime> {
None None
} }
@ -61,8 +62,8 @@ pub trait MycFormat: ToString+Clone+Default {
/// to get_less_well_known_mimetype() and the "application/octet-stream" type. /// to get_less_well_known_mimetype() and the "application/octet-stream" type.
/// ///
/// The default implementation knows the following associations: /// The default implementation knows the following associations:
/// * `text`: `text/plain` /// * `text`: `text/plain; charset=utf-8`
/// * `html`: `text/html` /// * `html`: `text/html; charset=utf-8`
/// * `json`: `application/json` /// * `json`: `application/json`
/// * `xml`: `application/xml` /// * `xml`: `application/xml`
/// * `rss`: `application/rss+xml` /// * `rss`: `application/rss+xml`
@ -71,17 +72,20 @@ pub trait MycFormat: ToString+Clone+Default {
/// *Implementation Note:* It may be possible that two different views /// *Implementation Note:* It may be possible that two different views
/// have the same MimeType (maybe two json representations for different consumers). /// have the same MimeType (maybe two json representations for different consumers).
/// ///
fn get_mime_type(&self) -> &'static str { fn get_mime_type(&self) -> Mime {
match self.get_name().as_str() { match self.get_name().as_str() {
"text" => "text/plain", "text" => mime::TEXT_PLAIN_UTF_8,
"html" => "text/html", "html" => mime::TEXT_HTML_UTF_8,
"json" => "application/json", "json" => mime::APPLICATION_JSON,
"xml" => "application/xml", "xml" => "application/xml".parse()
"rss" => "application/rss+xml", .expect("Parse static application/xml"),
"atom" => "application/atom+xml", "rss" => "application/rss+xml".parse()
.expect("Parse static application/rss+xml"),
"atom" => "application/atom+xml".parse()
.expect("Parse static application/atom+xml"),
_ => _ =>
self.get_less_well_known_mimetype() self.get_less_well_known_mimetype()
.unwrap_or_else(||"application/octet-stream"), .unwrap_or(mime::APPLICATION_OCTET_STREAM),
} }
} }

View File

@ -4,10 +4,11 @@
*/ */
use axum::{ use axum::{
body::{Bytes,Full},
headers::HeaderValue, headers::HeaderValue,
http::StatusCode, http::StatusCode,
http::header,
http::header::SET_COOKIE, http::header::SET_COOKIE,
response::Html,
response::IntoResponse, response::IntoResponse,
response::Response, response::Response,
response::Json, response::Json,
@ -22,7 +23,6 @@ use crate::mycelium::MycView;
use crate::mycelium::MycFormat; use crate::mycelium::MycFormat;
use crate::mycelium::MycFormatFamily; use crate::mycelium::MycFormatFamily;
use crate::settings::QuerySettings; use crate::settings::QuerySettings;
use crate::settings::ResponseFormat;
/* The engine itself */ /* The engine itself */
@ -41,12 +41,13 @@ impl Engine {
let mut response = match settings.format.get_family() { let mut response = match settings.format.get_family() {
MycFormatFamily::Template => { MycFormatFamily::Template => {
let template_name = view.get_template_name(); let template_name = view.get_template_name();
let mime_type = settings.format.get_mime_type();
let mut context = tera::Context::new(); let mut context = tera::Context::new();
context.insert("view", &template_name); context.insert("view", &template_name);
//intented for shared macros //intented for shared macros
context.insert("format", &settings.format.get_name()); context.insert("format", &settings.format.get_name());
context.insert("mimetype", &settings.format.get_mime_type()); context.insert("mimetype", &mime_type.to_string());
context.insert("language", &settings.lang); context.insert("language", &settings.lang);
context.insert("dns_resolvers", &settings.available_dns_resolvers); context.insert("dns_resolvers", &settings.available_dns_resolvers);
context.insert("dns_resolver_id", &settings.dns_resolver_id); context.insert("dns_resolver_id", &settings.dns_resolver_id);
@ -55,10 +56,14 @@ impl Engine {
match self.tera.render(&(template_name.clone()+&settings.format.get_file_extension()), &context) { match self.tera.render(&(template_name.clone()+&settings.format.get_file_extension()), &context) {
Ok(text) => Ok(text) =>
match settings.format { (
ResponseFormat::Html => Html(text).into_response(), [(
_ => text.into_response(), header::CONTENT_TYPE,
} HeaderValue::from_str(mime_type.as_ref())
.expect("MimeType should always be a valid header value.")
)],
Into::<Full<Bytes>>::into(text),
).into_response(),
Err(e) => { Err(e) => {
println!("There was an error while rendering template {}: {e:?}", template_name); println!("There was an error while rendering template {}: {e:?}", template_name);
( (