support multi-line http headers; based on a patch from Moshe Litvin

svn:r890
This commit is contained in:
Niels Provos 2008-06-29 01:30:06 +00:00
parent 9998c0cbc8
commit cb7c3bd671
3 changed files with 91 additions and 1 deletions

View File

@ -112,6 +112,7 @@ Changes in current version:
o Do not use SO_REUSEADDR when connecting
o Support 64-bit integers in RPC structs
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
Changes in 1.4.0:
o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.

30
http.c
View File

@ -1412,6 +1412,29 @@ evhttp_parse_firstline(struct evhttp_request *req, struct evbuffer *buffer)
return (status);
}
static int
evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line)
{
struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
char *newval;
size_t old_len, line_len;
if (header == NULL)
return (-1);
old_len = strlen(header->value);
line_len = strlen(line);
newval = mm_realloc(header->value, old_len + line_len + 1);
if (newval == NULL)
return (-1);
memcpy(newval + old_len, line, line_len + 1);
header->value = newval;
return (0);
}
enum message_read_status
evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer)
{
@ -1429,6 +1452,13 @@ evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer)
break;
}
/* Check if this is a continuation line */
if (*line == ' ' || *line == '\t') {
if (evhttp_append_to_last_header(headers, line) == -1)
goto error;
continue;
}
/* Processing of header lines */
svalue = line;
skey = strsep(&svalue, ":");

View File

@ -232,6 +232,17 @@ http_basic_cb(struct evhttp_request *req, void *arg)
event_debug(("%s: called\n", __func__));
evbuffer_add_printf(evb, "This is funny");
/* For multi-line headers test */
{
const char *multi =
evhttp_find_header(req->input_headers,"X-multi");
if (multi) {
if (strcmp("END", multi + strlen(multi) - 3) == 0)
test_ok++;
if (evhttp_find_header(req->input_headers, "X-Last"))
test_ok++;
}
}
/* allow sending of an empty reply */
evhttp_send_reply(req, HTTP_OK, "Everything is fine",
!empty ? evb : NULL);
@ -2126,6 +2137,52 @@ failed:
exit(1);
}
static void
http_multi_line_header_test(void)
{
struct bufferevent *bev;
int fd;
const char *http_start_request;
short port = -1;
test_ok = 0;
fprintf(stdout, "Testing HTTP Server with multi line: ");
http = http_setup(&port, NULL);
fd = http_connect("127.0.0.1", port);
/* Stupid thing to send a request */
bev = bufferevent_new(fd, http_readcb, http_writecb,
http_errorcb, NULL);
http_start_request =
"GET /test HTTP/1.1\r\n"
"Host: somehost\r\n"
"Connection: close\r\n"
"X-Multi: aaaaaaaa\r\n"
" a\r\n"
"\tEND\r\n"
"X-Last: last\r\n"
"\r\n";
bufferevent_write(bev, http_start_request, strlen(http_start_request));
event_dispatch();
bufferevent_free(bev);
close(fd);
evhttp_free(http);
if (test_ok != 4) {
fprintf(stdout, "FAILED\n");
exit(1);
}
fprintf(stdout, "OK\n");
}
void
http_suite(void)
{
@ -2146,6 +2203,8 @@ http_suite(void)
http_highport_test();
http_dispatcher_test();
http_multi_line_header_test();
http_incomplete_test(0 /* use_timeout */);
http_incomplete_test(1 /* use_timeout */);