summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cfg_utils.c2
-rw-r--r--src/http.c735
-rw-r--r--src/http.h74
3 files changed, 521 insertions, 290 deletions
diff --git a/src/cfg_utils.c b/src/cfg_utils.c
index 56310669e..9216fb6ef 100644
--- a/src/cfg_utils.c
+++ b/src/cfg_utils.c
@@ -125,7 +125,7 @@ parse_host_port_priority_strv (memory_pool_t *pool, gchar **tokens,
}
}
else if (default_port != 0) {
- rspamd_snprintf (portbuf, sizeof (portbuf), "%u", default_port);
+ rspamd_snprintf (portbuf, sizeof (portbuf), "%ud", default_port);
cur_port = portbuf;
}
else {
diff --git a/src/http.c b/src/http.c
index 6c37d069e..7d9b93469 100644
--- a/src/http.c
+++ b/src/http.c
@@ -24,6 +24,7 @@
#include "config.h"
#include "http.h"
#include "utlist.h"
+#include "printf.h"
struct rspamd_http_connection_private {
GString *buf;
@@ -34,8 +35,11 @@ struct rspamd_http_connection_private {
struct event ev;
struct timeval tv;
struct timeval *ptv;
- gboolean in_body;
- struct rspamd_http_message *req;
+ struct rspamd_http_message *msg;
+ struct iovec *out;
+ guint outlen;
+ gsize wr_pos;
+ gsize wr_total;
};
#define HTTP_ERROR http_error_quark ()
@@ -45,274 +49,31 @@ http_error_quark (void)
return g_quark_from_static_string ("http-error-quark");
}
-static inline void
-rspamd_http_check_date (struct rspamd_http_connection_private *priv)
-{
- if (g_ascii_strcasecmp (priv->header->name->str, "date") == 0) {
- priv->req->date = rspamd_http_parse_date (priv->header->value->str,
- priv->header->value->len);
- }
-}
-
-static gint
-rspamd_http_on_url (http_parser* parser, const gchar *at, size_t length)
-{
- struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
- struct rspamd_http_connection_private *priv;
-
- priv = conn->priv;
-
- g_string_append_len (priv->req->url, at, length);
-
- return 0;
-}
-
-static gint
-rspamd_http_on_header_field (http_parser* parser, const gchar *at, size_t length)
-{
- struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
- struct rspamd_http_connection_private *priv;
-
- priv = conn->priv;
-
- if (priv->header == NULL) {
- priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
- priv->header->name = g_string_sized_new (32);
- priv->header->value = g_string_sized_new (32);
- }
- else if (priv->new_header) {
- LL_PREPEND (priv->req->headers, priv->header);
- rspamd_http_check_date (priv);
- priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
- priv->header->name = g_string_sized_new (32);
- priv->header->value = g_string_sized_new (32);
- }
-
- priv->new_header = FALSE;
- g_string_append_len (priv->header->name, at, length);
-
- return 0;
-}
-
-static gint
-rspamd_http_on_header_value (http_parser* parser, const gchar *at, size_t length)
+static const gchar *
+rspamd_http_code_to_str (gint code)
{
- struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
- struct rspamd_http_connection_private *priv;
-
- priv = conn->priv;
-
- if (priv->header == NULL) {
- /* Should not happen */
- return -1;
- }
-
- priv->new_header = TRUE;
- g_string_append_len (priv->header->value, at, length);
-
- return 0;
-}
-
-static int
-rspamd_http_on_headers_complete (http_parser* parser)
-{
- struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
- struct rspamd_http_connection_private *priv;
-
- priv = conn->priv;
-
- if (priv->header != NULL) {
- LL_PREPEND (priv->req->headers, priv->header);
- rspamd_http_check_date (priv);
- priv->header = NULL;
- }
-
- priv->in_body = TRUE;
- if (parser->content_length != 0 && parser->content_length != ULLONG_MAX) {
- priv->req->body = g_string_sized_new (parser->content_length + 1);
- }
- else {
- priv->req->body = g_string_sized_new (BUFSIZ);
- }
-
- return 0;
-}
-
-static int
-rspamd_http_on_body (http_parser* parser, const gchar *at, size_t length)
-{
- struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
- struct rspamd_http_connection_private *priv;
-
- priv = conn->priv;
-
- g_string_append_len (priv->req->body, at, length);
-
- if (conn->opts & RSPAMD_HTTP_BODY_PARTIAL) {
- return (conn->body_handler (conn, priv->req, at, length));
- }
-
- return 0;
-}
-
-static int
-rspamd_http_on_message_complete (http_parser* parser)
-{
- struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
- struct rspamd_http_connection_private *priv;
- int ret;
-
- priv = conn->priv;
-
- if (conn->opts & RSPAMD_HTTP_BODY_PARTIAL) {
- ret = conn->body_handler (conn, priv->req, NULL, 0);
- }
- else {
- ret = conn->body_handler (conn, priv->req, priv->req->body->str, priv->req->body->len);
- }
-
- return ret;
-}
-
-static void
-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;
- GString *buf;
- gssize r;
- GError *err;
-
- priv = conn->priv;
- buf = priv->buf;
-
- r = read (fd, buf->str, buf->allocated_len);
- if (r == -1) {
- err = g_error_new (HTTP_ERROR, errno, "IO read error: %s", strerror (errno));
- conn->error_handler (conn, err);
- g_error_free (err);
+ if (code == 200) {
+ return "OK";
}
- else {
- buf->len = r;
- if (http_parser_execute (&priv->parser, &priv->parser_cb, buf->str, r) != (size_t)r) {
- err = g_error_new (HTTP_ERROR, priv->parser.http_errno,
- "HTTP parser error: %s", http_errno_description (priv->parser.http_errno));
- conn->error_handler (conn, err);
- g_error_free (err);
- }
- /* TODO: handle EOF */
+ else if (code == 404) {
+ return "Not found";
}
-}
-
-struct rspamd_http_connection*
-rspamd_http_connection_new (rspamd_http_body_handler body_handler,
- rspamd_http_error_handler error_handler, enum rspamd_http_options opts)
-{
- struct rspamd_http_connection *new;
- struct rspamd_http_connection_private *priv;
-
- new = g_slice_alloc0 (sizeof (struct rspamd_http_connection));
- new->opts = opts;
- new->body_handler = body_handler;
- new->error_handler = error_handler;
- new->fd = -1;
-
- /* Init priv */
- priv = g_slice_alloc0 (sizeof (struct rspamd_http_connection_private));
- http_parser_init (&priv->parser, HTTP_REQUEST);
- priv->parser.data = new;
- priv->parser_cb.on_url = rspamd_http_on_url;
- priv->parser_cb.on_header_field = rspamd_http_on_header_field;
- priv->parser_cb.on_header_value = rspamd_http_on_header_value;
- priv->parser_cb.on_headers_complete = rspamd_http_on_headers_complete;
- priv->parser_cb.on_body = rspamd_http_on_body;
- priv->parser_cb.on_message_complete = rspamd_http_on_message_complete;
-
- new->priv = priv;
-
- return new;
-}
-
-void
-rspamd_http_connection_reset (struct rspamd_http_connection *conn)
-{
- struct rspamd_http_connection_private *priv;
- struct rspamd_http_message *req;
- struct rspamd_http_header *hdr, *tmp_hdr;
-
- priv = conn->priv;
- req = priv->req;
-
- /* Clear request */
- if (req != NULL) {
- LL_FOREACH_SAFE(req->headers, hdr, tmp_hdr) {
- g_string_free (hdr->name, TRUE);
- g_string_free (hdr->value, TRUE);
- g_slice_free1 (sizeof (struct rspamd_http_header), hdr);
- }
- g_string_free (req->body, TRUE);
- g_string_free (req->url, TRUE);
- g_slice_free1 (sizeof (struct rspamd_http_message), req);
- priv->req = NULL;
+ else if (code == 403 || code == 401) {
+ return "Not authorized";
}
-
- /* Clear priv */
- event_del (&priv->ev);
- if (priv->buf != NULL) {
- g_string_free (priv->buf, TRUE);
- priv->buf = NULL;
+ else if (code >= 400 && code < 500) {
+ return "Bad request";
}
-
- /* Clear conn itself */
- if (conn->fd != -1) {
- close (conn->fd);
+ else if (code >= 300 && code < 400) {
+ return "See Other";
}
-}
-
-void
-rspamd_http_connection_free (struct rspamd_http_connection *conn)
-{
- struct rspamd_http_connection_private *priv;
-
- priv = conn->priv;
- rspamd_http_connection_reset (conn);
- g_slice_free1 (sizeof (struct rspamd_http_connection_private), priv);
- g_slice_free1 (sizeof (struct rspamd_http_connection), conn);
-}
-
-void
-rspamd_http_connection_handle_request (struct rspamd_http_connection *conn,
- gpointer ud, gint fd, struct timeval *timeout, struct event_base *base)
-{
- struct rspamd_http_connection_private *priv = conn->priv;
- struct rspamd_http_message *req;
-
- conn->fd = fd;
- conn->ud = ud;
- req = g_slice_alloc (sizeof (struct rspamd_http_message));
- req->url = g_string_sized_new (32);
- req->headers = NULL;
- req->date = 0;
- priv->req = req;
-
- if (timeout == NULL) {
- priv->ptv = NULL;
+ else if (code >= 500 && code < 600) {
+ return "Internal server error";
}
- else {
- memcpy (&priv->tv, timeout, sizeof (struct timeval));
- priv->ptv = &priv->tv;
- }
- priv->header = NULL;
- priv->buf = g_string_sized_new (BUFSIZ);
- priv->in_body = FALSE;
- priv->new_header = TRUE;
- event_set (&priv->ev, fd, EV_READ | EV_PERSIST, rspamd_http_event_handler, conn);
- event_base_set (base, &priv->ev);
- event_add (&priv->ev, priv->ptv);
+ return "Unknown error";
}
-
/*
* Obtained from nginx
* Copyright (C) Igor Sysoev
@@ -580,3 +341,457 @@ rspamd_http_parse_date (const gchar *header, gsize len)
return (time_t) time;
}
+
+static inline void
+rspamd_http_check_date (struct rspamd_http_connection_private *priv)
+{
+ if (g_ascii_strcasecmp (priv->header->name->str, "date") == 0) {
+ priv->msg->date = rspamd_http_parse_date (priv->header->value->str,
+ priv->header->value->len);
+ }
+}
+
+static gint
+rspamd_http_on_url (http_parser* parser, const gchar *at, size_t length)
+{
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
+
+ priv = conn->priv;
+
+ g_string_append_len (priv->msg->url, at, length);
+
+ return 0;
+}
+
+static gint
+rspamd_http_on_header_field (http_parser* parser, const gchar *at, size_t length)
+{
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
+
+ priv = conn->priv;
+
+ if (priv->header == NULL) {
+ priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
+ priv->header->name = g_string_sized_new (32);
+ priv->header->value = g_string_sized_new (32);
+ }
+ else if (priv->new_header) {
+ LL_PREPEND (priv->msg->headers, priv->header);
+ rspamd_http_check_date (priv);
+ priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
+ priv->header->name = g_string_sized_new (32);
+ priv->header->value = g_string_sized_new (32);
+ }
+
+ priv->new_header = FALSE;
+ g_string_append_len (priv->header->name, at, length);
+
+ return 0;
+}
+
+static gint
+rspamd_http_on_header_value (http_parser* parser, const gchar *at, size_t length)
+{
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
+
+ priv = conn->priv;
+
+ if (priv->header == NULL) {
+ /* Should not happen */
+ return -1;
+ }
+
+ priv->new_header = TRUE;
+ g_string_append_len (priv->header->value, at, length);
+
+ return 0;
+}
+
+static int
+rspamd_http_on_headers_complete (http_parser* parser)
+{
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
+
+ priv = conn->priv;
+
+ if (priv->header != NULL) {
+ LL_PREPEND (priv->msg->headers, priv->header);
+ rspamd_http_check_date (priv);
+ priv->header = NULL;
+ }
+
+ if (parser->content_length != 0 && parser->content_length != ULLONG_MAX) {
+ priv->msg->body = g_string_sized_new (parser->content_length + 1);
+ }
+ else {
+ priv->msg->body = g_string_sized_new (BUFSIZ);
+ }
+
+ return 0;
+}
+
+static int
+rspamd_http_on_body (http_parser* parser, const gchar *at, size_t length)
+{
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
+
+ priv = conn->priv;
+
+ g_string_append_len (priv->msg->body, at, length);
+
+ if (conn->opts & RSPAMD_HTTP_BODY_PARTIAL) {
+ return (conn->body_handler (conn, priv->msg, at, length));
+ }
+
+ return 0;
+}
+
+static int
+rspamd_http_on_message_complete (http_parser* parser)
+{
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
+ int ret;
+
+ priv = conn->priv;
+
+ if (conn->body_handler != NULL) {
+ if (conn->opts & RSPAMD_HTTP_BODY_PARTIAL) {
+ ret = conn->body_handler (conn, priv->msg, NULL, 0);
+ }
+ else {
+ ret = conn->body_handler (conn, priv->msg, priv->msg->body->str, priv->msg->body->len);
+ }
+ }
+ conn->finish_handler (conn, priv->msg);
+
+ return ret;
+}
+
+static void
+rspamd_http_write_helper (struct rspamd_http_connection *conn)
+{
+ struct rspamd_http_connection_private *priv;
+ struct iovec *start;
+ guint niov, i;
+ gsize remain;
+ gssize r;
+ GError *err;
+
+ priv = conn->priv;
+
+ if (priv->wr_pos == priv->wr_total) {
+ conn->finish_handler (conn, priv->msg);
+ return;
+ }
+
+ start = &priv->out[0];
+ niov = priv->outlen;
+ remain = priv->wr_pos;
+ for (i = 0; i < priv->outlen && remain > 0; i ++) {
+ /* Find out the first iov required */
+ start = &priv->out[i];
+ if (start->iov_len <= remain) {
+ remain -= start->iov_len;
+ start = &priv->out[i + 1];
+ niov --;
+ }
+ else {
+ start->iov_base = (void *)((char *)start->iov_base + remain);
+ start->iov_len -= remain;
+ remain = 0;
+ }
+ }
+
+ r = writev (conn->fd, start, MIN (IOV_MAX, niov));
+
+ if (r == -1) {
+ err = g_error_new (HTTP_ERROR, errno, "IO write error: %s", strerror (errno));
+ conn->error_handler (conn, err);
+ g_error_free (err);
+ }
+ else {
+ priv->wr_pos += r;
+ }
+
+ if (priv->wr_pos >= priv->wr_total) {
+ conn->finish_handler (conn, priv->msg);
+ }
+}
+
+static void
+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;
+ GString *buf;
+ gssize r;
+ GError *err;
+
+ priv = conn->priv;
+ buf = priv->buf;
+
+ if (what == EV_READ) {
+ r = read (fd, buf->str, buf->allocated_len);
+ if (r == -1) {
+ err = g_error_new (HTTP_ERROR, errno, "IO read error: %s", strerror (errno));
+ conn->error_handler (conn, err);
+ g_error_free (err);
+ }
+ else {
+ buf->len = r;
+ if (http_parser_execute (&priv->parser, &priv->parser_cb, buf->str, r) != (size_t)r) {
+ err = g_error_new (HTTP_ERROR, priv->parser.http_errno,
+ "HTTP parser error: %s", http_errno_description (priv->parser.http_errno));
+ conn->error_handler (conn, err);
+ g_error_free (err);
+ }
+ }
+ }
+ else if (what == EV_TIMEOUT) {
+ err = g_error_new (HTTP_ERROR, ETIMEDOUT,
+ "IO timeout");
+ conn->error_handler (conn, err);
+ g_error_free (err);
+ }
+ else if (what == EV_WRITE) {
+ rspamd_http_write_helper (conn);
+ }
+}
+
+struct rspamd_http_connection*
+rspamd_http_connection_new (rspamd_http_body_handler body_handler,
+ rspamd_http_error_handler error_handler,
+ rspamd_http_finish_handler finish_handler,
+ enum rspamd_http_options opts,
+ enum rspamd_http_connection_type type)
+{
+ struct rspamd_http_connection *new;
+ struct rspamd_http_connection_private *priv;
+
+ if (error_handler == NULL || finish_handler == NULL) {
+ return NULL;
+ }
+
+ new = g_slice_alloc0 (sizeof (struct rspamd_http_connection));
+ new->opts = opts;
+ new->type = type;
+ new->body_handler = body_handler;
+ new->error_handler = error_handler;
+ new->finish_handler = finish_handler;
+ new->fd = -1;
+
+ /* Init priv */
+ priv = g_slice_alloc0 (sizeof (struct rspamd_http_connection_private));
+ http_parser_init (&priv->parser, type == RSPAMD_HTTP_SERVER ? HTTP_REQUEST : HTTP_RESPONSE);
+ priv->parser.data = new;
+ priv->parser_cb.on_url = rspamd_http_on_url;
+ priv->parser_cb.on_header_field = rspamd_http_on_header_field;
+ priv->parser_cb.on_header_value = rspamd_http_on_header_value;
+ priv->parser_cb.on_headers_complete = rspamd_http_on_headers_complete;
+ priv->parser_cb.on_body = rspamd_http_on_body;
+ priv->parser_cb.on_message_complete = rspamd_http_on_message_complete;
+
+ new->priv = priv;
+
+ return new;
+}
+
+void
+rspamd_http_connection_reset (struct rspamd_http_connection *conn)
+{
+ struct rspamd_http_connection_private *priv;
+ struct rspamd_http_message *msg;
+
+ priv = conn->priv;
+ msg = priv->msg;
+
+ /* Clear request */
+ if (msg != NULL) {
+ rspamd_http_message_free (msg);
+ priv->msg = NULL;
+ }
+
+ /* Clear priv */
+ event_del (&priv->ev);
+ if (priv->buf != NULL) {
+ g_string_free (priv->buf, TRUE);
+ priv->buf = NULL;
+ }
+ if (priv->out != NULL) {
+ g_slice_free1 (sizeof (struct iovec) * priv->outlen, priv->out);
+ priv->out = NULL;
+ }
+
+ /* Clear conn itself */
+ if (conn->fd != -1) {
+ close (conn->fd);
+ }
+}
+
+void
+rspamd_http_connection_free (struct rspamd_http_connection *conn)
+{
+ struct rspamd_http_connection_private *priv;
+
+ priv = conn->priv;
+ rspamd_http_connection_reset (conn);
+ g_slice_free1 (sizeof (struct rspamd_http_connection_private), priv);
+ g_slice_free1 (sizeof (struct rspamd_http_connection), conn);
+}
+
+void
+rspamd_http_connection_read_message (struct rspamd_http_connection *conn,
+ gpointer ud, gint fd, struct timeval *timeout, struct event_base *base)
+{
+ struct rspamd_http_connection_private *priv = conn->priv;
+ struct rspamd_http_message *req;
+
+ conn->fd = fd;
+ conn->ud = ud;
+ req = rspamd_http_new_message (conn->type == RSPAMD_HTTP_SERVER ? HTTP_REQUEST : HTTP_RESPONSE);
+ priv->msg = req;
+
+ if (timeout == NULL) {
+ priv->ptv = NULL;
+ }
+ else {
+ memcpy (&priv->tv, timeout, sizeof (struct timeval));
+ priv->ptv = &priv->tv;
+ }
+ priv->header = NULL;
+ priv->buf = g_string_sized_new (BUFSIZ);
+ priv->new_header = TRUE;
+
+ event_set (&priv->ev, fd, EV_READ | EV_PERSIST, rspamd_http_event_handler, conn);
+ event_base_set (base, &priv->ev);
+ event_add (&priv->ev, priv->ptv);
+}
+
+void
+rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
+ struct rspamd_http_message *msg, const gchar *host,
+ gpointer ud, gint fd, struct timeval *timeout, struct event_base *base)
+{
+ struct rspamd_http_connection_private *priv = conn->priv;
+ struct rspamd_http_header *hdr;
+ gint i;
+
+ conn->fd = fd;
+ conn->ud = ud;
+ priv->msg = msg;
+
+ if (timeout == NULL) {
+ priv->ptv = NULL;
+ }
+ else {
+ memcpy (&priv->tv, timeout, sizeof (struct timeval));
+ priv->ptv = &priv->tv;
+ }
+ priv->header = NULL;
+ priv->buf = g_string_sized_new (64);
+
+ if (conn->type == RSPAMD_HTTP_SERVER) {
+ /* Format reply */
+ rspamd_printf_gstring (priv->buf, "HTTP/1.1 %d %s\r\n"
+ "Connection: close\r\n"
+ "Content-Length: %z\r\n",
+ msg->code, rspamd_http_code_to_str (msg->code),
+ msg->body->len);
+ }
+ else {
+ /* Format request */
+ if (host != NULL) {
+ rspamd_printf_gstring (priv->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, msg->body->len);
+ }
+ else {
+ /* Fallback to HTTP/1.0 */
+ rspamd_printf_gstring (priv->buf, "%s %v HTTP/1.0\r\n"
+ "Content-Length: %z\r\n",
+ http_method_str (msg->method), msg->url, msg->body->len);
+ }
+ }
+
+ /* Allocate iov */
+ priv->outlen = 3;
+ priv->wr_total = msg->body->len + priv->buf->len + 2;
+ LL_FOREACH (msg->headers, hdr) {
+ /* <name><: ><value><\r\n> */
+ priv->wr_total += hdr->name->len + hdr->value->len + 4;
+ priv->outlen += 4;
+ }
+ priv->out = g_slice_alloc (sizeof (struct iovec) * priv->outlen);
+ priv->wr_pos = 0;
+
+ /* Now set up all iov */
+ priv->out[0].iov_base = priv->buf->str;
+ priv->out[0].iov_len = priv->buf->len;
+ i = 1;
+ LL_FOREACH (msg->headers, hdr) {
+ priv->out[i].iov_base = hdr->name->str;
+ priv->out[i++].iov_len = hdr->name->len;
+ priv->out[i].iov_base = ": ";
+ priv->out[i++].iov_len = 2;
+ priv->out[i].iov_base = hdr->value->str;
+ priv->out[i++].iov_len = hdr->value->len;
+ priv->out[i].iov_base = "\r\n";
+ priv->out[i++].iov_len = 2;
+ }
+ priv->out[i].iov_base = "\r\n";
+ priv->out[i++].iov_len = 2;
+ priv->out[i].iov_base = msg->body->str;
+ priv->out[i++].iov_len = msg->body->len;
+
+ event_set (&priv->ev, fd, EV_WRITE, rspamd_http_event_handler, conn);
+ event_base_set (base, &priv->ev);
+ event_add (&priv->ev, priv->ptv);
+}
+
+struct rspamd_http_message*
+rspamd_http_new_message (enum http_parser_type type)
+{
+ struct rspamd_http_message *new;
+
+ new = g_slice_alloc (sizeof (struct rspamd_http_message));
+ if (type == HTTP_REQUEST) {
+ new->url = g_string_sized_new (32);
+ }
+ else {
+ new->url = NULL;
+ new->code = 200;
+ }
+ new->headers = NULL;
+ new->date = 0;
+ new->body = NULL;
+ new->type = type;
+
+ return new;
+}
+
+void
+rspamd_http_message_free (struct rspamd_http_message *msg)
+{
+ struct rspamd_http_header *hdr, *tmp_hdr;
+
+ LL_FOREACH_SAFE (msg->headers, hdr, tmp_hdr) {
+ g_string_free (hdr->name, TRUE);
+ g_string_free (hdr->value, TRUE);
+ g_slice_free1 (sizeof (struct rspamd_http_header), hdr);
+ }
+ if (msg->body != NULL) {
+ g_string_free (msg->body, TRUE);
+ }
+ if (msg->url != NULL) {
+ g_string_free (msg->url, TRUE);
+ }
+ g_slice_free1 (sizeof (struct rspamd_http_message), msg);
+}
diff --git a/src/http.h b/src/http.h
index fe9c8d643..d26a99d95 100644
--- a/src/http.h
+++ b/src/http.h
@@ -34,9 +34,9 @@
#include "config.h"
#include "http_parser.h"
-enum rspamd_http_message_type {
- RSPAMD_HTTP_REQUEST,
- RSPAMD_HTTP_REPLY
+enum rspamd_http_connection_type {
+ RSPAMD_HTTP_SERVER,
+ RSPAMD_HTTP_CLIENT
};
/**
@@ -55,9 +55,10 @@ struct rspamd_http_message {
GString *url;
struct rspamd_http_header *headers;
GString *body;
- enum rspamd_http_message_type type;
+ enum http_parser_type type;
time_t date;
gint code;
+ enum http_method method;
};
@@ -71,65 +72,80 @@ enum rspamd_http_options {
struct rspamd_http_connection_private;
struct rspamd_http_connection;
-typedef gboolean (*rspamd_http_body_handler) (struct rspamd_http_connection *srv,
- struct rspamd_http_message *req,
+typedef gboolean (*rspamd_http_body_handler) (struct rspamd_http_connection *conn,
+ struct rspamd_http_message *msg,
const gchar *chunk,
gsize len);
-typedef void (*rspamd_http_error_handler) (struct rspamd_http_connection *srv, GError *err);
+typedef void (*rspamd_http_error_handler) (struct rspamd_http_connection *conn, GError *err);
-typedef void (*rspamd_http_reply_handler) (struct rspamd_http_connection *srv,
- struct rspamd_http_message *reply, GError *err);
+typedef void (*rspamd_http_finish_handler) (struct rspamd_http_connection *conn,
+ struct rspamd_http_message *msg);
/**
- * HTTP conn structure
+ * HTTP connection structure
*/
struct rspamd_http_connection {
- gint fd;
struct rspamd_http_connection_private *priv;
- enum rspamd_http_options opts;
rspamd_http_body_handler body_handler;
rspamd_http_error_handler error_handler;
+ rspamd_http_finish_handler finish_handler;
gpointer ud;
+ enum rspamd_http_options opts;
+ enum rspamd_http_connection_type type;
+ gint fd;
};
/**
- * Create new http conn
+ * Create new http connection
* @param handler handler for body
* @param opts options
- * @return new conn structure
+ * @return new connection structure
*/
-struct rspamd_http_connection* rspamd_http_connection_new (rspamd_http_body_handler body_handler,
+struct rspamd_http_connection* rspamd_http_connection_new (
+ rspamd_http_body_handler body_handler,
rspamd_http_error_handler error_handler,
- enum rspamd_http_options opts);
+ rspamd_http_finish_handler finish_handler,
+ enum rspamd_http_options opts,
+ enum rspamd_http_connection_type type);
/**
* Handle a request using socket fd and user data ud
- * @param conn conn structure
+ * @param conn connection structure
* @param ud opaque user data
* @param fd fd to read/write
*/
-void rspamd_http_connection_handle_request (struct rspamd_http_connection *conn, gpointer ud, gint fd,
- struct timeval *timeout, struct event_base *base);
+void rspamd_http_connection_read_message (
+ struct rspamd_http_connection *conn,
+ gpointer ud,
+ gint fd,
+ struct timeval *timeout,
+ struct event_base *base);
/**
- * Send reply using initialised conn
- * @param conn conn structure
- * @param reply HTTP reply
- * @return TRUE if request can be sent
+ * Send reply using initialised connection
+ * @param conn connection structure
+ * @param msg HTTP message
+ * @param ud opaque user data
+ * @param fd fd to read/write
*/
-gboolean rspamd_http_connection_write_reply (struct rspamd_http_connection *conn,
- struct rspamd_http_message *reply,
- rspamd_http_reply_handler *handler);
+void rspamd_http_connection_write_message (
+ struct rspamd_http_connection *conn,
+ struct rspamd_http_message *msg,
+ const gchar *host,
+ gpointer ud,
+ gint fd,
+ struct timeval *timeout,
+ struct event_base *base);
/**
- * Free conn structure
+ * Free connection structure
* @param conn
*/
void rspamd_http_connection_free (struct rspamd_http_connection *conn);
/**
- * Reset conn for a new request
+ * Reset connection for a new request
* @param conn
*/
void rspamd_http_connection_reset (struct rspamd_http_connection *conn);
@@ -139,7 +155,7 @@ void rspamd_http_connection_reset (struct rspamd_http_connection *conn);
* @param code code to pass
* @return new reply object
*/
-struct rspamd_http_message* rspamd_http_new_message (enum rspamd_http_message_type);
+struct rspamd_http_message* rspamd_http_new_message (enum http_parser_type type);
/**
* Append a header to reply