Rspamd currently sends reply in JSON format. However, message pack seems to be a better choice for a compatible client. It is faster and does not need escaping or even UTF8 validation. This is a surface for further updates.pull/4867/head
@@ -1574,7 +1574,6 @@ rspamd_controller_handle_lua_history(lua_State *L, | |||
} | |||
task->http_conn = rspamd_http_connection_ref(conn_ent->conn); | |||
; | |||
task->sock = -1; | |||
session->task = task; | |||
@@ -1904,7 +1903,6 @@ rspamd_controller_handle_lua(struct rspamd_http_connection_entry *conn_ent, | |||
task); | |||
task->fin_arg = conn_ent; | |||
task->http_conn = rspamd_http_connection_ref(conn_ent->conn); | |||
; | |||
task->sock = -1; | |||
session->task = task; | |||
@@ -2005,16 +2003,25 @@ rspamd_controller_scan_reply(struct rspamd_task *task) | |||
{ | |||
struct rspamd_http_message *msg; | |||
struct rspamd_http_connection_entry *conn_ent; | |||
int out_type = UCL_EMIT_JSON_COMPACT; | |||
const char *ctype = "application/json"; | |||
const rspamd_ftok_t *accept_hdr = rspamd_task_get_request_header(task, "Accept"); | |||
if (accept_hdr && rspamd_substring_search(accept_hdr->begin, accept_hdr->len, | |||
"application/msgpack", sizeof("application/msgpack") - 1)) { | |||
ctype = "application/msgpack"; | |||
out_type = UCL_EMIT_MSGPACK; | |||
} | |||
conn_ent = task->fin_arg; | |||
msg = rspamd_http_new_message(HTTP_RESPONSE); | |||
msg->date = time(NULL); | |||
msg->code = 200; | |||
rspamd_protocol_http_reply(msg, task, NULL); | |||
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, | |||
"application/json", conn_ent, conn_ent->rt->timeout); | |||
ctype, conn_ent, conn_ent->rt->timeout); | |||
conn_ent->is_reply = TRUE; | |||
} | |||
@@ -1636,7 +1636,7 @@ rspamd_protocol_write_ucl(struct rspamd_task *task, | |||
} | |||
void rspamd_protocol_http_reply(struct rspamd_http_message *msg, | |||
struct rspamd_task *task, ucl_object_t **pobj) | |||
struct rspamd_task *task, ucl_object_t **pobj, int how) | |||
{ | |||
struct rspamd_scan_result *metric_res; | |||
const struct rspamd_re_cache_stat *restat; | |||
@@ -1695,7 +1695,7 @@ void rspamd_protocol_http_reply(struct rspamd_http_message *msg, | |||
if (msg->method < HTTP_SYMBOLS && !RSPAMD_TASK_IS_SPAMC(task)) { | |||
msg_debug_protocol("writing json reply"); | |||
rspamd_ucl_emit_fstring(top, UCL_EMIT_JSON_COMPACT, &reply); | |||
rspamd_ucl_emit_fstring(top, how, &reply); | |||
} | |||
else { | |||
if (RSPAMD_TASK_IS_SPAMC(task)) { | |||
@@ -2111,6 +2111,16 @@ void rspamd_protocol_write_reply(struct rspamd_task *task, ev_tstamp timeout) | |||
MESSAGE_FIELD_CHECK(task, message_id)); | |||
} | |||
const rspamd_ftok_t *accept_hdr; | |||
int out_type = UCL_EMIT_JSON_COMPACT; | |||
accept_hdr = rspamd_task_get_request_header(task, "Accept"); | |||
if (accept_hdr && rspamd_substring_search(accept_hdr->begin, accept_hdr->len, | |||
"application/msgpack", sizeof("application/msgpack") - 1)) { | |||
ctype = "application/msgpack"; | |||
out_type = UCL_EMIT_MSGPACK; | |||
} | |||
/* Compatibility */ | |||
if (task->cmd == CMD_CHECK_RSPAMC) { | |||
msg->method = HTTP_SYMBOLS; | |||
@@ -2134,15 +2144,15 @@ void rspamd_protocol_write_reply(struct rspamd_task *task, ev_tstamp timeout) | |||
ucl_object_fromstring(g_quark_to_string(task->err->domain)), | |||
"error_domain", 0, false); | |||
reply = rspamd_fstring_sized_new(256); | |||
rspamd_ucl_emit_fstring(top, UCL_EMIT_JSON_COMPACT, &reply); | |||
rspamd_ucl_emit_fstring(top, out_type, &reply); | |||
ucl_object_unref(top); | |||
/* We also need to validate utf8 */ | |||
if (rspamd_fast_utf8_validate(reply->str, reply->len) != 0) { | |||
if (out_type != UCL_EMIT_MSGPACK && rspamd_fast_utf8_validate(reply->str, reply->len) != 0) { | |||
gsize valid_len; | |||
gchar *validated; | |||
/* We copy reply several times here but it should be a rare case */ | |||
/* We copy reply several times here, but it should be a rare case */ | |||
validated = rspamd_str_make_utf_valid(reply->str, reply->len, | |||
&valid_len, task->task_pool); | |||
rspamd_http_message_set_body(msg, validated, valid_len); | |||
@@ -2161,7 +2171,7 @@ void rspamd_protocol_write_reply(struct rspamd_task *task, ev_tstamp timeout) | |||
case CMD_CHECK_SPAMC: | |||
case CMD_SKIP: | |||
case CMD_CHECK_V2: | |||
rspamd_protocol_http_reply(msg, task, NULL); | |||
rspamd_protocol_http_reply(msg, task, NULL, out_type); | |||
rspamd_protocol_write_log_pipe(task); | |||
break; | |||
case CMD_PING: |
@@ -1,3 +1,19 @@ | |||
/* | |||
* Copyright 2024 Vsevolod Stakhov | |||
* | |||
* Licensed under the Apache License, Version 2.0 (the "License"); | |||
* you may not use this file except in compliance with the License. | |||
* You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
*/ | |||
/** | |||
* @file protocol.h | |||
* Rspamd protocol definition | |||
@@ -70,7 +86,8 @@ gboolean rspamd_protocol_handle_request(struct rspamd_task *task, | |||
* @param task | |||
*/ | |||
void rspamd_protocol_http_reply(struct rspamd_http_message *msg, | |||
struct rspamd_task *task, ucl_object_t **pobj); | |||
struct rspamd_task *task, ucl_object_t **pobj, | |||
int how); | |||
/** | |||
* Write data to log pipes |
@@ -1974,8 +1974,7 @@ rspamd_lua_check_udata_common(lua_State *L, gint pos, const gchar *classname, | |||
gboolean fatal) | |||
{ | |||
void *p = lua_touserdata(L, pos); | |||
guint i, top = lua_gettop(L); | |||
khiter_t k; | |||
gint i, top = lua_gettop(L); | |||
if (p == NULL) { | |||
goto err; |
@@ -1713,7 +1713,15 @@ rspamd_proxy_scan_self_reply(struct rspamd_task *task) | |||
struct rspamd_http_message *msg; | |||
struct rspamd_proxy_session *session = task->fin_arg, *nsession; | |||
ucl_object_t *rep = NULL; | |||
int out_type = UCL_EMIT_JSON_COMPACT; | |||
const char *ctype = "application/json"; | |||
const rspamd_ftok_t *accept_hdr = rspamd_task_get_request_header(task, "Accept"); | |||
if (accept_hdr && rspamd_substring_search(accept_hdr->begin, accept_hdr->len, | |||
"application/msgpack", sizeof("application/msgpack") - 1)) { | |||
ctype = "application/msgpack"; | |||
out_type = UCL_EMIT_MSGPACK; | |||
} | |||
msg = rspamd_http_new_message(HTTP_RESPONSE); | |||
msg->date = time(NULL); | |||
@@ -1726,7 +1734,7 @@ rspamd_proxy_scan_self_reply(struct rspamd_task *task) | |||
case CMD_CHECK_SPAMC: | |||
case CMD_CHECK_V2: | |||
rspamd_task_set_finish_time(task); | |||
rspamd_protocol_http_reply(msg, task, &rep); | |||
rspamd_protocol_http_reply(msg, task, &rep, out_type); | |||
rspamd_protocol_write_log_pipe(task); | |||
break; | |||
case CMD_PING: |