aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libserver/protocol.c7
-rw-r--r--src/libserver/task.c120
-rw-r--r--src/libserver/task.h1
-rw-r--r--src/libserver/url.h3
4 files changed, 97 insertions, 34 deletions
diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c
index 323838b6d..e6407d3a0 100644
--- a/src/libserver/protocol.c
+++ b/src/libserver/protocol.c
@@ -248,6 +248,13 @@ rspamd_protocol_handle_url (struct rspamd_task *task,
break;
}
+ if (u.field_set & (1 << UF_QUERY)) {
+ /* In case if we have a query, we need to store it somewhere */
+ task->msg.start = msg->url->str + u.field_data[UF_QUERY].off;
+ task->msg.len = u.field_data[UF_QUERY].len;
+ task->flags |= RSPAMD_TASK_FLAG_FILE;
+ }
+
return TRUE;
err:
diff --git a/src/libserver/task.c b/src/libserver/task.c
index 97ed76b5c..3cd4dc526 100644
--- a/src/libserver/task.c
+++ b/src/libserver/task.c
@@ -235,58 +235,110 @@ rspamd_task_free_soft (gpointer ud)
rspamd_task_free (task, FALSE);
}
+static void
+rspamd_task_unmapper (gpointer ud)
+{
+ struct rspamd_task *task = ud;
+
+ munmap ((void *)task->msg.start, task->msg.len);
+}
+
gboolean
rspamd_task_load_message (struct rspamd_task *task,
struct rspamd_http_message *msg, const gchar *start, gsize len)
{
- guint control_len;
+ guint control_len, r;
struct ucl_parser *parser;
ucl_object_t *control_obj;
-
- debug_task ("got input of length %z", task->msg.len);
- task->msg.start = start;
- task->msg.len = len;
-
- if (task->msg.len == 0) {
- msg_warn ("message has invalid message length: %ud",
- task->msg.len);
- g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
- "Invalid length");
- return FALSE;
- }
+ gchar filepath[PATH_MAX];
+ gint fd;
+ gpointer map;
+ struct stat st;
if (msg) {
rspamd_protocol_handle_headers (task, msg);
}
- if (task->flags & RSPAMD_TASK_FLAG_HAS_CONTROL) {
- /* We have control chunk, so we need to process it separately */
- if (task->msg.len < task->message_len) {
- msg_warn ("message has invalid message length: %ud and total len: %ud",
- task->message_len, task->msg.len);
+ if (task->flags & RSPAMD_TASK_FLAG_FILE) {
+ g_assert (task->msg.len > 0);
+
+ r = rspamd_strlcpy (filepath, task->msg.start,
+ MIN (sizeof (filepath), task->msg.len + 1));
+
+ rspamd_unescape_uri (filepath, filepath, r);
+
+ if (access (filepath, R_OK) == -1 || stat (filepath, &st) == -1) {
g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
- "Invalid length");
+ "Invalid file (%s): %s", filepath, strerror (errno));
return FALSE;
}
- control_len = task->msg.len - task->message_len;
- if (control_len > 0) {
- parser = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE);
+ fd = open (filepath, O_RDONLY);
- if (!ucl_parser_add_chunk (parser, task->msg.start, control_len)) {
- msg_warn ("processing of control chunk failed: %s",
- ucl_parser_get_error (parser));
- ucl_parser_free (parser);
- }
- else {
- control_obj = ucl_parser_get_object (parser);
- ucl_parser_free (parser);
- rspamd_protocol_handle_control (task, control_obj);
- ucl_object_unref (control_obj);
+ if (fd == -1) {
+ g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
+ "Cannot open file (%s): %s", filepath, strerror (errno));
+ return FALSE;
+ }
+
+ map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+
+ if (map == MAP_FAILED) {
+ close (fd);
+ g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
+ "Cannot mmap file (%s): %s", filepath, strerror (errno));
+ return FALSE;
+ }
+
+ close (fd);
+ task->msg.start = map;
+ task->msg.len = st.st_size;
+
+ rspamd_mempool_add_destructor (task->task_pool, rspamd_task_unmapper, task);
+ }
+ else {
+ debug_task ("got input of length %z", task->msg.len);
+ task->msg.start = start;
+ task->msg.len = len;
+
+ if (task->msg.len == 0) {
+ msg_warn ("message has invalid message length: %ud",
+ task->msg.len);
+ g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
+ "Invalid length");
+ return FALSE;
+ }
+
+ if (task->flags & RSPAMD_TASK_FLAG_HAS_CONTROL) {
+ /* We have control chunk, so we need to process it separately */
+ if (task->msg.len < task->message_len) {
+ msg_warn ("message has invalid message length: %ud and total len: %ud",
+ task->message_len, task->msg.len);
+ g_set_error (&task->err, rspamd_task_quark(), RSPAMD_PROTOCOL_ERROR,
+ "Invalid length");
+ return FALSE;
}
+ control_len = task->msg.len - task->message_len;
+
+ if (control_len > 0) {
+ parser = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE);
- task->msg.start += control_len;
- task->msg.len -= control_len;
+ if (!ucl_parser_add_chunk (parser, task->msg.start, control_len)) {
+ msg_warn ("processing of control chunk failed: %s",
+ ucl_parser_get_error (parser));
+ ucl_parser_free (parser);
+ }
+ else {
+ control_obj = ucl_parser_get_object (parser);
+ ucl_parser_free (parser);
+ rspamd_protocol_handle_control (task, control_obj);
+ ucl_object_unref (control_obj);
+ }
+
+ task->msg.start += control_len;
+ task->msg.len -= control_len;
+ }
}
}
diff --git a/src/libserver/task.h b/src/libserver/task.h
index 25694be9a..79aa19fb5 100644
--- a/src/libserver/task.h
+++ b/src/libserver/task.h
@@ -89,6 +89,7 @@ enum rspamd_task_stage {
#define RSPAMD_TASK_FLAG_HAS_CONTROL (1 << 9)
#define RSPAMD_TASK_FLAG_PROCESSING (1 << 10)
#define RSPAMD_TASK_FLAG_GTUBE (1 << 11)
+#define RSPAMD_TASK_FLAG_FILE (1 << 12)
#define RSPAMD_TASK_IS_SKIPPED(task) (((task)->flags & RSPAMD_TASK_FLAG_SKIP))
#define RSPAMD_TASK_IS_JSON(task) (((task)->flags & RSPAMD_TASK_FLAG_JSON))
diff --git a/src/libserver/url.h b/src/libserver/url.h
index 8666b8c9f..be9ca3b55 100644
--- a/src/libserver/url.h
+++ b/src/libserver/url.h
@@ -122,4 +122,7 @@ struct rspamd_url *
rspamd_url_get_next (rspamd_mempool_t *pool,
const gchar *start, gchar const **pos, gint *statep);
+void
+rspamd_unescape_uri (gchar *dst, const gchar *src, gsize size);
+
#endif