aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/handler.rs6
-rw-r--r--src/response.rs199
-rw-r--r--src/router.rs72
3 files changed, 116 insertions, 161 deletions
diff --git a/src/handler.rs b/src/handler.rs
index c5e23e8..bd64f03 100644
--- a/src/handler.rs
+++ b/src/handler.rs
@@ -17,15 +17,15 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::{
+ response::Response,
returnable,
returnable::{CallbackContext, RouteContext},
- Response,
};
pub type RouteResponse =
- Box<dyn FnMut(RouteContext<'_>) -> Response<'_> + Send + Sync>;
+ Box<dyn FnMut(RouteContext<'_>) -> Response + Send + Sync>;
pub type ErrorResponse =
- Box<dyn FnMut(returnable::ErrorContext<'_>) -> Response<'_> + Send + Sync>;
+ Box<dyn FnMut(returnable::ErrorContext<'_>) -> Response + Send + Sync>;
pub type Callback = Box<dyn FnMut(CallbackContext<'_>) + Send + Sync>;
pub type CleanupCallback =
Box<dyn FnMut(CallbackContext<'_>, &mut String) + Send + Sync>;
diff --git a/src/response.rs b/src/response.rs
index 806eebb..4ab513e 100644
--- a/src/response.rs
+++ b/src/response.rs
@@ -18,149 +18,110 @@
//! Content and response handlers
+macro_rules! response {
+ ($name:ident, $status:expr) => {
+ pub fn $name<S>(content: S) -> Self
+ where S: AsRef<str> {
+ Self::new($status, content.as_ref())
+ }
+ };
+}
+
/// The content and response type a handler should reply with.
-pub enum Response<'a> {
- Input(String),
- SensitiveInput(String),
- Success(String),
- /// A successful response where the MIME type of the response is manually
- /// specific by the user
- SuccessWithMime(String, String),
- #[cfg(feature = "auto-deduce-mime")]
- /// A successful response where the MIME type of the response is
- /// automatically deduced from the provided bytes
- SuccessFileAuto(&'a [u8]),
- SuccessFile(&'a [u8], String),
- TemporaryRedirect(String),
- PermanentRedirect(String),
- TemporaryFailure(String),
- ServerUnavailable(String),
- CGIError(String),
- ProxyError(String),
- SlowDown(String),
- PermanentFailure(String),
- NotFound(String),
- Gone(String),
- ProxyRefused(String),
- BadRequest(String),
- ClientCertificateRequired(String),
- CertificateNotAuthorised(String),
- CertificateNotValid(String),
+#[derive(Clone)]
+pub struct Response {
+ pub status: i32,
+ pub mime: Option<String>,
+ pub content: String,
+ pub character_set: Option<String>,
+ pub language: Option<String>,
}
-pub(crate) fn to_value_set_status(
- response: Response<'_>,
- status: &mut i32,
- mime: &mut String,
-) -> String {
- match response {
- Response::Input(value) => {
- *status = 10;
+impl Response {
+ response!(input, 10);
- value
- }
- Response::SensitiveInput(value) => {
- *status = 11;
+ response!(sensitive_input, 11);
- value
- }
- Response::Success(value) => {
- *status = 20;
+ response!(temporary_redirect, 30);
- value
- }
- Response::SuccessWithMime(value, value_mime) => {
- *status = 23;
- *mime = value_mime;
+ response!(permanent_redirect, 31);
- value
- }
- Response::SuccessFile(value, value_mime) => {
- *status = 21; // Internal status code, not real.
- *mime = value_mime;
+ response!(temporary_failure, 40);
- String::from_utf8(value.to_vec()).unwrap()
- }
- #[cfg(feature = "auto-deduce-mime")]
- Response::SuccessFileAuto(value) => {
- *status = 22; // Internal status code, not real.
+ response!(server_unavailable, 41);
- String::from_utf8(value.to_vec()).unwrap()
- }
- Response::TemporaryRedirect(value) => {
- *status = 30;
+ response!(cgi_error, 42);
- value
- }
- Response::PermanentRedirect(value) => {
- *status = 31;
+ response!(proxy_error, 43);
- value
- }
- Response::TemporaryFailure(value) => {
- *status = 40;
+ response!(slow_down, 44);
- value
- }
- Response::ServerUnavailable(value) => {
- *status = 41;
+ response!(permanent_failure, 50);
- value
- }
- Response::CGIError(value) => {
- *status = 42;
+ response!(not_found, 51);
- value
- }
- Response::ProxyError(value) => {
- *status = 43;
+ response!(gone, 52);
- value
- }
- Response::SlowDown(value) => {
- *status = 44;
+ response!(proxy_refused, 53);
- value
- }
- Response::PermanentFailure(value) => {
- *status = 50;
+ response!(bad_request, 59);
- value
- }
- Response::NotFound(value) => {
- *status = 51;
+ response!(client_certificate_required, 60);
- value
- }
- Response::Gone(value) => {
- *status = 52;
+ response!(certificate_not_authorised, 61);
- value
- }
- Response::ProxyRefused(value) => {
- *status = 53;
+ response!(certificate_not_valid, 62);
- value
- }
- Response::BadRequest(value) => {
- *status = 59;
+ pub fn success<S>(content: S) -> Self
+ where S: AsRef<str> {
+ Self::new(20, content.as_ref())
+ .with_mime("text/gemini")
+ .with_language("en")
+ .with_character_set("utf-8")
+ .clone()
+ }
- value
- }
- Response::ClientCertificateRequired(value) => {
- *status = 60;
+ #[must_use]
+ pub fn binary_success(content: &[u8], mime: &str) -> Self {
+ Self::new(21, &String::from_utf8_lossy(content))
+ .with_mime(mime)
+ .clone()
+ }
- value
- }
- Response::CertificateNotAuthorised(value) => {
- *status = 61;
+ #[cfg(feature = "auto-deduce-mime")]
+ #[must_use]
+ pub fn binary_success_auto(content: &[u8]) -> Self {
+ Self::new(22, &String::from_utf8_lossy(content))
+ .with_mime(&tree_magic::from_u8(&*content))
+ .clone()
+ }
- value
+ #[must_use]
+ pub fn new(status: i32, content: &str) -> Self {
+ Self {
+ status,
+ mime: None,
+ content: content.to_string(),
+ character_set: None,
+ language: None,
}
- Response::CertificateNotValid(value) => {
- *status = 62;
+ }
- value
- }
+ pub fn with_mime(&mut self, mime: &str) -> &mut Self {
+ self.mime = Some(mime.to_string());
+
+ self
+ }
+
+ pub fn with_character_set(&mut self, character_set: &str) -> &mut Self {
+ self.character_set = Some(character_set.to_string());
+
+ self
+ }
+
+ pub fn with_language(&mut self, language: &str) -> &mut Self {
+ self.language = Some(language.to_string());
+
+ self
}
}
diff --git a/src/router.rs b/src/router.rs
index a28eb67..e1e7a11 100644
--- a/src/router.rs
+++ b/src/router.rs
@@ -29,7 +29,7 @@ use url::Url;
use crate::{
handler::{Callback, CleanupCallback, ErrorResponse, Partial, RouteResponse},
module::Module,
- response::{to_value_set_status, Response},
+ response::Response,
returnable::{CallbackContext, ErrorContext, RouteContext},
};
@@ -271,8 +271,6 @@ impl Router {
) -> Result<(), Box<dyn Error>> {
let mut buffer = [0u8; 1024];
let mut url = Url::parse("gemini://fuwn.me/")?;
- let mut response_status = 0;
- let mut response_mime_type = String::new();
let mut footer = String::new();
let mut header = String::new();
@@ -356,26 +354,19 @@ impl Router {
},
));
}
- to_value_set_status(
- (*route.value).lock().unwrap()(RouteContext::new(
- stream.get_ref(),
- &url,
- &route.params,
- &stream.ssl().peer_certificate(),
- )),
- &mut response_status,
- &mut response_mime_type,
- )
+
+ (*route.value).lock().unwrap()(RouteContext::new(
+ stream.get_ref(),
+ &url,
+ &route.params,
+ &stream.ssl().peer_certificate(),
+ ))
} else {
- to_value_set_status(
- (*self.error_handler).lock().unwrap()(ErrorContext::new(
- stream.get_ref(),
- &url,
- &stream.ssl().peer_certificate(),
- )),
- &mut response_status,
- &mut response_mime_type,
- )
+ (*self.error_handler).lock().unwrap()(ErrorContext::new(
+ stream.get_ref(),
+ &url,
+ &stream.ssl().peer_certificate(),
+ ))
};
for module in &mut *self.modules.lock().unwrap() {
@@ -394,36 +385,39 @@ impl Router {
route.as_ref().map_or(None, |route| Some(&route.params)),
&stream.ssl().peer_certificate(),
),
- &mut content,
+ &mut content.content,
);
stream
.write_all(
format!(
"{}{}\r\n{}",
- if response_status == 21
- || response_status == 22
- || response_status == 23
+ if content.status == 21
+ || content.status == 22
+ || content.status == 23
{
20
} else {
- response_status
+ content.status
},
- match response_status {
+ match content.status {
20 =>
format!(
- " text/gemini; charset={}; lang={}",
- self.charset, self.language
+ " {}; charset={}; lang={}",
+ content.mime.unwrap_or_else(|| "text/gemini".to_string()),
+ content
+ .character_set
+ .unwrap_or_else(|| self.charset.clone()),
+ content.language.unwrap_or_else(|| self.language.clone())
),
- 21 => response_mime_type,
+ 21 => content.mime.unwrap_or_default(),
#[cfg(feature = "auto-deduce-mime")]
- 22 => format!(" {}", tree_magic::from_u8(&*content.as_bytes())),
- 23 => response_mime_type,
- _ => format!(" {content}"),
+ 22 => format!(" {}", content.mime.unwrap_or_default()),
+ _ => format!(" {}", content.content),
},
- match response_status {
- 20 => format!("{header}{content}\n{footer}"),
- 21 | 22 | 23 => content.to_string(),
+ match content.status {
+ 20 => format!("{header}{}\n{footer}", content.content),
+ 21 | 22 => content.content,
_ => String::new(),
}
)
@@ -749,8 +743,8 @@ impl Default for Router {
Self {
routes: matchit::Router::new(),
error_handler: Arc::new(Mutex::new(Box::new(|_| {
- Response::NotFound(
- "This capsule has not implemented an error handler...".to_string(),
+ Response::not_found(
+ "This capsule has not implemented an error handler...",
)
}))),
private_key_file_name: String::new(),