summaryrefslogtreecommitdiffstats
path: root/utils/rspamd_http_server.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 21:30:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 21:30:40 +0000
commit133a45c109da5310add55824db21af5239951f93 (patch)
treeba6ac4c0a950a0dda56451944315d66409923918 /utils/rspamd_http_server.c
parentInitial commit. (diff)
downloadrspamd-133a45c109da5310add55824db21af5239951f93.tar.xz
rspamd-133a45c109da5310add55824db21af5239951f93.zip
Adding upstream version 3.8.1.upstream/3.8.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'utils/rspamd_http_server.c')
-rw-r--r--utils/rspamd_http_server.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/utils/rspamd_http_server.c b/utils/rspamd_http_server.c
new file mode 100644
index 0000000..ecd1d38
--- /dev/null
+++ b/utils/rspamd_http_server.c
@@ -0,0 +1,300 @@
+/*-
+ * Copyright 2016 Vsevolod Stakhov
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "config.h"
+#include "rspamd.h"
+#include "util.h"
+#include "libutil/fstring.h"
+#include "libutil/http.h"
+#include "libutil/http_private.h"
+#include "ottery.h"
+#include "cryptobox.h"
+#include "keypair.h"
+#include "unix-std.h"
+#include <math.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+static guint port = 43000;
+static guint cache_size = 10;
+static guint nworkers = 1;
+static gboolean openssl_mode = FALSE;
+static GHashTable *maps = NULL;
+static gchar *key = NULL;
+static struct rspamd_keypair_cache *c;
+static struct rspamd_cryptobox_keypair *server_key;
+static struct timeval io_tv = {
+ .tv_sec = 20,
+ .tv_usec = 0};
+
+static GOptionEntry entries[] = {
+ {"port", 'p', 0, G_OPTION_ARG_INT, &port,
+ "Port number (default: 43000)", NULL},
+ {"cache", 'c', 0, G_OPTION_ARG_INT, &cache_size,
+ "Keys cache size (default: 10)", NULL},
+ {"workers", 'n', 0, G_OPTION_ARG_INT, &nworkers,
+ "Number of workers to start (default: 1)", NULL},
+ {"openssl", 'o', 0, G_OPTION_ARG_NONE, &openssl_mode,
+ "Use openssl crypto", NULL},
+ {"key", 'k', 0, G_OPTION_ARG_STRING, &key,
+ "Use static keypair instead of new one (base32 encoded sk || pk)", NULL},
+ {NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL}};
+
+struct rspamd_http_server_session {
+ struct rspamd_http_connection *conn;
+ struct ev_loop *ev_base;
+ guint req_size;
+ gboolean reply;
+ gint fd;
+};
+
+static void
+rspamd_server_error(struct rspamd_http_connection *conn,
+ GError *err)
+{
+ struct rspamd_http_server_session *session = conn->ud;
+
+ rspamd_fprintf(stderr, "http error occurred: %s\n", err->message);
+ rspamd_http_connection_unref(conn);
+ close(session->fd);
+ g_slice_free1(sizeof(*session), session);
+}
+
+static int
+rspamd_server_finish(struct rspamd_http_connection *conn,
+ struct rspamd_http_message *msg)
+{
+ struct rspamd_http_server_session *session = conn->ud;
+ struct rspamd_http_message *reply;
+ gulong size;
+ const gchar *url_str;
+ guint url_len;
+ rspamd_fstring_t *body;
+
+ if (!session->reply) {
+ session->reply = TRUE;
+ reply = rspamd_http_new_message(HTTP_RESPONSE);
+ url_str = msg->url->str;
+ url_len = msg->url->len;
+
+ if (url_str[0] == '/') {
+ url_str++;
+ url_len--;
+ }
+
+ if (rspamd_strtoul(url_str, url_len, &size)) {
+ session->req_size = size;
+
+ reply->code = 200;
+ reply->status = rspamd_fstring_new_init("OK", 2);
+ body = rspamd_fstring_sized_new(size);
+ body->len = size;
+ memset(body->str, 0, size);
+ rspamd_http_message_set_body_from_fstring_steal(msg, body);
+ }
+ else {
+ reply->code = 404;
+ reply->status = rspamd_fstring_new_init("Not found", 9);
+ }
+
+ rspamd_http_connection_reset(conn);
+ rspamd_http_connection_write_message(conn, reply, NULL,
+ "application/octet-stream", session, session->fd,
+ &io_tv, session->ev_base);
+ }
+ else {
+ /* Destroy session */
+ rspamd_http_connection_unref(conn);
+ close(session->fd);
+ g_slice_free1(sizeof(*session), session);
+ }
+
+ return 0;
+}
+
+static void
+rspamd_server_accept(gint fd, short what, void *arg)
+{
+ struct ev_loop *ev_base = arg;
+ struct rspamd_http_server_session *session;
+ rspamd_inet_addr_t *addr;
+ gint nfd;
+
+ do {
+ if ((nfd =
+ rspamd_accept_from_socket(fd, &addr, NULL)) == -1) {
+ rspamd_fprintf(stderr, "accept failed: %s", strerror(errno));
+ return;
+ }
+ /* Check for EAGAIN */
+ if (nfd == 0) {
+ rspamd_inet_address_free(addr);
+ return;
+ }
+
+ rspamd_inet_address_free(addr);
+ session = g_slice_alloc(sizeof(*session));
+ session->conn = rspamd_http_connection_new(NULL,
+ rspamd_server_error,
+ rspamd_server_finish,
+ 0,
+ RSPAMD_HTTP_SERVER,
+ c,
+ NULL);
+ rspamd_http_connection_set_key(session->conn, server_key);
+ rspamd_http_connection_read_message(session->conn,
+ session,
+ nfd,
+ &io_tv,
+ ev_base);
+ session->reply = FALSE;
+ session->fd = nfd;
+ session->ev_base = ev_base;
+ } while (nfd > 0);
+}
+
+static void
+rspamd_http_term_handler(gint fd, short what, void *arg)
+{
+ struct ev_loop *ev_base = arg;
+ struct timeval tv = {0, 0};
+
+ event_base_loopexit(ev_base, &tv);
+}
+
+static void
+rspamd_http_server_func(gint fd, rspamd_inet_addr_t *addr)
+{
+ struct ev_loop *ev_base = event_init();
+ struct event accept_ev, term_ev;
+
+ event_set(&accept_ev, fd, EV_READ | EV_PERSIST, rspamd_server_accept, ev_base);
+ event_base_set(ev_base, &accept_ev);
+ event_add(&accept_ev, NULL);
+
+ evsignal_set(&term_ev, SIGTERM, rspamd_http_term_handler, ev_base);
+ event_base_set(ev_base, &term_ev);
+ event_add(&term_ev, NULL);
+
+ event_base_loop(ev_base, 0);
+}
+
+static void
+rspamd_http_start_servers(pid_t *sfd, rspamd_inet_addr_t *addr)
+{
+ guint i;
+ gint fd;
+
+ fd = rspamd_inet_address_listen(addr, SOCK_STREAM, TRUE);
+ g_assert(fd != -1);
+
+ for (i = 0; i < nworkers; i++) {
+ sfd[i] = fork();
+ g_assert(sfd[i] != -1);
+
+ if (sfd[i] == 0) {
+ rspamd_http_server_func(fd, addr);
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ close(fd);
+}
+
+static void
+rspamd_http_stop_servers(pid_t *sfd)
+{
+ guint i;
+ gint res;
+
+ for (i = 0; i < nworkers; i++) {
+ kill(sfd[i], SIGTERM);
+ wait(&res);
+ }
+}
+
+static void
+rspamd_http_server_term(int fd, short what, void *arg)
+{
+ pid_t *sfd = arg;
+
+ rspamd_http_stop_servers(sfd);
+ event_loopexit(NULL);
+}
+
+int main(int argc, gchar **argv)
+{
+ GOptionContext *context;
+ GError *error = NULL;
+ struct ev_loop *ev_base;
+ GString *b32_key;
+ pid_t *sfd;
+ rspamd_inet_addr_t *addr;
+ struct event term_ev, int_ev;
+ struct in_addr ina = {INADDR_ANY};
+
+ rspamd_init_libs();
+
+ context = g_option_context_new(
+ "rspamd-http-server - test server for benchmarks");
+ g_option_context_set_summary(context,
+ "Summary:\n Rspamd test HTTP server " RVERSION
+ "\n Release id: " RID);
+ g_option_context_add_main_entries(context, entries, NULL);
+
+ if (!g_option_context_parse(context, &argc, &argv, &error)) {
+ rspamd_fprintf(stderr, "option parsing failed: %s\n", error->message);
+ g_error_free(error);
+ exit(EXIT_FAILURE);
+ }
+
+ maps = g_hash_table_new(g_int_hash, g_int_equal);
+
+ if (key == NULL) {
+ server_key = rspamd_keypair_new(RSPAMD_KEYPAIR_KEX,
+ openssl_mode ? RSPAMD_CRYPTOBOX_MODE_NIST : RSPAMD_CRYPTOBOX_MODE_25519);
+ b32_key = rspamd_keypair_print(server_key,
+ RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32);
+ rspamd_printf("key: %v\n", b32_key);
+ }
+ else {
+ /* TODO: add key loading */
+ }
+
+ if (cache_size > 0) {
+ c = rspamd_keypair_cache_new(cache_size);
+ }
+
+ sfd = g_alloca(sizeof(*sfd) * nworkers);
+ addr = rspamd_inet_address_new(AF_INET, &ina);
+ rspamd_inet_address_set_port(addr, port);
+ rspamd_http_start_servers(sfd, addr);
+
+ /* Just wait for workers */
+ ev_base = event_init();
+
+ event_set(&term_ev, SIGTERM, EV_SIGNAL, rspamd_http_server_term, sfd);
+ event_base_set(ev_base, &term_ev);
+ event_add(&term_ev, NULL);
+ event_set(&int_ev, SIGINT, EV_SIGNAL, rspamd_http_server_term, sfd);
+ event_base_set(ev_base, &int_ev);
+ event_add(&int_ev, NULL);
+
+ event_base_loop(ev_base, 0);
+
+ return 0;
+}