aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/client/rspamc.c4
-rw-r--r--src/client/rspamdclient.c14
-rw-r--r--src/controller.c67
-rw-r--r--src/http_proxy.c4
-rw-r--r--src/libserver/protocol.c155
-rw-r--r--src/libserver/protocol.h2
-rw-r--r--src/libserver/task.c31
-rw-r--r--src/libserver/worker_util.c14
-rw-r--r--src/libutil/fstring.c122
-rw-r--r--src/libutil/fstring.h62
-rw-r--r--src/libutil/http.c450
-rw-r--r--src/libutil/http.h25
-rw-r--r--src/libutil/map.c2
-rw-r--r--src/libutil/printf.c8
-rw-r--r--src/libutil/str_util.c197
-rw-r--r--src/libutil/str_util.h26
-rw-r--r--src/libutil/util.c80
-rw-r--r--src/libutil/util.h11
-rw-r--r--src/lua/lua_http.c18
-rw-r--r--src/lua/lua_task.c20
-rw-r--r--src/plugins/fuzzy_check.c17
-rw-r--r--src/plugins/surbl.c6
-rw-r--r--test/functional/cases/scan_file.sh5
23 files changed, 856 insertions, 484 deletions
diff --git a/src/client/rspamc.c b/src/client/rspamc.c
index 150c780a1..1d9252147 100644
--- a/src/client/rspamc.c
+++ b/src/client/rspamc.c
@@ -796,7 +796,7 @@ rspamc_output_headers (FILE *out, struct rspamd_http_message *msg)
LL_FOREACH (msg->headers, h)
{
- rspamd_fprintf (out, "%v: %v\n", h->name, h->value);
+ rspamd_fprintf (out, "%T: %T\n", h->name, h->value);
}
rspamd_fprintf (out, "\n");
}
@@ -1107,7 +1107,7 @@ rspamc_client_cb (struct rspamd_client_connection *conn,
if (json && msg != NULL && msg->body != NULL) {
/* We can also output the resulting json */
- rspamd_fprintf (out, "%v\n", msg->body);
+ rspamd_fprintf (out, "%V\n", msg->body);
}
}
}
diff --git a/src/client/rspamdclient.c b/src/client/rspamdclient.c
index 7f4e8aff5..272fe581b 100644
--- a/src/client/rspamdclient.c
+++ b/src/client/rspamdclient.c
@@ -123,10 +123,10 @@ rspamd_client_finish_handler (struct rspamd_http_connection *conn,
return 0;
}
else {
- if (msg->body == NULL || msg->body->len == 0 || msg->code != 200) {
- err = g_error_new (RCLIENT_ERROR, msg->code, "HTTP error: %d, %s",
+ if (msg->body == NULL || msg->body_buf.len == 0 || msg->code != 200) {
+ err = g_error_new (RCLIENT_ERROR, msg->code, "HTTP error: %d, %.*s",
msg->code,
- msg->status ? msg->status->str : "unknown error");
+ (gint)msg->status->len, msg->status->str);
req->cb (c, msg, c->server_name->str, NULL, req->input, req->ud, err);
g_error_free (err);
@@ -134,7 +134,7 @@ rspamd_client_finish_handler (struct rspamd_http_connection *conn,
}
parser = ucl_parser_new (0);
- if (!ucl_parser_add_chunk (parser, msg->body->str, msg->body->len)) {
+ if (!ucl_parser_add_chunk (parser, msg->body_buf.begin, msg->body_buf.len)) {
err = g_error_new (RCLIENT_ERROR, msg->code, "Cannot parse UCL: %s",
ucl_parser_get_error (parser));
ucl_parser_free (parser);
@@ -247,7 +247,7 @@ rspamd_client_command (struct rspamd_client_connection *conn,
return FALSE;
}
- req->msg->body = g_string_new_len (input->str, input->len);
+ req->msg->body = rspamd_fstring_new_init (input->str, input->len);
req->input = input;
}
else {
@@ -261,8 +261,8 @@ rspamd_client_command (struct rspamd_client_connection *conn,
rspamd_http_message_add_header (req->msg, hn, hv);
}
- g_string_append_c (req->msg->url, '/');
- g_string_append (req->msg->url, command);
+ req->msg->url = rspamd_fstring_append (req->msg->url, "/", 1);
+ req->msg->url = rspamd_fstring_append (req->msg->url, command, strlen (command));
conn->req = req;
diff --git a/src/controller.c b/src/controller.c
index c68cd1bdc..871037b32 100644
--- a/src/controller.c
+++ b/src/controller.c
@@ -252,7 +252,7 @@ rspamd_encrypted_password_get_str (const gchar * password, gsize skip,
static gboolean
rspamd_check_encrypted_password (struct rspamd_controller_worker_ctx *ctx,
- const GString * password, const gchar * check,
+ const rspamd_ftok_t * password, const gchar * check,
const struct rspamd_controller_pbkdf *pbkdf,
gboolean is_enable)
{
@@ -267,7 +267,7 @@ rspamd_check_encrypted_password (struct rspamd_controller_worker_ctx *ctx,
/* First of all check cached versions to save resources */
if (is_enable && ctx->cached_enable_password.len != 0) {
if (password->len != ctx->cached_enable_password.len ||
- !rspamd_constant_memcmp (password->str,
+ !rspamd_constant_memcmp (password->begin,
ctx->cached_enable_password.begin, password->len)) {
msg_info_ctx ("incorrect or absent enable password has been specified");
return FALSE;
@@ -277,7 +277,7 @@ rspamd_check_encrypted_password (struct rspamd_controller_worker_ctx *ctx,
}
else if (!is_enable && ctx->cached_password.len != 0) {
if (password->len != ctx->cached_password.len ||
- !rspamd_constant_memcmp (password->str,
+ !rspamd_constant_memcmp (password->begin,
ctx->cached_password.begin, password->len)) {
msg_info_ctx ("incorrect or absent password has been specified");
return FALSE;
@@ -314,7 +314,7 @@ rspamd_check_encrypted_password (struct rspamd_controller_worker_ctx *ctx,
}
local_key = g_alloca (pbkdf->key_len);
- rspamd_cryptobox_pbkdf (password->str, password->len,
+ rspamd_cryptobox_pbkdf (password->begin, password->len,
salt_decoded, salt_len,
local_key, pbkdf->key_len, pbkdf->rounds);
@@ -335,7 +335,7 @@ rspamd_check_encrypted_password (struct rspamd_controller_worker_ctx *ctx,
/* Mmap region */
m = mmap (NULL, password->len, PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
- memcpy (m, password->str, password->len);
+ memcpy (m, password->begin, password->len);
(void)mprotect (m, password->len, PROT_READ);
(void)mlock (m, password->len);
cache->begin = m;
@@ -353,8 +353,8 @@ static gboolean rspamd_controller_check_password(
struct rspamd_http_message *msg, gboolean is_enable)
{
const gchar *check;
- const GString *password;
- GString lookup;
+ const rspamd_ftok_t *password;
+ rspamd_ftok_t lookup;
GHashTable *query_args = NULL;
struct rspamd_controller_worker_ctx *ctx = session->ctx;
gboolean check_normal = TRUE, check_enable = TRUE, ret = TRUE,
@@ -381,7 +381,7 @@ static gboolean rspamd_controller_check_password(
/* Try to get password from query args */
query_args = rspamd_http_message_parse_query (msg);
- lookup.str = (gchar *)"password";
+ lookup.begin = (gchar *)"password";
lookup.len = sizeof ("password") - 1;
password = g_hash_table_lookup (query_args, &lookup);
@@ -415,7 +415,7 @@ static gboolean rspamd_controller_check_password(
}
if (check != NULL) {
if (!rspamd_is_encrypted_password (check, &pbkdf)) {
- ret = rspamd_constant_memcmp (password->str, check, password->len);
+ ret = rspamd_constant_memcmp (password->begin, check, password->len);
}
else {
ret = rspamd_check_encrypted_password (ctx, password, check,
@@ -437,7 +437,7 @@ static gboolean rspamd_controller_check_password(
if (ctx->password != NULL) {
check = ctx->password;
if (!rspamd_is_encrypted_password (check, &pbkdf)) {
- check_normal = rspamd_constant_memcmp (password->str, check,
+ check_normal = rspamd_constant_memcmp (password->begin, check,
password->len);
}
else {
@@ -453,7 +453,7 @@ static gboolean rspamd_controller_check_password(
if (ctx->enable_password != NULL) {
check = ctx->enable_password;
if (!rspamd_is_encrypted_password (check, &pbkdf)) {
- check_enable = rspamd_constant_memcmp (password->str, check,
+ check_enable = rspamd_constant_memcmp (password->begin, check,
password->len);
}
else {
@@ -748,11 +748,10 @@ rspamd_controller_handle_get_map (struct rspamd_http_connection_entry *conn_ent,
struct rspamd_controller_session *session = conn_ent->ud;
GList *cur;
struct rspamd_map *map;
- const GString *idstr;
- gchar *errstr;
+ const rspamd_ftok_t *idstr;
struct stat st;
gint fd;
- guint32 id;
+ gulong id;
gboolean found = FALSE;
struct rspamd_http_message *reply;
@@ -769,8 +768,7 @@ rspamd_controller_handle_get_map (struct rspamd_http_connection_entry *conn_ent,
return 0;
}
- id = strtoul (idstr->str, &errstr, 10);
- if (*errstr != '\0' && !g_ascii_isspace (*errstr)) {
+ if (!rspamd_strtoul (idstr->begin, idstr->len, &id)) {
msg_info_session ("invalid map id");
rspamd_controller_send_error (conn_ent, 400, "400 invalid map id");
return 0;
@@ -802,7 +800,7 @@ rspamd_controller_handle_get_map (struct rspamd_http_connection_entry *conn_ent,
reply = rspamd_http_new_message (HTTP_RESPONSE);
reply->date = time (NULL);
reply->code = 200;
- reply->body = g_string_sized_new (st.st_size);
+ reply->body = rspamd_fstring_sized_new (st.st_size);
/* Read the whole buffer */
if (read (fd, reply->body->str, st.st_size) == -1) {
@@ -814,7 +812,6 @@ rspamd_controller_handle_get_map (struct rspamd_http_connection_entry *conn_ent,
}
reply->body->len = st.st_size;
- reply->body->str[reply->body->len] = '\0';
close (fd);
@@ -925,7 +922,7 @@ rspamd_controller_handle_graph (
GHashTable *query;
struct rspamd_controller_session *session = conn_ent->ud;
struct rspamd_controller_worker_ctx *ctx;
- GString srch, *value;
+ rspamd_ftok_t srch, *value;
struct rspamd_rrd_query_result *rrd_result;
gulong i, j, ts, start_row, cnt, t;
ucl_object_t *res, *elt[4], *data_elt;
@@ -951,7 +948,7 @@ rspamd_controller_handle_graph (
}
query = rspamd_http_message_parse_query (msg);
- srch.str = (gchar *)"type";
+ srch.begin = (gchar *)"type";
srch.len = 4;
if (query == NULL || (value = g_hash_table_lookup (query, &srch)) == NULL) {
@@ -965,16 +962,16 @@ rspamd_controller_handle_graph (
return 0;
}
- if (strncmp (value->str, "hourly", value->len) == 0) {
+ if (strncmp (value->begin, "hourly", value->len) == 0) {
rra_num = rra_hourly;
}
- else if (strncmp (value->str, "daily", value->len) == 0) {
+ else if (strncmp (value->begin, "daily", value->len) == 0) {
rra_num = rra_hourly;
}
- else if (strncmp (value->str, "weekly", value->len) == 0) {
+ else if (strncmp (value->begin, "weekly", value->len) == 0) {
rra_num = rra_hourly;
}
- else if (strncmp (value->str, "monthly", value->len) == 0) {
+ else if (strncmp (value->begin, "monthly", value->len) == 0) {
rra_num = rra_monthly;
}
@@ -1277,7 +1274,7 @@ rspamd_controller_handle_learn_common (
session->cl = cl;
- if (!rspamd_task_load_message (task, msg, msg->body->str, msg->body->len)) {
+ if (!rspamd_task_load_message (task, msg, msg->body_buf.begin, msg->body_buf.len)) {
rspamd_controller_send_error (conn_ent, task->err->code, task->err->message);
return 0;
}
@@ -1369,7 +1366,7 @@ rspamd_controller_handle_scan (struct rspamd_http_connection_entry *conn_ent,
task->flags |= RSPAMD_TASK_FLAG_MIME;
task->resolver = ctx->resolver;
- if (!rspamd_task_load_message (task, msg, msg->body->str, msg->body->len)) {
+ if (!rspamd_task_load_message (task, msg, msg->body_buf.begin, msg->body_buf.len)) {
rspamd_controller_send_error (conn_ent, task->err->code, task->err->message);
rspamd_session_destroy (task->s);
return 0;
@@ -1444,7 +1441,7 @@ rspamd_controller_handle_saveactions (
}
parser = ucl_parser_new (0);
- ucl_parser_add_chunk (parser, msg->body->str, msg->body->len);
+ ucl_parser_add_chunk (parser, msg->body_buf.begin, msg->body_buf.len);
if ((error = ucl_parser_get_error (parser)) != NULL) {
msg_err_session ("cannot parse input: %s", error);
@@ -1558,7 +1555,7 @@ rspamd_controller_handle_savesymbols (
}
parser = ucl_parser_new (0);
- ucl_parser_add_chunk (parser, msg->body->str, msg->body->len);
+ ucl_parser_add_chunk (parser, msg->body_buf.begin, msg->body_buf.len);
if ((error = ucl_parser_get_error (parser)) != NULL) {
msg_err_session ("cannot parse input: %s", error);
@@ -1640,9 +1637,8 @@ rspamd_controller_handle_savemap (struct rspamd_http_connection_entry *conn_ent,
GList *cur;
struct rspamd_map *map;
struct rspamd_controller_worker_ctx *ctx;
- const GString *idstr;
- gchar *errstr;
- guint32 id;
+ const rspamd_ftok_t *idstr;
+ gulong id;
gboolean found = FALSE;
gint fd;
@@ -1668,9 +1664,8 @@ rspamd_controller_handle_savemap (struct rspamd_http_connection_entry *conn_ent,
return 0;
}
- id = strtoul (idstr->str, &errstr, 10);
- if (*errstr != '\0' && !g_ascii_isspace (*errstr)) {
- msg_info_session ("invalid map id: %v", idstr);
+ if (!rspamd_strtoul (idstr->begin, idstr->len, &id)) {
+ msg_info_session ("invalid map id: %T", idstr);
rspamd_controller_send_error (conn_ent, 400, "Map id is invalid");
return 0;
}
@@ -1708,7 +1703,7 @@ rspamd_controller_handle_savemap (struct rspamd_http_connection_entry *conn_ent,
return 0;
}
- if (write (fd, msg->body->str, msg->body->len) == -1) {
+ if (write (fd, msg->body_buf.begin, msg->body_buf.len) == -1) {
msg_info_session ("map %s write error: %s", map->uri, strerror (errno));
close (fd);
g_atomic_int_set (map->locked, 0);
@@ -1983,7 +1978,7 @@ rspamd_controller_handle_custom (struct rspamd_http_connection_entry *conn_ent,
cmd = g_hash_table_lookup (session->ctx->custom_commands, msg->url->str);
if (cmd == NULL || cmd->handler == NULL) {
- msg_err_session ("custom command %v has not been found", msg->url);
+ msg_err_session ("custom command %V has not been found", msg->url);
rspamd_controller_send_error (conn_ent, 404, "No command associated");
return 0;
}
diff --git a/src/http_proxy.c b/src/http_proxy.c
index f71adc3f6..6570e01cc 100644
--- a/src/http_proxy.c
+++ b/src/http_proxy.c
@@ -295,7 +295,7 @@ proxy_client_finish_handler (struct rspamd_http_connection *conn,
{
struct http_proxy_session *session = conn->ud;
struct rspamd_http_upstream *backend = NULL;
- const GString *host;
+ const rspamd_ftok_t *host;
gchar hostbuf[512];
if (!session->replied) {
@@ -305,7 +305,7 @@ proxy_client_finish_handler (struct rspamd_http_connection *conn,
backend = session->ctx->default_upstream;
}
else {
- rspamd_strlcpy (hostbuf, host->str, sizeof (hostbuf));
+ rspamd_strlcpy (hostbuf, host->begin, MIN(host->len + 1, sizeof (hostbuf)));
backend = g_hash_table_lookup (session->ctx->upstreams, hostbuf);
if (backend == NULL) {
diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c
index 221db1513..ba2599f5f 100644
--- a/src/libserver/protocol.c
+++ b/src/libserver/protocol.c
@@ -112,7 +112,7 @@ rspamd_protocol_quark (void)
* Remove <> from the fixed string and copy it to the pool
*/
static gchar *
-rspamd_protocol_escape_braces (struct rspamd_task *task, GString *in)
+rspamd_protocol_escape_braces (struct rspamd_task *task, rspamd_fstring_t *in)
{
gint len = 0;
gchar *orig, *p, *res;
@@ -155,7 +155,7 @@ rspamd_protocol_handle_url (struct rspamd_task *task,
struct http_parser_url u;
const gchar *p;
gsize pathlen;
- GString lookup, *res, *key, *value;
+ rspamd_ftok_t *key, *value;
gpointer k, v;
if (msg->url == NULL || msg->url->len == 0) {
@@ -257,29 +257,6 @@ rspamd_protocol_handle_url (struct rspamd_task *task,
/* In case if we have a query, we need to store it somewhere */
query_args = rspamd_http_message_parse_query (msg);
- lookup.str = (gchar *)"file";
- lookup.len = sizeof ("file") - 1;
-
- res = g_hash_table_lookup (query_args, &lookup);
-
- if (res == NULL) {
- lookup.str = (gchar *)"path";
- lookup.len = sizeof ("path") - 1;
- res = g_hash_table_lookup (query_args, &lookup);
- }
-
- if (res == NULL) {
- /* Treat the whole query as path */
- task->msg.begin = msg->url->str + u.field_data[UF_QUERY].off;
- task->msg.len = u.field_data[UF_QUERY].len;
- }
- else {
- task->msg.begin = rspamd_mempool_strdup (task->task_pool, res->str);
- task->msg.len = res->len;
- }
-
- task->flags |= RSPAMD_TASK_FLAG_FILE;
-
/* Insert the rest of query params as HTTP headers */
g_hash_table_iter_init (&it, query_args);
@@ -308,20 +285,24 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
struct rspamd_http_message *msg)
{
gchar *headern;
- GString *hn, *hv;
+ rspamd_fstring_t *hn, *hv;
+ rspamd_ftok_t *hn_tok, *hv_tok;
gboolean res = TRUE, validh, fl, has_ip = FALSE;
gsize hlen;
struct rspamd_http_header *h;
LL_FOREACH (msg->headers, h)
{
- hn = g_string_new_len (h->name->str, h->name->len);
- hv = g_string_new_len (h->value->str, h->value->len);
+ hn = rspamd_fstring_new_init (h->name->begin, h->name->len);
+ hv = rspamd_fstring_new_init (h->value->begin, h->value->len);
+ hn_tok = rspamd_ftok_map (hn);
+ hv_tok = rspamd_ftok_map (hv);
+
headern = hn->str;
hlen = hn->len;
validh = TRUE;
- g_hash_table_insert (task->request_headers, hn, hv);
+ g_hash_table_insert (task->request_headers, hn_tok, hv_tok);
switch (headern[0]) {
case 'd':
@@ -332,7 +313,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
task->deliver_to);
}
else {
- debug_task ("wrong header: %v", hn);
+ debug_task ("wrong header: %V", hn);
validh = FALSE;
}
break;
@@ -347,7 +328,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
debug_task ("read hostname header, value: %s", task->hostname);
}
else {
- debug_task ("wrong header: %v", hn);
+ debug_task ("wrong header: %V", hn);
validh = FALSE;
}
break;
@@ -355,12 +336,12 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
case 'F':
if (g_ascii_strncasecmp (headern, FROM_HEADER, hlen) == 0) {
if (!rspamd_task_add_sender (task, hv->str)) {
- msg_err_task ("bad from header: '%v'", hv);
+ msg_err_task ("bad from header: '%V'", hv);
validh = FALSE;
}
}
else {
- debug_task ("wrong header: %v", hn);
+ debug_task ("wrong header: %V", hn);
validh = FALSE;
}
break;
@@ -376,7 +357,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
}
}
else {
- debug_task ("wrong header: %v", hn);
+ debug_task ("wrong header: %V", hn);
validh = FALSE;
}
break;
@@ -387,7 +368,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
debug_task ("read queue_id header, value: %s", task->queue_id);
}
else {
- debug_task ("wrong header: %v", hn);
+ debug_task ("wrong header: %V", hn);
validh = FALSE;
}
break;
@@ -395,13 +376,13 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
case 'R':
if (g_ascii_strncasecmp (headern, RCPT_HEADER, hlen) == 0) {
if (!rspamd_task_add_recipient (task, hv->str)) {
- msg_err_task ("bad from header: '%v'", h->value);
+ msg_err_task ("bad from header: '%V'", h->value);
validh = FALSE;
}
- debug_task ("read rcpt header, value: %v", hv);
+ debug_task ("read rcpt header, value: %V", hv);
}
else {
- debug_task ("wrong header: %v", hn);
+ debug_task ("wrong header: %V", hn);
validh = FALSE;
}
break;
@@ -409,14 +390,14 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
case 'I':
if (g_ascii_strncasecmp (headern, IP_ADDR_HEADER, hlen) == 0) {
if (!rspamd_parse_inet_address (&task->from_addr, hv->str)) {
- msg_err_task ("bad ip header: '%v'", hv);
+ msg_err_task ("bad ip header: '%V'", hv);
return FALSE;
}
- debug_task ("read IP header, value: %v", hv);
+ debug_task ("read IP header, value: %V", hv);
has_ip = TRUE;
}
else {
- debug_task ("wrong header: %v", hn);
+ debug_task ("wrong header: %V", hn);
validh = FALSE;
}
break;
@@ -482,7 +463,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
task->message_len = strtoul (hv->str, NULL, 10);
if (task->message_len == 0) {
- msg_err_task ("Invalid message length header: %v", hv);
+ msg_err_task ("Invalid message length header: %V", hv);
validh = FALSE;
}
else {
@@ -494,7 +475,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
}
break;
default:
- debug_task ("unknown header: %v", hn);
+ debug_task ("unknown header: %V", hn);
validh = FALSE;
break;
}
@@ -657,7 +638,7 @@ rspamd_protocol_handle_request (struct rspamd_task *task,
}
static void
-write_hashes_to_log (struct rspamd_task *task, GString *logbuf)
+write_hashes_to_log (struct rspamd_task *task, rspamd_fstring_t **logbuf)
{
struct mime_text_part *text_part;
guint i;
@@ -838,13 +819,13 @@ rspamd_str_list_ucl (GList *str_list)
static ucl_object_t *
rspamd_metric_symbol_ucl (struct rspamd_task *task, struct metric *m,
- struct symbol *sym, GString *logbuf)
+ struct symbol *sym, rspamd_fstring_t **logbuf)
{
ucl_object_t *obj = NULL;
const gchar *description = NULL;
if (logbuf != NULL) {
- rspamd_printf_gstring (logbuf, "%s,", sym->name);
+ rspamd_printf_fstring (logbuf, "%s,", sym->name);
}
if (sym->def != NULL) {
@@ -871,7 +852,7 @@ rspamd_metric_symbol_ucl (struct rspamd_task *task, struct metric *m,
static ucl_object_t *
rspamd_metric_result_ucl (struct rspamd_task *task,
struct metric_result *mres,
- GString *logbuf)
+ rspamd_fstring_t **logbuf)
{
GHashTableIter hiter;
struct symbol *sym;
@@ -902,7 +883,7 @@ rspamd_metric_result_ucl (struct rspamd_task *task,
}
if (logbuf != NULL) {
- rspamd_printf_gstring (logbuf, "(%s: %c (%s): [%.2f/%.2f] [",
+ rspamd_printf_fstring (logbuf, "(%s: %c (%s): [%.2f/%.2f] [",
m->name, action_char,
rspamd_action_to_str (action),
mres->score, required_score);
@@ -936,11 +917,13 @@ rspamd_metric_result_ucl (struct rspamd_task *task,
if (logbuf != NULL) {
/* Cut the trailing comma if needed */
- if (logbuf->str[logbuf->len - 1] == ',') {
- logbuf->len--;
+ rspamd_fstring_t *log = *logbuf;
+
+ if (log->str[log->len - 1] == ',') {
+ log->len--;
}
- rspamd_printf_gstring (logbuf, "]), len: %z, time: %s, dns req: %d,",
+ rspamd_printf_fstring (logbuf, "]), len: %z, time: %s, dns req: %d,",
task->msg.len,
rspamd_log_check_time (task->time_real,
task->time_virtual,
@@ -954,7 +937,7 @@ rspamd_metric_result_ucl (struct rspamd_task *task,
static void
rspamd_ucl_torspamc_output (struct rspamd_task *task,
ucl_object_t *top,
- GString *out)
+ rspamd_fstring_t **out)
{
const ucl_object_t *metric, *score,
*required_score, *is_spam, *elt, *cur;
@@ -965,14 +948,14 @@ rspamd_ucl_torspamc_output (struct rspamd_task *task,
score = ucl_object_find_key (metric, "score");
required_score = ucl_object_find_key (metric, "required_score");
is_spam = ucl_object_find_key (metric, "is_spam");
- g_string_append_printf (out,
+ rspamd_printf_fstring (out,
"Metric: default; %s; %.2f / %.2f / 0.0\r\n",
ucl_object_toboolean (is_spam) ? "True" : "False",
ucl_object_todouble (score),
ucl_object_todouble (required_score));
elt = ucl_object_find_key (metric, "action");
if (elt != NULL) {
- g_string_append_printf (out, "Action: %s\r\n",
+ rspamd_printf_fstring (out, "Action: %s\r\n",
ucl_object_tostring (elt));
}
@@ -981,7 +964,7 @@ rspamd_ucl_torspamc_output (struct rspamd_task *task,
if (elt->type == UCL_OBJECT) {
const ucl_object_t *sym_score;
sym_score = ucl_object_find_key (elt, "score");
- g_string_append_printf (out, "Symbol: %s(%.2f)\r\n",
+ rspamd_printf_fstring (out, "Symbol: %s(%.2f)\r\n",
ucl_object_key (elt),
ucl_object_todouble (sym_score));
}
@@ -989,7 +972,7 @@ rspamd_ucl_torspamc_output (struct rspamd_task *task,
elt = ucl_object_find_key (metric, "subject");
if (elt != NULL) {
- g_string_append_printf (out, "Subject: %s\r\n",
+ rspamd_printf_fstring (out, "Subject: %s\r\n",
ucl_object_tostring (elt));
}
}
@@ -999,30 +982,31 @@ rspamd_ucl_torspamc_output (struct rspamd_task *task,
iter = NULL;
while ((cur = ucl_iterate_object (elt, &iter, true)) != NULL) {
if (cur->type == UCL_STRING) {
- g_string_append_printf (out, "Message: %s\r\n",
+ rspamd_printf_fstring (out, "Message: %s\r\n",
ucl_object_tostring (cur));
}
}
}
- g_string_append_printf (out, "Message-ID: %s\r\n", task->message_id);
+ rspamd_printf_fstring (out, "Message-ID: %s\r\n", task->message_id);
}
static void
rspamd_ucl_tospamc_output (struct rspamd_task *task,
ucl_object_t *top,
- GString *out)
+ rspamd_fstring_t **out)
{
const ucl_object_t *metric, *score,
*required_score, *is_spam, *elt;
ucl_object_iter_t iter = NULL;
+ rspamd_fstring_t *f;
metric = ucl_object_find_key (top, DEFAULT_METRIC);
if (metric != NULL) {
score = ucl_object_find_key (metric, "score");
required_score = ucl_object_find_key (metric, "required_score");
is_spam = ucl_object_find_key (metric, "is_spam");
- g_string_append_printf (out,
+ rspamd_printf_fstring (out,
"Spam: %s ; %.2f / %.2f\r\n\r\n",
ucl_object_toboolean (is_spam) ? "True" : "False",
ucl_object_todouble (score),
@@ -1030,20 +1014,22 @@ rspamd_ucl_tospamc_output (struct rspamd_task *task,
while ((elt = ucl_iterate_object (metric, &iter, true)) != NULL) {
if (elt->type == UCL_OBJECT) {
- g_string_append_printf (out, "%s,",
+ rspamd_printf_fstring (out, "%s,",
ucl_object_key (elt));
}
}
/* Ugly hack, but the whole spamc is ugly */
- if (out->str[out->len - 1] == ',') {
- g_string_truncate (out, out->len - 1);
- g_string_append (out, CRLF);
+ f = *out;
+ if (f->str[f->len - 1] == ',') {
+ f->len --;
+
+ *out = rspamd_fstring_append (*out, CRLF, 2);
}
}
}
ucl_object_t *
-rspamd_protocol_write_ucl (struct rspamd_task *task, GString *logbuf)
+rspamd_protocol_write_ucl (struct rspamd_task *task, rspamd_fstring_t **logbuf)
{
struct metric_result *metric_res;
ucl_object_t *top = NULL, *obj;
@@ -1051,14 +1037,14 @@ rspamd_protocol_write_ucl (struct rspamd_task *task, GString *logbuf)
gpointer h, v;
if (logbuf != NULL) {
- rspamd_printf_gstring (logbuf,
+ rspamd_printf_fstring (logbuf,
"id: <%s>, qid: <%s>, ip: %s, ",
task->message_id,
task->queue_id,
rspamd_inet_address_to_string (task->from_addr));
if (task->user) {
- rspamd_printf_gstring (logbuf, "user: %s, ", task->user);
+ rspamd_printf_fstring (logbuf, "user: %s, ", task->user);
}
else if (task->from_envelope) {
InternetAddress *ia;
@@ -1068,7 +1054,7 @@ rspamd_protocol_write_ucl (struct rspamd_task *task, GString *logbuf)
if (ia && INTERNET_ADDRESS_IS_MAILBOX (ia)) {
InternetAddressMailbox *iamb = INTERNET_ADDRESS_MAILBOX (ia);
- rspamd_printf_gstring (logbuf, "from: %s, ", iamb->addr);
+ rspamd_printf_fstring (logbuf, "from: %s, ", iamb->addr);
}
}
}
@@ -1109,7 +1095,7 @@ void
rspamd_protocol_http_reply (struct rspamd_http_message *msg,
struct rspamd_task *task)
{
- GString *logbuf;
+ rspamd_fstring_t *logbuf;
struct metric_result *metric_res;
GHashTableIter hiter;
gpointer h, v;
@@ -1118,40 +1104,42 @@ rspamd_protocol_http_reply (struct rspamd_http_message *msg,
gint action;
/* Output the first line - check status */
- logbuf = g_string_sized_new (BUFSIZ);
+ logbuf = rspamd_fstring_sized_new (1000);
/* Write custom headers */
g_hash_table_iter_init (&hiter, task->reply_headers);
while (g_hash_table_iter_next (&hiter, &h, &v)) {
- GString *hn = (GString *)h, *hv = (GString *)v;
+ rspamd_ftok_t *hn = h, *hv = v;
- rspamd_http_message_add_header (msg, hn->str, hv->str);
+ rspamd_http_message_add_header (msg, hn->begin, hv->begin);
}
- top = rspamd_protocol_write_ucl (task, logbuf);
+ top = rspamd_protocol_write_ucl (task, &logbuf);
if (!(task->flags & RSPAMD_TASK_FLAG_NO_LOG)) {
rspamd_roll_history_update (task->worker->srv->history, task);
}
if (!(task->flags & RSPAMD_TASK_FLAG_NO_LOG)) {
- msg_info_task ("%v", logbuf);
+ msg_info_task ("%V", logbuf);
}
- g_string_free (logbuf, TRUE);
- msg->body = g_string_sized_new (BUFSIZ);
+ rspamd_fstring_free (logbuf);
+
+ msg->body = rspamd_fstring_sized_new (1000);
if (msg->method < HTTP_SYMBOLS && !RSPAMD_TASK_IS_SPAMC (task)) {
- rspamd_ucl_emit_gstring (top, UCL_EMIT_JSON_COMPACT, msg->body);
+ rspamd_ucl_emit_fstring (top, UCL_EMIT_JSON_COMPACT, &msg->body);
}
else {
if (RSPAMD_TASK_IS_SPAMC (task)) {
- rspamd_ucl_tospamc_output (task, top, msg->body);
+ rspamd_ucl_tospamc_output (task, top, &msg->body);
}
else {
- rspamd_ucl_torspamc_output (task, top, msg->body);
+ rspamd_ucl_torspamc_output (task, top, &msg->body);
}
}
+
ucl_object_unref (top);
if (!(task->flags & RSPAMD_TASK_FLAG_NO_STAT)) {
@@ -1200,14 +1188,15 @@ rspamd_protocol_write_reply (struct rspamd_task *task)
top = ucl_object_typed_new (UCL_OBJECT);
msg->code = 500 + task->err->code % 100;
- msg->status = g_string_new (task->err->message);
+ msg->status = rspamd_fstring_new_init (task->err->message,
+ strlen (task->err->message));
ucl_object_insert_key (top, ucl_object_fromstring (task->err->message),
"error", 0, false);
ucl_object_insert_key (top,
ucl_object_fromstring (g_quark_to_string (task->err->domain)),
"error_domain", 0, false);
- msg->body = g_string_sized_new (256);
- rspamd_ucl_emit_gstring (top, UCL_EMIT_JSON_COMPACT, msg->body);
+ msg->body = rspamd_fstring_sized_new (256);
+ rspamd_ucl_emit_fstring (top, UCL_EMIT_JSON_COMPACT, &msg->body);
ucl_object_unref (top);
}
else {
@@ -1221,7 +1210,7 @@ rspamd_protocol_write_reply (struct rspamd_task *task)
rspamd_protocol_http_reply (msg, task);
break;
case CMD_PING:
- msg->body = g_string_new ("pong" CRLF);
+ msg->body = rspamd_fstring_new_init ("pong" CRLF, 6);
ctype = "text/plain";
break;
case CMD_OTHER:
diff --git a/src/libserver/protocol.h b/src/libserver/protocol.h
index c1a44bb5a..0342f4ed6 100644
--- a/src/libserver/protocol.h
+++ b/src/libserver/protocol.h
@@ -62,7 +62,7 @@ void rspamd_protocol_http_reply (struct rspamd_http_message *msg,
* @return
*/
ucl_object_t * rspamd_protocol_write_ucl (struct rspamd_task *task,
- GString *logbuf);
+ rspamd_fstring_t **logbuf);
/**
* Write reply for specified task command
diff --git a/src/libserver/task.c b/src/libserver/task.c
index 6d0eca2a2..6dd00b8bf 100644
--- a/src/libserver/task.c
+++ b/src/libserver/task.c
@@ -71,15 +71,15 @@ rspamd_task_new (struct rspamd_worker *worker)
new_task->re_cache);
new_task->raw_headers = g_hash_table_new (rspamd_strcase_hash,
rspamd_strcase_equal);
- new_task->request_headers = g_hash_table_new_full (rspamd_gstring_icase_hash,
- rspamd_gstring_icase_equal, rspamd_gstring_free_hard,
- rspamd_gstring_free_hard);
+ new_task->request_headers = g_hash_table_new_full (rspamd_ftok_icase_hash,
+ rspamd_ftok_icase_equal, rspamd_fstring_mapped_ftok_free,
+ rspamd_fstring_mapped_ftok_free);
rspamd_mempool_add_destructor (new_task->task_pool,
(rspamd_mempool_destruct_t) g_hash_table_unref,
new_task->request_headers);
- new_task->reply_headers = g_hash_table_new_full (rspamd_gstring_icase_hash,
- rspamd_gstring_icase_equal, rspamd_gstring_free_hard,
- rspamd_gstring_free_hard);
+ new_task->reply_headers = g_hash_table_new_full (rspamd_ftok_icase_hash,
+ rspamd_ftok_icase_equal, rspamd_fstring_mapped_ftok_free,
+ rspamd_fstring_mapped_ftok_free);
rspamd_mempool_add_destructor (new_task->task_pool,
(rspamd_mempool_destruct_t) g_hash_table_unref,
new_task->reply_headers);
@@ -261,6 +261,7 @@ rspamd_task_load_message (struct rspamd_task *task,
ucl_object_t *control_obj;
gchar filepath[PATH_MAX], *fp;
gint fd, flen;
+ rspamd_ftok_t srch, *tok;
gpointer map;
struct stat st;
@@ -268,11 +269,21 @@ rspamd_task_load_message (struct rspamd_task *task,
rspamd_protocol_handle_headers (task, msg);
}
- if (task->flags & RSPAMD_TASK_FLAG_FILE) {
- g_assert (task->msg.len > 0);
+ srch.begin = "file";
+ srch.len = 4;
+ tok = g_hash_table_lookup (task->request_headers, &srch);
- r = rspamd_strlcpy (filepath, task->msg.begin,
- MIN (sizeof (filepath), task->msg.len + 1));
+ if (tok == NULL) {
+ srch.begin = "path";
+ srch.len = 4;
+ tok = g_hash_table_lookup (task->request_headers, &srch);
+ }
+
+ if (tok) {
+ debug_task ("want to scan file %T", tok);
+
+ r = rspamd_strlcpy (filepath, tok->begin,
+ MIN (sizeof (filepath), tok->len + 1));
rspamd_decode_url (filepath, filepath, r + 1);
flen = strlen (filepath);
diff --git a/src/libserver/worker_util.c b/src/libserver/worker_util.c
index eee200a41..ddd72acb9 100644
--- a/src/libserver/worker_util.c
+++ b/src/libserver/worker_util.c
@@ -278,14 +278,14 @@ rspamd_controller_send_error (struct rspamd_http_connection_entry *entry,
msg = rspamd_http_new_message (HTTP_RESPONSE);
va_start (args, error_msg);
- msg->status = g_string_sized_new (128);
- rspamd_vprintf_gstring (msg->status, error_msg, args);
+ msg->status = rspamd_fstring_sized_new (128);
+ rspamd_vprintf_fstring (&msg->status, error_msg, args);
va_end (args);
msg->date = time (NULL);
msg->code = code;
- msg->body = g_string_sized_new (128);
- rspamd_printf_gstring (msg->body, "{\"error\":\"%v\"}", msg->status);
+ msg->body = rspamd_fstring_sized_new (128);
+ rspamd_printf_fstring (&msg->body, "{\"error\":\"%V\"}", msg->status);
rspamd_http_connection_reset (entry->conn);
rspamd_http_connection_write_message (entry->conn,
msg,
@@ -307,7 +307,7 @@ rspamd_controller_send_string (struct rspamd_http_connection_entry *entry,
msg = rspamd_http_new_message (HTTP_RESPONSE);
msg->date = time (NULL);
msg->code = 200;
- msg->body = g_string_new (str);
+ msg->body = rspamd_fstring_new_init (str, strlen (str));
rspamd_http_connection_reset (entry->conn);
rspamd_http_connection_write_message (entry->conn,
msg,
@@ -329,8 +329,8 @@ rspamd_controller_send_ucl (struct rspamd_http_connection_entry *entry,
msg = rspamd_http_new_message (HTTP_RESPONSE);
msg->date = time (NULL);
msg->code = 200;
- msg->body = g_string_sized_new (BUFSIZ);
- rspamd_ucl_emit_gstring (obj, UCL_EMIT_JSON_COMPACT, msg->body);
+ msg->body = rspamd_fstring_sized_new (BUFSIZ);
+ rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON_COMPACT, &msg->body);
rspamd_http_connection_reset (entry->conn);
rspamd_http_connection_write_message (entry->conn,
msg,
diff --git a/src/libutil/fstring.c b/src/libutil/fstring.c
index 6a1304423..e6ce5a052 100644
--- a/src/libutil/fstring.c
+++ b/src/libutil/fstring.c
@@ -23,6 +23,7 @@
*/
#include "fstring.h"
+#include "str_util.h"
static const gsize default_initial_size = 48;
/* Maximum size when we double the size of new string */
@@ -71,6 +72,24 @@ rspamd_fstring_new_init (const gchar *init, gsize len)
return s;
}
+rspamd_fstring_t *
+rspamd_fstring_assign (rspamd_fstring_t *str, const gchar *init, gsize len)
+{
+ gsize avail = str->allocated;
+
+ if (avail < len) {
+ str = rspamd_fstring_grow (str, len);
+ }
+
+ if (len > 0) {
+ memcpy (str->str, init, len);
+ }
+
+ str->len = len;
+
+ return str;
+}
+
void
rspamd_fstring_free (rspamd_fstring_t *str)
{
@@ -125,6 +144,22 @@ rspamd_fstring_append (rspamd_fstring_t *str, const char *in, gsize len)
return str;
}
+rspamd_fstring_t *
+rspamd_fstring_append_chars (rspamd_fstring_t *str,
+ char c, gsize len)
+{
+ gsize avail = fstravail (str);
+
+ if (avail < len) {
+ str = rspamd_fstring_grow (str, len);
+ }
+
+ memset (str->str + str->len, c, len);
+ str->len += len;
+
+ return str;
+}
+
void
rspamd_fstring_erase (rspamd_fstring_t *str, gsize pos, gsize len)
{
@@ -238,3 +273,90 @@ rspamd_fstring_equal (const rspamd_fstring_t *s1,
return FALSE;
}
+
+gint
+rspamd_fstring_casecmp (const rspamd_fstring_t *s1,
+ const rspamd_fstring_t *s2)
+{
+ gint ret = 0;
+
+ g_assert (s1 != NULL && s2 != NULL);
+
+ if (s1->len == s2->len) {
+ ret = rspamd_lc_cmp (s1->str, s2->str, s1->len);
+ }
+ else {
+ ret = s1->len - s2->len;
+ }
+
+ return ret;
+}
+
+gint
+rspamd_fstring_cmp (const rspamd_fstring_t *s1,
+ const rspamd_fstring_t *s2)
+{
+ g_assert (s1 != NULL && s2 != NULL);
+
+ if (s1->len == s2->len) {
+ return memcmp (s1->str, s2->str, s1->len);
+ }
+
+ return s1->len - s2->len;
+}
+
+gint
+rspamd_ftok_casecmp (const rspamd_ftok_t *s1,
+ const rspamd_ftok_t *s2)
+{
+ gint ret = 0;
+
+ g_assert (s1 != NULL && s2 != NULL);
+
+ if (s1->len == s2->len) {
+ ret = rspamd_lc_cmp (s1->begin, s2->begin, s1->len);
+ }
+ else {
+ ret = s1->len - s2->len;
+ }
+
+ return ret;
+}
+
+gint
+rspamd_ftok_cmp (const rspamd_ftok_t *s1,
+ const rspamd_ftok_t *s2)
+{
+ g_assert (s1 != NULL && s2 != NULL);
+
+ if (s1->len == s2->len) {
+ return memcmp (s1->begin, s2->begin, s1->len);
+ }
+
+ return s1->len - s2->len;
+}
+
+void
+rspamd_fstring_mapped_ftok_free (gpointer p)
+{
+ rspamd_ftok_t *tok = p;
+ rspamd_fstring_t *storage;
+
+ storage = (rspamd_fstring_t *) (tok->begin - 2 * sizeof (gsize));
+ rspamd_fstring_free (storage);
+ g_slice_free1 (sizeof (*tok), tok);
+}
+
+rspamd_ftok_t *
+rspamd_ftok_map (const rspamd_fstring_t *s)
+{
+ rspamd_ftok_t *tok;
+
+ g_assert (s != NULL);
+
+ tok = g_slice_alloc (sizeof (*tok));
+ tok->begin = s->str;
+ tok->len = s->len;
+
+ return tok;
+}
diff --git a/src/libutil/fstring.h b/src/libutil/fstring.h
index 02b92bea3..d3b51821f 100644
--- a/src/libutil/fstring.h
+++ b/src/libutil/fstring.h
@@ -48,17 +48,26 @@ typedef struct f_str_tok {
/**
* Create new fixed length string
*/
-rspamd_fstring_t* rspamd_fstring_new (void);
+rspamd_fstring_t* rspamd_fstring_new (void)
+ G_GNUC_WARN_UNUSED_RESULT;
/**
* Create new fixed length string with preallocated size
*/
-rspamd_fstring_t *rspamd_fstring_sized_new (gsize initial_size);
+rspamd_fstring_t *rspamd_fstring_sized_new (gsize initial_size)
+ G_GNUC_WARN_UNUSED_RESULT;
/**
* Create new fixed length string and initialize it with the initial data
*/
-rspamd_fstring_t *rspamd_fstring_new_init (const gchar *init, gsize len);
+rspamd_fstring_t *rspamd_fstring_new_init (const gchar *init, gsize len)
+ G_GNUC_WARN_UNUSED_RESULT;
+
+/**
+ * Assign new value to fixed string
+ */
+rspamd_fstring_t *rspamd_fstring_assign (rspamd_fstring_t *str,
+ const gchar *init, gsize len) G_GNUC_WARN_UNUSED_RESULT;
/**
* Free fixed length string
@@ -71,6 +80,11 @@ void rspamd_fstring_free (rspamd_fstring_t *str);
rspamd_fstring_t* rspamd_fstring_append (rspamd_fstring_t *str,
const char *in, gsize len) G_GNUC_WARN_UNUSED_RESULT;
+/**
+ * Append `len` repeated chars `c` to string `str`
+ */
+rspamd_fstring_t *rspamd_fstring_append_chars (rspamd_fstring_t *str,
+ char c, gsize len) G_GNUC_WARN_UNUSED_RESULT;
/**
* Erase `len` characters at postion `pos`
@@ -81,7 +95,8 @@ void rspamd_fstring_erase (rspamd_fstring_t *str, gsize pos, gsize len);
* Convert fixed string to a zero terminated string. This string should be
* freed by a caller
*/
-char * rspamd_fstring_cstr (const rspamd_fstring_t *str);
+char * rspamd_fstring_cstr (const rspamd_fstring_t *str)
+ G_GNUC_WARN_UNUSED_RESULT;
/*
* Return fast hash value for fixed string converted to lowercase
@@ -94,4 +109,43 @@ guint32 rspamd_fstrhash_lc (const rspamd_ftok_t *str, gboolean is_utf);
gboolean rspamd_fstring_equal (const rspamd_fstring_t *s1,
const rspamd_fstring_t *s2);
+/**
+ * Compare two fixed strings ignoring case
+ */
+gint rspamd_fstring_casecmp (const rspamd_fstring_t *s1,
+ const rspamd_fstring_t *s2);
+
+/**
+ * Compare two fixed strings
+ */
+gint rspamd_fstring_cmp (const rspamd_fstring_t *s1,
+ const rspamd_fstring_t *s2);
+
+/**
+ * Compare two fixed tokens ignoring case
+ */
+gint rspamd_ftok_casecmp (const rspamd_ftok_t *s1,
+ const rspamd_ftok_t *s2);
+
+/**
+ * Compare two fixed tokens
+ */
+gint rspamd_ftok_cmp (const rspamd_ftok_t *s1,
+ const rspamd_ftok_t *s2);
+
+/**
+ * Free fstring_t that is mapped to ftok_t
+ *
+ * | len | allocated | <data> -- fstring_t
+ * <begin> -- tok
+ *
+ * tok is expected to be allocated with g_slice_alloc
+ */
+void rspamd_fstring_mapped_ftok_free (gpointer p);
+
+/**
+ * Map token to a specified string. Token must be freed using g_slice_free1
+ */
+rspamd_ftok_t *rspamd_ftok_map (const rspamd_fstring_t *s);
+
#endif
diff --git a/src/libutil/http.c b/src/libutil/http.c
index f1a1dac75..6c9617ae5 100644
--- a/src/libutil/http.c
+++ b/src/libutil/http.c
@@ -36,11 +36,13 @@
#define ENCRYPTED_VERSION " HTTP/1.0"
+struct _rspamd_http_privbuf {
+ rspamd_fstring_t *data;
+ ref_entry_t ref;
+};
+
struct rspamd_http_connection_private {
- struct _rspamd_http_privbuf {
- GString *data;
- ref_entry_t ref;
- } *buf;
+ struct _rspamd_http_privbuf *buf;
gboolean new_header;
gboolean encrypted;
gpointer peer_key;
@@ -82,8 +84,14 @@ static const struct _rspamd_http_magic {
static const gchar *http_week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const gchar *http_month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-static const gchar *key_header = "Key";
-static const gchar *date_header = "Date";
+static const rspamd_ftok_t key_header = {
+ .begin = "Key",
+ .len = 3
+};
+static const rspamd_ftok_t date_header = {
+ .begin = "Date",
+ .len = 4
+};
#define RSPAMD_HTTP_KEY_ID_LEN 5
@@ -108,8 +116,9 @@ rspamd_http_privbuf_dtor (gpointer ud)
struct _rspamd_http_privbuf *p = (struct _rspamd_http_privbuf *)ud;
if (p->data) {
- g_string_free (p->data, TRUE);
+ rspamd_fstring_free (p->data);
}
+
g_slice_free1 (sizeof (struct _rspamd_http_privbuf), p);
}
@@ -407,7 +416,7 @@ rspamd_http_parse_date (const gchar *header, gsize len)
}
static void
-rspamd_http_parse_key (GString *data, struct rspamd_http_connection *conn,
+rspamd_http_parse_key (rspamd_ftok_t *data, struct rspamd_http_connection *conn,
struct rspamd_http_connection_private *priv)
{
guchar *decoded_id, *decoded_key;
@@ -421,11 +430,11 @@ rspamd_http_parse_key (GString *data, struct rspamd_http_connection *conn,
}
else {
/* Check sanity of what we have */
- eq_pos = memchr (data->str, '=', data->len);
+ eq_pos = memchr (data->begin, '=', data->len);
if (eq_pos != NULL) {
- decoded_id = rspamd_decode_base32 (data->str, eq_pos - data->str,
+ decoded_id = rspamd_decode_base32 (data->begin, eq_pos - data->begin,
&id_len);
- decoded_key = rspamd_decode_base32 (eq_pos + 1, data->str + data->len -
+ decoded_key = rspamd_decode_base32 (eq_pos + 1, data->begin + data->len -
eq_pos - 1, &key_len);
if (decoded_id != NULL && decoded_key != NULL) {
if (id_len >= RSPAMD_HTTP_KEY_ID_LEN &&
@@ -455,13 +464,11 @@ static inline void
rspamd_http_check_special_header (struct rspamd_http_connection *conn,
struct rspamd_http_connection_private *priv)
{
- if (g_ascii_strncasecmp (priv->header->name->str, date_header,
- priv->header->name->len) == 0) {
- priv->msg->date = rspamd_http_parse_date (priv->header->value->str,
+ if (rspamd_ftok_casecmp (priv->header->name, &date_header) == 0) {
+ priv->msg->date = rspamd_http_parse_date (priv->header->value->begin,
priv->header->value->len);
}
- else if (g_ascii_strncasecmp (priv->header->name->str, key_header,
- priv->header->name->len) == 0) {
+ else if (rspamd_ftok_casecmp (priv->header->name, &key_header) == 0) {
rspamd_http_parse_key (priv->header->value, conn, priv);
}
}
@@ -475,7 +482,7 @@ rspamd_http_on_url (http_parser * parser, const gchar *at, size_t length)
priv = conn->priv;
- g_string_append_len (priv->msg->url, at, length);
+ priv->msg->url = rspamd_fstring_append (priv->msg->url, at, length);
return 0;
}
@@ -491,14 +498,39 @@ rspamd_http_on_status (http_parser * parser, const gchar *at, size_t length)
if (parser->status_code != 200) {
if (priv->msg->status == NULL) {
- priv->msg->status = g_string_sized_new (128);
+ priv->msg->status = rspamd_fstring_new ();
}
- g_string_append_len (priv->msg->status, at, length);
+
+ priv->msg->status = rspamd_fstring_append (priv->msg->status, at, length);
}
return 0;
}
+static void
+rspamd_http_finish_header (struct rspamd_http_connection *conn,
+ struct rspamd_http_connection_private *priv)
+{
+ priv->header->combined = rspamd_fstring_append (priv->header->combined,
+ "\r\n", 2);
+ priv->header->value->len = priv->header->combined->len -
+ priv->header->name->len - 4;
+ priv->header->value->begin = priv->header->combined->str +
+ priv->header->name->len + 2;
+ DL_APPEND (priv->msg->headers, priv->header);
+
+ rspamd_http_check_special_header (conn, priv);
+}
+
+static void
+rspamd_http_init_header (struct rspamd_http_connection_private *priv)
+{
+ priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
+ priv->header->name = g_slice_alloc0 (sizeof (*priv->header->name));
+ priv->header->value = g_slice_alloc0 (sizeof (*priv->header->value));
+ priv->header->combined = rspamd_fstring_new ();
+}
+
static gint
rspamd_http_on_header_field (http_parser * parser,
const gchar *at,
@@ -511,27 +543,16 @@ rspamd_http_on_header_field (http_parser * parser,
priv = conn->priv;
if (priv->header == NULL) {
- priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
- priv->header->name = g_slice_alloc0 (sizeof (GString));
- priv->header->value = g_slice_alloc0 (sizeof (GString));
- priv->header->combined = g_string_sized_new (64);
+ rspamd_http_init_header (priv);
}
else if (priv->new_header) {
- g_string_append_len (priv->header->combined, "\r\n", 2);
- priv->header->value->len = priv->header->combined->len -
- priv->header->name->len - 4;
- priv->header->value->str = priv->header->combined->str +
- priv->header->name->len + 2;
- DL_APPEND (priv->msg->headers, priv->header);
- rspamd_http_check_special_header (conn, priv);
- priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
- priv->header->name = g_slice_alloc0 (sizeof (GString));
- priv->header->value = g_slice_alloc0 (sizeof (GString));
- priv->header->combined = g_string_sized_new (64);
+ rspamd_http_finish_header (conn, priv);
+ rspamd_http_init_header (priv);
}
priv->new_header = FALSE;
- g_string_append_len (priv->header->combined, at, length);
+ priv->header->combined = rspamd_fstring_append (priv->header->combined,
+ at, length);
return 0;
}
@@ -554,12 +575,14 @@ rspamd_http_on_header_value (http_parser * parser,
if (!priv->new_header) {
priv->new_header = TRUE;
- g_string_append_len (priv->header->combined, ": ", 2);
- priv->header->name->str = priv->header->combined->str;
+ priv->header->combined = rspamd_fstring_append (priv->header->combined,
+ ": ", 2);
+ priv->header->name->begin = priv->header->combined->str;
priv->header->name->len = priv->header->combined->len - 2;
}
- g_string_append_len (priv->header->combined, at, length);
+ priv->header->combined = rspamd_fstring_append (priv->header->combined,
+ at, length);
return 0;
}
@@ -574,29 +597,24 @@ rspamd_http_on_headers_complete (http_parser * parser)
priv = conn->priv;
if (priv->header != NULL) {
- g_string_append_len (priv->header->combined, "\r\n", 2);
- priv->header->value->str = priv->header->combined->str +
- priv->header->name->len + 2;
- priv->header->value->len = priv->header->combined->len -
- priv->header->name->len - 4;
- DL_APPEND (priv->msg->headers, priv->header);
- rspamd_http_check_special_header (conn, priv);
+ rspamd_http_finish_header (conn, priv);
+
priv->header = NULL;
priv->new_header = FALSE;
}
if (parser->content_length != 0 && parser->content_length != ULLONG_MAX) {
- priv->msg->body = g_string_sized_new (parser->content_length + 1);
+ priv->msg->body = rspamd_fstring_sized_new (parser->content_length + 1);
}
else {
- priv->msg->body = g_string_sized_new (BUFSIZ);
+ priv->msg->body = rspamd_fstring_new ();
}
if (parser->flags & F_SPAMC) {
priv->msg->flags |= RSPAMD_HTTP_FLAG_SPAMC;
}
- priv->msg->body_buf.str = priv->msg->body->str;
+ priv->msg->body_buf.begin = priv->msg->body->str;
priv->msg->method = parser->method;
priv->msg->code = parser->status_code;
@@ -612,12 +630,14 @@ rspamd_http_on_body (http_parser * parser, const gchar *at, size_t length)
priv = conn->priv;
- g_string_append_len (priv->msg->body, at, length);
+ priv->msg->body = rspamd_fstring_append (priv->msg->body, at, length);
+
/* Append might cause realloc */
- priv->msg->body_buf.str = priv->msg->body->str;
+ priv->msg->body_buf.begin = priv->msg->body->str;
+ priv->msg->body_buf.len = priv->msg->body->len;
if ((conn->opts & RSPAMD_HTTP_BODY_PARTIAL) && !priv->encrypted) {
- /* Incremental update is basically impossible for encrypted requests */
+ /* Incremental update is impossible for encrypted requests so far */
return (conn->body_handler (conn, priv->msg, at, length));
}
@@ -634,23 +654,18 @@ rspamd_http_on_body_decrypted (http_parser * parser, const gchar *at, size_t len
priv = conn->priv;
if (priv->header != NULL) {
- g_string_append_len (priv->header->combined, "\r\n", 2);
- priv->header->value->str = priv->header->combined->str +
- priv->header->name->len + 2;
- priv->header->value->len = priv->header->combined->len -
- priv->header->name->len - 4;
- DL_APPEND (priv->msg->headers, priv->header);
- rspamd_http_check_special_header (conn, priv);
+ rspamd_http_finish_header (conn, priv);
priv->header = NULL;
}
- if (priv->msg->body->str == 0) {
- priv->msg->body->str = (gchar *)at;
+ if (priv->msg->body_buf.len == 0) {
+
+ priv->msg->body_buf.begin = at;
priv->msg->method = parser->method;
priv->msg->code = parser->status_code;
}
- priv->msg->body->len += length;
+ priv->msg->body_buf.len += length;
return 0;
}
@@ -691,17 +706,19 @@ rspamd_http_decrypt_message (struct rspamd_http_connection *conn,
/* Cleanup message */
DL_FOREACH_SAFE (msg->headers, hdr, hdrtmp) {
- g_string_free (hdr->combined, TRUE);
- g_slice_free1 (sizeof (GString), hdr->name);
- g_slice_free1 (sizeof (GString), hdr->value);
+ rspamd_fstring_free (hdr->combined);
+ g_slice_free1 (sizeof (*hdr->name), hdr->name);
+ g_slice_free1 (sizeof (*hdr->value), hdr->value);
g_slice_free1 (sizeof (struct rspamd_http_header), hdr);
}
+
msg->headers = NULL;
+
if (msg->url != NULL) {
- g_string_assign (msg->url, "");
+ msg->url = rspamd_fstring_assign (msg->url, "", 0);
}
- msg->body->len = 0;
- msg->body->str = NULL;
+
+ msg->body_buf.len = 0;
http_parser_init (&decrypted_parser,
conn->type == RSPAMD_HTTP_SERVER ? HTTP_REQUEST : HTTP_RESPONSE);
@@ -757,8 +774,8 @@ rspamd_http_on_message_complete (http_parser * parser)
rspamd_http_connection_ref (conn);
ret = conn->body_handler (conn,
priv->msg,
- priv->msg->body->str,
- priv->msg->body->len);
+ priv->msg->body_buf.begin,
+ priv->msg->body_buf.len);
rspamd_http_connection_unref (conn);
}
}
@@ -767,8 +784,8 @@ rspamd_http_on_message_complete (http_parser * parser)
rspamd_http_connection_ref (conn);
ret = conn->body_handler (conn,
priv->msg,
- priv->msg->body->str,
- priv->msg->body->len);
+ priv->msg->body_buf.begin,
+ priv->msg->body_buf.len);
rspamd_http_connection_unref (conn);
}
@@ -890,7 +907,7 @@ rspamd_http_event_handler (int fd, short what, gpointer ud)
struct rspamd_http_connection *conn = (struct rspamd_http_connection *)ud;
struct rspamd_http_connection_private *priv;
struct _rspamd_http_privbuf *pbuf;
- GString *buf;
+ rspamd_fstring_t *buf;
gssize r;
GError *err;
@@ -901,7 +918,7 @@ rspamd_http_event_handler (int fd, short what, gpointer ud)
buf = priv->buf->data;
if (what == EV_READ) {
- r = read (fd, buf->str, buf->allocated_len);
+ r = read (fd, buf->str, buf->allocated);
if (r == -1) {
err = g_error_new (HTTP_ERROR,
errno,
@@ -933,8 +950,8 @@ rspamd_http_event_handler (int fd, short what, gpointer ud)
else {
buf->len = r;
- if (http_parser_execute (&priv->parser, &priv->parser_cb, buf->str,
- r) != (size_t)r || priv->parser.http_errno != 0) {
+ if (http_parser_execute (&priv->parser, &priv->parser_cb,
+ buf->str, r) != (size_t)r || priv->parser.http_errno != 0) {
err = g_error_new (HTTP_ERROR, priv->parser.http_errno,
"HTTP parser error: %s",
http_errno_description (priv->parser.http_errno));
@@ -1038,9 +1055,11 @@ rspamd_http_connection_reset (struct rspamd_http_connection *conn)
rspamd_http_message_free (msg);
priv->msg = NULL;
}
+
conn->finished = FALSE;
/* Clear priv */
event_del (&priv->ev);
+
if (priv->buf != NULL) {
REF_RELEASE (priv->buf);
priv->buf = NULL;
@@ -1130,7 +1149,7 @@ rspamd_http_connection_read_message (struct rspamd_http_connection *conn,
priv->header = NULL;
priv->buf = g_slice_alloc0 (sizeof (*priv->buf));
REF_INIT_RETAIN (priv->buf, rspamd_http_privbuf_dtor);
- priv->buf->data = g_string_sized_new (BUFSIZ);
+ priv->buf->data = rspamd_fstring_sized_new (8192);
priv->new_header = TRUE;
event_set (&priv->ev,
@@ -1258,7 +1277,7 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
gchar datebuf[64], repbuf[512], *pbody;
gint i, hdrcount, meth_len, preludelen = 0;
gsize bodylen, enclen;
- GString *buf;
+ rspamd_fstring_t *buf;
gboolean encrypted = FALSE;
gchar *b32_key, *b32_id;
guchar nonce[rspamd_cryptobox_NONCEBYTES], mac[rspamd_cryptobox_MACBYTES],
@@ -1281,7 +1300,7 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
priv->header = NULL;
priv->buf = g_slice_alloc0 (sizeof (*priv->buf));
REF_INIT_RETAIN (priv->buf, rspamd_http_privbuf_dtor);
- priv->buf->data = g_string_sized_new (512);
+ priv->buf->data = rspamd_fstring_sized_new (512);
buf = priv->buf->data;
if (priv->peer_key && priv->local_key) {
@@ -1424,22 +1443,21 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
if (encrypted) {
/* Internal reply (encrypted) */
meth_len = rspamd_snprintf (repbuf, sizeof (repbuf),
- "HTTP/1.1 %d %s\r\n"
+ "HTTP/1.1 %d %V\r\n"
"Connection: close\r\n"
"Server: %s\r\n"
"Date: %s\r\n"
"Content-Length: %z\r\n"
"Content-Type: %s", /* NO \r\n at the end ! */
msg->code,
- msg->status ? msg->status->str :
- rspamd_http_code_to_str (msg->code),
+ msg->status,
"rspamd/" RVERSION,
datebuf,
bodylen,
mime_type);
enclen += meth_len;
/* External reply */
- rspamd_printf_gstring (buf, "HTTP/1.1 200 OK\r\n"
+ rspamd_printf_fstring (&buf, "HTTP/1.1 200 OK\r\n"
"Connection: close\r\n"
"Server: rspamd\r\n"
"Date: %s\r\n"
@@ -1449,15 +1467,14 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
enclen);
}
else {
- rspamd_printf_gstring (buf, "HTTP/1.1 %d %s\r\n"
+ rspamd_printf_fstring (&buf, "HTTP/1.1 %d %V\r\n"
"Connection: close\r\n"
"Server: %s\r\n"
"Date: %s\r\n"
"Content-Length: %z\r\n"
"Content-Type: %s\r\n",
msg->code,
- msg->status ? msg->status->str :
- rspamd_http_code_to_str (msg->code),
+ msg->status,
"rspamd/" RVERSION,
datebuf,
bodylen,
@@ -1467,10 +1484,10 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
else {
/* Legacy spamd reply */
if (msg->flags & RSPAMD_HTTP_FLAG_SPAMC) {
- rspamd_printf_gstring (buf, "SPAMD/1.1 0 EX_OK\r\n");
+ rspamd_printf_fstring (&buf, "SPAMD/1.1 0 EX_OK\r\n");
}
else {
- rspamd_printf_gstring (buf, "RSPAMD/1.3 0 EX_OK\r\n");
+ rspamd_printf_fstring (&buf, "RSPAMD/1.3 0 EX_OK\r\n");
}
}
}
@@ -1481,40 +1498,64 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
if (host == NULL && msg->host == NULL) {
/* Fallback to HTTP/1.0 */
if (encrypted) {
- rspamd_printf_gstring (buf, "%s %s HTTP/1.0\r\n"
+ rspamd_printf_fstring (&buf, "%s %s HTTP/1.0\r\n"
"Content-Length: %z\r\n",
"POST",
"/post",
enclen);
}
else {
- rspamd_printf_gstring (buf, "%s %s HTTP/1.0\r\n"
+ rspamd_printf_fstring (&buf, "%s %V HTTP/1.0\r\n"
"Content-Length: %z\r\n",
http_method_str (msg->method),
- msg->url->str,
+ msg->url,
bodylen);
}
}
else {
if (encrypted) {
- rspamd_printf_gstring (buf, "%s %s HTTP/1.1\r\n"
- "Connection: close\r\n"
- "Host: %s\r\n"
- "Content-Length: %z\r\n",
- "POST",
- "/post",
- host != NULL ? host : msg->host->str,
- enclen);
+ if (host != NULL) {
+ rspamd_printf_fstring (&buf, "%s %s HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "Host: %s\r\n"
+ "Content-Length: %z\r\n",
+ "POST",
+ "/post",
+ host,
+ enclen);
+ }
+ else {
+ rspamd_printf_fstring (&buf, "%s %s HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "Host: %V\r\n"
+ "Content-Length: %z\r\n",
+ "POST",
+ "/post",
+ msg->host,
+ enclen);
+ }
}
else {
- rspamd_printf_gstring (buf, "%s %s HTTP/1.1\r\n"
- "Connection: close\r\n"
- "Host: %s\r\n"
- "Content-Length: %z\r\n",
- http_method_str (msg->method),
- msg->url->str,
- host != NULL ? host : msg->host->str,
- bodylen);
+ if (host != NULL) {
+ rspamd_printf_fstring (&buf, "%s %V HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "Host: %s\r\n"
+ "Content-Length: %z\r\n",
+ http_method_str (msg->method),
+ msg->url,
+ host,
+ bodylen);
+ }
+ else {
+ rspamd_printf_fstring (&buf, "%s %V HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "Host: %V\r\n"
+ "Content-Length: %z\r\n",
+ http_method_str (msg->method),
+ msg->url,
+ msg->host,
+ bodylen);
+ }
}
}
@@ -1524,16 +1565,17 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
sizeof (priv->local_key->pk));
b32_id = rspamd_encode_base32 (id, RSPAMD_HTTP_KEY_ID_LEN);
/* XXX: add some fuzz here */
- rspamd_printf_gstring (buf, "Key: %s=%s\r\n", b32_id, b32_key);
+ rspamd_printf_fstring (&buf, "Key: %s=%s\r\n", b32_id, b32_key);
g_free (b32_key);
g_free (b32_id);
}
}
- /* Now set up all iov */
+ /* Setup external request body */
priv->out[0].iov_base = buf->str;
priv->out[0].iov_len = buf->len;
+ /* Buf will be used eventually for encryption */
if (encrypted) {
gint meth_offset, nonce_offset, mac_offset;
@@ -1542,26 +1584,26 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
meth_offset = buf->len;
if (conn->type == RSPAMD_HTTP_SERVER) {
- g_string_append_len (buf, repbuf, meth_len);
+ buf = rspamd_fstring_append (buf, repbuf, meth_len);
}
else {
meth_len = strlen (http_method_str (msg->method)) + 1; /* + space */
- g_string_append_len (buf, http_method_str (msg->method),
+ buf = rspamd_fstring_append (buf, http_method_str (msg->method),
meth_len - 1);
- g_string_append_c (buf, ' ');
+ buf = rspamd_fstring_append (buf, " ", 1);
}
nonce_offset = buf->len;
- g_string_append_len (buf, nonce, sizeof (nonce));
+ buf = rspamd_fstring_append (buf, nonce, sizeof (nonce));
mac_offset = buf->len;
- g_string_append_len (buf, mac, sizeof (mac));
+ buf = rspamd_fstring_append (buf, mac, sizeof (mac));
/* Need to be encrypted */
if (conn->type == RSPAMD_HTTP_SERVER) {
- g_string_append (buf, "\r\n\r\n");
+ buf = rspamd_fstring_append (buf, "\r\n\r\n", 4);
}
else {
- g_string_append_len (buf, repbuf, preludelen);
+ buf = rspamd_fstring_append (buf, repbuf, preludelen);
}
meth_pos = buf->str + meth_offset;
@@ -1569,6 +1611,8 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
mp = buf->str + mac_offset;
}
+ /* During previous writes, buf might be reallocated and changed */
+ priv->buf->data = buf;
if (encrypted) {
/* Finish external HTTP request */
@@ -1595,9 +1639,10 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
if (pbody != NULL) {
- if (msg->body_buf.str == NULL && msg->body_buf.len == 0) {
- msg->body_buf.str = msg->body->str;
+ if (msg->body_buf.begin == NULL && msg->body_buf.len == 0) {
+ msg->body_buf.begin = msg->body->str;
}
+
priv->out[i].iov_base = pbody;
priv->out[i++].iov_len = bodylen;
}
@@ -1623,12 +1668,13 @@ rspamd_http_new_message (enum http_parser_type type)
new = g_slice_alloc (sizeof (struct rspamd_http_message));
if (type == HTTP_REQUEST) {
- new->url = g_string_sized_new (32);
+ new->url = rspamd_fstring_new ();
}
else {
new->url = NULL;
new->code = 200;
}
+
new->headers = NULL;
new->date = 0;
new->body = NULL;
@@ -1686,8 +1732,8 @@ rspamd_http_message_from_url (const gchar *url)
msg->port = 80;
}
- msg->host = g_string_new_len (host, pu.field_data[UF_HOST].len);
- g_string_append_len (msg->url, path, pathlen);
+ msg->host = rspamd_fstring_new_init (host, pu.field_data[UF_HOST].len);
+ msg->host = rspamd_fstring_append (msg->url, path, pathlen);
return msg;
}
@@ -1699,27 +1745,27 @@ rspamd_http_message_free (struct rspamd_http_message *msg)
LL_FOREACH_SAFE (msg->headers, hdr, tmp_hdr)
{
- g_string_free (hdr->combined, TRUE);
- g_slice_free1 (sizeof (GString), hdr->name);
- g_slice_free1 (sizeof (GString), hdr->value);
+ rspamd_fstring_free (hdr->combined);
+ g_slice_free1 (sizeof (*hdr->name), hdr->name);
+ g_slice_free1 (sizeof (*hdr->name), hdr->value);
g_slice_free1 (sizeof (struct rspamd_http_header), hdr);
}
if (msg->body != NULL) {
- g_string_free (msg->body, FALSE);
- g_free (msg->body_buf.str);
+ rspamd_fstring_free (msg->body);
}
if (msg->url != NULL) {
- g_string_free (msg->url, TRUE);
+ rspamd_fstring_free (msg->url);
}
if (msg->status != NULL) {
- g_string_free (msg->status, TRUE);
+ rspamd_fstring_free (msg->status);
}
if (msg->host != NULL) {
- g_string_free (msg->host, TRUE);
+ rspamd_fstring_free (msg->host);
}
if (msg->peer_key != NULL) {
rspamd_http_connection_key_unref (msg->peer_key);
}
+
g_slice_free1 (sizeof (struct rspamd_http_message), msg);
}
@@ -1735,34 +1781,35 @@ rspamd_http_message_add_header (struct rspamd_http_message *msg,
hdr = g_slice_alloc (sizeof (struct rspamd_http_header));
nlen = strlen (name);
vlen = strlen (value);
- hdr->combined = g_string_sized_new (nlen + vlen + 4);
- rspamd_printf_gstring (hdr->combined, "%s: %s\r\n", name, value);
+ hdr->combined = rspamd_fstring_sized_new (nlen + vlen + 4);
+ rspamd_printf_fstring (&hdr->combined, "%s: %s\r\n", name, value);
hdr->value = g_slice_alloc (sizeof (GString));
hdr->name = g_slice_alloc (sizeof (GString));
- hdr->name->str = hdr->combined->str;
+ hdr->name->begin = hdr->combined->str;
hdr->name->len = nlen;
- hdr->value->str = hdr->combined->str + nlen + 2;
+ hdr->value->begin = hdr->combined->str + nlen + 2;
hdr->value->len = vlen;
DL_APPEND (msg->headers, hdr);
}
}
-const GString *
+const rspamd_ftok_t *
rspamd_http_message_find_header (struct rspamd_http_message *msg,
const gchar *name)
{
struct rspamd_http_header *hdr;
- const GString *res = NULL;
+ const rspamd_ftok_t *res = NULL;
+ rspamd_ftok_t cmp;
guint slen = strlen (name);
if (msg != NULL) {
- LL_FOREACH (msg->headers, hdr)
- {
- if (hdr->name->len == slen) {
- if (g_ascii_strncasecmp (hdr->name->str, name, slen) == 0) {
- res = hdr->value;
- break;
- }
+ cmp.begin = name;
+ cmp.len = slen;
+
+ LL_FOREACH (msg->headers, hdr) {
+ if (rspamd_ftok_casecmp (hdr->name, &cmp) == 0) {
+ res = hdr->value;
+ break;
}
}
}
@@ -1776,18 +1823,21 @@ gboolean rspamd_http_message_remove_header (struct rspamd_http_message *msg,
struct rspamd_http_header *hdr, *tmp;
gboolean res = FALSE;
guint slen = strlen (name);
+ rspamd_ftok_t cmp;
if (msg != NULL) {
+ cmp.begin = name;
+ cmp.len = slen;
+
DL_FOREACH_SAFE (msg->headers, hdr, tmp) {
- if (hdr->name->len == slen) {
- if (g_ascii_strncasecmp (hdr->name->str, name, slen) == 0) {
- res = TRUE;
- DL_DELETE (msg->headers, hdr);
- g_string_free (hdr->combined, TRUE);
- g_slice_free1 (sizeof (GString), hdr->value);
- g_slice_free1 (sizeof (GString), hdr->name);
- g_slice_free1 (sizeof (*hdr), hdr);
- }
+ if (rspamd_ftok_casecmp (hdr->name, &cmp) == 0) {
+ res = TRUE;
+ DL_DELETE (msg->headers, hdr);
+
+ rspamd_fstring_free (hdr->combined);
+ g_slice_free1 (sizeof (*hdr->value), hdr->value);
+ g_slice_free1 (sizeof (*hdr->name), hdr->name);
+ g_slice_free1 (sizeof (*hdr), hdr);
}
}
}
@@ -1836,7 +1886,7 @@ rspamd_http_router_error_handler (struct rspamd_http_connection *conn,
msg = rspamd_http_new_message (HTTP_RESPONSE);
msg->date = time (NULL);
msg->code = err->code;
- msg->body = g_string_new (err->message);
+ msg->body = rspamd_fstring_new_init (err->message, strlen (err->message));
rspamd_http_connection_reset (entry->conn);
rspamd_http_connection_write_message (entry->conn,
msg,
@@ -1896,14 +1946,14 @@ rspamd_http_router_is_subdir (const gchar *parent, const gchar *sub)
static gboolean
rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
- GString *lookup, gboolean expand_path)
+ rspamd_ftok_t *lookup, gboolean expand_path)
{
struct stat st;
gint fd;
gchar filebuf[PATH_MAX], realbuf[PATH_MAX], *dir;
struct rspamd_http_message *reply_msg;
- rspamd_snprintf (filebuf, sizeof (filebuf), "%s%c%v",
+ rspamd_snprintf (filebuf, sizeof (filebuf), "%s%c%T",
entry->rt->default_fs_path, G_DIR_SEPARATOR, lookup);
if (realpath (filebuf, realbuf) == NULL ||
@@ -1913,14 +1963,17 @@ rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
if (S_ISDIR (st.st_mode) && expand_path) {
/* Try to append 'index.html' to the url */
- GString *nlookup;
+ rspamd_fstring_t *nlookup;
+ rspamd_ftok_t tok;
gboolean ret;
- nlookup = g_string_sized_new (lookup->len + sizeof ("index.html") + 1);
- rspamd_printf_gstring (nlookup, "%v%c%s", lookup, G_DIR_SEPARATOR,
+ nlookup = rspamd_fstring_sized_new (lookup->len + sizeof ("index.html"));
+ rspamd_printf_fstring (&nlookup, "%T%c%s", lookup, G_DIR_SEPARATOR,
"index.html");
- ret = rspamd_http_router_try_file (entry, nlookup, FALSE);
- g_string_free (nlookup, TRUE);
+ tok.begin = nlookup->str;
+ tok.len = nlookup->len;
+ ret = rspamd_http_router_try_file (entry, &tok, FALSE);
+ rspamd_fstring_free (nlookup);
return ret;
}
@@ -1931,6 +1984,7 @@ rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
/* We also need to ensure that file is inside the defined dir */
rspamd_strlcpy (filebuf, realbuf, sizeof (filebuf));
dir = dirname (filebuf);
+
if (dir == NULL ||
!rspamd_http_router_is_subdir (entry->rt->default_fs_path,
dir)) {
@@ -1946,10 +2000,10 @@ rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
reply_msg->date = time (NULL);
reply_msg->code = 200;
- reply_msg->body = g_string_sized_new (st.st_size);
+ reply_msg->body = rspamd_fstring_sized_new (st.st_size);
reply_msg->body->len = st.st_size;
reply_msg->body_buf.len = st.st_size;
- reply_msg->body_buf.str = reply_msg->body->str;
+ reply_msg->body_buf.begin = reply_msg->body->str;
if (read (fd, reply_msg->body->str, st.st_size) != st.st_size) {
close (fd);
@@ -1957,8 +2011,6 @@ rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
return FALSE;
}
- reply_msg->body_buf.str[st.st_size] = '\0';
-
close (fd);
rspamd_http_connection_reset (entry->conn);
@@ -1980,7 +2032,7 @@ rspamd_http_router_finish_handler (struct rspamd_http_connection *conn,
gpointer found;
struct rspamd_http_message *err_msg;
GError *err;
- GString lookup;
+ rspamd_ftok_t lookup;
struct http_parser_url u;
G_STATIC_ASSERT (sizeof (rspamd_http_router_handler_t) ==
@@ -1999,17 +2051,17 @@ rspamd_http_router_finish_handler (struct rspamd_http_connection *conn,
http_parser_parse_url (msg->url->str, msg->url->len, TRUE, &u);
if (u.field_set & (1 << UF_PATH)) {
- lookup.str = msg->url->str + u.field_data[UF_PATH].off;
+ lookup.begin = msg->url->str + u.field_data[UF_PATH].off;
lookup.len = u.field_data[UF_PATH].len;
}
else {
- lookup.str = msg->url->str;
+ lookup.begin = msg->url->str;
lookup.len = msg->url->len;
}
found = g_hash_table_lookup (entry->rt->paths, &lookup);
memcpy (&handler, &found, sizeof (found));
- msg_debug ("requested known path: %v", &lookup);
+ msg_debug ("requested known path: %T", &lookup);
}
entry->is_reply = TRUE;
if (handler != NULL) {
@@ -2023,11 +2075,12 @@ rspamd_http_router_finish_handler (struct rspamd_http_connection *conn,
if (entry->rt->error_handler != NULL) {
entry->rt->error_handler (entry, err);
}
- msg_info ("path: %v not found", &lookup);
+ msg_info ("path: %T not found", &lookup);
err_msg = rspamd_http_new_message (HTTP_RESPONSE);
err_msg->date = time (NULL);
err_msg->code = err->code;
- err_msg->body = g_string_new (err->message);
+ err_msg->body = rspamd_fstring_new_init (err->message,
+ strlen (err->message));
rspamd_http_connection_reset (entry->conn);
rspamd_http_connection_write_message (entry->conn,
err_msg,
@@ -2056,12 +2109,13 @@ rspamd_http_router_new (rspamd_http_router_error_handler_t eh,
struct stat st;
new = g_slice_alloc0 (sizeof (struct rspamd_http_connection_router));
- new->paths = g_hash_table_new_full (rspamd_gstring_icase_hash,
- rspamd_gstring_icase_equal, rspamd_gstring_free_hard, NULL);
+ new->paths = g_hash_table_new_full (rspamd_ftok_icase_hash,
+ rspamd_ftok_icase_equal, rspamd_fstring_mapped_ftok_free, NULL);
new->conns = NULL;
new->error_handler = eh;
new->finish_handler = fh;
new->ev_base = base;
+
if (timeout) {
new->tv = *timeout;
new->ptv = &new->tv;
@@ -2108,13 +2162,17 @@ rspamd_http_router_add_path (struct rspamd_http_connection_router *router,
const gchar *path, rspamd_http_router_handler_t handler)
{
gpointer ptr;
- GString *key;
+ rspamd_ftok_t *key;
+ rspamd_fstring_t *storage;
G_STATIC_ASSERT (sizeof (rspamd_http_router_handler_t) ==
sizeof (gpointer));
if (path != NULL && handler != NULL && router != NULL) {
memcpy (&ptr, &handler, sizeof (ptr));
- key = g_string_new (path);
+ storage = rspamd_fstring_new_init (path, strlen (path));
+ key = g_slice_alloc0 (sizeof (*key));
+ key->begin = storage->str;
+ key->len = storage->len;
g_hash_table_insert (router->paths, key, ptr);
}
}
@@ -2338,7 +2396,8 @@ GHashTable *
rspamd_http_message_parse_query (struct rspamd_http_message *msg)
{
GHashTable *res;
- GString *key = NULL, *value = NULL;
+ rspamd_fstring_t *key = NULL, *value = NULL;
+ rspamd_ftok_t *key_tok, *value_tok;
const gchar *p, *c, *end;
struct http_parser_url u;
enum {
@@ -2348,9 +2407,10 @@ rspamd_http_message_parse_query (struct rspamd_http_message *msg)
parse_ampersand
} state = parse_key;
- res = g_hash_table_new_full (rspamd_gstring_icase_hash,
- rspamd_gstring_icase_equal, rspamd_gstring_free_hard,
- rspamd_gstring_free_hard);
+ res = g_hash_table_new_full (rspamd_ftok_icase_hash,
+ rspamd_ftok_icase_equal,
+ rspamd_fstring_mapped_ftok_free,
+ rspamd_fstring_mapped_ftok_free);
if (msg->url && msg->url->len > 0) {
http_parser_parse_url (msg->url->str, msg->url->len, TRUE, &u);
@@ -2365,19 +2425,24 @@ rspamd_http_message_parse_query (struct rspamd_http_message *msg)
case parse_key:
if ((*p == '&' || p == end) && p > c) {
/* We have a single parameter without a value */
- key = g_string_sized_new (p - c);
- g_string_append_len (key, c, p - c);
- key->len = rspamd_decode_url (key->str, key->str,
+ key = rspamd_fstring_new_init (c, p - c);
+ key_tok = g_slice_alloc (sizeof (*key_tok));
+ key_tok->begin = key->str;
+ key_tok->len = rspamd_decode_url (key->str, key->str,
key->len);
- value = g_string_new ("");
- g_hash_table_insert (res, key, value);
+ value = rspamd_fstring_new_init ("", 0);
+ value_tok = g_slice_alloc (sizeof (*value_tok));
+ value_tok->begin = value->str;
+ value_tok->len = value->len;
+ g_hash_table_insert (res, key_tok, value_tok);
state = parse_ampersand;
}
else if (*p == '=' && p > c) {
/* We have something like key=value */
- key = g_string_sized_new (p - c);
- g_string_append_len (key, c, p - c);
- key->len = rspamd_decode_url (key->str, key->str,
+ key = rspamd_fstring_new_init (c, p - c);
+ key_tok = g_slice_alloc (sizeof (*key_tok));
+ key_tok->begin = key->str;
+ key_tok->len = rspamd_decode_url (key->str, key->str,
key->len);
state = parse_eqsign;
}
@@ -2400,16 +2465,21 @@ rspamd_http_message_parse_query (struct rspamd_http_message *msg)
if ((*p == '&' || p == end) && p >= c) {
g_assert (key != NULL);
if (p > c) {
- value = g_string_sized_new (p - c);
- g_string_append_len (value, c, p - c);
- value->len = rspamd_decode_url (value->str, value->str,
+ value = rspamd_fstring_new_init (c, p - c);
+ value_tok = g_slice_alloc (sizeof (*value_tok));
+ value_tok->begin = value->str;
+ value_tok->len = rspamd_decode_url (value->str,
+ value->str,
value->len);
}
else {
- value = g_string_new ("");
+ value = rspamd_fstring_new_init ("", 0);
+ value_tok = g_slice_alloc (sizeof (*value_tok));
+ value_tok->begin = value->str;
+ value_tok->len = value->len;
}
- g_hash_table_insert (res, key, value);
+ g_hash_table_insert (res, key_tok, value_tok);
key = value = NULL;
state = parse_ampersand;
}
@@ -2432,7 +2502,7 @@ rspamd_http_message_parse_query (struct rspamd_http_message *msg)
}
if (state != parse_ampersand && key != NULL) {
- g_string_free (key, TRUE);
+ rspamd_fstring_free (key);
}
}
diff --git a/src/libutil/http.h b/src/libutil/http.h
index ffc820ce8..7a5a875dd 100644
--- a/src/libutil/http.h
+++ b/src/libutil/http.h
@@ -34,6 +34,7 @@
#include "config.h"
#include "http_parser.h"
#include "keypairs_cache.h"
+#include "fstring.h"
enum rspamd_http_connection_type {
RSPAMD_HTTP_SERVER,
@@ -44,9 +45,9 @@ enum rspamd_http_connection_type {
* HTTP header structure
*/
struct rspamd_http_header {
- GString *name;
- GString *value;
- GString *combined;
+ rspamd_ftok_t *name;
+ rspamd_ftok_t *value;
+ rspamd_fstring_t *combined;
struct rspamd_http_header *next, *prev;
};
@@ -59,13 +60,13 @@ struct rspamd_http_header {
* HTTP message structure, used for requests and replies
*/
struct rspamd_http_message {
- GString *url;
- GString *host;
+ rspamd_fstring_t *url;
+ rspamd_fstring_t *host;
unsigned port;
- GString *status;
+ rspamd_fstring_t *status;
struct rspamd_http_header *headers;
- GString *body;
- GString body_buf;
+ rspamd_fstring_t *body;
+ rspamd_ftok_t body_buf;
gpointer peer_key;
enum http_parser_type type;
time_t date;
@@ -326,8 +327,9 @@ void rspamd_http_message_add_header (struct rspamd_http_message *msg,
* @param msg message
* @param name name of header
*/
-const GString * rspamd_http_message_find_header (struct rspamd_http_message *msg,
- const gchar *name);
+const rspamd_ftok_t * rspamd_http_message_find_header (
+ struct rspamd_http_message *msg,
+ const gchar *name);
/**
* Remove specific header from a message
@@ -403,7 +405,8 @@ void rspamd_http_router_free (struct rspamd_http_connection_router *router);
* Extract arguments from a messsage's URI contained inside query string decoding
* them if needed
* @param msg HTTP request message
- * @return new GHashTable which maps GString * to GString * (table must be freed by a caller)
+ * @return new GHashTable which maps rspamd_ftok_t* to rspamd_ftok_t*
+ * (table must be freed by a caller)
*/
GHashTable* rspamd_http_message_parse_query (struct rspamd_http_message *msg);
diff --git a/src/libutil/map.c b/src/libutil/map.c
index cba82ba41..28faf13c4 100644
--- a/src/libutil/map.c
+++ b/src/libutil/map.c
@@ -111,7 +111,7 @@ write_http_request (struct http_callback_data *cbd)
msg = rspamd_http_new_message (HTTP_REQUEST);
- msg->url = g_string_new (cbd->data->path);
+ msg->url = rspamd_fstring_new_init (cbd->data->path, strlen (cbd->data->path));
if (cbd->data->last_checked != 0) {
tm = gmtime (&cbd->data->last_checked);
strftime (datebuf, sizeof (datebuf), "%a, %d %b %Y %H:%M:%S %Z", tm);
diff --git a/src/libutil/printf.c b/src/libutil/printf.c
index 345682f28..3813524a0 100644
--- a/src/libutil/printf.c
+++ b/src/libutil/printf.c
@@ -485,7 +485,9 @@ rspamd_vprintf_common (rspamd_printf_append_func func,
case 'V':
v = va_arg (args, rspamd_fstring_t *);
- RSPAMD_PRINTF_APPEND (v->str, v->len);
+ if (v) {
+ RSPAMD_PRINTF_APPEND (v->str, v->len);
+ }
continue;
@@ -496,7 +498,9 @@ rspamd_vprintf_common (rspamd_printf_append_func func,
case 'v':
gs = va_arg (args, GString *);
- RSPAMD_PRINTF_APPEND (gs->str, gs->len);
+ if (gs) {
+ RSPAMD_PRINTF_APPEND (gs->str, gs->len);
+ }
continue;
diff --git a/src/libutil/str_util.c b/src/libutil/str_util.c
index d92ceb1ad..96a26e1c1 100644
--- a/src/libutil/str_util.c
+++ b/src/libutil/str_util.c
@@ -94,6 +94,51 @@ rspamd_str_lc (gchar *str, guint size)
}
+gint
+rspamd_lc_cmp (const gchar *s, const gchar *d, gsize l)
+{
+ guint fp, i;
+ guchar c1, c2, c3, c4;
+ union {
+ guchar c[4];
+ guint32 n;
+ } cmp1, cmp2;
+ gsize leftover = l % 4;
+ gint ret = 0;
+
+ fp = l - leftover;
+
+ for (i = 0; i != fp; i += 4) {
+ c1 = s[i], c2 = s[i + 1], c3 = s[i + 2], c4 = s[i + 3];
+ cmp1.c[0] = lc_map[c1];
+ cmp1.c[1] = lc_map[c2];
+ cmp1.c[2] = lc_map[c3];
+ cmp1.c[3] = lc_map[c4];
+
+ c1 = d[i], c2 = d[i + 1], c3 = d[i + 2], c4 = d[i + 3];
+ cmp2.c[0] = lc_map[c1];
+ cmp2.c[1] = lc_map[c2];
+ cmp2.c[2] = lc_map[c3];
+ cmp2.c[3] = lc_map[c4];
+
+ if (cmp1.n != cmp2.n) {
+ return cmp1.n - cmp2.n;
+ }
+ }
+
+ while (leftover > 0) {
+ if (g_ascii_tolower (*s) != g_ascii_tolower (*d)) {
+ return (*s) - (*d);
+ }
+
+ leftover--;
+ s++;
+ d++;
+ }
+
+ return ret;
+}
+
/*
* The purpose of this function is fast and in place conversion of a unicode
* string to lower case, so some locale peculiarities are simply ignored
@@ -220,7 +265,7 @@ rspamd_ftok_icase_equal (gconstpointer v, gconstpointer v2)
const rspamd_ftok_t *f1 = v, *f2 = v2;
if (f1->len == f2->len &&
- g_ascii_strncasecmp (f1->begin, f2->begin, f1->len) == 0) {
+ rspamd_lc_cmp (f1->begin, f2->begin, f1->len) == 0) {
return TRUE;
}
@@ -241,7 +286,7 @@ rspamd_gstring_icase_equal (gconstpointer v, gconstpointer v2)
{
const GString *f1 = v, *f2 = v2;
if (f1->len == f2->len &&
- g_ascii_strncasecmp (f1->str, f2->str, f1->len) == 0) {
+ rspamd_lc_cmp (f1->str, f2->str, f1->len) == 0) {
return TRUE;
}
@@ -1178,3 +1223,151 @@ rspamd_string_find_eoh (GString *input)
return -1;
}
+
+/*
+ * GString ucl emitting functions
+ */
+static int
+rspamd_gstring_append_character (unsigned char c, size_t len, void *ud)
+{
+ GString *buf = ud;
+ gsize old_len;
+
+ if (len == 1) {
+ g_string_append_c (buf, c);
+ }
+ else {
+ if (buf->allocated_len - buf->len <= len) {
+ old_len = buf->len;
+ g_string_set_size (buf, buf->len + len + 1);
+ buf->len = old_len;
+ }
+ memset (&buf->str[buf->len], c, len);
+ buf->len += len;
+ }
+
+ return 0;
+}
+
+static int
+rspamd_gstring_append_len (const unsigned char *str, size_t len, void *ud)
+{
+ GString *buf = ud;
+
+ g_string_append_len (buf, str, len);
+
+ return 0;
+}
+
+static int
+rspamd_gstring_append_int (int64_t val, void *ud)
+{
+ GString *buf = ud;
+
+ rspamd_printf_gstring (buf, "%L", (intmax_t) val);
+ return 0;
+}
+
+static int
+rspamd_gstring_append_double (double val, void *ud)
+{
+ GString *buf = ud;
+ const double delta = 0.0000001;
+
+ if (val == (double) (int) val) {
+ rspamd_printf_gstring (buf, "%.1f", val);
+ }
+ else if (fabs (val - (double) (int) val) < delta) {
+ /* Write at maximum precision */
+ rspamd_printf_gstring (buf, "%.*g", DBL_DIG, val);
+ }
+ else {
+ rspamd_printf_gstring (buf, "%f", val);
+ }
+
+ return 0;
+}
+
+void
+rspamd_ucl_emit_gstring (ucl_object_t *obj,
+ enum ucl_emitter emit_type,
+ GString *target)
+{
+ struct ucl_emitter_functions func = {
+ .ucl_emitter_append_character = rspamd_gstring_append_character,
+ .ucl_emitter_append_len = rspamd_gstring_append_len,
+ .ucl_emitter_append_int = rspamd_gstring_append_int,
+ .ucl_emitter_append_double = rspamd_gstring_append_double
+ };
+
+ func.ud = target;
+ ucl_object_emit_full (obj, emit_type, &func);
+}
+
+/*
+ * FString ucl emitting functions
+ */
+static int
+rspamd_fstring_emit_append_character (unsigned char c, size_t len, void *ud)
+{
+ rspamd_fstring_t **buf = ud;
+
+ *buf = rspamd_fstring_append_chars (*buf, c, len);
+
+ return 0;
+}
+
+static int
+rspamd_fstring_emit_append_len (const unsigned char *str, size_t len, void *ud)
+{
+ rspamd_fstring_t **buf = ud;
+
+ *buf = rspamd_fstring_append (*buf, str, len);
+
+ return 0;
+}
+
+static int
+rspamd_fstring_emit_append_int (int64_t val, void *ud)
+{
+ rspamd_fstring_t **buf = ud;
+
+ rspamd_printf_fstring (buf, "%L", (intmax_t) val);
+ return 0;
+}
+
+static int
+rspamd_fstring_emit_append_double (double val, void *ud)
+{
+ rspamd_fstring_t **buf = ud;
+ const double delta = 0.0000001;
+
+ if (val == (double)((gint) val)) {
+ rspamd_printf_fstring (buf, "%.1f", val);
+ }
+ else if (fabs (val - (double) (int) val) < delta) {
+ /* Write at maximum precision */
+ rspamd_printf_fstring (buf, "%.*g", DBL_DIG, val);
+ }
+ else {
+ rspamd_printf_fstring (buf, "%f", val);
+ }
+
+ return 0;
+}
+
+void
+rspamd_ucl_emit_fstring (ucl_object_t *obj,
+ enum ucl_emitter emit_type,
+ rspamd_fstring_t **buf)
+{
+ struct ucl_emitter_functions func = {
+ .ucl_emitter_append_character = rspamd_fstring_emit_append_character,
+ .ucl_emitter_append_len = rspamd_fstring_emit_append_len,
+ .ucl_emitter_append_int = rspamd_fstring_emit_append_int,
+ .ucl_emitter_append_double = rspamd_fstring_emit_append_double
+ };
+
+ func.ud = buf;
+ ucl_object_emit_full (obj, emit_type, &func);
+}
diff --git a/src/libutil/str_util.h b/src/libutil/str_util.h
index fdadc4811..75938668b 100644
--- a/src/libutil/str_util.h
+++ b/src/libutil/str_util.h
@@ -27,6 +27,12 @@
#define SRC_LIBUTIL_STR_UTIL_H_
#include "config.h"
+#include "ucl.h"
+
+/**
+ * Compare two memory regions of size `l` using case insensitive matching
+ */
+gint rspamd_lc_cmp (const gchar *s, const gchar *d, gsize l);
/**
* Convert string to lowercase in-place using ASCII conversion
@@ -192,4 +198,24 @@ goffset rspamd_substring_search (const gchar *in, gsize inlen,
*/
goffset rspamd_string_find_eoh (GString *input);
+/**
+ * Emit UCL object to gstring
+ * @param obj object to emit
+ * @param emit_type emitter type
+ * @param target target string
+ */
+void rspamd_ucl_emit_gstring (ucl_object_t *obj,
+ enum ucl_emitter emit_type,
+ GString *target);
+
+/**
+ * Emit UCL object to fstring
+ * @param obj object to emit
+ * @param emit_type emitter type
+ * @param target target string
+ */
+void rspamd_ucl_emit_fstring (ucl_object_t *obj,
+ enum ucl_emitter emit_type,
+ rspamd_fstring_t **target);
+
#endif /* SRC_LIBUTIL_STR_UTIL_H_ */
diff --git a/src/libutil/util.c b/src/libutil/util.c
index fd66cc321..5706a2f49 100644
--- a/src/libutil/util.c
+++ b/src/libutil/util.c
@@ -1743,86 +1743,6 @@ restart:
#endif
}
-/*
- * GString ucl emitting functions
- */
-static int
-rspamd_gstring_append_character (unsigned char c, size_t len, void *ud)
-{
- GString *buf = ud;
- gsize old_len;
-
- if (len == 1) {
- g_string_append_c (buf, c);
- }
- else {
- if (buf->allocated_len - buf->len <= len) {
- old_len = buf->len;
- g_string_set_size (buf, buf->len + len + 1);
- buf->len = old_len;
- }
- memset (&buf->str[buf->len], c, len);
- buf->len += len;
- }
-
- return 0;
-}
-
-static int
-rspamd_gstring_append_len (const unsigned char *str, size_t len, void *ud)
-{
- GString *buf = ud;
-
- g_string_append_len (buf, str, len);
-
- return 0;
-}
-
-static int
-rspamd_gstring_append_int (int64_t val, void *ud)
-{
- GString *buf = ud;
-
- rspamd_printf_gstring (buf, "%L", (intmax_t)val);
- return 0;
-}
-
-static int
-rspamd_gstring_append_double (double val, void *ud)
-{
- GString *buf = ud;
- const double delta = 0.0000001;
-
- if (val == (double)(int)val) {
- rspamd_printf_gstring (buf, "%.1f", val);
- }
- else if (fabs (val - (double)(int)val) < delta) {
- /* Write at maximum precision */
- rspamd_printf_gstring (buf, "%.*g", DBL_DIG, val);
- }
- else {
- rspamd_printf_gstring (buf, "%f", val);
- }
-
- return 0;
-}
-
-void
-rspamd_ucl_emit_gstring (ucl_object_t *obj,
- enum ucl_emitter emit_type,
- GString *target)
-{
- struct ucl_emitter_functions func = {
- .ucl_emitter_append_character = rspamd_gstring_append_character,
- .ucl_emitter_append_len = rspamd_gstring_append_len,
- .ucl_emitter_append_int = rspamd_gstring_append_int,
- .ucl_emitter_append_double = rspamd_gstring_append_double
- };
-
- func.ud = target;
- ucl_object_emit_full (obj, emit_type, &func);
-}
-
gdouble
rspamd_get_ticks (void)
{
diff --git a/src/libutil/util.h b/src/libutil/util.h
index df1c30e7d..8284557d9 100644
--- a/src/libutil/util.h
+++ b/src/libutil/util.h
@@ -5,7 +5,6 @@
#include "mem_pool.h"
#include "printf.h"
#include "fstring.h"
-#include "ucl.h"
#include "addr.h"
#include "str_util.h"
@@ -336,16 +335,6 @@ void rspamd_hash_table_copy (GHashTable *src, GHashTable *dst,
gint rspamd_read_passphrase (gchar *buf, gint size, gint rwflag, gpointer key);
/**
- * Emit UCL object to gstring
- * @param obj object to emit
- * @param emit_type emitter type
- * @param target target string
- */
-void rspamd_ucl_emit_gstring (ucl_object_t *obj,
- enum ucl_emitter emit_type,
- GString *target);
-
-/**
* Portably return the current clock ticks as seconds
* @return
*/
diff --git a/src/lua/lua_http.c b/src/lua/lua_http.c
index e87da02b1..bbea1ebce 100644
--- a/src/lua/lua_http.c
+++ b/src/lua/lua_http.c
@@ -168,7 +168,9 @@ lua_http_finish_handler (struct rspamd_http_connection *conn,
/* Headers */
lua_newtable (cbd->L);
LL_FOREACH (msg->headers, h) {
- rspamd_lua_table_set (cbd->L, h->name->str, h->value->str);
+ lua_pushlstring (cbd->L, h->name->begin, h->name->len);
+ lua_pushlstring (cbd->L, h->value->begin, h->value->len);
+ lua_settable (cbd->L, -3);
}
if (lua_pcall (cbd->L, 4, 0, 0) != 0) {
msg_info ("callback call failed: %s", lua_tostring (cbd->L, -1));
@@ -269,8 +271,9 @@ lua_http_push_headers (lua_State *L, struct rspamd_http_message *msg)
static gint
lua_http_request (lua_State *L)
{
- const gchar *url;
+ const gchar *url, *lua_body;
gint cbref;
+ gsize bodylen;
struct event_base *ev_base;
struct rspamd_http_message *msg;
struct lua_http_cbdata *cbd;
@@ -403,17 +406,14 @@ lua_http_request (lua_State *L)
lua_pushstring (L, "body");
lua_gettable (L, -2);
if (lua_type (L, -1) == LUA_TSTRING) {
- msg->body = g_string_new (lua_tostring (L, -1));
+ lua_body = lua_tolstring (L, -1, &bodylen);
+ msg->body = rspamd_fstring_new_init (lua_body, bodylen);
}
else if (lua_type (L, -1) == LUA_TUSERDATA) {
t = lua_check_text (L, -1);
+ /* TODO: think about zero-copy possibilities */
if (t) {
- /* XXX: is it safe ? */
- msg->body = g_string_new (NULL);
- msg->body->str = (gchar *)t->start;
- msg->body->len = t->len;
- /* It is not safe unless we set len to avoid body_buf to be freed */
- msg->body_buf.len = t->len;
+ msg->body = rspamd_fstring_new_init (t->start, t->len);
}
}
diff --git a/src/lua/lua_task.c b/src/lua/lua_task.c
index 4ef772a5c..3bc40efe4 100644
--- a/src/lua/lua_task.c
+++ b/src/lua/lua_task.c
@@ -963,7 +963,7 @@ lua_task_get_parts (lua_State * L)
static gint
lua_task_get_request_header (lua_State *L)
{
- GString *hdr, srch;
+ rspamd_ftok_t *hdr, srch;
struct rspamd_task *task = lua_check_task (L, 1);
const gchar *s;
struct rspamd_lua_text *t;
@@ -972,7 +972,7 @@ lua_task_get_request_header (lua_State *L)
s = luaL_checklstring (L, 2, &len);
if (s) {
- srch.str = (gchar *)s;
+ srch.begin = (gchar *)s;
srch.len = len;
hdr = g_hash_table_lookup (task->request_headers, &srch);
@@ -980,7 +980,7 @@ lua_task_get_request_header (lua_State *L)
if (hdr) {
t = lua_newuserdata (L, sizeof (*t));
rspamd_lua_setclass (L, "rspamd{text}", -1);
- t->start = hdr->str;
+ t->start = hdr->begin;
t->len = hdr->len;
t->own = FALSE;
@@ -997,8 +997,9 @@ lua_task_set_request_header (lua_State *L)
{
struct rspamd_task *task = lua_check_task (L, 1);
const gchar *s, *v = NULL;
+ rspamd_fstring_t *buf;
struct rspamd_lua_text *t;
- GString *hdr, srch, *new_name;
+ rspamd_ftok_t *hdr, srch, *new_name;
gsize len, vlen;
s = luaL_checklstring (L, 2, &len);
@@ -1017,19 +1018,22 @@ lua_task_set_request_header (lua_State *L)
}
if (v != NULL) {
- srch.str = (gchar *)s;
+ srch.begin = (gchar *)s;
srch.len = len;
hdr = g_hash_table_lookup (task->request_headers, &srch);
- if (hdr) {
+ if (!hdr) {
new_name = &srch;
}
else {
/* Not found, need to allocate */
- new_name = g_string_new_len (srch.str, srch.len);
+ buf = rspamd_fstring_new_init (srch.begin, srch.len);
+ new_name = rspamd_ftok_map (buf);
}
- hdr = g_string_new_len (v, vlen);
+
+ buf = rspamd_fstring_new_init (v, vlen);
+ hdr = rspamd_ftok_map (buf);
/* This does not destroy key if it exists */
g_hash_table_insert (task->request_headers, new_name, hdr);
diff --git a/src/plugins/fuzzy_check.c b/src/plugins/fuzzy_check.c
index bc4822b17..6ca18aaf8 100644
--- a/src/plugins/fuzzy_check.c
+++ b/src/plugins/fuzzy_check.c
@@ -1549,26 +1549,23 @@ static gboolean
fuzzy_controller_handler (struct rspamd_http_connection_entry *conn_ent,
struct rspamd_http_message *msg, struct module_ctx *ctx, gint cmd)
{
- const GString *arg;
- gchar *err_str;
- gint value = 1, flag = 0;
+ const rspamd_ftok_t *arg;
+ glong value = 1, flag = 0;
/* Get size */
arg = rspamd_http_message_find_header (msg, "Weight");
if (arg) {
errno = 0;
- value = strtol (arg->str, &err_str, 10);
- if (*err_str != '\0' && *err_str != '\r') {
- msg_info ("error converting numeric argument %v", arg);
- value = 0;
+
+ if (!rspamd_strtol (arg->begin, arg->len, &value)) {
+ msg_info ("error converting numeric argument %T", arg);
}
}
arg = rspamd_http_message_find_header (msg, "Flag");
if (arg) {
errno = 0;
- flag = strtol (arg->str, &err_str, 10);
- if (*err_str != '\0' && *err_str != '\r') {
- msg_info ("error converting numeric argument %v", arg);
+ if (!rspamd_strtol (arg->begin, arg->len, &flag)) {
+ msg_info ("error converting numeric argument %T", arg);
flag = 0;
}
}
diff --git a/src/plugins/surbl.c b/src/plugins/surbl.c
index 0c1d6887f..7ce58ab1d 100644
--- a/src/plugins/surbl.c
+++ b/src/plugins/surbl.c
@@ -988,7 +988,7 @@ surbl_redirector_finish (struct rspamd_http_connection *conn,
struct redirector_param *param = (struct redirector_param *)conn->ud;
struct rspamd_task *task;
gint r, urllen;
- const GString *hdr;
+ const rspamd_ftok_t *hdr;
gchar *urlstr;
task = param->task;
@@ -1003,7 +1003,7 @@ surbl_redirector_finish (struct rspamd_http_connection *conn,
urllen = hdr->len;
urlstr = rspamd_mempool_alloc (param->task->task_pool,
urllen + 1);
- rspamd_strlcpy (urlstr, hdr->str, urllen + 1);
+ rspamd_strlcpy (urlstr, hdr->begin, urllen + 1);
r = rspamd_url_parse (param->url, urlstr, urllen,
param->task->task_pool);
@@ -1066,7 +1066,7 @@ register_redirector_call (struct rspamd_url *url, struct rspamd_task *task,
RSPAMD_HTTP_CLIENT_SIMPLE,
RSPAMD_HTTP_CLIENT, NULL);
msg = rspamd_http_new_message (HTTP_REQUEST);
- g_string_assign (msg->url, struri (url));
+ msg->url = rspamd_fstring_assign (msg->url, struri (url), strlen (struri (url)));
param->sock = s;
param->suffix = suffix;
param->redirector = selected;
diff --git a/test/functional/cases/scan_file.sh b/test/functional/cases/scan_file.sh
index 1a0606785..107d335e4 100644
--- a/test/functional/cases/scan_file.sh
+++ b/test/functional/cases/scan_file.sh
@@ -4,9 +4,6 @@
export RSPAMD_CONFIG="$TEST_DIRNAME/configs/trivial.conf"
run_rspamd
-run perl "$TEST_DIRNAME/cases/scan_file.pl" "$TEST_DIRNAME/messages/gtube.eml"
-check_output 'GTUBE'
-
run perl "$TEST_DIRNAME/cases/scan_file.pl" "file=$TEST_DIRNAME/messages/gtube.eml"
check_output 'GTUBE'
@@ -18,8 +15,6 @@ check_output 'GTUBE'
# Hex encode every character
_hex_name=`printf "$TEST_DIRNAME/messages/gtube.eml" | hexdump -v -e '/1 "%02x"' | sed 's/\(..\)/%\1/g'`
-run perl "$TEST_DIRNAME/cases/scan_file.pl" "${_hex_name}"
-check_output 'GTUBE'
run perl "$TEST_DIRNAME/cases/scan_file.pl" "file=${_hex_name}"
check_output 'GTUBE'