diff options
-rw-r--r-- | src/or/buffers.c | 70 | ||||
-rw-r--r-- | src/or/buffers.h | 4 |
2 files changed, 74 insertions, 0 deletions
diff --git a/src/or/buffers.c b/src/or/buffers.c index 6ba2f1f65..374c37c86 100644 --- a/src/or/buffers.c +++ b/src/or/buffers.c @@ -1347,6 +1347,76 @@ fetch_from_buf_http(buf_t *buf, return 1; } +#ifdef USE_BUFFEREVENTS +int +fetch_from_evbuffer_http(struct evbuffer *buf, + char **headers_out, size_t max_headerlen, + char **body_out, size_t *body_used, size_t max_bodylen, + int force_complete) +{ + struct evbuffer_ptr crlf; + unsigned char *headers; + size_t headerlen, bodylen, contentlen; + char *p; + + crlf = evbuffer_search(buf, "\r\n\r\n", 4, NULL); + if (crlf.pos < 0) { + if (evbuffer_get_length(buf) > max_headerlen) + return -1; /* Headers too long. */ + return 0; /* Headers not here yet. */ + } else if (crlf.pos > (int)max_headerlen) + return -1; /* Headers too long. */ + + /* Okay, we've found the end of the headers. Pull them into the first + * chunk. */ + /* XXXX Or don't! It would be better to scan for the Content-Length as-is.*/ + headerlen = crlf.pos + 4; + bodylen = evbuffer_get_length(buf) - headerlen; + if (bodylen > max_bodylen) + return -1; /* body too long */ + + headers = evbuffer_pullup(buf, headerlen); + tor_assert(headers && evbuffer_get_contiguous_space(buf) >= headerlen); + p = (char*) tor_memstr(headers, headerlen, CONTENT_LENGTH); + if (p) { + int i = atoi(p+strlen(CONTENT_LENGTH)); + if (i < 0) { + log_warn(LD_PROTOCOL, "Content-Length is less than zero; it looks like " + "someone is trying to crash us."); + return -1; + } + contentlen = i; + /* if content-length is malformed, then our body length is 0. fine. */ + log_debug(LD_HTTP,"Got a contentlen of %d.",(int)contentlen); + if (bodylen < contentlen) { + if (!force_complete) { + log_debug(LD_HTTP,"body not all here yet."); + return 0; /* not all there yet */ + } + } + if (bodylen > contentlen) { + bodylen = contentlen; + log_debug(LD_HTTP,"bodylen reduced to %d.",(int)bodylen); + } + } + + if (headers_out) { + *headers_out = tor_malloc(headerlen+1); + evbuffer_remove(buf, *headers_out, headerlen); + (*headers_out)[headerlen] = '\0'; + } + if (body_out) { + tor_assert(headers_out); + tor_assert(body_used); + *body_used = bodylen; + *body_out = tor_malloc(bodylen+1); + evbuffer_remove(buf, *body_out, bodylen); + (*body_out)[bodylen] = '\0'; + } + return 1; +} +#endif + /** There is a (possibly incomplete) socks handshake on <b>buf</b>, of one * of the forms * - socks4: "socksheader username\\0" diff --git a/src/or/buffers.h b/src/or/buffers.h index d6ff79e93..ca01dc807 100644 --- a/src/or/buffers.h +++ b/src/or/buffers.h @@ -53,6 +53,10 @@ int fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out, int linkproto); int fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req, int log_sockstype, int safe_socks); +int fetch_from_evbuffer_http(struct evbuffer *buf, + char **headers_out, size_t max_headerlen, + char **body_out, size_t *body_used, size_t max_bodylen, + int force_complete); #endif void assert_buf_ok(buf_t *buf); |