from trunk: reject negative content-length headers

svn:r895
This commit is contained in:
Niels Provos 2008-07-02 04:28:12 +00:00
parent e7d5dfda49
commit 3add69df67
3 changed files with 78 additions and 7 deletions

View File

@ -3,6 +3,7 @@ Changes in 1.4.6-stable:
o switch all uses of [v]snprintf over to evutil
o Correct handling of trailing headers in chunked replies; from Scott Lamb.
o Support multi-line HTTP headers; based on a patch from Moshe Litvin
o Reject negative Content-Length headers; anonymous bug report
Changes in 1.4.5-stable:
o Fix connection keep-alive behavior for HTTP/1.0

19
http.c
View File

@ -391,7 +391,7 @@ evhttp_make_header_request(struct evhttp_connection *evcon,
evhttp_find_header(req->output_headers, "Content-Length") == NULL){
char size[12];
evutil_snprintf(size, sizeof(size), "%ld",
(long)EVBUFFER_LENGTH(req->output_buffer));
(long)EVBUFFER_LENGTH(req->output_buffer));
evhttp_add_header(req->output_headers, "Content-Length", size);
}
}
@ -791,6 +791,7 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
while ((len = EVBUFFER_LENGTH(buf)) > 0) {
if (req->ntoread < 0) {
/* Read chunk size */
ev_int64_t ntoread;
char *p = evbuffer_readline(buf);
char *endp;
int error;
@ -801,13 +802,16 @@ evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
free(p);
continue;
}
req->ntoread = evutil_strtoll(p, &endp, 16);
error = *p == '\0' || (*endp != '\0' && *endp != ' ');
ntoread = evutil_strtoll(p, &endp, 16);
error = (*p == '\0' ||
(*endp != '\0' && *endp != ' ') ||
ntoread < 0);
free(p);
if (error) {
/* could not get chunk size */
return (DATA_CORRUPTED);
}
req->ntoread = ntoread;
if (req->ntoread == 0) {
/* Last chunk */
return (ALL_DATA_READ);
@ -1507,12 +1511,13 @@ evhttp_get_body_length(struct evhttp_request *req)
req->ntoread = -1;
} else {
char *endp;
req->ntoread = evutil_strtoll(content_length, &endp, 10);
if (*content_length == '\0' || *endp != '\0') {
event_warnx("%s: illegal content length: %s",
__func__, content_length);
ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
event_debug(("%s: illegal content length: %s",
__func__, content_length));
return (-1);
}
req->ntoread = ntoread;
}
event_debug(("%s: bytes to read: %lld (in buffer %ld)\n",

View File

@ -227,6 +227,12 @@ http_basic_cb(struct evhttp_request *req, void *arg)
test_ok++;
}
}
/* injecting a bad content-length */
if (evhttp_find_header(req->input_headers, "X-Negative"))
evhttp_add_header(req->output_headers,
"Content-Length", "-100");
/* allow sending of an empty reply */
evhttp_send_reply(req, HTTP_OK, "Everything is fine",
!empty ? evb : NULL);
@ -1276,6 +1282,64 @@ http_multi_line_header_test(void)
fprintf(stdout, "OK\n");
}
static void
http_request_bad(struct evhttp_request *req, void *arg)
{
if (req != NULL) {
fprintf(stderr, "FAILED\n");
exit(1);
}
test_ok = 1;
event_loopexit(NULL);
}
static void
http_negative_content_length_test(void)
{
short port = -1;
struct evhttp_connection *evcon = NULL;
struct evhttp_request *req = NULL;
test_ok = 0;
fprintf(stdout, "Testing HTTP Negative Content Length: ");
http = http_setup(&port, NULL);
evcon = evhttp_connection_new("127.0.0.1", port);
if (evcon == NULL) {
fprintf(stdout, "FAILED\n");
exit(1);
}
/*
* At this point, we want to schedule a request to the HTTP
* server using our make request method.
*/
req = evhttp_request_new(http_request_bad, NULL);
/* Cause the response to have a negative content-length */
evhttp_add_header(req->output_headers, "X-Negative", "makeitso");
/* We give ownership of the request to the connection */
if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
fprintf(stdout, "FAILED\n");
exit(1);
}
event_dispatch();
evhttp_free(http);
if (test_ok != 1) {
fprintf(stdout, "FAILED\n");
exit(1);
}
fprintf(stdout, "OK\n");
}
void
http_suite(void)
{
@ -1291,6 +1355,7 @@ http_suite(void)
http_dispatcher_test();
http_multi_line_header_test();
http_negative_content_length_test();
http_chunked_test();
}