37 #include <sys/types.h>
39 #ifdef HAVE_SYS_TIME_H
42 #include <sys/queue.h>
44 #include <sys/socket.h>
58 #include "http-internal.h"
63 static struct evhttp *http;
67 void http_suite(
void);
70 static void http_chunked_cb(
struct evhttp_request *req,
void *arg);
73 static void http_large_delay_cb(
struct evhttp_request *req,
void *arg);
76 http_setup(
short *pport,
struct event_base *base)
84 for (i = 0; i < 50; ++
i) {
92 event_errx(1,
"Could not start web server");
98 evhttp_set_cb(myhttp,
"/largedelay", http_large_delay_cb, NULL);
106 #define NI_MAXSERV 1024
110 http_connect(
const char *address, u_short port)
115 struct sockaddr_in sin;
118 char strport[NI_MAXSERV];
125 if (!(he = gethostbyname(address))) {
126 event_warn(
"gethostbyname");
128 memcpy(&sin.sin_addr, he->h_addr_list[0], he->h_length);
129 sin.sin_family = AF_INET;
130 sin.sin_port = htons(port);
131 slen =
sizeof(
struct sockaddr_in);
132 sa = (
struct sockaddr*)&sin;
134 memset(&ai, 0,
sizeof (ai));
135 ai.ai_family = AF_INET;
136 ai.ai_socktype = SOCK_STREAM;
137 snprintf(strport,
sizeof (strport),
"%d", port);
138 if (getaddrinfo(address, strport, &ai, &aitop) != 0) {
139 event_warn(
"getaddrinfo");
143 slen = aitop->ai_addrlen;
146 fd = socket(AF_INET, SOCK_STREAM, 0);
148 event_err(1,
"socket failed");
150 if (connect(fd, sa, slen) == -1)
151 event_err(1,
"connect failed");
163 const char *what =
"This is funny";
165 event_debug((
"%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
167 if (evbuffer_find(bev->input,
168 (
const unsigned char*) what, strlen(what)) != NULL) {
170 enum message_read_status done;
172 req->kind = EVHTTP_RESPONSE;
173 done = evhttp_parse_firstline(req, bev->input);
174 if (done != ALL_DATA_READ)
177 done = evhttp_parse_headers(req, bev->input);
178 if (done != ALL_DATA_READ)
182 evhttp_find_header(req->input_headers,
183 "Content-Type") != NULL)
188 bufferevent_disable(bev, EV_READ);
190 event_base_loopexit(base, NULL);
192 event_loopexit(NULL);
199 if (EVBUFFER_LENGTH(bev->output) == 0) {
201 bufferevent_enable(bev, EV_READ);
207 http_errorcb(
struct bufferevent *bev,
short what,
void *arg)
210 event_loopexit(NULL);
216 struct evbuffer *evb = evbuffer_new();
217 int empty = evhttp_find_header(req->input_headers,
"Empty") != NULL;
218 event_debug((
"%s: called\n", __func__));
219 evbuffer_add_printf(evb,
"This is funny");
224 evhttp_find_header(req->input_headers,
"X-multi");
226 if (strcmp(
"END", multi + strlen(multi) - 3) == 0)
228 if (evhttp_find_header(req->input_headers,
"X-Last"))
234 if (evhttp_find_header(req->input_headers,
"X-Negative"))
235 evhttp_add_header(req->output_headers,
236 "Content-Length",
"-100");
240 !empty ? evb : NULL);
245 static char const*
const CHUNKS[] = {
247 "but not hilarious.",
257 http_chunked_trickle_cb(
int fd,
short events,
void *arg)
259 struct evbuffer *evb = evbuffer_new();
261 struct timeval when = { 0, 0 };
263 evbuffer_add_printf(evb,
"%s", CHUNKS[state->i]);
264 evhttp_send_reply_chunk(state->req, evb);
267 if (++state->i <
sizeof(CHUNKS)/
sizeof(CHUNKS[0])) {
269 http_chunked_trickle_cb, state, &when);
271 evhttp_send_reply_end(state->req);
279 struct timeval when = { 0, 0 };
281 event_debug((
"%s: called\n", __func__));
287 evhttp_send_reply_start(req, HTTP_OK,
"Everything is fine");
291 event_once(-1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
295 http_complete_write(
int fd,
short what,
void *arg)
298 const char *http_request =
"host\r\n"
299 "Connection: close\r\n"
301 bufferevent_write(bev, http_request, strlen(http_request));
305 http_basic_test(
void)
310 const char *http_request;
314 fprintf(stdout,
"Testing Basic HTTP Server: ");
316 http = http_setup(&port, NULL);
320 fprintf(stdout,
"FAILED (bind)\n");
324 fd = http_connect(
"127.0.0.1", port);
327 bev = bufferevent_new(fd, http_readcb, http_writecb,
332 "GET /test HTTP/1.1\r\n"
335 bufferevent_write(bev, http_request, strlen(http_request));
338 event_once(-1, EV_TIMEOUT, http_complete_write, bev, &tv);
343 fprintf(stdout,
"FAILED\n");
348 bufferevent_free(bev);
349 EVUTIL_CLOSESOCKET(fd);
351 fd = http_connect(
"127.0.0.1", port + 1);
354 bev = bufferevent_new(fd, http_readcb, http_writecb,
358 "GET /test HTTP/1.1\r\n"
360 "Connection: close\r\n"
363 bufferevent_write(bev, http_request, strlen(http_request));
367 bufferevent_free(bev);
368 EVUTIL_CLOSESOCKET(fd);
373 fprintf(stdout,
"FAILED\n");
377 fprintf(stdout,
"OK\n");
383 http_delay_reply(
int fd,
short what,
void *arg)
399 event_once(-1, EV_TIMEOUT, http_delay_reply, req, &tv);
402 evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
409 http_connection_test(
int persistent)
416 fprintf(stdout,
"Testing Request Connection Pipeline %s: ",
417 persistent ?
"(persistent)" :
"");
419 http = http_setup(&port, NULL);
423 fprintf(stdout,
"FAILED\n");
435 evhttp_add_header(req->output_headers,
"Host",
"somehost");
439 fprintf(stdout,
"FAILED\n");
446 fprintf(stdout,
"FAILED\n");
456 evhttp_add_header(req->output_headers,
"Host",
"somehost");
463 evhttp_add_header(req->output_headers,
"Connection",
"close");
467 fprintf(stdout,
"FAILED\n");
479 evhttp_add_header(req->output_headers,
"Empty",
"itis");
483 fprintf(stdout,
"FAILED\n");
490 fprintf(stdout,
"FAILED\n");
497 fprintf(stdout,
"OK\n");
503 const char *what =
"This is funny";
505 if (req->response_code != HTTP_OK) {
506 fprintf(stderr,
"FAILED\n");
510 if (evhttp_find_header(req->input_headers,
"Content-Type") == NULL) {
511 fprintf(stderr,
"FAILED\n");
515 if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
516 fprintf(stderr,
"FAILED\n");
520 if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
521 fprintf(stderr,
"FAILED\n");
526 event_loopexit(NULL);
534 if (req->response_code != HTTP_OK) {
535 fprintf(stderr,
"FAILED\n");
539 if (evhttp_find_header(req->input_headers,
"Date") == NULL) {
540 fprintf(stderr,
"FAILED\n");
545 if (evhttp_find_header(req->input_headers,
"Content-Length") == NULL) {
546 fprintf(stderr,
"FAILED\n");
550 if (strcmp(evhttp_find_header(req->input_headers,
"Content-Length"),
552 fprintf(stderr,
"FAILED\n");
556 if (EVBUFFER_LENGTH(req->input_buffer) != 0) {
557 fprintf(stderr,
"FAILED\n");
562 event_loopexit(NULL);
573 struct evbuffer *evb = evbuffer_new();
574 event_debug((
"%s: called\n", __func__));
575 evbuffer_add_printf(evb,
"DISPATCHER_TEST");
585 const char *what =
"DISPATCHER_TEST";
587 if (req->response_code != HTTP_OK) {
588 fprintf(stderr,
"FAILED\n");
592 if (evhttp_find_header(req->input_headers,
"Content-Type") == NULL) {
593 fprintf(stderr,
"FAILED (content type)\n");
597 if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
598 fprintf(stderr,
"FAILED (length %zu vs %zu)\n",
599 EVBUFFER_LENGTH(req->input_buffer), strlen(what));
603 if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
604 fprintf(stderr,
"FAILED (data)\n");
609 event_loopexit(NULL);
613 http_dispatcher_test(
void)
620 fprintf(stdout,
"Testing HTTP Dispatcher: ");
622 http = http_setup(&port, NULL);
626 fprintf(stdout,
"FAILED\n");
640 fprintf(stdout,
"FAILED\n");
645 evhttp_add_header(req->output_headers,
"Host",
"somehost");
648 fprintf(stdout,
"FAILED\n");
658 fprintf(stdout,
"FAILED: %d\n", test_ok);
662 fprintf(stdout,
"OK\n");
671 #define POST_DATA "Okay. Not really printf"
681 fprintf(stdout,
"Testing HTTP POST Request: ");
683 http = http_setup(&port, NULL);
687 fprintf(stdout,
"FAILED\n");
698 fprintf(stdout,
"FAILED\n");
703 evhttp_add_header(req->output_headers,
"Host",
"somehost");
704 evbuffer_add_printf(req->output_buffer, POST_DATA);
707 fprintf(stdout,
"FAILED\n");
717 fprintf(stdout,
"FAILED: %d\n", test_ok);
721 fprintf(stdout,
"OK\n");
728 event_debug((
"%s: called\n", __func__));
731 if (req->type != EVHTTP_REQ_POST) {
732 fprintf(stdout,
"FAILED (post type)\n");
736 if (EVBUFFER_LENGTH(req->input_buffer) != strlen(POST_DATA)) {
737 fprintf(stdout,
"FAILED (length: %zu vs %zu)\n",
738 EVBUFFER_LENGTH(req->input_buffer), strlen(POST_DATA));
742 if (memcmp(EVBUFFER_DATA(req->input_buffer), POST_DATA,
743 strlen(POST_DATA))) {
744 fprintf(stdout,
"FAILED (data)\n");
745 fprintf(stdout,
"Got :%s\n", EVBUFFER_DATA(req->input_buffer));
746 fprintf(stdout,
"Want:%s\n", POST_DATA);
750 evb = evbuffer_new();
751 evbuffer_add_printf(evb,
"This is funny");
761 const char *what =
"This is funny";
764 fprintf(stderr,
"FAILED (timeout)\n");
768 if (req->response_code != HTTP_OK) {
770 fprintf(stderr,
"FAILED (response code)\n");
774 if (evhttp_find_header(req->input_headers,
"Content-Type") == NULL) {
775 fprintf(stderr,
"FAILED (content type)\n");
779 if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
780 fprintf(stderr,
"FAILED (length %zu vs %zu)\n",
781 EVBUFFER_LENGTH(req->input_buffer), strlen(what));
785 if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
786 fprintf(stderr,
"FAILED (data)\n");
791 event_loopexit(NULL);
795 http_failure_readcb(
struct bufferevent *bev,
void *arg)
797 const char *what =
"400 Bad Request";
798 if (evbuffer_find(bev->input, (
const unsigned char*) what, strlen(what)) != NULL) {
800 bufferevent_disable(bev, EV_READ);
801 event_loopexit(NULL);
809 http_failure_test(
void)
813 const char *http_request;
817 fprintf(stdout,
"Testing Bad HTTP Request: ");
819 http = http_setup(&port, NULL);
821 fd = http_connect(
"127.0.0.1", port);
824 bev = bufferevent_new(fd, http_failure_readcb, http_writecb,
827 http_request =
"illegal request\r\n";
829 bufferevent_write(bev, http_request, strlen(http_request));
833 bufferevent_free(bev);
834 EVUTIL_CLOSESOCKET(fd);
839 fprintf(stdout,
"FAILED\n");
843 fprintf(stdout,
"OK\n");
850 if (req == NULL || req->response_code != HTTP_OK) {
852 fprintf(stderr,
"FAILED\n");
865 close_detect_launch(
int fd,
short what,
void *arg)
873 evhttp_add_header(req->output_headers,
"Host",
"somehost");
877 fprintf(stdout,
"FAILED\n");
888 if (req != NULL && req->response_code != HTTP_OK) {
890 fprintf(stderr,
"FAILED\n");
898 event_once(-1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
903 http_close_detection(
int with_delay)
910 fprintf(stdout,
"Testing Connection Close Detection%s: ",
911 with_delay ?
" (with delay)" :
"");
913 http = http_setup(&port, NULL);
920 fprintf(stdout,
"FAILED\n");
924 delayed_client = evcon;
934 evhttp_add_header(req->output_headers,
"Host",
"somehost");
938 req, EVHTTP_REQ_GET, with_delay ?
"/largedelay" :
"/test") == -1) {
939 fprintf(stdout,
"FAILED\n");
946 fprintf(stdout,
"FAILED\n");
951 if (TAILQ_FIRST(&http->connections) != NULL) {
952 fprintf(stdout,
"FAILED (left connections)\n");
959 fprintf(stdout,
"OK\n");
963 http_highport_test(
void)
966 struct evhttp *myhttp = NULL;
968 fprintf(stdout,
"Testing HTTP Server with high port: ");
971 for (i = 0; i < 50; ++
i) {
973 if (myhttp != NULL) {
974 fprintf(stdout,
"OK\n");
980 fprintf(stdout,
"FAILED\n");
985 http_bad_header_test(
void)
987 struct evkeyvalq headers;
989 fprintf(stdout,
"Testing HTTP Header filtering: ");
991 TAILQ_INIT(&headers);
993 if (evhttp_add_header(&headers,
"One",
"Two") != 0)
996 if (evhttp_add_header(&headers,
"One\r",
"Two") != -1)
998 if (evhttp_add_header(&headers,
"One",
"Two") != 0)
1000 if (evhttp_add_header(&headers,
"One",
"Two\r\n Three") != 0)
1002 if (evhttp_add_header(&headers,
"One\r",
"Two") != -1)
1004 if (evhttp_add_header(&headers,
"One\n",
"Two") != -1)
1006 if (evhttp_add_header(&headers,
"One",
"Two\r") != -1)
1008 if (evhttp_add_header(&headers,
"One",
"Two\n") != -1)
1011 evhttp_clear_headers(&headers);
1013 fprintf(stdout,
"OK\n");
1016 fprintf(stdout,
"FAILED\n");
1020 static int validate_header(
1021 const struct evkeyvalq* headers,
1022 const char *key,
const char *value)
1024 const char *real_val = evhttp_find_header(headers, key);
1025 if (real_val == NULL)
1027 if (strcmp(real_val, value) != 0)
1033 http_parse_query_test(
void)
1035 struct evkeyvalq headers;
1037 fprintf(stdout,
"Testing HTTP query parsing: ");
1039 TAILQ_INIT(&headers);
1042 if (validate_header(&headers,
"q",
"test") != 0)
1044 evhttp_clear_headers(&headers);
1047 if (validate_header(&headers,
"q",
"test") != 0)
1049 if (validate_header(&headers,
"foo",
"bar") != 0)
1051 evhttp_clear_headers(&headers);
1054 if (validate_header(&headers,
"q",
"test foo") != 0)
1056 evhttp_clear_headers(&headers);
1059 if (validate_header(&headers,
"q",
"test\nfoo") != 0)
1061 evhttp_clear_headers(&headers);
1064 if (validate_header(&headers,
"q",
"test\rfoo") != 0)
1066 evhttp_clear_headers(&headers);
1068 fprintf(stdout,
"OK\n");
1071 fprintf(stdout,
"FAILED\n");
1076 http_base_test(
void)
1080 const char *http_request;
1084 fprintf(stdout,
"Testing HTTP Server Event Base: ");
1086 base = event_init();
1094 http = http_setup(&port, base);
1096 fd = http_connect(
"127.0.0.1", port);
1099 bev = bufferevent_new(fd, http_readcb, http_writecb,
1100 http_errorcb, NULL);
1101 bufferevent_base_set(base, bev);
1104 "GET /test HTTP/1.1\r\n"
1105 "Host: somehost\r\n"
1106 "Connection: close\r\n"
1109 bufferevent_write(bev, http_request, strlen(http_request));
1111 event_base_dispatch(base);
1113 bufferevent_free(bev);
1114 EVUTIL_CLOSESOCKET(fd);
1118 event_base_free(base);
1122 fprintf(stdout,
"FAILED\n");
1126 fprintf(stdout,
"OK\n");
1134 http_chunked_readcb(
struct bufferevent *bev,
void *arg)
1140 http_chunked_errorcb(
struct bufferevent *bev,
short what,
void *arg)
1147 if ((what & EVBUFFER_EOF) != 0) {
1150 enum message_read_status done;
1152 req->kind = EVHTTP_RESPONSE;
1153 done = evhttp_parse_firstline(req, EVBUFFER_INPUT(bev));
1154 if (done != ALL_DATA_READ)
1157 done = evhttp_parse_headers(req, EVBUFFER_INPUT(bev));
1158 if (done != ALL_DATA_READ)
1161 header = evhttp_find_header(req->input_headers,
"Transfer-Encoding");
1162 if (header == NULL || strcmp(header,
"chunked"))
1165 header = evhttp_find_header(req->input_headers,
"Connection");
1166 if (header == NULL || strcmp(header,
"close"))
1169 header = evbuffer_readline(EVBUFFER_INPUT(bev));
1173 if (strcmp(header,
"d"))
1175 free((
char*)header);
1177 if (strncmp((
char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
1178 "This is funny", 13))
1181 evbuffer_drain(EVBUFFER_INPUT(bev), 13 + 2);
1183 header = evbuffer_readline(EVBUFFER_INPUT(bev));
1187 if (strcmp(header,
"12"))
1189 free((
char *)header);
1191 if (strncmp((
char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
1192 "but not hilarious.", 18))
1195 evbuffer_drain(EVBUFFER_INPUT(bev), 18 + 2);
1197 header = evbuffer_readline(EVBUFFER_INPUT(bev));
1201 if (strcmp(header,
"8"))
1203 free((
char *)header);
1205 if (strncmp((
char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
1209 evbuffer_drain(EVBUFFER_INPUT(bev), 8 + 2);
1211 header = evbuffer_readline(EVBUFFER_INPUT(bev));
1215 if (strcmp(header,
"0"))
1217 free((
char *)header);
1223 event_loopexit(NULL);
1227 http_chunked_writecb(
struct bufferevent *bev,
void *arg)
1229 if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(bev)) == 0) {
1231 bufferevent_enable(bev, EV_READ);
1239 if (req->response_code != HTTP_OK) {
1240 fprintf(stderr,
"FAILED\n");
1244 if (evhttp_find_header(req->input_headers,
1245 "Transfer-Encoding") == NULL) {
1246 fprintf(stderr,
"FAILED\n");
1250 if (EVBUFFER_LENGTH(req->input_buffer) != 13 + 18 + 8) {
1251 fprintf(stderr,
"FAILED\n");
1255 if (strncmp((
char *)EVBUFFER_DATA(req->input_buffer),
1256 "This is funnybut not hilarious.bwv 1052",
1258 fprintf(stderr,
"FAILED\n");
1263 event_loopexit(NULL);
1267 http_chunked_test(
void)
1271 const char *http_request;
1273 struct timeval tv_start, tv_end;
1279 fprintf(stdout,
"Testing Chunked HTTP Reply: ");
1281 http = http_setup(&port, NULL);
1283 fd = http_connect(
"127.0.0.1", port);
1286 bev = bufferevent_new(fd,
1287 http_chunked_readcb, http_chunked_writecb,
1288 http_chunked_errorcb, NULL);
1291 "GET /chunked HTTP/1.1\r\n"
1292 "Host: somehost\r\n"
1293 "Connection: close\r\n"
1296 bufferevent_write(bev, http_request, strlen(http_request));
1298 evutil_gettimeofday(&tv_start, NULL);
1302 evutil_gettimeofday(&tv_end, NULL);
1303 evutil_timersub(&tv_end, &tv_start, &tv_end);
1305 if (tv_end.tv_sec >= 1) {
1306 fprintf(stdout,
"FAILED (time)\n");
1312 fprintf(stdout,
"FAILED\n");
1318 if (evcon == NULL) {
1319 fprintf(stdout,
"FAILED\n");
1324 for (i = 0; i < 2; i++) {
1329 evhttp_add_header(req->output_headers,
"Host",
"somehost");
1333 EVHTTP_REQ_GET,
"/chunked") == -1) {
1334 fprintf(stdout,
"FAILED\n");
1341 fprintf(stdout,
"FAILED\n");
1349 fprintf(stdout,
"OK\n");
1353 http_multi_line_header_test(
void)
1357 const char *http_start_request;
1361 fprintf(stdout,
"Testing HTTP Server with multi line: ");
1363 http = http_setup(&port, NULL);
1365 fd = http_connect(
"127.0.0.1", port);
1368 bev = bufferevent_new(fd, http_readcb, http_writecb,
1369 http_errorcb, NULL);
1371 http_start_request =
1372 "GET /test HTTP/1.1\r\n"
1373 "Host: somehost\r\n"
1374 "Connection: close\r\n"
1375 "X-Multi: aaaaaaaa\r\n"
1381 bufferevent_write(bev, http_start_request, strlen(http_start_request));
1385 bufferevent_free(bev);
1386 EVUTIL_CLOSESOCKET(fd);
1391 fprintf(stdout,
"FAILED\n");
1395 fprintf(stdout,
"OK\n");
1402 fprintf(stderr,
"FAILED\n");
1407 event_loopexit(NULL);
1411 http_negative_content_length_test(
void)
1418 fprintf(stdout,
"Testing HTTP Negative Content Length: ");
1420 http = http_setup(&port, NULL);
1423 if (evcon == NULL) {
1424 fprintf(stdout,
"FAILED\n");
1436 evhttp_add_header(req->output_headers,
"X-Negative",
"makeitso");
1440 fprintf(stdout,
"FAILED\n");
1449 fprintf(stdout,
"FAILED\n");
1453 fprintf(stdout,
"OK\n");
1460 http_bad_header_test();
1461 http_parse_query_test();
1463 http_connection_test(0 );
1464 http_connection_test(1 );
1465 http_close_detection(0 );
1466 http_close_detection(1 );
1468 http_failure_test();
1469 http_highport_test();
1470 http_dispatcher_test();
1472 http_multi_line_header_test();
1473 http_negative_content_length_test();
1475 http_chunked_test();