#include "http.h"
#include "utlist.h"
-struct rspamd_http_server_private {
+struct rspamd_http_connection_private {
GString *buf;
gboolean new_header;
struct rspamd_http_header *header;
struct timeval tv;
struct timeval *ptv;
gboolean in_body;
- struct rspamd_http_request *req;
+ struct rspamd_http_message *req;
};
#define HTTP_ERROR http_error_quark ()
}
static inline void
-rspamd_http_check_date (struct rspamd_http_server_private *priv)
+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,
static gint
rspamd_http_on_url (http_parser* parser, const gchar *at, size_t length)
{
- struct rspamd_http_server *serv = (struct rspamd_http_server *)parser->data;
- struct rspamd_http_server_private *priv;
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
- priv = serv->priv;
+ priv = conn->priv;
g_string_append_len (priv->req->url, at, length);
static gint
rspamd_http_on_header_field (http_parser* parser, const gchar *at, size_t length)
{
- struct rspamd_http_server *serv = (struct rspamd_http_server *)parser->data;
- struct rspamd_http_server_private *priv;
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
- priv = serv->priv;
+ priv = conn->priv;
if (priv->header == NULL) {
priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
static gint
rspamd_http_on_header_value (http_parser* parser, const gchar *at, size_t length)
{
- struct rspamd_http_server *serv = (struct rspamd_http_server *)parser->data;
- struct rspamd_http_server_private *priv;
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
- priv = serv->priv;
+ priv = conn->priv;
if (priv->header == NULL) {
/* Should not happen */
static int
rspamd_http_on_headers_complete (http_parser* parser)
{
- struct rspamd_http_server *serv = (struct rspamd_http_server *)parser->data;
- struct rspamd_http_server_private *priv;
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
- priv = serv->priv;
+ priv = conn->priv;
if (priv->header != NULL) {
LL_PREPEND (priv->req->headers, priv->header);
priv->in_body = TRUE;
if (parser->content_length != 0 && parser->content_length != ULLONG_MAX) {
- priv->req->body = g_string_sized_new (parser->content_length);
+ priv->req->body = g_string_sized_new (parser->content_length + 1);
}
else {
priv->req->body = g_string_sized_new (BUFSIZ);
static int
rspamd_http_on_body (http_parser* parser, const gchar *at, size_t length)
{
- struct rspamd_http_server *serv = (struct rspamd_http_server *)parser->data;
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
- if (serv->opts & RSPAMD_HTTP_BODY_PARTIAL) {
- return (serv->body_handler (serv, serv->priv->req, at, length));
+ 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_server *serv = (struct rspamd_http_server *)parser->data;
- struct rspamd_http_server_private *priv;
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)parser->data;
+ struct rspamd_http_connection_private *priv;
int ret;
- priv = serv->priv;
+ priv = conn->priv;
- if (serv->opts & RSPAMD_HTTP_BODY_PARTIAL) {
- ret = serv->body_handler (serv, priv->req, NULL, 0);
+ if (conn->opts & RSPAMD_HTTP_BODY_PARTIAL) {
+ ret = conn->body_handler (conn, priv->req, NULL, 0);
}
else {
- ret = serv->body_handler (serv, priv->req, priv->req->body->str, priv->req->body->len);
+ 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_server *serv = (struct rspamd_http_server *)ud;
- struct rspamd_http_server_private *priv;
+ struct rspamd_http_connection *conn = (struct rspamd_http_connection *)ud;
+ struct rspamd_http_connection_private *priv;
GString *buf;
- gchar *start;
gssize r;
- gint64 remain;
GError *err;
- priv = serv->priv;
- if (priv->in_body) {
- buf = priv->req->body;
- }
- else {
- priv->buf->len = 0;
- buf = priv->buf;
- }
+ priv = conn->priv;
+ buf = priv->buf;
- remain = buf->allocated_len - buf->len;
- if (remain <= 0) {
- /* Expand string */
- g_string_set_size (buf, buf->allocated_len * 2);
- remain = buf->allocated_len - buf->len;
- }
- start = buf->str + buf->len;
- r = read (fd, start, remain);
+ r = read (fd, buf->str, buf->allocated_len);
if (r == -1) {
err = g_error_new (HTTP_ERROR, errno, "IO read error: %s", strerror (errno));
- serv->error_handler (serv, err);
+ conn->error_handler (conn, err);
g_error_free (err);
}
else {
- buf->len += r;
- if (http_parser_execute (&priv->parser, &priv->parser_cb, start, r) != (size_t)r) {
+ 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));
- serv->error_handler (serv, err);
+ conn->error_handler (conn, err);
g_error_free (err);
}
+ /* TODO: handle EOF */
}
}
-struct rspamd_http_server*
-rspamd_http_server_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)
{
- struct rspamd_http_server *new;
- struct rspamd_http_server_private *priv;
+ struct rspamd_http_connection *new;
+ struct rspamd_http_connection_private *priv;
- new = g_slice_alloc0 (sizeof (struct rspamd_http_server));
+ 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_server_private));
+ 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;
}
void
-rspamd_http_server_reset (struct rspamd_http_server *server)
+rspamd_http_connection_reset (struct rspamd_http_connection *conn)
{
- struct rspamd_http_server_private *priv;
- struct rspamd_http_request *req;
+ struct rspamd_http_connection_private *priv;
+ struct rspamd_http_message *req;
struct rspamd_http_header *hdr, *tmp_hdr;
- priv = server->priv;
+ priv = conn->priv;
req = priv->req;
/* Clear request */
}
g_string_free (req->body, TRUE);
g_string_free (req->url, TRUE);
- g_slice_free1 (sizeof (struct rspamd_http_request), req);
+ g_slice_free1 (sizeof (struct rspamd_http_message), req);
priv->req = NULL;
}
priv->buf = NULL;
}
- /* Clear server itself */
- if (server->fd != -1) {
- close (server->fd);
+ /* Clear conn itself */
+ if (conn->fd != -1) {
+ close (conn->fd);
}
}
void
-rspamd_http_server_free (struct rspamd_http_server *server)
+rspamd_http_connection_free (struct rspamd_http_connection *conn)
{
- struct rspamd_http_server_private *priv;
+ struct rspamd_http_connection_private *priv;
- priv = server->priv;
- rspamd_http_server_reset (server);
- g_slice_free1 (sizeof (struct rspamd_http_server_private), priv);
- g_slice_free1 (sizeof (struct rspamd_http_server), server);
+ 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_server_handle_request (struct rspamd_http_server *server,
+rspamd_http_connection_handle_request (struct rspamd_http_connection *conn,
gpointer ud, gint fd, struct timeval *timeout, struct event_base *base)
{
- struct rspamd_http_server_private *priv = server->priv;
- struct rspamd_http_request *req;
+ struct rspamd_http_connection_private *priv = conn->priv;
+ struct rspamd_http_message *req;
- server->fd = fd;
- server->ud = ud;
- req = g_slice_alloc (sizeof (struct rspamd_http_request));
+ 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->in_body = FALSE;
priv->new_header = TRUE;
- event_set (&priv->ev, fd, EV_READ | EV_PERSIST, rspamd_http_event_handler, server);
+ 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);
}
/**
* @file http.h
*
- * This is an interface for HTTP client and server. This code uses HTTP parser written
+ * This is an interface for HTTP client and conn. This code uses HTTP parser written
* by Joyent Inc based on nginx code.
*/
#include "config.h"
#include "http_parser.h"
+enum rspamd_http_message_type {
+ RSPAMD_HTTP_REQUEST,
+ RSPAMD_HTTP_REPLY
+};
+
/**
* HTTP header structure
*/
};
/**
- * HTTP request structure, used for requests
+ * HTTP message structure, used for requests and replies
*/
-struct rspamd_http_request {
+struct rspamd_http_message {
GString *url;
struct rspamd_http_header *headers;
GString *body;
+ enum rspamd_http_message_type type;
time_t date;
gint code;
};
-struct rspamd_http_reply {
- struct rspamd_http_header *headers;
- GString *body;
- gint code;
-};
/**
- * Options for HTTP client and server
+ * Options for HTTP connection
*/
enum rspamd_http_options {
RSPAMD_HTTP_BODY_PARTIAL = 0x1//!< RSPAMD_HTTP_BODY_PARTIAL
};
-struct rspamd_http_server_private;
-struct rspamd_http_server;
+struct rspamd_http_connection_private;
+struct rspamd_http_connection;
-typedef gboolean (*rspamd_http_body_handler) (struct rspamd_http_server *srv,
- struct rspamd_http_request *req,
+typedef gboolean (*rspamd_http_body_handler) (struct rspamd_http_connection *srv,
+ struct rspamd_http_message *req,
const gchar *chunk,
gsize len);
-typedef void (*rspamd_http_error_handler) (struct rspamd_http_server *srv, GError *err);
+typedef void (*rspamd_http_error_handler) (struct rspamd_http_connection *srv, GError *err);
-typedef void (*rspamd_http_reply_handler) (struct rspamd_http_server *srv,
- struct rspamd_http_reply *reply, GError *err);
+typedef void (*rspamd_http_reply_handler) (struct rspamd_http_connection *srv,
+ struct rspamd_http_message *reply, GError *err);
/**
- * HTTP server structure
+ * HTTP conn structure
*/
-struct rspamd_http_server {
+struct rspamd_http_connection {
gint fd;
- struct rspamd_http_server_private *priv;
+ struct rspamd_http_connection_private *priv;
enum rspamd_http_options opts;
rspamd_http_body_handler body_handler;
rspamd_http_error_handler error_handler;
};
/**
- * Create new http server
+ * Create new http conn
* @param handler handler for body
* @param opts options
- * @return new server structure
+ * @return new conn structure
*/
-struct rspamd_http_server* rspamd_http_server_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);
/**
* Handle a request using socket fd and user data ud
- * @param server server structure
+ * @param conn conn structure
* @param ud opaque user data
* @param fd fd to read/write
*/
-void rspamd_http_server_handle_request (struct rspamd_http_server *server, gpointer ud, gint fd,
+void rspamd_http_connection_handle_request (struct rspamd_http_connection *conn, gpointer ud, gint fd,
struct timeval *timeout, struct event_base *base);
/**
- * Send reply using initialised server
- * @param server server structure
+ * Send reply using initialised conn
+ * @param conn conn structure
* @param reply HTTP reply
* @return TRUE if request can be sent
*/
-gboolean rspamd_http_server_write_reply (struct rspamd_http_server *server, struct rspamd_http_reply *reply,
+gboolean rspamd_http_connection_write_reply (struct rspamd_http_connection *conn,
+ struct rspamd_http_message *reply,
rspamd_http_reply_handler *handler);
/**
- * Free server structure
- * @param server
+ * Free conn structure
+ * @param conn
*/
-void rspamd_http_server_free (struct rspamd_http_server *server);
+void rspamd_http_connection_free (struct rspamd_http_connection *conn);
/**
- * Reset server for a new request
- * @param server
+ * Reset conn for a new request
+ * @param conn
*/
-void rspamd_http_server_reset (struct rspamd_http_server *server);
+void rspamd_http_connection_reset (struct rspamd_http_connection *conn);
/**
* Create new HTTP reply
* @param code code to pass
* @return new reply object
*/
-struct rspamd_http_reply * rspamd_http_new_reply (gint code);
+struct rspamd_http_message* rspamd_http_new_message (enum rspamd_http_message_type);
/**
* Append a header to reply
* @param name
* @param value
*/
-void rspamd_http_reply_add_header (struct rspamd_http_reply *rep, const gchar *name, const gchar *value);
+void rspamd_http_message_add_header (struct rspamd_http_message *rep, const gchar *name, const gchar *value);
/**
* Free HTTP reply
* @param rep
*/
-void rspamd_http_reply_free (struct rspamd_http_reply *rep);
+void rspamd_http_message_free (struct rspamd_http_message *msg);
/**
* Parse HTTP date header and return it as time_t