From f23a281012d37b560a3bd152b64970c928d55cbc Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Sun, 30 Mar 2014 22:04:25 +0100 Subject: [PATCH] Allow rspamd HTTP router to serve static files. --- src/http.c | 96 +++++++++++++++++++++++++++++++++++++++++++++-------- src/http.h | 6 +++- src/rdns | 2 +- src/webui.c | 3 +- 4 files changed, 90 insertions(+), 17 deletions(-) diff --git a/src/http.c b/src/http.c index e64f8a2e9..81e8f8f5c 100644 --- a/src/http.c +++ b/src/http.c @@ -940,6 +940,56 @@ rspamd_http_router_error_handler (struct rspamd_http_connection *conn, GError *e } } +static gboolean +rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry, + struct rspamd_http_message *msg) +{ + struct stat st; + int fd; + char filebuf[PATH_MAX], realbuf[PATH_MAX]; + struct rspamd_http_message *reply_msg; + + /* XXX: filter filename component only */ + rspamd_snprintf (filebuf, sizeof (filebuf), "%s%c%v", + entry->rt->default_fs_path, G_DIR_SEPARATOR, msg->url); + + if (realpath (filebuf, realbuf) == NULL || + lstat (realbuf, &st) == -1 || + !S_ISREG (st.st_mode)) { + /* Skip everything suspicious */ + return FALSE; + } + + fd = open (realbuf, O_RDONLY); + if (fd == -1) { + return FALSE; + } + + reply_msg = rspamd_http_new_message (HTTP_RESPONSE); + reply_msg->date = time (NULL); + reply_msg->code = 200; + reply_msg->body = g_string_sized_new (st.st_size); + + if (read (fd, reply_msg->body->str, st.st_size) != st.st_size) { + close (fd); + rspamd_http_message_free (reply_msg); + return FALSE; + } + + reply_msg->body->len = st.st_size; + reply_msg->body->str[st.st_size] = '\0'; + close (fd); + + rspamd_http_connection_reset (entry->conn); + + /* XXX: detect content type */ + rspamd_http_connection_write_message (entry->conn, reply_msg, NULL, + "text/plain", entry, entry->conn->fd, + entry->rt->ptv, entry->rt->ev_base); + + return TRUE; +} + static int rspamd_http_router_finish_handler (struct rspamd_http_connection *conn, struct rspamd_http_message *msg) @@ -967,19 +1017,23 @@ rspamd_http_router_finish_handler (struct rspamd_http_connection *conn, return handler (entry, msg); } else { - err = g_error_new (HTTP_ERROR, 404, - "Not found"); - if (entry->rt->error_handler != NULL) { - entry->rt->error_handler (entry, err); + if (entry->rt->default_fs_path == NULL || + rspamd_http_router_try_file (entry, msg)) { + err = g_error_new (HTTP_ERROR, 404, + "Not found"); + if (entry->rt->error_handler != NULL) { + entry->rt->error_handler (entry, err); + } + 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); + rspamd_http_connection_reset (entry->conn); + rspamd_http_connection_write_message (entry->conn, err_msg, NULL, + "text/plain", entry, entry->conn->fd, + entry->rt->ptv, entry->rt->ev_base); + g_error_free (err); } - 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); - rspamd_http_connection_reset (entry->conn); - rspamd_http_connection_write_message (entry->conn, err_msg, NULL, - "text/plain", entry, entry->conn->fd, entry->rt->ptv, entry->rt->ev_base); - g_error_free (err); } } @@ -989,9 +1043,11 @@ rspamd_http_router_finish_handler (struct rspamd_http_connection *conn, struct rspamd_http_connection_router* rspamd_http_router_new (rspamd_http_router_error_handler_t eh, rspamd_http_router_finish_handler_t fh, - struct timeval *timeout, struct event_base *base) + struct timeval *timeout, struct event_base *base, + const char *default_fs_path) { struct rspamd_http_connection_router* new; + struct stat st; new = g_slice_alloc (sizeof (struct rspamd_http_connection_router)); new->paths = g_hash_table_new (rspamd_strcase_hash, rspamd_strcase_equal); @@ -1007,6 +1063,14 @@ rspamd_http_router_new (rspamd_http_router_error_handler_t eh, new->ptv = NULL; } + if (default_fs_path != NULL && stat (default_fs_path, &st) != -1 && + S_ISDIR (st.st_mode)) { + new->default_fs_path = g_strdup (default_fs_path); + } + else { + new->default_fs_path = NULL; + } + return new; } @@ -1037,7 +1101,8 @@ rspamd_http_router_handle_socket (struct rspamd_http_connection_router *router, conn->conn = rspamd_http_connection_new (NULL, rspamd_http_router_error_handler, rspamd_http_router_finish_handler, 0, RSPAMD_HTTP_SERVER); - rspamd_http_connection_read_message (conn->conn, conn, fd, router->ptv, router->ev_base); + rspamd_http_connection_read_message (conn->conn, conn, fd, router->ptv, + router->ev_base); LL_PREPEND (router->conns, conn); } @@ -1051,6 +1116,9 @@ rspamd_http_router_free (struct rspamd_http_connection_router *router) rspamd_http_entry_free (conn); } + if (router->default_fs_path != NULL) { + g_free (router->default_fs_path); + } g_hash_table_unref (router->paths); g_slice_free1 (sizeof (struct rspamd_http_connection_router), router); } diff --git a/src/http.h b/src/http.h index ffa2ecca2..8af4429c6 100644 --- a/src/http.h +++ b/src/http.h @@ -119,6 +119,7 @@ struct rspamd_http_connection_router { struct timeval tv; struct timeval *ptv; struct event_base *ev_base; + gchar *default_fs_path; rspamd_http_router_error_handler_t error_handler; rspamd_http_router_finish_handler_t finish_handler; }; @@ -242,13 +243,16 @@ time_t rspamd_http_parse_date (const gchar *header, gsize len); * Create new http connection router and the associated HTTP connection * @param eh error handler callback * @param fh finish handler callback + * @param default_fs_path if not NULL try to serve static files from + * the specified directory * @return */ struct rspamd_http_connection_router* rspamd_http_router_new ( rspamd_http_router_error_handler_t eh, rspamd_http_router_finish_handler_t fh, struct timeval *timeout, - struct event_base *base); + struct event_base *base, + const char *default_fs_path); /** * Add new path to the router diff --git a/src/rdns b/src/rdns index 5ca36d831..38f3dc889 160000 --- a/src/rdns +++ b/src/rdns @@ -1 +1 @@ -Subproject commit 5ca36d831ef871fbc7b76846b554a875c1ef5a87 +Subproject commit 38f3dc889752939835591ee1d29495c00117f41e diff --git a/src/webui.c b/src/webui.c index 99cb95ec0..c7441461d 100644 --- a/src/webui.c +++ b/src/webui.c @@ -1812,7 +1812,8 @@ start_webui_worker (struct rspamd_worker *worker) } /* Accept event */ ctx->http = rspamd_http_router_new (rspamd_webui_error_handler, - rspamd_webui_finish_handler, &ctx->io_tv, ctx->ev_base); + rspamd_webui_finish_handler, &ctx->io_tv, ctx->ev_base, + NULL); /* Add callbacks for different methods */ rspamd_http_router_add_path (ctx->http, PATH_AUTH, rspamd_webui_handle_auth); -- 2.39.5