public inbox for pdm-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Shannon Sterz <s.sterz@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: [pdm-devel] [PATCH proxmox v3 03/21] router/rest-server: add new `AsyncHttpBodyParameters` api handler type
Date: Thu, 27 Feb 2025 15:06:54 +0100	[thread overview]
Message-ID: <20250227140712.209679-4-s.sterz@proxmox.com> (raw)
In-Reply-To: <20250227140712.209679-1-s.sterz@proxmox.com>

this allows us to write api handlers that have access to a request's
headers and to create a low level response while being able to also
specify the parameter in the request's body. this is useful for
endpoints that should not use url parameters, but still need to
access/set specific headers.

previously, `AsyncHttp` did not allow for parameters that were marked
as non-optional to be passed in the body of a request.

as a side-effect, the body is parsed by the rest server to check for
parameters and consumed. so it cannot be passed on by the handler.

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 proxmox-rest-server/src/rest.rs   |  5 ++++
 proxmox-router/src/cli/command.rs | 12 +++++++++
 proxmox-router/src/format.rs      |  6 +++++
 proxmox-router/src/router.rs      | 45 +++++++++++++++++++++++++++++++
 4 files changed, 68 insertions(+)

diff --git a/proxmox-rest-server/src/rest.rs b/proxmox-rest-server/src/rest.rs
index 78339b75..350ce957 100644
--- a/proxmox-rest-server/src/rest.rs
+++ b/proxmox-rest-server/src/rest.rs
@@ -546,6 +546,11 @@ pub(crate) async fn handle_api_request<Env: RpcEnvironment, S: 'static + BuildHa
             let params = parse_query_parameters(info.parameters, "", &parts, &uri_param)?;
             (handler)(parts, req_body, params, info, Box::new(rpcenv)).await
         }
+        ApiHandler::AsyncHttpBodyParameters(handler) => {
+            let params =
+                get_request_parameters(info.parameters, &parts, req_body, uri_param).await?;
+            (handler)(parts, params, info, Box::new(rpcenv)).await
+        }
         ApiHandler::StreamSync(handler) => {
             let params =
                 get_request_parameters(info.parameters, &parts, req_body, uri_param).await?;
diff --git a/proxmox-router/src/cli/command.rs b/proxmox-router/src/cli/command.rs
index 01f64d19..2ca2356a 100644
--- a/proxmox-router/src/cli/command.rs
+++ b/proxmox-router/src/cli/command.rs
@@ -107,6 +107,12 @@ async fn handle_simple_command_future(
         ApiHandler::AsyncHttp(_) => {
             bail!("CliHandler does not support ApiHandler::AsyncHttp - internal error")
         }
+        #[cfg(feature = "server")]
+        ApiHandler::AsyncHttpBodyParameters(_) => {
+            bail!(
+                "CliHandler does not support ApiHandler::AsyncHttpBodyParameters - internal error"
+            )
+        }
     };
 
     match result {
@@ -159,6 +165,12 @@ pub(crate) fn handle_simple_command<'cli>(
         ApiHandler::AsyncHttp(_) => {
             bail!("CliHandler does not support ApiHandler::AsyncHttp - internal error");
         }
+        #[cfg(feature = "server")]
+        ApiHandler::AsyncHttpBodyParameters(_) => {
+            bail!(
+                "CliHandler does not support ApiHandler::AsyncHttpBodyParameters - internal error"
+            );
+        }
     };
 
     match result {
diff --git a/proxmox-router/src/format.rs b/proxmox-router/src/format.rs
index 67568af0..be40895a 100644
--- a/proxmox-router/src/format.rs
+++ b/proxmox-router/src/format.rs
@@ -32,6 +32,12 @@ fn dump_method_definition(method: &str, path: &str, def: Option<&ApiMethod>) ->
                 method = if method == "GET" { "DOWNLOAD" } else { method };
             }
 
+            #[cfg(feature = "server")]
+            if let ApiHandler::AsyncHttpBodyParameters(_) = api_method.handler {
+                method = if method == "POST" { "UPLOAD" } else { method };
+                method = if method == "GET" { "DOWNLOAD" } else { method };
+            }
+
             let res = format!(
                 "**{} {}**\n\n{}{}\n\n{}",
                 method, path, description, param_descr, return_descr
diff --git a/proxmox-router/src/router.rs b/proxmox-router/src/router.rs
index 33b598da..12ba863e 100644
--- a/proxmox-router/src/router.rs
+++ b/proxmox-router/src/router.rs
@@ -435,6 +435,44 @@ pub type ApiAsyncHttpHandlerFn = &'static (dyn Fn(
 pub type ApiResponseFuture =
     Pin<Box<dyn Future<Output = Result<Response<Body>, anyhow::Error>> + Send>>;
 
+/// Asynchronous HTTP API handlers with parameters specified in their bodies
+///
+/// They get low level access to request and response data, but it is also possible to specify
+/// their parameters in the request body.
+///
+/// ```
+/// # use serde_json::{json, Value};
+/// #
+/// use hyper::{Body, Response, http::request::Parts};
+///
+/// use proxmox_router::{ApiHandler, ApiMethod, ApiResponseFuture, RpcEnvironment};
+/// use proxmox_schema::ObjectSchema;
+///
+/// fn low_level_hello(
+///    parts: Parts,
+///    param: Value,
+///    info: &ApiMethod,
+///    rpcenv: Box<dyn RpcEnvironment>,
+/// ) -> ApiResponseFuture {
+///    Box::pin(async move {
+///        let response = http::Response::builder()
+///            .status(200)
+///            .body(Body::from("Hello world!"))?;
+///        Ok(response)
+///    })
+/// }
+///
+/// const API_METHOD_LOW_LEVEL_HELLO_BODY_PARAMETER: ApiMethod = ApiMethod::new(
+///    &ApiHandler::AsyncHttpBodyParameters(&low_level_hello),
+///    &ObjectSchema::new("Hello World Example (low level)", &[])
+/// );
+/// ```
+#[cfg(feature = "server")]
+pub type ApiAsyncHttpHandlerBodyParametersFn = &'static (dyn Fn(Parts, Value, &'static ApiMethod, Box<dyn RpcEnvironment>) -> ApiResponseFuture
+              + Send
+              + Sync
+              + 'static);
+
 /// Enum for different types of API handler functions.
 #[non_exhaustive]
 pub enum ApiHandler {
@@ -446,6 +484,8 @@ pub enum ApiHandler {
     StreamAsync(StreamApiAsyncHandlerFn),
     #[cfg(feature = "server")]
     AsyncHttp(ApiAsyncHttpHandlerFn),
+    #[cfg(feature = "server")]
+    AsyncHttpBodyParameters(ApiAsyncHttpHandlerBodyParametersFn),
 }
 
 #[cfg(feature = "test-harness")]
@@ -478,6 +518,11 @@ impl PartialEq for ApiHandler {
                 (ApiHandler::AsyncHttp(l), ApiHandler::AsyncHttp(r)) => {
                     core::mem::transmute::<_, usize>(l) == core::mem::transmute::<_, usize>(r)
                 }
+                #[cfg(feature = "server")]
+                (
+                    ApiHandler::AsyncHttpBodyParameters(l),
+                    ApiHandler::AsyncHttpBodyParameters(r),
+                ) => core::mem::transmute::<_, usize>(l) == core::mem::transmute::<_, usize>(r),
                 _ => false,
             }
         }
-- 
2.39.5



_______________________________________________
pdm-devel mailing list
pdm-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel


  parent reply	other threads:[~2025-02-27 14:08 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-27 14:06 [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp v3 00/21] use HttpOnly cookies in new projects Shannon Sterz
2025-02-27 14:06 ` [pdm-devel] [PATCH proxmox v3 01/21] time: add new `epoch_to_http_date` helper Shannon Sterz
2025-02-27 14:06 ` [pdm-devel] [PATCH proxmox v3 02/21] rest-server: borrow parts parameter in `get_request_parameter` Shannon Sterz
2025-02-27 14:06 ` Shannon Sterz [this message]
2025-02-27 14:06 ` [pdm-devel] [PATCH proxmox v3 04/21] auth-api: extend `AuthContext` with prefixed cookie name Shannon Sterz
2025-02-27 14:06 ` [pdm-devel] [PATCH proxmox v3 05/21] auth-api: check for new prefixed cookies as well Shannon Sterz
2025-02-27 14:06 ` [pdm-devel] [PATCH proxmox v3 06/21] auth-api: introduce new CreateTicket and CreateTickeReponse api types Shannon Sterz
2025-02-27 14:06 ` [pdm-devel] [PATCH proxmox v3 07/21] auth-api: add endpoint for issuing tickets as HttpOnly tickets Shannon Sterz
2025-02-27 14:06 ` [pdm-devel] [PATCH proxmox v3 08/21] auth-api: make regular ticket endpoint use the new types and handler Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH proxmox v3 09/21] auth-api: add logout method Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH proxmox v3 10/21] login: add optional field for ticket_info and make password optional Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH proxmox v3 11/21] login: make password optional when creating Login requests Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH proxmox v3 12/21] login: add helpers to pass cookie values when parsing login responses Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH proxmox v3 13/21] login: add `TicketResult::HttpOnly` member Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH proxmox v3 14/21] login: add helper to check whether a ticket is just informational Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH proxmox v3 15/21] login: add functions to specify full cookie names Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH proxmox v3 16/21] client: add compatibility with HttpOnly cookies Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH proxmox v3 17/21] client: specify cookie names for authentication headers where possible Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH yew-comp v3 18/21] HttpClient: add helpers to refresh HttpOnly cookies and remove them Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH yew-comp v3 19/21] LoginPanel/http helpers: add support for handling HttpOnly cookies Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH yew-comp v3 20/21] http helpers: ask server to remove `__Host-` prefixed cookie on logout Shannon Sterz
2025-02-27 14:07 ` [pdm-devel] [PATCH datacenter-manager v3 21/21] api: switch ticket endpoint over to new http only endpoint Shannon Sterz
2025-02-27 14:08 ` [pdm-devel] [PATCH datacenter-manager/proxmox/yew-comp v3 00/21] use HttpOnly cookies in new projects Shannon Sterz
2025-03-04 12:08 ` Shannon Sterz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250227140712.209679-4-s.sterz@proxmox.com \
    --to=s.sterz@proxmox.com \
    --cc=pdm-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal