aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libutil/http.c442
-rw-r--r--src/libutil/http.h25
2 files changed, 270 insertions, 197 deletions
diff --git a/src/libutil/http.c b/src/libutil/http.c
index f1a1dac75..e476c3111 100644
--- a/src/libutil/http.c
+++ b/src/libutil/http.c
@@ -36,11 +36,13 @@
#define ENCRYPTED_VERSION " HTTP/1.0"
+struct _rspamd_http_privbuf {
+ rspamd_fstring_t *data;
+ ref_entry_t ref;
+};
+
struct rspamd_http_connection_private {
- struct _rspamd_http_privbuf {
- GString *data;
- ref_entry_t ref;
- } *buf;
+ struct _rspamd_http_privbuf *buf;
gboolean new_header;
gboolean encrypted;
gpointer peer_key;
@@ -82,8 +84,14 @@ static const struct _rspamd_http_magic {
static const gchar *http_week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
static const gchar *http_month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-static const gchar *key_header = "Key";
-static const gchar *date_header = "Date";
+static const rspamd_ftok_t key_header = {
+ .begin = "Key",
+ .len = 3
+};
+static const rspamd_ftok_t date_header = {
+ .begin = "Date",
+ .len = 4
+};
#define RSPAMD_HTTP_KEY_ID_LEN 5
@@ -108,8 +116,9 @@ 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);
+ rspamd_fstring_free (p->data);
}
+
g_slice_free1 (sizeof (struct _rspamd_http_privbuf), p);
}
@@ -407,7 +416,7 @@ rspamd_http_parse_date (const gchar *header, gsize len)
}
static void
-rspamd_http_parse_key (GString *data, struct rspamd_http_connection *conn,
+rspamd_http_parse_key (rspamd_ftok_t *data, struct rspamd_http_connection *conn,
struct rspamd_http_connection_private *priv)
{
guchar *decoded_id, *decoded_key;
@@ -421,11 +430,11 @@ rspamd_http_parse_key (GString *data, struct rspamd_http_connection *conn,
}
else {
/* Check sanity of what we have */
- eq_pos = memchr (data->str, '=', data->len);
+ eq_pos = memchr (data->begin, '=', data->len);
if (eq_pos != NULL) {
- decoded_id = rspamd_decode_base32 (data->str, eq_pos - data->str,
+ decoded_id = rspamd_decode_base32 (data->begin, eq_pos - data->begin,
&id_len);
- decoded_key = rspamd_decode_base32 (eq_pos + 1, data->str + data->len -
+ decoded_key = rspamd_decode_base32 (eq_pos + 1, data->begin + data->len -
eq_pos - 1, &key_len);
if (decoded_id != NULL && decoded_key != NULL) {
if (id_len >= RSPAMD_HTTP_KEY_ID_LEN &&
@@ -455,13 +464,11 @@ static inline void
rspamd_http_check_special_header (struct rspamd_http_connection *conn,
struct rspamd_http_connection_private *priv)
{
- if (g_ascii_strncasecmp (priv->header->name->str, date_header,
- priv->header->name->len) == 0) {
- priv->msg->date = rspamd_http_parse_date (priv->header->value->str,
+ if (rspamd_ftok_casecmp (priv->header->name, &date_header) == 0) {
+ priv->msg->date = rspamd_http_parse_date (priv->header->value->begin,
priv->header->value->len);
}
- else if (g_ascii_strncasecmp (priv->header->name->str, key_header,
- priv->header->name->len) == 0) {
+ else if (rspamd_ftok_casecmp (priv->header->name, &key_header) == 0) {
rspamd_http_parse_key (priv->header->value, conn, priv);
}
}
@@ -475,7 +482,7 @@ rspamd_http_on_url (http_parser * parser, const gchar *at, size_t length)
priv = conn->priv;
- g_string_append_len (priv->msg->url, at, length);
+ priv->msg->url = rspamd_fstring_append (priv->msg->url, at, length);
return 0;
}
@@ -491,14 +498,39 @@ rspamd_http_on_status (http_parser * parser, const gchar *at, size_t length)
if (parser->status_code != 200) {
if (priv->msg->status == NULL) {
- priv->msg->status = g_string_sized_new (128);
+ priv->msg->status = rspamd_fstring_new ();
}
- g_string_append_len (priv->msg->status, at, length);
+
+ priv->msg->status = rspamd_fstring_append (priv->msg->status, at, length);
}
return 0;
}
+static void
+rspamd_http_finish_header (struct rspamd_http_connection *conn,
+ struct rspamd_http_connection_private *priv)
+{
+ priv->header->combined = rspamd_fstring_append (priv->header->combined,
+ "\r\n", 2);
+ priv->header->value->len = priv->header->combined->len -
+ priv->header->name->len - 4;
+ priv->header->value->begin = priv->header->combined->str +
+ priv->header->name->len + 2;
+ DL_APPEND (priv->msg->headers, priv->header);
+
+ rspamd_http_check_special_header (conn, priv);
+}
+
+static void
+rspamd_http_init_header (struct rspamd_http_connection_private *priv)
+{
+ priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
+ priv->header->name = g_slice_alloc0 (sizeof (*priv->header->name));
+ priv->header->value = g_slice_alloc0 (sizeof (*priv->header->value));
+ priv->header->combined = rspamd_fstring_new ();
+}
+
static gint
rspamd_http_on_header_field (http_parser * parser,
const gchar *at,
@@ -511,27 +543,16 @@ rspamd_http_on_header_field (http_parser * parser,
priv = conn->priv;
if (priv->header == NULL) {
- priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
- priv->header->name = g_slice_alloc0 (sizeof (GString));
- priv->header->value = g_slice_alloc0 (sizeof (GString));
- priv->header->combined = g_string_sized_new (64);
+ rspamd_http_init_header (priv);
}
else if (priv->new_header) {
- g_string_append_len (priv->header->combined, "\r\n", 2);
- priv->header->value->len = priv->header->combined->len -
- priv->header->name->len - 4;
- priv->header->value->str = priv->header->combined->str +
- priv->header->name->len + 2;
- DL_APPEND (priv->msg->headers, priv->header);
- rspamd_http_check_special_header (conn, priv);
- priv->header = g_slice_alloc (sizeof (struct rspamd_http_header));
- priv->header->name = g_slice_alloc0 (sizeof (GString));
- priv->header->value = g_slice_alloc0 (sizeof (GString));
- priv->header->combined = g_string_sized_new (64);
+ rspamd_http_finish_header (conn, priv);
+ rspamd_http_init_header (priv);
}
priv->new_header = FALSE;
- g_string_append_len (priv->header->combined, at, length);
+ priv->header->combined = rspamd_fstring_append (priv->header->combined,
+ at, length);
return 0;
}
@@ -554,12 +575,14 @@ rspamd_http_on_header_value (http_parser * parser,
if (!priv->new_header) {
priv->new_header = TRUE;
- g_string_append_len (priv->header->combined, ": ", 2);
- priv->header->name->str = priv->header->combined->str;
+ priv->header->combined = rspamd_fstring_append (priv->header->combined,
+ ": ", 2);
+ priv->header->name->begin = priv->header->combined->str;
priv->header->name->len = priv->header->combined->len - 2;
}
- g_string_append_len (priv->header->combined, at, length);
+ priv->header->combined = rspamd_fstring_append (priv->header->combined,
+ at, length);
return 0;
}
@@ -574,29 +597,24 @@ rspamd_http_on_headers_complete (http_parser * parser)
priv = conn->priv;
if (priv->header != NULL) {
- g_string_append_len (priv->header->combined, "\r\n", 2);
- priv->header->value->str = priv->header->combined->str +
- priv->header->name->len + 2;
- priv->header->value->len = priv->header->combined->len -
- priv->header->name->len - 4;
- DL_APPEND (priv->msg->headers, priv->header);
- rspamd_http_check_special_header (conn, priv);
+ rspamd_http_finish_header (conn, priv);
+
priv->header = NULL;
priv->new_header = FALSE;
}
if (parser->content_length != 0 && parser->content_length != ULLONG_MAX) {
- priv->msg->body = g_string_sized_new (parser->content_length + 1);
+ priv->msg->body = rspamd_fstring_sized_new (parser->content_length + 1);
}
else {
- priv->msg->body = g_string_sized_new (BUFSIZ);
+ priv->msg->body = rspamd_fstring_new ();
}
if (parser->flags & F_SPAMC) {
priv->msg->flags |= RSPAMD_HTTP_FLAG_SPAMC;
}
- priv->msg->body_buf.str = priv->msg->body->str;
+ priv->msg->body_buf.begin = priv->msg->body->str;
priv->msg->method = parser->method;
priv->msg->code = parser->status_code;
@@ -612,12 +630,13 @@ rspamd_http_on_body (http_parser * parser, const gchar *at, size_t length)
priv = conn->priv;
- g_string_append_len (priv->msg->body, at, length);
+ priv->msg->body = rspamd_fstring_append (priv->msg->body, at, length);
+
/* Append might cause realloc */
- priv->msg->body_buf.str = priv->msg->body->str;
+ priv->msg->body_buf.begin = priv->msg->body->str;
if ((conn->opts & RSPAMD_HTTP_BODY_PARTIAL) && !priv->encrypted) {
- /* Incremental update is basically impossible for encrypted requests */
+ /* Incremental update is impossible for encrypted requests so far */
return (conn->body_handler (conn, priv->msg, at, length));
}
@@ -634,23 +653,18 @@ rspamd_http_on_body_decrypted (http_parser * parser, const gchar *at, size_t len
priv = conn->priv;
if (priv->header != NULL) {
- g_string_append_len (priv->header->combined, "\r\n", 2);
- priv->header->value->str = priv->header->combined->str +
- priv->header->name->len + 2;
- priv->header->value->len = priv->header->combined->len -
- priv->header->name->len - 4;
- DL_APPEND (priv->msg->headers, priv->header);
- rspamd_http_check_special_header (conn, priv);
+ rspamd_http_finish_header (conn, priv);
priv->header = NULL;
}
- if (priv->msg->body->str == 0) {
- priv->msg->body->str = (gchar *)at;
+ if (priv->msg->body_buf.len == 0) {
+
+ priv->msg->body_buf.begin = at;
priv->msg->method = parser->method;
priv->msg->code = parser->status_code;
}
- priv->msg->body->len += length;
+ priv->msg->body_buf.len += length;
return 0;
}
@@ -691,17 +705,19 @@ rspamd_http_decrypt_message (struct rspamd_http_connection *conn,
/* Cleanup message */
DL_FOREACH_SAFE (msg->headers, hdr, hdrtmp) {
- g_string_free (hdr->combined, TRUE);
- g_slice_free1 (sizeof (GString), hdr->name);
- g_slice_free1 (sizeof (GString), hdr->value);
+ rspamd_fstring_free (hdr->combined);
+ g_slice_free1 (sizeof (*hdr->name), hdr->name);
+ g_slice_free1 (sizeof (*hdr->value), hdr->value);
g_slice_free1 (sizeof (struct rspamd_http_header), hdr);
}
+
msg->headers = NULL;
+
if (msg->url != NULL) {
- g_string_assign (msg->url, "");
+ msg->url = rspamd_fstring_assign (msg->url, "", 0);
}
- msg->body->len = 0;
- msg->body->str = NULL;
+
+ msg->body_buf.len = 0;
http_parser_init (&decrypted_parser,
conn->type == RSPAMD_HTTP_SERVER ? HTTP_REQUEST : HTTP_RESPONSE);
@@ -757,8 +773,8 @@ rspamd_http_on_message_complete (http_parser * parser)
rspamd_http_connection_ref (conn);
ret = conn->body_handler (conn,
priv->msg,
- priv->msg->body->str,
- priv->msg->body->len);
+ priv->msg->body_buf.begin,
+ priv->msg->body_buf.len);
rspamd_http_connection_unref (conn);
}
}
@@ -767,8 +783,8 @@ rspamd_http_on_message_complete (http_parser * parser)
rspamd_http_connection_ref (conn);
ret = conn->body_handler (conn,
priv->msg,
- priv->msg->body->str,
- priv->msg->body->len);
+ priv->msg->body_buf.begin,
+ priv->msg->body_buf.len);
rspamd_http_connection_unref (conn);
}
@@ -890,7 +906,7 @@ 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;
struct _rspamd_http_privbuf *pbuf;
- GString *buf;
+ rspamd_fstring_t *buf;
gssize r;
GError *err;
@@ -901,7 +917,7 @@ rspamd_http_event_handler (int fd, short what, gpointer ud)
buf = priv->buf->data;
if (what == EV_READ) {
- r = read (fd, buf->str, buf->allocated_len);
+ r = read (fd, buf->str, buf->allocated);
if (r == -1) {
err = g_error_new (HTTP_ERROR,
errno,
@@ -933,8 +949,8 @@ rspamd_http_event_handler (int fd, short what, gpointer ud)
else {
buf->len = r;
- if (http_parser_execute (&priv->parser, &priv->parser_cb, buf->str,
- r) != (size_t)r || priv->parser.http_errno != 0) {
+ if (http_parser_execute (&priv->parser, &priv->parser_cb,
+ buf->str, r) != (size_t)r || priv->parser.http_errno != 0) {
err = g_error_new (HTTP_ERROR, priv->parser.http_errno,
"HTTP parser error: %s",
http_errno_description (priv->parser.http_errno));
@@ -1038,9 +1054,11 @@ rspamd_http_connection_reset (struct rspamd_http_connection *conn)
rspamd_http_message_free (msg);
priv->msg = NULL;
}
+
conn->finished = FALSE;
/* Clear priv */
event_del (&priv->ev);
+
if (priv->buf != NULL) {
REF_RELEASE (priv->buf);
priv->buf = NULL;
@@ -1130,7 +1148,7 @@ rspamd_http_connection_read_message (struct rspamd_http_connection *conn,
priv->header = NULL;
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->buf->data = rspamd_fstring_sized_new (8192);
priv->new_header = TRUE;
event_set (&priv->ev,
@@ -1258,7 +1276,7 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
gchar datebuf[64], repbuf[512], *pbody;
gint i, hdrcount, meth_len, preludelen = 0;
gsize bodylen, enclen;
- GString *buf;
+ rspamd_fstring_t *buf;
gboolean encrypted = FALSE;
gchar *b32_key, *b32_id;
guchar nonce[rspamd_cryptobox_NONCEBYTES], mac[rspamd_cryptobox_MACBYTES],
@@ -1281,7 +1299,7 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
priv->header = NULL;
priv->buf = g_slice_alloc0 (sizeof (*priv->buf));
REF_INIT_RETAIN (priv->buf, rspamd_http_privbuf_dtor);
- priv->buf->data = g_string_sized_new (512);
+ priv->buf->data = rspamd_fstring_sized_new (512);
buf = priv->buf->data;
if (priv->peer_key && priv->local_key) {
@@ -1439,7 +1457,7 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
mime_type);
enclen += meth_len;
/* External reply */
- rspamd_printf_gstring (buf, "HTTP/1.1 200 OK\r\n"
+ rspamd_printf_fstring (&buf, "HTTP/1.1 200 OK\r\n"
"Connection: close\r\n"
"Server: rspamd\r\n"
"Date: %s\r\n"
@@ -1449,7 +1467,7 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
enclen);
}
else {
- rspamd_printf_gstring (buf, "HTTP/1.1 %d %s\r\n"
+ rspamd_printf_fstring (&buf, "HTTP/1.1 %d %s\r\n"
"Connection: close\r\n"
"Server: %s\r\n"
"Date: %s\r\n"
@@ -1467,10 +1485,10 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
else {
/* Legacy spamd reply */
if (msg->flags & RSPAMD_HTTP_FLAG_SPAMC) {
- rspamd_printf_gstring (buf, "SPAMD/1.1 0 EX_OK\r\n");
+ rspamd_printf_fstring (&buf, "SPAMD/1.1 0 EX_OK\r\n");
}
else {
- rspamd_printf_gstring (buf, "RSPAMD/1.3 0 EX_OK\r\n");
+ rspamd_printf_fstring (&buf, "RSPAMD/1.3 0 EX_OK\r\n");
}
}
}
@@ -1481,14 +1499,14 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
if (host == NULL && msg->host == NULL) {
/* Fallback to HTTP/1.0 */
if (encrypted) {
- rspamd_printf_gstring (buf, "%s %s HTTP/1.0\r\n"
+ rspamd_printf_fstring (&buf, "%s %s HTTP/1.0\r\n"
"Content-Length: %z\r\n",
"POST",
"/post",
enclen);
}
else {
- rspamd_printf_gstring (buf, "%s %s HTTP/1.0\r\n"
+ rspamd_printf_fstring (&buf, "%s %s HTTP/1.0\r\n"
"Content-Length: %z\r\n",
http_method_str (msg->method),
msg->url->str,
@@ -1497,24 +1515,48 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
}
else {
if (encrypted) {
- rspamd_printf_gstring (buf, "%s %s HTTP/1.1\r\n"
- "Connection: close\r\n"
- "Host: %s\r\n"
- "Content-Length: %z\r\n",
- "POST",
- "/post",
- host != NULL ? host : msg->host->str,
- enclen);
+ if (host != NULL) {
+ rspamd_printf_fstring (&buf, "%s %s HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "Host: %s\r\n"
+ "Content-Length: %z\r\n",
+ "POST",
+ "/post",
+ host,
+ enclen);
+ }
+ else {
+ rspamd_printf_fstring (&buf, "%s %s HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "Host: %V\r\n"
+ "Content-Length: %z\r\n",
+ "POST",
+ "/post",
+ msg->host,
+ enclen);
+ }
}
else {
- rspamd_printf_gstring (buf, "%s %s 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->str,
- host != NULL ? host : msg->host->str,
- bodylen);
+ if (host != NULL) {
+ rspamd_printf_fstring (&buf, "%s %s 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->str,
+ host,
+ bodylen);
+ }
+ else {
+ rspamd_printf_fstring (&buf, "%s %s HTTP/1.1\r\n"
+ "Connection: close\r\n"
+ "Host: %V\r\n"
+ "Content-Length: %z\r\n",
+ http_method_str (msg->method),
+ msg->url->str,
+ msg->host,
+ bodylen);
+ }
}
}
@@ -1524,16 +1566,12 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
sizeof (priv->local_key->pk));
b32_id = rspamd_encode_base32 (id, RSPAMD_HTTP_KEY_ID_LEN);
/* XXX: add some fuzz here */
- rspamd_printf_gstring (buf, "Key: %s=%s\r\n", b32_id, b32_key);
+ rspamd_printf_fstring (&buf, "Key: %s=%s\r\n", b32_id, b32_key);
g_free (b32_key);
g_free (b32_id);
}
}
- /* Now set up all iov */
- priv->out[0].iov_base = buf->str;
- priv->out[0].iov_len = buf->len;
-
if (encrypted) {
gint meth_offset, nonce_offset, mac_offset;
@@ -1542,26 +1580,26 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
meth_offset = buf->len;
if (conn->type == RSPAMD_HTTP_SERVER) {
- g_string_append_len (buf, repbuf, meth_len);
+ buf = rspamd_fstring_append (buf, repbuf, meth_len);
}
else {
meth_len = strlen (http_method_str (msg->method)) + 1; /* + space */
- g_string_append_len (buf, http_method_str (msg->method),
+ buf = rspamd_fstring_append (buf, http_method_str (msg->method),
meth_len - 1);
- g_string_append_c (buf, ' ');
+ buf = rspamd_fstring_append (buf, " ", 1);
}
nonce_offset = buf->len;
- g_string_append_len (buf, nonce, sizeof (nonce));
+ buf = rspamd_fstring_append (buf, nonce, sizeof (nonce));
mac_offset = buf->len;
- g_string_append_len (buf, mac, sizeof (mac));
+ buf = rspamd_fstring_append (buf, mac, sizeof (mac));
/* Need to be encrypted */
if (conn->type == RSPAMD_HTTP_SERVER) {
- g_string_append (buf, "\r\n\r\n");
+ buf = rspamd_fstring_append (buf, "\r\n\r\n", 4);
}
else {
- g_string_append_len (buf, repbuf, preludelen);
+ buf = rspamd_fstring_append (buf, repbuf, preludelen);
}
meth_pos = buf->str + meth_offset;
@@ -1569,6 +1607,12 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
mp = buf->str + mac_offset;
}
+ /* During previous writes, buf might be reallocated and changed */
+ priv->buf->data = buf;
+
+ /* Now set up all iov */
+ priv->out[0].iov_base = buf->str;
+ priv->out[0].iov_len = buf->len;
if (encrypted) {
/* Finish external HTTP request */
@@ -1595,9 +1639,10 @@ rspamd_http_connection_write_message (struct rspamd_http_connection *conn,
if (pbody != NULL) {
- if (msg->body_buf.str == NULL && msg->body_buf.len == 0) {
- msg->body_buf.str = msg->body->str;
+ if (msg->body_buf.begin == NULL && msg->body_buf.len == 0) {
+ msg->body_buf.begin = msg->body->str;
}
+
priv->out[i].iov_base = pbody;
priv->out[i++].iov_len = bodylen;
}
@@ -1623,12 +1668,13 @@ rspamd_http_new_message (enum http_parser_type type)
new = g_slice_alloc (sizeof (struct rspamd_http_message));
if (type == HTTP_REQUEST) {
- new->url = g_string_sized_new (32);
+ new->url = rspamd_fstring_new ();
}
else {
new->url = NULL;
new->code = 200;
}
+
new->headers = NULL;
new->date = 0;
new->body = NULL;
@@ -1686,8 +1732,8 @@ rspamd_http_message_from_url (const gchar *url)
msg->port = 80;
}
- msg->host = g_string_new_len (host, pu.field_data[UF_HOST].len);
- g_string_append_len (msg->url, path, pathlen);
+ msg->host = rspamd_fstring_new_init (host, pu.field_data[UF_HOST].len);
+ msg->host = rspamd_fstring_append (msg->url, path, pathlen);
return msg;
}
@@ -1699,27 +1745,27 @@ rspamd_http_message_free (struct rspamd_http_message *msg)
LL_FOREACH_SAFE (msg->headers, hdr, tmp_hdr)
{
- g_string_free (hdr->combined, TRUE);
- g_slice_free1 (sizeof (GString), hdr->name);
- g_slice_free1 (sizeof (GString), hdr->value);
+ rspamd_fstring_free (hdr->combined);
+ g_slice_free1 (sizeof (*hdr->name), hdr->name);
+ g_slice_free1 (sizeof (*hdr->name), hdr->value);
g_slice_free1 (sizeof (struct rspamd_http_header), hdr);
}
if (msg->body != NULL) {
- g_string_free (msg->body, FALSE);
- g_free (msg->body_buf.str);
+ rspamd_fstring_free (msg->body);
}
if (msg->url != NULL) {
- g_string_free (msg->url, TRUE);
+ rspamd_fstring_free (msg->url);
}
if (msg->status != NULL) {
- g_string_free (msg->status, TRUE);
+ rspamd_fstring_free (msg->status);
}
if (msg->host != NULL) {
- g_string_free (msg->host, TRUE);
+ rspamd_fstring_free (msg->host);
}
if (msg->peer_key != NULL) {
rspamd_http_connection_key_unref (msg->peer_key);
}
+
g_slice_free1 (sizeof (struct rspamd_http_message), msg);
}
@@ -1735,34 +1781,35 @@ rspamd_http_message_add_header (struct rspamd_http_message *msg,
hdr = g_slice_alloc (sizeof (struct rspamd_http_header));
nlen = strlen (name);
vlen = strlen (value);
- hdr->combined = g_string_sized_new (nlen + vlen + 4);
- rspamd_printf_gstring (hdr->combined, "%s: %s\r\n", name, value);
+ hdr->combined = rspamd_fstring_sized_new (nlen + vlen + 4);
+ rspamd_printf_fstring (&hdr->combined, "%s: %s\r\n", name, value);
hdr->value = g_slice_alloc (sizeof (GString));
hdr->name = g_slice_alloc (sizeof (GString));
- hdr->name->str = hdr->combined->str;
+ hdr->name->begin = hdr->combined->str;
hdr->name->len = nlen;
- hdr->value->str = hdr->combined->str + nlen + 2;
+ hdr->value->begin = hdr->combined->str + nlen + 2;
hdr->value->len = vlen;
DL_APPEND (msg->headers, hdr);
}
}
-const GString *
+const rspamd_ftok_t *
rspamd_http_message_find_header (struct rspamd_http_message *msg,
const gchar *name)
{
struct rspamd_http_header *hdr;
- const GString *res = NULL;
+ const rspamd_ftok_t *res = NULL;
+ rspamd_ftok_t cmp;
guint slen = strlen (name);
if (msg != NULL) {
- LL_FOREACH (msg->headers, hdr)
- {
- if (hdr->name->len == slen) {
- if (g_ascii_strncasecmp (hdr->name->str, name, slen) == 0) {
- res = hdr->value;
- break;
- }
+ cmp.begin = name;
+ cmp.len = slen;
+
+ LL_FOREACH (msg->headers, hdr) {
+ if (rspamd_ftok_casecmp (hdr->name, &cmp) == 0) {
+ res = hdr->value;
+ break;
}
}
}
@@ -1776,18 +1823,21 @@ gboolean rspamd_http_message_remove_header (struct rspamd_http_message *msg,
struct rspamd_http_header *hdr, *tmp;
gboolean res = FALSE;
guint slen = strlen (name);
+ rspamd_ftok_t cmp;
if (msg != NULL) {
+ cmp.begin = name;
+ cmp.len = slen;
+
DL_FOREACH_SAFE (msg->headers, hdr, tmp) {
- if (hdr->name->len == slen) {
- if (g_ascii_strncasecmp (hdr->name->str, name, slen) == 0) {
- res = TRUE;
- DL_DELETE (msg->headers, hdr);
- g_string_free (hdr->combined, TRUE);
- g_slice_free1 (sizeof (GString), hdr->value);
- g_slice_free1 (sizeof (GString), hdr->name);
- g_slice_free1 (sizeof (*hdr), hdr);
- }
+ if (rspamd_ftok_casecmp (hdr->name, &cmp) == 0) {
+ res = TRUE;
+ DL_DELETE (msg->headers, hdr);
+
+ rspamd_fstring_free (hdr->combined);
+ g_slice_free1 (sizeof (*hdr->value), hdr->value);
+ g_slice_free1 (sizeof (*hdr->name), hdr->name);
+ g_slice_free1 (sizeof (*hdr), hdr);
}
}
}
@@ -1836,7 +1886,7 @@ rspamd_http_router_error_handler (struct rspamd_http_connection *conn,
msg = rspamd_http_new_message (HTTP_RESPONSE);
msg->date = time (NULL);
msg->code = err->code;
- msg->body = g_string_new (err->message);
+ msg->body = rspamd_fstring_new_init (err->message, strlen (err->message));
rspamd_http_connection_reset (entry->conn);
rspamd_http_connection_write_message (entry->conn,
msg,
@@ -1896,14 +1946,14 @@ rspamd_http_router_is_subdir (const gchar *parent, const gchar *sub)
static gboolean
rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
- GString *lookup, gboolean expand_path)
+ rspamd_ftok_t *lookup, gboolean expand_path)
{
struct stat st;
gint fd;
gchar filebuf[PATH_MAX], realbuf[PATH_MAX], *dir;
struct rspamd_http_message *reply_msg;
- rspamd_snprintf (filebuf, sizeof (filebuf), "%s%c%v",
+ rspamd_snprintf (filebuf, sizeof (filebuf), "%s%c%T",
entry->rt->default_fs_path, G_DIR_SEPARATOR, lookup);
if (realpath (filebuf, realbuf) == NULL ||
@@ -1913,14 +1963,17 @@ rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
if (S_ISDIR (st.st_mode) && expand_path) {
/* Try to append 'index.html' to the url */
- GString *nlookup;
+ rspamd_fstring_t *nlookup;
+ rspamd_ftok_t tok;
gboolean ret;
- nlookup = g_string_sized_new (lookup->len + sizeof ("index.html") + 1);
- rspamd_printf_gstring (nlookup, "%v%c%s", lookup, G_DIR_SEPARATOR,
+ nlookup = rspamd_fstring_sized_new (lookup->len + sizeof ("index.html"));
+ rspamd_printf_fstring (&nlookup, "%T%c%s", lookup, G_DIR_SEPARATOR,
"index.html");
- ret = rspamd_http_router_try_file (entry, nlookup, FALSE);
- g_string_free (nlookup, TRUE);
+ tok.begin = nlookup->str;
+ tok.len = nlookup->len;
+ ret = rspamd_http_router_try_file (entry, &tok, FALSE);
+ rspamd_fstring_free (nlookup);
return ret;
}
@@ -1931,6 +1984,7 @@ rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
/* We also need to ensure that file is inside the defined dir */
rspamd_strlcpy (filebuf, realbuf, sizeof (filebuf));
dir = dirname (filebuf);
+
if (dir == NULL ||
!rspamd_http_router_is_subdir (entry->rt->default_fs_path,
dir)) {
@@ -1946,10 +2000,10 @@ rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
reply_msg->date = time (NULL);
reply_msg->code = 200;
- reply_msg->body = g_string_sized_new (st.st_size);
+ reply_msg->body = rspamd_fstring_sized_new (st.st_size);
reply_msg->body->len = st.st_size;
reply_msg->body_buf.len = st.st_size;
- reply_msg->body_buf.str = reply_msg->body->str;
+ reply_msg->body_buf.begin = reply_msg->body->str;
if (read (fd, reply_msg->body->str, st.st_size) != st.st_size) {
close (fd);
@@ -1957,8 +2011,6 @@ rspamd_http_router_try_file (struct rspamd_http_connection_entry *entry,
return FALSE;
}
- reply_msg->body_buf.str[st.st_size] = '\0';
-
close (fd);
rspamd_http_connection_reset (entry->conn);
@@ -1980,7 +2032,7 @@ rspamd_http_router_finish_handler (struct rspamd_http_connection *conn,
gpointer found;
struct rspamd_http_message *err_msg;
GError *err;
- GString lookup;
+ rspamd_ftok_t lookup;
struct http_parser_url u;
G_STATIC_ASSERT (sizeof (rspamd_http_router_handler_t) ==
@@ -1999,11 +2051,11 @@ rspamd_http_router_finish_handler (struct rspamd_http_connection *conn,
http_parser_parse_url (msg->url->str, msg->url->len, TRUE, &u);
if (u.field_set & (1 << UF_PATH)) {
- lookup.str = msg->url->str + u.field_data[UF_PATH].off;
+ lookup.begin = msg->url->str + u.field_data[UF_PATH].off;
lookup.len = u.field_data[UF_PATH].len;
}
else {
- lookup.str = msg->url->str;
+ lookup.begin = msg->url->str;
lookup.len = msg->url->len;
}
@@ -2023,11 +2075,12 @@ rspamd_http_router_finish_handler (struct rspamd_http_connection *conn,
if (entry->rt->error_handler != NULL) {
entry->rt->error_handler (entry, err);
}
- msg_info ("path: %v not found", &lookup);
+ msg_info ("path: %T not found", &lookup);
err_msg = rspamd_http_new_message (HTTP_RESPONSE);
err_msg->date = time (NULL);
err_msg->code = err->code;
- err_msg->body = g_string_new (err->message);
+ err_msg->body = rspamd_fstring_new_init (err->message,
+ strlen (err->message));
rspamd_http_connection_reset (entry->conn);
rspamd_http_connection_write_message (entry->conn,
err_msg,
@@ -2056,12 +2109,13 @@ rspamd_http_router_new (rspamd_http_router_error_handler_t eh,
struct stat st;
new = g_slice_alloc0 (sizeof (struct rspamd_http_connection_router));
- new->paths = g_hash_table_new_full (rspamd_gstring_icase_hash,
- rspamd_gstring_icase_equal, rspamd_gstring_free_hard, NULL);
+ new->paths = g_hash_table_new_full (rspamd_ftok_icase_hash,
+ rspamd_ftok_icase_equal, rspamd_fstring_mapped_ftok_free, NULL);
new->conns = NULL;
new->error_handler = eh;
new->finish_handler = fh;
new->ev_base = base;
+
if (timeout) {
new->tv = *timeout;
new->ptv = &new->tv;
@@ -2108,13 +2162,17 @@ rspamd_http_router_add_path (struct rspamd_http_connection_router *router,
const gchar *path, rspamd_http_router_handler_t handler)
{
gpointer ptr;
- GString *key;
+ rspamd_ftok_t *key;
+ rspamd_fstring_t *storage;
G_STATIC_ASSERT (sizeof (rspamd_http_router_handler_t) ==
sizeof (gpointer));
if (path != NULL && handler != NULL && router != NULL) {
memcpy (&ptr, &handler, sizeof (ptr));
- key = g_string_new (path);
+ storage = rspamd_fstring_new_init (path, strlen (path));
+ key = g_slice_alloc0 (sizeof (*key));
+ key->begin = storage->str;
+ key->len = storage->len;
g_hash_table_insert (router->paths, key, ptr);
}
}
@@ -2338,7 +2396,8 @@ GHashTable *
rspamd_http_message_parse_query (struct rspamd_http_message *msg)
{
GHashTable *res;
- GString *key = NULL, *value = NULL;
+ rspamd_fstring_t *key = NULL, *value = NULL;
+ rspamd_ftok_t *key_tok, *value_tok;
const gchar *p, *c, *end;
struct http_parser_url u;
enum {
@@ -2348,9 +2407,10 @@ rspamd_http_message_parse_query (struct rspamd_http_message *msg)
parse_ampersand
} state = parse_key;
- res = g_hash_table_new_full (rspamd_gstring_icase_hash,
- rspamd_gstring_icase_equal, rspamd_gstring_free_hard,
- rspamd_gstring_free_hard);
+ res = g_hash_table_new_full (rspamd_ftok_icase_hash,
+ rspamd_ftok_icase_equal,
+ rspamd_fstring_mapped_ftok_free,
+ rspamd_fstring_mapped_ftok_free);
if (msg->url && msg->url->len > 0) {
http_parser_parse_url (msg->url->str, msg->url->len, TRUE, &u);
@@ -2365,19 +2425,24 @@ rspamd_http_message_parse_query (struct rspamd_http_message *msg)
case parse_key:
if ((*p == '&' || p == end) && p > c) {
/* We have a single parameter without a value */
- key = g_string_sized_new (p - c);
- g_string_append_len (key, c, p - c);
- key->len = rspamd_decode_url (key->str, key->str,
+ key = rspamd_fstring_new_init (c, p - c);
+ key_tok = g_slice_alloc (sizeof (*key_tok));
+ key_tok->begin = key->str;
+ key_tok->len = rspamd_decode_url (key->str, key->str,
key->len);
- value = g_string_new ("");
- g_hash_table_insert (res, key, value);
+ value = rspamd_fstring_new_init ("", 0);
+ value_tok = g_slice_alloc (sizeof (*value_tok));
+ value_tok->begin = value->str;
+ value_tok->len = value->len;
+ g_hash_table_insert (res, key_tok, value_tok);
state = parse_ampersand;
}
else if (*p == '=' && p > c) {
/* We have something like key=value */
- key = g_string_sized_new (p - c);
- g_string_append_len (key, c, p - c);
- key->len = rspamd_decode_url (key->str, key->str,
+ key = rspamd_fstring_new_init (c, p - c);
+ key_tok = g_slice_alloc (sizeof (*key_tok));
+ key_tok->begin = key->str;
+ key_tok->len = rspamd_decode_url (key->str, key->str,
key->len);
state = parse_eqsign;
}
@@ -2400,16 +2465,21 @@ rspamd_http_message_parse_query (struct rspamd_http_message *msg)
if ((*p == '&' || p == end) && p >= c) {
g_assert (key != NULL);
if (p > c) {
- value = g_string_sized_new (p - c);
- g_string_append_len (value, c, p - c);
- value->len = rspamd_decode_url (value->str, value->str,
+ value = rspamd_fstring_new_init ("", 0);
+ value_tok = g_slice_alloc (sizeof (*value_tok));
+ value_tok->begin = value->str;
+ value_tok->len = rspamd_decode_url (value->str,
+ value->str,
value->len);
}
else {
- value = g_string_new ("");
+ value = rspamd_fstring_new_init ("", 0);
+ value_tok = g_slice_alloc (sizeof (*value_tok));
+ value_tok->begin = value->str;
+ value_tok->len = value->len;
}
- g_hash_table_insert (res, key, value);
+ g_hash_table_insert (res, key_tok, value_tok);
key = value = NULL;
state = parse_ampersand;
}
@@ -2432,7 +2502,7 @@ rspamd_http_message_parse_query (struct rspamd_http_message *msg)
}
if (state != parse_ampersand && key != NULL) {
- g_string_free (key, TRUE);
+ rspamd_fstring_free (key);
}
}
diff --git a/src/libutil/http.h b/src/libutil/http.h
index ffc820ce8..7a5a875dd 100644
--- a/src/libutil/http.h
+++ b/src/libutil/http.h
@@ -34,6 +34,7 @@
#include "config.h"
#include "http_parser.h"
#include "keypairs_cache.h"
+#include "fstring.h"
enum rspamd_http_connection_type {
RSPAMD_HTTP_SERVER,
@@ -44,9 +45,9 @@ enum rspamd_http_connection_type {
* HTTP header structure
*/
struct rspamd_http_header {
- GString *name;
- GString *value;
- GString *combined;
+ rspamd_ftok_t *name;
+ rspamd_ftok_t *value;
+ rspamd_fstring_t *combined;
struct rspamd_http_header *next, *prev;
};
@@ -59,13 +60,13 @@ struct rspamd_http_header {
* HTTP message structure, used for requests and replies
*/
struct rspamd_http_message {
- GString *url;
- GString *host;
+ rspamd_fstring_t *url;
+ rspamd_fstring_t *host;
unsigned port;
- GString *status;
+ rspamd_fstring_t *status;
struct rspamd_http_header *headers;
- GString *body;
- GString body_buf;
+ rspamd_fstring_t *body;
+ rspamd_ftok_t body_buf;
gpointer peer_key;
enum http_parser_type type;
time_t date;
@@ -326,8 +327,9 @@ void rspamd_http_message_add_header (struct rspamd_http_message *msg,
* @param msg message
* @param name name of header
*/
-const GString * rspamd_http_message_find_header (struct rspamd_http_message *msg,
- const gchar *name);
+const rspamd_ftok_t * rspamd_http_message_find_header (
+ struct rspamd_http_message *msg,
+ const gchar *name);
/**
* Remove specific header from a message
@@ -403,7 +405,8 @@ void rspamd_http_router_free (struct rspamd_http_connection_router *router);
* Extract arguments from a messsage's URI contained inside query string decoding
* them if needed
* @param msg HTTP request message
- * @return new GHashTable which maps GString * to GString * (table must be freed by a caller)
+ * @return new GHashTable which maps rspamd_ftok_t* to rspamd_ftok_t*
+ * (table must be freed by a caller)
*/
GHashTable* rspamd_http_message_parse_query (struct rspamd_http_message *msg);