mirror of
https://git.proxmox.com/git/proxmox
synced 2025-06-13 06:33:55 +00:00
router/rest-server: add new AsyncHttpBodyParameters
api handler type
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>
This commit is contained in:
parent
b1ed231ed2
commit
1f58e40f3f
@ -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?;
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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::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,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user