aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2009-09-15 15:47:35 +0400
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2009-09-15 15:47:35 +0400
commite03d0749928abdff045de0bd2eeb21c5989a94c4 (patch)
tree2bf57f89c0c257b83aa0d61e4a37e8890486771a /src
parent3fbcf7f04616acf1f367af6d1c9c7ac271edf551 (diff)
downloadrspamd-e03d0749928abdff045de0bd2eeb21c5989a94c4.tar.gz
rspamd-e03d0749928abdff045de0bd2eeb21c5989a94c4.zip
* Add chunked replies support for http maps
Diffstat (limited to 'src')
-rw-r--r--src/map.c104
-rw-r--r--src/map.h3
2 files changed, 101 insertions, 6 deletions
diff --git a/src/map.c b/src/map.c
index f19b822b6..d250970b1 100644
--- a/src/map.c
+++ b/src/map.c
@@ -185,12 +185,90 @@ parse_http_reply (u_char *chunk, size_t len, struct http_reply *reply)
return s;
}
+static int
+read_chunk_header (u_char *buf, size_t len, struct http_map_data *data)
+{
+ u_char chunkbuf[32], *p, *c;
+ int skip;
+
+ p = chunkbuf;
+ c = buf;
+ while (g_ascii_isxdigit (*c) && p - chunkbuf < sizeof (chunkbuf) - 1) {
+ *p++ = *c++;
+ skip ++;
+ }
+ *p = '\0';
+ data->chunk = strtoul (chunkbuf, NULL, 16);
+ /* Now skip to CRLF */
+ while (*c != '\n' && c - buf < len) {
+ c ++;
+ skip ++;
+ }
+ if (*c == '\n') {
+ skip ++;
+ c ++;
+ }
+ data->chunk_read = 0;
+
+ return skip;
+}
+
+static gboolean
+read_http_chunked (u_char *buf, size_t len, struct rspamd_map *map, struct http_map_data *data, struct map_cb_data *cbdata)
+{
+ u_char *p = buf, *remain;
+ uint32_t skip = 0, rlen;
+
+ if (data->chunk == 0) {
+ /* Read first chunk data */
+ skip = read_chunk_header (buf, len, data);
+ p += skip;
+ }
+
+ len -= skip;
+ data->chunk_read += len;
+ if (data->chunk_read >= data->chunk) {
+ /* Read next chunk and feed callback with remaining buffer */
+ remain = map->read_callback (map->pool, p, len - (data->chunk_read - data->chunk), cbdata);
+ if (remain != NULL && remain != p) {
+ /* copy remaining buffer to start of buffer */
+ rlen = len - (remain - p);
+ memmove (p, remain, rlen);
+ }
+
+ p = buf + (len - (data->chunk_read - data->chunk));
+ if (*p != '\r') {
+ msg_info ("read_http_chunked: invalid chunked reply");
+ g_assert (0);
+ return FALSE;
+ }
+ p += 2;
+ len -= p - buf;
+ skip = read_chunk_header (p, len, data);
+ p += skip;
+ len -= skip;
+ if (data->chunk == 0) {
+ return FALSE;
+ }
+ }
+
+ remain = map->read_callback (map->pool, p, len, cbdata);
+ if (remain != NULL && remain != p) {
+ /* copy remaining buffer to start of buffer */
+ rlen = len - (remain - p);
+ memmove (p, remain, rlen);
+ }
+
+ return TRUE;
+}
+
static gboolean
read_http_common (struct rspamd_map *map, struct http_map_data *data, struct http_reply *reply, struct map_cb_data *cbdata, int fd)
{
- u_char buf[BUFSIZ], *remain;
+ u_char buf[BUFSIZ], *remain, *pos;
int rlen;
ssize_t r;
+ char *te;
rlen = 0;
if ((r = read (fd, buf + rlen, sizeof (buf) - rlen - 1)) > 0) {
@@ -200,21 +278,35 @@ read_http_common (struct rspamd_map *map, struct http_map_data *data, struct htt
/* copy remaining buffer to start of buffer */
rlen = r - (remain - buf);
memmove (buf, remain, rlen);
+ r = rlen;
}
if (reply->parser_state == 6) {
if (reply->code != 200 && reply->code != 304) {
msg_err ("read_http: got error reply from server %s, %d", data->host, reply->code);
return FALSE;
}
- remain = map->read_callback (map->pool, buf, r - 1, cbdata);
- if (remain != NULL && remain != buf) {
+ pos = buf;
+ if (!data->chunked && (te = g_hash_table_lookup (reply->headers, "Transfer-Encoding")) != NULL) {
+ if (g_ascii_strcasecmp (te, "chunked") == 0) {
+ data->chunked = TRUE;
+ }
+ }
+ if (data->chunked) {
+ return read_http_chunked (buf, r - 1, map, data, cbdata);
+ }
+ remain = map->read_callback (map->pool, pos, r - 1, cbdata);
+ if (remain != NULL && remain != pos) {
/* copy remaining buffer to start of buffer */
- rlen = r - (remain - buf);
- memmove (buf, remain, rlen);
+ rlen = r - (remain - pos);
+ memmove (pos, remain, rlen);
}
}
}
- return FALSE;
+ else {
+ return FALSE;
+ }
+
+ return TRUE;
}
static void
diff --git a/src/map.h b/src/map.h
index 7a207c28e..c5029b958 100644
--- a/src/map.h
+++ b/src/map.h
@@ -27,6 +27,9 @@ struct http_map_data {
char *path;
char *host;
time_t last_checked;
+ gboolean chunked;
+ uint32_t chunk;
+ uint32_t chunk_read;
};
typedef u_char* (*map_cb_t)(memory_pool_t *pool, u_char *chunk, size_t len, struct map_cb_data *data);