diff options
-rw-r--r-- | src/cfg_utils.c | 2 | ||||
-rw-r--r-- | src/http.c | 735 | ||||
-rw-r--r-- | src/http.h | 74 |
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 |