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
} | } | ||||
task->http_conn = rspamd_http_connection_ref(conn_ent->conn); | task->http_conn = rspamd_http_connection_ref(conn_ent->conn); | ||||
; | |||||
task->sock = -1; | task->sock = -1; | ||||
session->task = task; | session->task = task; | ||||
task); | task); | ||||
task->fin_arg = conn_ent; | task->fin_arg = conn_ent; | ||||
task->http_conn = rspamd_http_connection_ref(conn_ent->conn); | task->http_conn = rspamd_http_connection_ref(conn_ent->conn); | ||||
; | |||||
task->sock = -1; | task->sock = -1; | ||||
session->task = task; | session->task = task; | ||||
{ | { | ||||
struct rspamd_http_message *msg; | struct rspamd_http_message *msg; | ||||
struct rspamd_http_connection_entry *conn_ent; | 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; | conn_ent = task->fin_arg; | ||||
msg = rspamd_http_new_message(HTTP_RESPONSE); | msg = rspamd_http_new_message(HTTP_RESPONSE); | ||||
msg->date = time(NULL); | msg->date = time(NULL); | ||||
msg->code = 200; | 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_connection_reset(conn_ent->conn); | ||||
rspamd_http_router_insert_headers(conn_ent->rt, msg); | rspamd_http_router_insert_headers(conn_ent->rt, msg); | ||||
rspamd_http_connection_write_message(conn_ent->conn, msg, NULL, | 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; | conn_ent->is_reply = TRUE; | ||||
} | } | ||||
} | } | ||||
void rspamd_protocol_http_reply(struct rspamd_http_message *msg, | 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; | struct rspamd_scan_result *metric_res; | ||||
const struct rspamd_re_cache_stat *restat; | const struct rspamd_re_cache_stat *restat; | ||||
if (msg->method < HTTP_SYMBOLS && !RSPAMD_TASK_IS_SPAMC(task)) { | if (msg->method < HTTP_SYMBOLS && !RSPAMD_TASK_IS_SPAMC(task)) { | ||||
msg_debug_protocol("writing json reply"); | msg_debug_protocol("writing json reply"); | ||||
rspamd_ucl_emit_fstring(top, UCL_EMIT_JSON_COMPACT, &reply); | |||||
rspamd_ucl_emit_fstring(top, how, &reply); | |||||
} | } | ||||
else { | else { | ||||
if (RSPAMD_TASK_IS_SPAMC(task)) { | if (RSPAMD_TASK_IS_SPAMC(task)) { | ||||
MESSAGE_FIELD_CHECK(task, message_id)); | 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 */ | /* Compatibility */ | ||||
if (task->cmd == CMD_CHECK_RSPAMC) { | if (task->cmd == CMD_CHECK_RSPAMC) { | ||||
msg->method = HTTP_SYMBOLS; | msg->method = HTTP_SYMBOLS; | ||||
ucl_object_fromstring(g_quark_to_string(task->err->domain)), | ucl_object_fromstring(g_quark_to_string(task->err->domain)), | ||||
"error_domain", 0, false); | "error_domain", 0, false); | ||||
reply = rspamd_fstring_sized_new(256); | 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); | ucl_object_unref(top); | ||||
/* We also need to validate utf8 */ | /* 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; | gsize valid_len; | ||||
gchar *validated; | 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, | validated = rspamd_str_make_utf_valid(reply->str, reply->len, | ||||
&valid_len, task->task_pool); | &valid_len, task->task_pool); | ||||
rspamd_http_message_set_body(msg, validated, valid_len); | rspamd_http_message_set_body(msg, validated, valid_len); | ||||
case CMD_CHECK_SPAMC: | case CMD_CHECK_SPAMC: | ||||
case CMD_SKIP: | case CMD_SKIP: | ||||
case CMD_CHECK_V2: | 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); | rspamd_protocol_write_log_pipe(task); | ||||
break; | break; | ||||
case CMD_PING: | case CMD_PING: |
/* | |||||
* 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 | * @file protocol.h | ||||
* Rspamd protocol definition | * Rspamd protocol definition | ||||
* @param task | * @param task | ||||
*/ | */ | ||||
void rspamd_protocol_http_reply(struct rspamd_http_message *msg, | 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 | * Write data to log pipes |
gboolean fatal) | gboolean fatal) | ||||
{ | { | ||||
void *p = lua_touserdata(L, pos); | void *p = lua_touserdata(L, pos); | ||||
guint i, top = lua_gettop(L); | |||||
khiter_t k; | |||||
gint i, top = lua_gettop(L); | |||||
if (p == NULL) { | if (p == NULL) { | ||||
goto err; | goto err; |
struct rspamd_http_message *msg; | struct rspamd_http_message *msg; | ||||
struct rspamd_proxy_session *session = task->fin_arg, *nsession; | struct rspamd_proxy_session *session = task->fin_arg, *nsession; | ||||
ucl_object_t *rep = NULL; | ucl_object_t *rep = NULL; | ||||
int out_type = UCL_EMIT_JSON_COMPACT; | |||||
const char *ctype = "application/json"; | 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 = rspamd_http_new_message(HTTP_RESPONSE); | ||||
msg->date = time(NULL); | msg->date = time(NULL); | ||||
case CMD_CHECK_SPAMC: | case CMD_CHECK_SPAMC: | ||||
case CMD_CHECK_V2: | case CMD_CHECK_V2: | ||||
rspamd_task_set_finish_time(task); | 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); | rspamd_protocol_write_log_pipe(task); | ||||
break; | break; | ||||
case CMD_PING: | case CMD_PING: |