|
|
|
@ -19,6 +19,20 @@ use ring::digest;
|
|
|
|
|
use crate::user_management::{UserManager, User};
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
/// A request from a Gemini client to the app
|
|
|
|
|
///
|
|
|
|
|
/// When originally sent out by a client, a request is literally just a URL, and honestly,
|
|
|
|
|
/// if you want to use it as just a URL, that'll work fine!
|
|
|
|
|
///
|
|
|
|
|
/// That said, kochab and any proxies the request might hit add a little bit more
|
|
|
|
|
/// information that you can use, like
|
|
|
|
|
/// * [What TLS certificate (if any) did the client use](Self::certificate)
|
|
|
|
|
/// * [What part of the path is relevant (ie, everything after the route)](Self::trailing_segments)
|
|
|
|
|
/// * [Is the user registered with the user database?](Self::user)
|
|
|
|
|
///
|
|
|
|
|
/// The only way to get your hands on one of these bad boys is when you register an [`Fn`]
|
|
|
|
|
/// based handler to a [`Server`](crate::Server), and a user makes a request to the
|
|
|
|
|
/// endpoint.
|
|
|
|
|
pub struct Request {
|
|
|
|
|
uri: URIReference<'static>,
|
|
|
|
|
input: Option<String>,
|
|
|
|
@ -33,7 +47,34 @@ pub struct Request {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Request {
|
|
|
|
|
pub fn new(
|
|
|
|
|
/// Construct a new request
|
|
|
|
|
///
|
|
|
|
|
/// When in `gemini_srv` mode, this is done using a URL. If you do construct a
|
|
|
|
|
/// request this way, by default it will not have a certificate attached, so make
|
|
|
|
|
/// sure you add in a certificate with [`Request::set_cert()`].
|
|
|
|
|
///
|
|
|
|
|
/// By contrast, in `scgi_srv` mode, the certificate fingerprint is grabbed out of the
|
|
|
|
|
/// request parameters, so you don't need to do anything. The headers passed should
|
|
|
|
|
/// be the header sent by the SCGI client.
|
|
|
|
|
///
|
|
|
|
|
/// When in SCGI mode, the following headers are expected:
|
|
|
|
|
///
|
|
|
|
|
/// * `PATH_INFO`: The part of the path following the route the app is bound to
|
|
|
|
|
/// * `QUERY_STRING`: The part of the request following ?, url encoded. Will produce
|
|
|
|
|
/// an error if it contains invalid UTF-8. No error if missing
|
|
|
|
|
/// * `TLS_CLIENT_HASH`: Optional. The base64 or hex encoded SHA256 sum of the DER
|
|
|
|
|
/// certificate of the requester.
|
|
|
|
|
/// * `SCRIPT_PATH` or `SCRIPT_NAME`: The base path the app is mounted on
|
|
|
|
|
///
|
|
|
|
|
/// # Errors
|
|
|
|
|
///
|
|
|
|
|
/// Produces an error if:
|
|
|
|
|
/// * The SCGI server didn't include the mandatory `PATH_INFO` header
|
|
|
|
|
/// * The provided URI reference is invalid, including if the SCGI server sent an
|
|
|
|
|
/// invalid `PATH_INFO`
|
|
|
|
|
/// * The `TLS_CLIENT_HASH` sent by the SCGI server isn't sha256, or is encoded with
|
|
|
|
|
/// something other than base64 or hexadecimal
|
|
|
|
|
pub (crate) fn new(
|
|
|
|
|
#[cfg(feature = "gemini_srv")]
|
|
|
|
|
mut uri: URIReference<'static>,
|
|
|
|
|
#[cfg(feature = "scgi_srv")]
|
|
|
|
@ -112,6 +153,19 @@ impl Request {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// The URI reference requested by the user
|
|
|
|
|
///
|
|
|
|
|
/// Although they are not exactly the same thing, it is generally preferred to use the
|
|
|
|
|
/// [`Request::trailing_segments()`] method if possible.
|
|
|
|
|
///
|
|
|
|
|
/// Returns the URIReference requested by the user. **If running in SCGI mode, this
|
|
|
|
|
/// will contain only the parts of the URIReference that were relevant to the app.**
|
|
|
|
|
/// This means you will get `/path`, not `/app/path`.
|
|
|
|
|
///
|
|
|
|
|
/// When running in `scgi_srv` mode, this is guaranteed to be a relative reference.
|
|
|
|
|
/// When running in `gemini_srv` mode, clients are obliged by the spec to send a full
|
|
|
|
|
/// URI, but if a client fails to respect this, kochab will still accept and pass on
|
|
|
|
|
/// the relative reference.
|
|
|
|
|
pub const fn uri(&self) -> &URIReference {
|
|
|
|
|
&self.uri
|
|
|
|
|
}
|
|
|
|
@ -123,11 +177,6 @@ impl Request {
|
|
|
|
|
/// received to `/api/v1/endpoint`, then this value would be `["v1", "endpoint"]`.
|
|
|
|
|
/// This should not be confused with [`path_segments()`](Self::path_segments()), which
|
|
|
|
|
/// contains *all* of the segments, not just those trailing the route.
|
|
|
|
|
///
|
|
|
|
|
/// If the trailing segments have not been set, this method will panic, but this
|
|
|
|
|
/// should only be possible if you are constructing the Request yourself. Requests
|
|
|
|
|
/// to handlers registered through [`add_route()`](crate::Server::add_route()) will
|
|
|
|
|
/// always have trailing segments set.
|
|
|
|
|
pub fn trailing_segments(&self) -> &Vec<String> {
|
|
|
|
|
self.trailing_segments.as_ref().unwrap()
|
|
|
|
|
}
|
|
|
|
@ -167,6 +216,10 @@ impl Request {
|
|
|
|
|
/// the request otherwise. Bear in mind that **not all SCGI clients send the same
|
|
|
|
|
/// headers**, and these are *never* available when operating in `gemini_srv` mode.
|
|
|
|
|
///
|
|
|
|
|
/// By using this method, you are almost certainly reducing the number of proxy
|
|
|
|
|
/// servers your app supports, and you are strongly encouraged to find a different
|
|
|
|
|
/// method.
|
|
|
|
|
///
|
|
|
|
|
/// Some examples of headers mollybrown sets are:
|
|
|
|
|
/// - `REMOTE_ADDR` (The user's IP address and port)
|
|
|
|
|
/// - `TLS_CLIENT_SUBJECT_CN` (The CommonName on the user's certificate, when present)
|
|
|
|
@ -187,7 +240,8 @@ impl Request {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn set_trailing(&mut self, segments: Vec<String>) {
|
|
|
|
|
/// Sets the segments returned by [`Request::trailing_segments()`]
|
|
|
|
|
pub (crate) fn set_trailing(&mut self, segments: Vec<String>) {
|
|
|
|
|
self.trailing_segments = Some(segments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|