#include "util.h"
#include "printf.h"
#include "logger.h"
+#include "ref.h"
#include <limits.h>
struct rspamd_http_connection_private {
- GString *buf;
+ struct _rspamd_http_privbuf {
+ GString *data;
+ ref_entry_t ref;
+ } *buf;
gboolean new_header;
struct rspamd_http_header *header;
struct http_parser parser;
return g_quark_from_static_string ("http-error-quark");
}
+static void
+rspamd_http_privbuf_dtor (gpointer ud)
+{
+ struct _rspamd_http_privbuf *p = (struct _rspamd_http_privbuf *)ud;
+
+ if (p->data) {
+ g_string_free (p->data, TRUE);
+ }
+ g_slice_free1 (sizeof (struct _rspamd_http_privbuf), p);
+}
+
static const gchar *
rspamd_http_code_to_str (gint code)
{
{
struct rspamd_http_connection *conn = (struct rspamd_http_connection *)ud;
struct rspamd_http_connection_private *priv;
+ struct _rspamd_http_privbuf *pbuf;
GString *buf;
gssize r;
GError *err;
priv = conn->priv;
- buf = priv->buf;
+ pbuf = priv->buf;
+ REF_RETAIN (pbuf);
+ rspamd_http_connection_ref (conn);
+ buf = priv->buf->data;
if (what == EV_READ) {
r = read (fd, buf->str, buf->allocated_len);
strerror (errno));
conn->error_handler (conn, err);
g_error_free (err);
+
+ REF_RELEASE (pbuf);
+ rspamd_http_connection_unref (conn);
+
return;
}
else if (r == 0) {
if (conn->finished) {
+ REF_RELEASE (pbuf);
rspamd_http_connection_unref (conn);
return;
}
"IO read error: unexpected EOF");
conn->error_handler (conn, err);
g_error_free (err);
+
+ REF_RELEASE (pbuf);
+ rspamd_http_connection_unref (conn);
+
return;
}
}
else {
buf->len = r;
- rspamd_http_connection_ref (conn);
+
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_errno_description (priv->parser.http_errno));
conn->error_handler (conn, err);
g_error_free (err);
+
+ REF_RELEASE (pbuf);
rspamd_http_connection_unref (conn);
+
return;
}
- rspamd_http_connection_unref (conn);
}
}
else if (what == EV_TIMEOUT) {
"IO timeout");
rspamd_http_connection_ref (conn);
conn->error_handler (conn, err);
- rspamd_http_connection_unref (conn);
g_error_free (err);
+
+ REF_RELEASE (pbuf);
+ rspamd_http_connection_unref (conn);
+
return;
}
else if (what == EV_WRITE) {
rspamd_http_write_helper (conn);
}
+
+ REF_RELEASE (pbuf);
+ rspamd_http_connection_unref (conn);
}
static void
/* Clear priv */
event_del (&priv->ev);
if (priv->buf != NULL) {
- g_string_free (priv->buf, TRUE);
- priv->buf = NULL;
+ REF_RELEASE (priv->buf);
}
rspamd_http_parser_reset (conn);
priv->ptv = &priv->tv;
}
priv->header = NULL;
- priv->buf = g_string_sized_new (BUFSIZ);
+ priv->buf = g_slice_alloc0 (sizeof (*priv->buf));
+ REF_INIT_RETAIN (priv->buf, rspamd_http_privbuf_dtor);
+ priv->buf->data = g_string_sized_new (BUFSIZ);
priv->new_header = TRUE;
event_set (&priv->ev,
gchar datebuf[64], *pbody;
gint i;
gsize bodylen;
+ GString *buf;
conn->fd = fd;
conn->ud = ud;
priv->ptv = &priv->tv;
}
priv->header = NULL;
- priv->buf = g_string_sized_new (128);
+ priv->buf = g_slice_alloc0 (sizeof (*priv->buf));
+ REF_INIT_RETAIN (priv->buf, rspamd_http_privbuf_dtor);
+ priv->buf->data = g_string_sized_new (128);
+ buf = priv->buf->data;
if (msg->method < HTTP_SYMBOLS) {
if (msg->body == NULL || msg->body->len == 0) {
if (mime_type == NULL) {
mime_type = "text/plain";
}
- rspamd_printf_gstring (priv->buf, "HTTP/1.1 %d %s\r\n"
+ rspamd_printf_gstring (buf, "HTTP/1.1 %d %s\r\n"
"Connection: close\r\n"
"Server: %s\r\n"
"Date: %s\r\n"
}
else {
/* Legacy spamd reply */
- rspamd_printf_gstring (priv->buf, "RSPAMD/1.3 0 EX_OK\r\n");
+ rspamd_printf_gstring (buf, "RSPAMD/1.3 0 EX_OK\r\n");
}
}
else {
/* Format request */
if (host == NULL && msg->host == NULL) {
/* Fallback to HTTP/1.0 */
- rspamd_printf_gstring (priv->buf, "%s %v HTTP/1.0\r\n"
+ rspamd_printf_gstring (buf, "%s %v HTTP/1.0\r\n"
"Content-Length: %z\r\n",
http_method_str (msg->method), msg->url, bodylen);
}
else {
- rspamd_printf_gstring (priv->buf, "%s %v HTTP/1.1\r\n"
+ rspamd_printf_gstring (buf, "%s %v HTTP/1.1\r\n"
"Connection: close\r\n"
"Host: %s\r\n"
"Content-Length: %z\r\n",
}
}
/* Allocate iov */
- priv->wr_total = bodylen + priv->buf->len + 2;
+ priv->wr_total = bodylen + buf->len + 2;
DL_FOREACH (msg->headers, hdr)
{
/* <name><: ><value><\r\n> */
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;
+ priv->out[0].iov_base = buf->str;
+ priv->out[0].iov_len = buf->len;
i = 1;
LL_FOREACH (msg->headers, hdr)
{
} ref_entry_t;
#define REF_INIT(obj, dtor_cb) do { \
+ if ((obj) != NULL) { \
(obj)->ref.refcount = 0; \
(obj)->ref.dtor = (ref_dtor_cb_t)(dtor_cb); \
+ } \
} while (0)
#define REF_INIT_RETAIN(obj, dtor_cb) do { \
+ if ((obj) != NULL) { \
(obj)->ref.refcount = 1; \
(obj)->ref.dtor = (ref_dtor_cb_t)(dtor_cb); \
+ } \
} while (0)
#ifdef HAVE_ATOMIC_BUILTINS
#define REF_RETAIN(obj) do { \
+ if ((obj) != NULL) { \
__sync_add_and_fetch (&(obj)->ref.refcount, 1); \
+ } \
} while (0)
#define REF_RELEASE(obj) do { \
- unsigned int rc = __sync_sub_and_fetch (&(obj)->ref.refcount, 1); \
- if (rc == 0 && (obj)->ref.dtor) { \
+ if ((obj) != NULL) { \
+ unsigned int _rc_priv = __sync_sub_and_fetch (&(obj)->ref.refcount, 1); \
+ if (_rc_priv == 0 && (obj)->ref.dtor) { \
(obj)->ref.dtor (obj); \
} \
+ } \
} while (0)
#else
#define REF_RETAIN(obj) do { \
+ if ((obj) != NULL) { \
(obj)->ref.refcount ++; \
+ } \
} while (0)
#define REF_RELEASE(obj) do { \
+ if ((obj) != NULL) { \
if (--(obj)->ref.refcount == 0 && (obj)->ref.dtor) { \
(obj)->ref.dtor (obj); \
} \
+ } \
} while (0)
#endif
msg_info ("abnormally closing connection from: %s, error: %s",
rspamd_inet_address_to_string (&task->client_addr), err->message);
- if (task->state != CLOSING_CONNECTION && task->state != WRITING_REPLY) {
+ if (task->state != WRITING_REPLY && task->state != CLOSING_CONNECTION) {
/* We still need to write a reply */
task->error_code = err->code;
task->last_error =
{
struct rspamd_task *task = (struct rspamd_task *) conn->ud;
- if (task->state == CLOSING_CONNECTION) {
+ if (msg->type == HTTP_RESPONSE) {
+ /* We are done here */
msg_debug ("normally closing connection from: %s",
rspamd_inet_address_to_string (&task->client_addr));
destroy_session (task->s);
}
- else if (task->state != WRITING_REPLY) {
+ else {
/*
* If all filters have finished their tasks, this function will trigger
* writing a reply.
task->s->wanna_die = TRUE;
check_session_pending (task->s);
}
- else {
- /*
- * We are going to write a reply to a client
- */
- task->state = CLOSING_CONNECTION;
- }
return 0;
}