HTTP injection max message size

I’m trying to inject a message using the HTTP API with a 12MB attachment (a report PDF) and getting Failed to buffer the request body: length limit exceeded from Kumo - I don’t see an option for specifying the max message size for kumo.start_http_listener(). Is there another configuration parameter to increase the max message size for messages injected using the HTTP API?

root@ahasend:~# curl -H 'Content-Type: application/json' -X POST http://10.1.0.3:8000/api/inject/v1 -d @./request.json
Failed to buffer the request body: length limit exceeded

Hey there @original-baboon, thanks for posting. Please read the “Troubleshooting” and “How to Ask for Help” buttons below. If you would like a 1:1 support session from the KumoMTA team, details are at the “Book a Support Session” button below.

It should be the same as in the smtp listener but seems to be undocumented. (max_message_size)

I haven’t set max_message_size for the smtp listener explicitly, and based on the documentation it should be 20MB by default and that’s working fine: I can send the same message using SMTP without any problems, but I get the length limit exceeded error when I try to inject the message using the HTTP API.

Also, this doesn’t work:

  kumo.start_http_listener {
    listen = '0.0.0.0:8000',
    trusted_hosts = { '127.0.0.1', '::1', '10.1.0.0/16' },
    use_tls = false,
    max_message_size = '20 MB',
  }

After adding max_message_size starting kumo fails with this error:

Mar 17 14:04:51 send kumod[561738]: Error: Initialization raised an error: call init callback: callback error
Mar 17 14:04:51 send kumod[561738]: stack traceback:
Mar 17 14:04:51 send kumod[561738]:         [C]: in local 'poll'
Mar 17 14:04:51 send kumod[561738]:         [string "?"]:5: in function 'kumo.start_http_listener'
Mar 17 14:04:51 send kumod[561738]:         [string "/opt/kumomta/etc/policy/init.lua"]:190: in function <[string "/opt/kumomta/etc/policy/init.lua"]:132>
Mar 17 14:04:51 send kumod[561738]: caused by: deserialize error: unknown field `max_message_size`, expected one of `hostname`, `listen`, `use_tls`, `tls_certificate`, `tls_private_key`, `trusted_hosts`, while processing {"use_tls":false,"trusted_hosts":["127.0.0.1","::1","10.1.0.0/16"],"max_message_size":"20 MB","listen":"0.0.0.0:8000"}

Can you add -v to the curl invocation so that we can see more details about the http response?

root@ahasend:~# curl -v -H 'Content-Type: application/json' -X POST http://10.1.0.3:8000/api/inject/v1 -d @./request.json 
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying 10.1.0.3:8000...
* Connected to 10.1.0.3 (10.1.0.3) port 8000 (#0)
> POST /api/inject/v1 HTTP/1.1
> Host: 10.1.0.3:8000
> User-Agent: curl/7.81.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 18142423
> Expect: 100-continue
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 100 Continue
* Mark bundle as not supporting multiuse
< HTTP/1.1 413 Payload Too Large
< content-type: text/plain; charset=utf-8
< content-length: 56
< date: Sun, 17 Mar 2024 14:17:17 GMT
* HTTP error before end of send, stop sending
< 
* Closing connection 0
Failed to buffer the request body: length limit exceededroot@ahasend:~# 
root@ahasend:~# ls -lh request.json 
-rw-r--r-- 1 root root 18M Mar 17 08:24 request.json
diff --git a/crates/kumo-server-common/src/http_server/mod.rs b/crates/kumo-server-common/src/http_server/mod.rs
index dd609bef..adb8cdcf 100644
--- a/crates/kumo-server-common/src/http_server/mod.rs
+++ b/crates/kumo-server-common/src/http_server/mod.rs
@@ -70,6 +70,9 @@ pub struct HttpListenerParams {
     #[serde(default)]
     pub use_tls: bool,

+    #[serde(default)]
+    pub request_body_limit: Option<usize>,
+
     #[serde(default)]
     pub tls_certificate: Option<KeySource>,
     #[serde(default)]
@@ -146,6 +149,10 @@ impl HttpListenerParams {

         let app = router_and_docs
             .router
+            // Remove default limit..
+            .layer(DefaultBodyLimit::disable())
+            // ... so that we can apply our limit
+            .layer(RequestBodyLimitLayer::new(self.request_body_limit.unwrap_or(2 * 1024 * 1024))
             .merge(RapiDoc::with_openapi("/api-docs/openapi.json", api_docs).path("/rapidoc"))
             .route(
                 "/api/admin/set_diagnostic_log_filter/v1",

I think that will give you an option to control the limit; I’m currently experiencing hardware issues on my dev system (bad ram) that prevent me from testing this immediately :confused:

there is a default limit of 2MB that that diff will remove and replace with an option called request_body_limit that you can pass into the http listener when you start it

Yeah, I suspected it should be something like that. Thanks!

This was reported by a customer, I’ve asked them to use SMTP for now until this gets fixed, will just wait for a new dev release and update then - better not to tinker with patching and compiling this on production :grinning_face_with_smiling_eyes:

makes sense!

time to fire up memtest and see if I can pull the bad stick(s) of ram

Ha, gif doesn’t work here!

“it’s fine, I’ve taken care of it, I’ve sent an email!”

http_listener: allow configuring max request size · KumoCorp/kumomta@5596d7c · GitHub should let you set the limit. That’s currently building out, will probably take about 40 minutes until all platforms are built and publish

Thanks, I’ll deploy and test and report back here.