168
214
http_basic_cb(struct evhttp_request *req, void *arg)
171
216
struct evbuffer *evb = evbuffer_new();
217
int empty = evhttp_find_header(req->input_headers, "Empty") != NULL;
172
218
event_debug(("%s: called\n", __func__));
173
219
evbuffer_add_printf(evb, "This is funny");
175
evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
221
/* For multi-line headers test */
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"))
233
/* injecting a bad content-length */
234
if (evhttp_find_header(req->input_headers, "X-Negative"))
235
evhttp_add_header(req->output_headers,
236
"Content-Length", "-100");
238
/* allow sending of an empty reply */
239
evhttp_send_reply(req, HTTP_OK, "Everything is fine",
240
!empty ? evb : NULL);
245
static char const* const CHUNKS[] = {
247
"but not hilarious.",
251
struct chunk_req_state {
252
struct evhttp_request *req;
257
http_chunked_trickle_cb(int fd, short events, void *arg)
259
struct evbuffer *evb = evbuffer_new();
260
struct chunk_req_state *state = arg;
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])) {
268
event_once(-1, EV_TIMEOUT,
269
http_chunked_trickle_cb, state, &when);
271
evhttp_send_reply_end(state->req);
277
http_chunked_cb(struct evhttp_request *req, void *arg)
279
struct timeval when = { 0, 0 };
280
struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
281
event_debug(("%s: called\n", __func__));
283
memset(state, 0, sizeof(struct chunk_req_state));
286
/* generate a chunked reply */
287
evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
289
/* but trickle it across several iterations to ensure we're not
290
* assuming it comes all at once */
291
event_once(-1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
295
http_complete_write(int fd, short what, void *arg)
297
struct bufferevent *bev = arg;
298
const char *http_request = "host\r\n"
299
"Connection: close\r\n"
301
bufferevent_write(bev, http_request, strlen(http_request));
181
305
http_basic_test(void)
183
308
struct bufferevent *bev;
310
const char *http_request;
189
314
fprintf(stdout, "Testing Basic HTTP Server: ");
191
http = http_setup(&port);
316
http = http_setup(&port, NULL);
318
/* bind to a second socket */
319
if (evhttp_bind_socket(http, "127.0.0.1", port + 1) == -1) {
320
fprintf(stdout, "FAILED (bind)\n");
193
324
fd = http_connect("127.0.0.1", port);
738
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)
741
1004
if (evhttp_add_header(&headers, "One\n", "Two") != -1)
744
1006
if (evhttp_add_header(&headers, "One", "Two\r") != -1)
747
1008
if (evhttp_add_header(&headers, "One", "Two\n") != -1)
750
fprintf(stdout, "OK\n");
753
fprintf(stdout, "FAILED\n");
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);
1041
evhttp_parse_query("http://www.test.com/?q=test", &headers);
1042
if (validate_header(&headers, "q", "test") != 0)
1044
evhttp_clear_headers(&headers);
1046
evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
1047
if (validate_header(&headers, "q", "test") != 0)
1049
if (validate_header(&headers, "foo", "bar") != 0)
1051
evhttp_clear_headers(&headers);
1053
evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
1054
if (validate_header(&headers, "q", "test foo") != 0)
1056
evhttp_clear_headers(&headers);
1058
evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
1059
if (validate_header(&headers, "q", "test\nfoo") != 0)
1061
evhttp_clear_headers(&headers);
1063
evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &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)
1078
struct bufferevent *bev;
1080
const char *http_request;
1084
fprintf(stdout, "Testing HTTP Server Event Base: ");
1086
base = event_init();
1089
* create another bogus base - which is being used by all subsequen
1094
http = http_setup(&port, base);
1096
fd = http_connect("127.0.0.1", port);
1098
/* Stupid thing to send a request */
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");
1130
* the server is going to reply with chunked data.
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) {
1148
struct evhttp_request *req = evhttp_request_new(NULL, NULL);
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) {
1230
/* enable reading of the reply */
1231
bufferevent_enable(bev, EV_READ);
1237
http_chunked_request_done(struct evhttp_request *req, void *arg)
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)
1269
struct bufferevent *bev;
1271
const char *http_request;
1273
struct timeval tv_start, tv_end;
1274
struct evhttp_connection *evcon = NULL;
1275
struct evhttp_request *req = NULL;
1279
fprintf(stdout, "Testing Chunked HTTP Reply: ");
1281
http = http_setup(&port, NULL);
1283
fd = http_connect("127.0.0.1", port);
1285
/* Stupid thing to send a request */
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");
1316
/* now try again with the regular connection object */
1317
evcon = evhttp_connection_new("127.0.0.1", port);
1318
if (evcon == NULL) {
1319
fprintf(stdout, "FAILED\n");
1323
/* make two requests to check the keepalive behavior */
1324
for (i = 0; i < 2; i++) {
1326
req = evhttp_request_new(http_chunked_request_done, NULL);
1328
/* Add the information that we care about */
1329
evhttp_add_header(req->output_headers, "Host", "somehost");
1331
/* We give ownership of the request to the connection */
1332
if (evhttp_make_request(evcon, req,
1333
EVHTTP_REQ_GET, "/chunked") == -1) {
1334
fprintf(stdout, "FAILED\n");
1341
fprintf(stdout, "FAILED\n");
1346
evhttp_connection_free(evcon);
1349
fprintf(stdout, "OK\n");
1353
http_multi_line_header_test(void)
1355
struct bufferevent *bev;
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);
1367
/* Stupid thing to send a request */
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");
1399
http_request_bad(struct evhttp_request *req, void *arg)
1402
fprintf(stderr, "FAILED\n");
1407
event_loopexit(NULL);
1411
http_negative_content_length_test(void)
1414
struct evhttp_connection *evcon = NULL;
1415
struct evhttp_request *req = NULL;
1418
fprintf(stdout, "Testing HTTP Negative Content Length: ");
1420
http = http_setup(&port, NULL);
1422
evcon = evhttp_connection_new("127.0.0.1", port);
1423
if (evcon == NULL) {
1424
fprintf(stdout, "FAILED\n");
1429
* At this point, we want to schedule a request to the HTTP
1430
* server using our make request method.
1433
req = evhttp_request_new(http_request_bad, NULL);
1435
/* Cause the response to have a negative content-length */
1436
evhttp_add_header(req->output_headers, "X-Negative", "makeitso");
1438
/* We give ownership of the request to the connection */
1439
if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1440
fprintf(stdout, "FAILED\n");
1449
fprintf(stdout, "FAILED\n");
1453
fprintf(stdout, "OK\n");
758
1457
http_suite(void)
760
1460
http_bad_header_test();
1461
http_parse_query_test();
761
1462
http_basic_test();
762
1463
http_connection_test(0 /* not-persistent */);
763
1464
http_connection_test(1 /* persistent */);
764
http_close_detection();
1465
http_close_detection(0 /* with delay */);
1466
http_close_detection(1 /* with delay */);
765
1467
http_post_test();
766
1468
http_failure_test();
767
1469
http_highport_test();
768
1470
http_dispatcher_test();
1472
http_multi_line_header_test();
1473
http_negative_content_length_test();
1475
http_chunked_test();