]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] controller: support the /checkv3 endpoint
authorVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 6 Jun 2026 12:45:18 +0000 (13:45 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Sat, 6 Jun 2026 12:45:18 +0000 (13:45 +0100)
The scan worker and rspamd_proxy both handle /checkv3 (multipart
metadata + message in, multipart/mixed results out), but the
controller's HTTP path router never registered it. Since rspamc
defaults to the controller port (11334) for localhost, a plain
`rspamc --protocol-v3` returned 404 with
"rspamd_http_router_finish_handler: path: /checkv3 not found".

Register /checkv3 on the controller (routed to the existing scan
handler) and branch on CMD_CHECK_V3 in both directions:
parse the body via rspamd_protocol_handle_v3_request() on input and
emit the multipart reply via rspamd_protocol_http_reply_v3() on
output, mirroring the proxy. Auth posture matches /check and
/checkv2 (read command, no enable password).

src/controller.c

index db6b4604e00f5206529af3f22839e3083c23106c..0799151ef504f57c7f7b1693c46150957f5d9609 100644 (file)
@@ -63,6 +63,7 @@
 #define PATH_SCAN "/scan"
 #define PATH_CHECK "/check"
 #define PATH_CHECKV2 "/checkv2"
+#define PATH_CHECKV3 "/checkv3"
 #define PATH_STAT "/stat"
 #define PATH_STAT_RESET "/statreset"
 #define PATH_COUNTERS "/counters"
@@ -2072,7 +2073,16 @@ rspamd_controller_scan_reply(struct rspamd_task *task)
        msg = rspamd_http_new_message(HTTP_RESPONSE);
        msg->date = time(NULL);
        msg->code = 200;
-       rspamd_protocol_http_reply(msg, task, NULL, out_type);
+
+       if (task->cmd == CMD_CHECK_V3) {
+               /* v3 returns a multipart/mixed reply; ctype carries the boundary */
+               rspamd_task_set_finish_time(task);
+               ctype = rspamd_protocol_http_reply_v3(msg, task);
+       }
+       else {
+               rspamd_protocol_http_reply(msg, task, NULL, out_type);
+       }
+
        rspamd_http_connection_reset(conn_ent->conn);
        rspamd_http_router_insert_headers(conn_ent->rt, msg);
        rspamd_http_connection_write_message(conn_ent->conn, msg, NULL,
@@ -2348,7 +2358,15 @@ rspamd_controller_handle_scan(struct rspamd_http_connection_entry *conn_ent,
                goto end;
        }
 
-       if (!rspamd_task_load_message(task, msg, msg->body_buf.begin, msg->body_buf.len)) {
+       if (task->cmd == CMD_CHECK_V3) {
+               /* checkv3 carries metadata + message inside a multipart/form-data body */
+               if (!rspamd_protocol_handle_v3_request(task, msg,
+                                                                                          msg->body_buf.begin,
+                                                                                          msg->body_buf.len)) {
+                       goto end;
+               }
+       }
+       else if (!rspamd_task_load_message(task, msg, msg->body_buf.begin, msg->body_buf.len)) {
                goto end;
        }
 
@@ -4236,6 +4254,9 @@ start_controller_worker(struct rspamd_worker *worker)
        rspamd_http_router_add_path(ctx->http,
                                                                PATH_CHECKV2,
                                                                rspamd_controller_handle_scan);
+       rspamd_http_router_add_path(ctx->http,
+                                                               PATH_CHECKV3,
+                                                               rspamd_controller_handle_scan);
        rspamd_http_router_add_path(ctx->http,
                                                                PATH_STAT,
                                                                rspamd_controller_handle_stat);