Browse Source

Reorganize HTTP library.

tags/0.6.7
Vsevolod Stakhov 10 years ago
parent
commit
49b2e92d1a
2 changed files with 105 additions and 112 deletions
  1. 67
    76
      src/http.c
  2. 38
    36
      src/http.h

+ 67
- 76
src/http.c View File

@@ -25,7 +25,7 @@
#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;
@@ -35,7 +35,7 @@ struct rspamd_http_server_private {
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 ()
@@ -46,7 +46,7 @@ http_error_quark (void)
}

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,
@@ -57,10 +57,10 @@ rspamd_http_check_date (struct rspamd_http_server_private *priv)
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);

@@ -70,10 +70,10 @@ rspamd_http_on_url (http_parser* parser, const gchar *at, size_t 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));
@@ -97,10 +97,10 @@ rspamd_http_on_header_field (http_parser* parser, const gchar *at, size_t length
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 */
@@ -116,10 +116,10 @@ rspamd_http_on_header_value (http_parser* parser, const gchar *at, size_t length
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);
@@ -129,7 +129,7 @@ rspamd_http_on_headers_complete (http_parser* parser)

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);
@@ -141,10 +141,15 @@ rspamd_http_on_headers_complete (http_parser* parser)
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;
@@ -153,17 +158,17 @@ rspamd_http_on_body (http_parser* parser, const gchar *at, size_t length)
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;
@@ -172,62 +177,48 @@ rspamd_http_on_message_complete (http_parser* parser)
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;
@@ -243,13 +234,13 @@ rspamd_http_server_new (rspamd_http_body_handler body_handler,
}

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 */
@@ -261,7 +252,7 @@ rspamd_http_server_reset (struct rspamd_http_server *server)
}
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;
}

@@ -272,33 +263,33 @@ rspamd_http_server_reset (struct rspamd_http_server *server)
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;
@@ -316,7 +307,7 @@ rspamd_http_server_handle_request (struct rspamd_http_server *server,
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);
}

+ 38
- 36
src/http.h View File

@@ -27,13 +27,18 @@
/**
* @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
*/
@@ -44,48 +49,44 @@ struct rspamd_http_header {
};

/**
* 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;
@@ -93,51 +94,52 @@ struct rspamd_http_server {
};

/**
* 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
@@ -145,13 +147,13 @@ struct rspamd_http_reply * rspamd_http_new_reply (gint code);
* @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

Loading…
Cancel
Save