diff options
-rw-r--r-- | src/client/rspamc.c | 4 | ||||
-rw-r--r-- | src/client/rspamdclient.c | 14 | ||||
-rw-r--r-- | src/controller.c | 67 | ||||
-rw-r--r-- | src/http_proxy.c | 4 | ||||
-rw-r--r-- | src/libserver/protocol.c | 155 | ||||
-rw-r--r-- | src/libserver/protocol.h | 2 | ||||
-rw-r--r-- | src/libserver/task.c | 31 | ||||
-rw-r--r-- | src/libserver/worker_util.c | 14 | ||||
-rw-r--r-- | src/libutil/fstring.c | 122 | ||||
-rw-r--r-- | src/libutil/fstring.h | 62 | ||||
-rw-r--r-- | src/libutil/http.c | 450 | ||||
-rw-r--r-- | src/libutil/http.h | 25 | ||||
-rw-r--r-- | src/libutil/map.c | 2 | ||||
-rw-r--r-- | src/libutil/printf.c | 8 | ||||
-rw-r--r-- | src/libutil/str_util.c | 197 | ||||
-rw-r--r-- | src/libutil/str_util.h | 26 | ||||
-rw-r--r-- | src/libutil/util.c | 80 | ||||
-rw-r--r-- | src/libutil/util.h | 11 | ||||
-rw-r--r-- | src/lua/lua_http.c | 18 | ||||
-rw-r--r-- | src/lua/lua_task.c | 20 | ||||
-rw-r--r-- | src/plugins/fuzzy_check.c | 17 | ||||
-rw-r--r-- | src/plugins/surbl.c | 6 | ||||
-rw-r--r-- | test/functional/cases/scan_file.sh | 5 |
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' |