Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Side by Side Diff: third_party/libevent/test/regress_http.c

Issue 1531573008: move libevent into base (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix shim path Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/libevent/test/regress_dns.c ('k') | third_party/libevent/test/regress_rpc.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #ifdef WIN32
29 #include <winsock2.h>
30 #include <windows.h>
31 #endif
32
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #ifdef HAVE_SYS_TIME_H
40 #include <sys/time.h>
41 #endif
42 #include <sys/queue.h>
43 #ifndef WIN32
44 #include <sys/socket.h>
45 #include <signal.h>
46 #include <unistd.h>
47 #include <netdb.h>
48 #endif
49 #include <fcntl.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <errno.h>
54
55 #include "event.h"
56 #include "evhttp.h"
57 #include "log.h"
58 #include "http-internal.h"
59
60 extern int pair[];
61 extern int test_ok;
62
63 static struct evhttp *http;
64 /* set if a test needs to call loopexit on a base */
65 static struct event_base *base;
66
67 void http_suite(void);
68
69 void http_basic_cb(struct evhttp_request *req, void *arg);
70 static void http_chunked_cb(struct evhttp_request *req, void *arg);
71 void http_post_cb(struct evhttp_request *req, void *arg);
72 void http_dispatcher_cb(struct evhttp_request *req, void *arg);
73 static void http_large_delay_cb(struct evhttp_request *req, void *arg);
74 static void http_badreq_cb(struct evhttp_request *req, void *arg);
75
76 static struct evhttp *
77 http_setup(short *pport, struct event_base *base)
78 {
79 int i;
80 struct evhttp *myhttp;
81 short port = -1;
82
83 /* Try a few different ports */
84 myhttp = evhttp_new(base);
85 for (i = 0; i < 50; ++i) {
86 if (evhttp_bind_socket(myhttp, "127.0.0.1", 8080 + i) != -1) {
87 port = 8080 + i;
88 break;
89 }
90 }
91
92 if (port == -1)
93 event_errx(1, "Could not start web server");
94
95 /* Register a callback for certain types of requests */
96 evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL);
97 evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, NULL);
98 evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL);
99 evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, NULL);
100 evhttp_set_cb(myhttp, "/badrequest", http_badreq_cb, NULL);
101 evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL);
102
103 *pport = port;
104 return (myhttp);
105 }
106
107 #ifndef NI_MAXSERV
108 #define NI_MAXSERV 1024
109 #endif
110
111 static int
112 http_connect(const char *address, u_short port)
113 {
114 /* Stupid code for connecting */
115 #ifdef WIN32
116 struct hostent *he;
117 struct sockaddr_in sin;
118 #else
119 struct addrinfo ai, *aitop;
120 char strport[NI_MAXSERV];
121 #endif
122 struct sockaddr *sa;
123 int slen;
124 int fd;
125
126 #ifdef WIN32
127 if (!(he = gethostbyname(address))) {
128 event_warn("gethostbyname");
129 }
130 memcpy(&sin.sin_addr, he->h_addr_list[0], he->h_length);
131 sin.sin_family = AF_INET;
132 sin.sin_port = htons(port);
133 slen = sizeof(struct sockaddr_in);
134 sa = (struct sockaddr*)&sin;
135 #else
136 memset(&ai, 0, sizeof (ai));
137 ai.ai_family = AF_INET;
138 ai.ai_socktype = SOCK_STREAM;
139 snprintf(strport, sizeof (strport), "%d", port);
140 if (getaddrinfo(address, strport, &ai, &aitop) != 0) {
141 event_warn("getaddrinfo");
142 return (-1);
143 }
144 sa = aitop->ai_addr;
145 slen = aitop->ai_addrlen;
146 #endif
147
148 fd = socket(AF_INET, SOCK_STREAM, 0);
149 if (fd == -1)
150 event_err(1, "socket failed");
151
152 if (connect(fd, sa, slen) == -1)
153 event_err(1, "connect failed");
154
155 #ifndef WIN32
156 freeaddrinfo(aitop);
157 #endif
158
159 return (fd);
160 }
161
162 static void
163 http_readcb(struct bufferevent *bev, void *arg)
164 {
165 const char *what = "This is funny";
166
167 event_debug(("%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
168
169 if (evbuffer_find(bev->input,
170 (const unsigned char*) what, strlen(what)) != NULL) {
171 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
172 enum message_read_status done;
173
174 req->kind = EVHTTP_RESPONSE;
175 done = evhttp_parse_firstline(req, bev->input);
176 if (done != ALL_DATA_READ)
177 goto out;
178
179 done = evhttp_parse_headers(req, bev->input);
180 if (done != ALL_DATA_READ)
181 goto out;
182
183 if (done == 1 &&
184 evhttp_find_header(req->input_headers,
185 "Content-Type") != NULL)
186 test_ok++;
187
188 out:
189 evhttp_request_free(req);
190 bufferevent_disable(bev, EV_READ);
191 if (base)
192 event_base_loopexit(base, NULL);
193 else
194 event_loopexit(NULL);
195 }
196 }
197
198 static void
199 http_writecb(struct bufferevent *bev, void *arg)
200 {
201 if (EVBUFFER_LENGTH(bev->output) == 0) {
202 /* enable reading of the reply */
203 bufferevent_enable(bev, EV_READ);
204 test_ok++;
205 }
206 }
207
208 static void
209 http_errorcb(struct bufferevent *bev, short what, void *arg)
210 {
211 test_ok = -2;
212 event_loopexit(NULL);
213 }
214
215 void
216 http_basic_cb(struct evhttp_request *req, void *arg)
217 {
218 struct evbuffer *evb = evbuffer_new();
219 int empty = evhttp_find_header(req->input_headers, "Empty") != NULL;
220 event_debug(("%s: called\n", __func__));
221 evbuffer_add_printf(evb, "This is funny");
222
223 /* For multi-line headers test */
224 {
225 const char *multi =
226 evhttp_find_header(req->input_headers,"X-multi");
227 if (multi) {
228 if (strcmp("END", multi + strlen(multi) - 3) == 0)
229 test_ok++;
230 if (evhttp_find_header(req->input_headers, "X-Last"))
231 test_ok++;
232 }
233 }
234
235 /* injecting a bad content-length */
236 if (evhttp_find_header(req->input_headers, "X-Negative"))
237 evhttp_add_header(req->output_headers,
238 "Content-Length", "-100");
239
240 /* allow sending of an empty reply */
241 evhttp_send_reply(req, HTTP_OK, "Everything is fine",
242 !empty ? evb : NULL);
243
244 evbuffer_free(evb);
245 }
246
247 static char const* const CHUNKS[] = {
248 "This is funny",
249 "but not hilarious.",
250 "bwv 1052"
251 };
252
253 struct chunk_req_state {
254 struct evhttp_request *req;
255 int i;
256 };
257
258 static void
259 http_chunked_trickle_cb(int fd, short events, void *arg)
260 {
261 struct evbuffer *evb = evbuffer_new();
262 struct chunk_req_state *state = arg;
263 struct timeval when = { 0, 0 };
264
265 evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
266 evhttp_send_reply_chunk(state->req, evb);
267 evbuffer_free(evb);
268
269 if (++state->i < sizeof(CHUNKS)/sizeof(CHUNKS[0])) {
270 event_once(-1, EV_TIMEOUT,
271 http_chunked_trickle_cb, state, &when);
272 } else {
273 evhttp_send_reply_end(state->req);
274 free(state);
275 }
276 }
277
278 static void
279 http_chunked_cb(struct evhttp_request *req, void *arg)
280 {
281 struct timeval when = { 0, 0 };
282 struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
283 event_debug(("%s: called\n", __func__));
284
285 memset(state, 0, sizeof(struct chunk_req_state));
286 state->req = req;
287
288 /* generate a chunked reply */
289 evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
290
291 /* but trickle it across several iterations to ensure we're not
292 * assuming it comes all at once */
293 event_once(-1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
294 }
295
296 static void
297 http_complete_write(int fd, short what, void *arg)
298 {
299 struct bufferevent *bev = arg;
300 const char *http_request = "host\r\n"
301 "Connection: close\r\n"
302 "\r\n";
303 bufferevent_write(bev, http_request, strlen(http_request));
304 }
305
306 static void
307 http_basic_test(void)
308 {
309 struct timeval tv;
310 struct bufferevent *bev;
311 int fd;
312 const char *http_request;
313 short port = -1;
314
315 test_ok = 0;
316 fprintf(stdout, "Testing Basic HTTP Server: ");
317
318 http = http_setup(&port, NULL);
319
320 /* bind to a second socket */
321 if (evhttp_bind_socket(http, "127.0.0.1", port + 1) == -1) {
322 fprintf(stdout, "FAILED (bind)\n");
323 exit(1);
324 }
325
326 fd = http_connect("127.0.0.1", port);
327
328 /* Stupid thing to send a request */
329 bev = bufferevent_new(fd, http_readcb, http_writecb,
330 http_errorcb, NULL);
331
332 /* first half of the http request */
333 http_request =
334 "GET /test HTTP/1.1\r\n"
335 "Host: some";
336
337 bufferevent_write(bev, http_request, strlen(http_request));
338 timerclear(&tv);
339 tv.tv_usec = 10000;
340 event_once(-1, EV_TIMEOUT, http_complete_write, bev, &tv);
341
342 event_dispatch();
343
344 if (test_ok != 3) {
345 fprintf(stdout, "FAILED\n");
346 exit(1);
347 }
348
349 /* connect to the second port */
350 bufferevent_free(bev);
351 EVUTIL_CLOSESOCKET(fd);
352
353 fd = http_connect("127.0.0.1", port + 1);
354
355 /* Stupid thing to send a request */
356 bev = bufferevent_new(fd, http_readcb, http_writecb,
357 http_errorcb, NULL);
358
359 http_request =
360 "GET /test HTTP/1.1\r\n"
361 "Host: somehost\r\n"
362 "Connection: close\r\n"
363 "\r\n";
364
365 bufferevent_write(bev, http_request, strlen(http_request));
366
367 event_dispatch();
368
369 bufferevent_free(bev);
370 EVUTIL_CLOSESOCKET(fd);
371
372 evhttp_free(http);
373
374 if (test_ok != 5) {
375 fprintf(stdout, "FAILED\n");
376 exit(1);
377 }
378
379 fprintf(stdout, "OK\n");
380 }
381
382 static void
383 http_badreq_cb(struct evhttp_request *req, void *arg)
384 {
385 struct evbuffer *buf = evbuffer_new();
386
387 evhttp_add_header(req->output_headers, "Content-Type", "text/xml; charse t=UTF-8");
388 evbuffer_add_printf(buf, "Hello, %s!", "127.0.0.1");
389
390 evhttp_send_reply(req, HTTP_OK, "OK", buf);
391 evbuffer_free(buf);
392 }
393
394 static void
395 http_badreq_errorcb(struct bufferevent *bev, short what, void *arg)
396 {
397 event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
398 /* ignore */
399 }
400
401 static void
402 http_badreq_readcb(struct bufferevent *bev, void *arg)
403 {
404 const char *what = "Hello, 127.0.0.1";
405 const char *bad_request = "400 Bad Request";
406
407 event_debug(("%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
408
409 if (evbuffer_find(bev->input,
410 (const unsigned char *) bad_request, strlen(bad_request)) != NUL L) {
411 event_debug(("%s: bad request detected", __func__));
412 test_ok = -10;
413 bufferevent_disable(bev, EV_READ);
414 event_loopexit(NULL);
415 return;
416 }
417
418 if (evbuffer_find(bev->input,
419 (const unsigned char*) what, strlen(what)) != NULL) {
420 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
421 enum message_read_status done;
422
423 req->kind = EVHTTP_RESPONSE;
424 done = evhttp_parse_firstline(req, bev->input);
425 if (done != ALL_DATA_READ)
426 goto out;
427
428 done = evhttp_parse_headers(req, bev->input);
429 if (done != ALL_DATA_READ)
430 goto out;
431
432 if (done == 1 &&
433 evhttp_find_header(req->input_headers,
434 "Content-Type") != NULL)
435 test_ok++;
436
437 out:
438 evhttp_request_free(req);
439 evbuffer_drain(bev->input, EVBUFFER_LENGTH(bev->input));
440 }
441
442 shutdown(bev->ev_read.ev_fd, SHUT_WR);
443 }
444
445 static void
446 http_badreq_successcb(int fd, short what, void *arg)
447 {
448 event_debug(("%s: called (what=%04x, arg=%p)", __func__, what, arg));
449 event_loopexit(NULL);
450 }
451
452 static void
453 http_bad_request(void)
454 {
455 struct timeval tv;
456 struct bufferevent *bev;
457 int fd;
458 const char *http_request;
459 short port = -1;
460
461 test_ok = 0;
462 fprintf(stdout, "Testing \"Bad Request\" on connection close: ");
463
464 http = http_setup(&port, NULL);
465
466 /* bind to a second socket */
467 if (evhttp_bind_socket(http, "127.0.0.1", port + 1) == -1) {
468 fprintf(stdout, "FAILED (bind)\n");
469 exit(1);
470 }
471
472 /* NULL request test */
473 fd = http_connect("127.0.0.1", port);
474
475 /* Stupid thing to send a request */
476 bev = bufferevent_new(fd, http_badreq_readcb, http_writecb,
477 http_badreq_errorcb, NULL);
478 bufferevent_enable(bev, EV_READ);
479
480 /* real NULL request */
481 http_request = "";
482
483 shutdown(fd, SHUT_WR);
484 timerclear(&tv);
485 tv.tv_usec = 10000;
486 event_once(-1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
487
488 event_dispatch();
489
490 bufferevent_free(bev);
491 EVUTIL_CLOSESOCKET(fd);
492
493 if (test_ok != 0) {
494 fprintf(stdout, "FAILED\n");
495 exit(1);
496 }
497
498 /* Second answer (BAD REQUEST) on connection close */
499
500 /* connect to the second port */
501 fd = http_connect("127.0.0.1", port + 1);
502
503 /* Stupid thing to send a request */
504 bev = bufferevent_new(fd, http_badreq_readcb, http_writecb,
505 http_badreq_errorcb, NULL);
506 bufferevent_enable(bev, EV_READ);
507
508 /* first half of the http request */
509 http_request =
510 "GET /badrequest HTTP/1.0\r\n" \
511 "Connection: Keep-Alive\r\n" \
512 "\r\n";
513
514 bufferevent_write(bev, http_request, strlen(http_request));
515
516 timerclear(&tv);
517 tv.tv_usec = 10000;
518 event_once(-1, EV_TIMEOUT, http_badreq_successcb, bev, &tv);
519
520 event_dispatch();
521
522 evhttp_free(http);
523
524 if (test_ok != 2) {
525 fprintf(stdout, "FAILED\n");
526 exit(1);
527 }
528
529 fprintf(stdout, "OK\n");
530 }
531 static struct evhttp_connection *delayed_client;
532
533 static void
534 http_delay_reply(int fd, short what, void *arg)
535 {
536 struct evhttp_request *req = arg;
537
538 evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
539
540 ++test_ok;
541 }
542
543 static void
544 http_large_delay_cb(struct evhttp_request *req, void *arg)
545 {
546 struct timeval tv;
547 timerclear(&tv);
548 tv.tv_sec = 3;
549
550 event_once(-1, EV_TIMEOUT, http_delay_reply, req, &tv);
551
552 /* here we close the client connection which will cause an EOF */
553 evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
554 }
555
556 void http_request_done(struct evhttp_request *, void *);
557 void http_request_empty_done(struct evhttp_request *, void *);
558
559 static void
560 http_connection_test(int persistent)
561 {
562 short port = -1;
563 struct evhttp_connection *evcon = NULL;
564 struct evhttp_request *req = NULL;
565
566 test_ok = 0;
567 fprintf(stdout, "Testing Request Connection Pipeline %s: ",
568 persistent ? "(persistent)" : "");
569
570 http = http_setup(&port, NULL);
571
572 evcon = evhttp_connection_new("127.0.0.1", port);
573 if (evcon == NULL) {
574 fprintf(stdout, "FAILED\n");
575 exit(1);
576 }
577
578 /*
579 * At this point, we want to schedule a request to the HTTP
580 * server using our make request method.
581 */
582
583 req = evhttp_request_new(http_request_done, NULL);
584
585 /* Add the information that we care about */
586 evhttp_add_header(req->output_headers, "Host", "somehost");
587
588 /* We give ownership of the request to the connection */
589 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
590 fprintf(stdout, "FAILED\n");
591 exit(1);
592 }
593
594 event_dispatch();
595
596 if (test_ok != 1) {
597 fprintf(stdout, "FAILED\n");
598 exit(1);
599 }
600
601 /* try to make another request over the same connection */
602 test_ok = 0;
603
604 req = evhttp_request_new(http_request_done, NULL);
605
606 /* Add the information that we care about */
607 evhttp_add_header(req->output_headers, "Host", "somehost");
608
609 /*
610 * if our connections are not supposed to be persistent; request
611 * a close from the server.
612 */
613 if (!persistent)
614 evhttp_add_header(req->output_headers, "Connection", "close");
615
616 /* We give ownership of the request to the connection */
617 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
618 fprintf(stdout, "FAILED\n");
619 exit(1);
620 }
621
622 event_dispatch();
623
624 /* make another request: request empty reply */
625 test_ok = 0;
626
627 req = evhttp_request_new(http_request_empty_done, NULL);
628
629 /* Add the information that we care about */
630 evhttp_add_header(req->output_headers, "Empty", "itis");
631
632 /* We give ownership of the request to the connection */
633 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
634 fprintf(stdout, "FAILED\n");
635 exit(1);
636 }
637
638 event_dispatch();
639
640 if (test_ok != 1) {
641 fprintf(stdout, "FAILED\n");
642 exit(1);
643 }
644
645 evhttp_connection_free(evcon);
646 evhttp_free(http);
647
648 fprintf(stdout, "OK\n");
649 }
650
651 void
652 http_request_done(struct evhttp_request *req, void *arg)
653 {
654 const char *what = "This is funny";
655
656 if (req->response_code != HTTP_OK) {
657 fprintf(stderr, "FAILED\n");
658 exit(1);
659 }
660
661 if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
662 fprintf(stderr, "FAILED\n");
663 exit(1);
664 }
665
666 if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
667 fprintf(stderr, "FAILED\n");
668 exit(1);
669 }
670
671 if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
672 fprintf(stderr, "FAILED\n");
673 exit(1);
674 }
675
676 test_ok = 1;
677 event_loopexit(NULL);
678 }
679
680 /* test date header and content length */
681
682 void
683 http_request_empty_done(struct evhttp_request *req, void *arg)
684 {
685 if (req->response_code != HTTP_OK) {
686 fprintf(stderr, "FAILED\n");
687 exit(1);
688 }
689
690 if (evhttp_find_header(req->input_headers, "Date") == NULL) {
691 fprintf(stderr, "FAILED\n");
692 exit(1);
693 }
694
695
696 if (evhttp_find_header(req->input_headers, "Content-Length") == NULL) {
697 fprintf(stderr, "FAILED\n");
698 exit(1);
699 }
700
701 if (strcmp(evhttp_find_header(req->input_headers, "Content-Length"),
702 "0")) {
703 fprintf(stderr, "FAILED\n");
704 exit(1);
705 }
706
707 if (EVBUFFER_LENGTH(req->input_buffer) != 0) {
708 fprintf(stderr, "FAILED\n");
709 exit(1);
710 }
711
712 test_ok = 1;
713 event_loopexit(NULL);
714 }
715
716 /*
717 * HTTP DISPATCHER test
718 */
719
720 void
721 http_dispatcher_cb(struct evhttp_request *req, void *arg)
722 {
723
724 struct evbuffer *evb = evbuffer_new();
725 event_debug(("%s: called\n", __func__));
726 evbuffer_add_printf(evb, "DISPATCHER_TEST");
727
728 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
729
730 evbuffer_free(evb);
731 }
732
733 static void
734 http_dispatcher_test_done(struct evhttp_request *req, void *arg)
735 {
736 const char *what = "DISPATCHER_TEST";
737
738 if (req->response_code != HTTP_OK) {
739 fprintf(stderr, "FAILED\n");
740 exit(1);
741 }
742
743 if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
744 fprintf(stderr, "FAILED (content type)\n");
745 exit(1);
746 }
747
748 if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
749 fprintf(stderr, "FAILED (length %zu vs %zu)\n",
750 EVBUFFER_LENGTH(req->input_buffer), strlen(what));
751 exit(1);
752 }
753
754 if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
755 fprintf(stderr, "FAILED (data)\n");
756 exit(1);
757 }
758
759 test_ok = 1;
760 event_loopexit(NULL);
761 }
762
763 static void
764 http_dispatcher_test(void)
765 {
766 short port = -1;
767 struct evhttp_connection *evcon = NULL;
768 struct evhttp_request *req = NULL;
769
770 test_ok = 0;
771 fprintf(stdout, "Testing HTTP Dispatcher: ");
772
773 http = http_setup(&port, NULL);
774
775 evcon = evhttp_connection_new("127.0.0.1", port);
776 if (evcon == NULL) {
777 fprintf(stdout, "FAILED\n");
778 exit(1);
779 }
780
781 /* also bind to local host */
782 evhttp_connection_set_local_address(evcon, "127.0.0.1");
783
784 /*
785 * At this point, we want to schedule an HTTP GET request
786 * server using our make request method.
787 */
788
789 req = evhttp_request_new(http_dispatcher_test_done, NULL);
790 if (req == NULL) {
791 fprintf(stdout, "FAILED\n");
792 exit(1);
793 }
794
795 /* Add the information that we care about */
796 evhttp_add_header(req->output_headers, "Host", "somehost");
797
798 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/?arg=val") == -1) {
799 fprintf(stdout, "FAILED\n");
800 exit(1);
801 }
802
803 event_dispatch();
804
805 evhttp_connection_free(evcon);
806 evhttp_free(http);
807
808 if (test_ok != 1) {
809 fprintf(stdout, "FAILED: %d\n", test_ok);
810 exit(1);
811 }
812
813 fprintf(stdout, "OK\n");
814 }
815
816 /*
817 * HTTP POST test.
818 */
819
820 void http_postrequest_done(struct evhttp_request *, void *);
821
822 #define POST_DATA "Okay. Not really printf"
823
824 static void
825 http_post_test(void)
826 {
827 short port = -1;
828 struct evhttp_connection *evcon = NULL;
829 struct evhttp_request *req = NULL;
830
831 test_ok = 0;
832 fprintf(stdout, "Testing HTTP POST Request: ");
833
834 http = http_setup(&port, NULL);
835
836 evcon = evhttp_connection_new("127.0.0.1", port);
837 if (evcon == NULL) {
838 fprintf(stdout, "FAILED\n");
839 exit(1);
840 }
841
842 /*
843 * At this point, we want to schedule an HTTP POST request
844 * server using our make request method.
845 */
846
847 req = evhttp_request_new(http_postrequest_done, NULL);
848 if (req == NULL) {
849 fprintf(stdout, "FAILED\n");
850 exit(1);
851 }
852
853 /* Add the information that we care about */
854 evhttp_add_header(req->output_headers, "Host", "somehost");
855 evbuffer_add_printf(req->output_buffer, POST_DATA);
856
857 if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
858 fprintf(stdout, "FAILED\n");
859 exit(1);
860 }
861
862 event_dispatch();
863
864 evhttp_connection_free(evcon);
865 evhttp_free(http);
866
867 if (test_ok != 1) {
868 fprintf(stdout, "FAILED: %d\n", test_ok);
869 exit(1);
870 }
871
872 fprintf(stdout, "OK\n");
873 }
874
875 void
876 http_post_cb(struct evhttp_request *req, void *arg)
877 {
878 struct evbuffer *evb;
879 event_debug(("%s: called\n", __func__));
880
881 /* Yes, we are expecting a post request */
882 if (req->type != EVHTTP_REQ_POST) {
883 fprintf(stdout, "FAILED (post type)\n");
884 exit(1);
885 }
886
887 if (EVBUFFER_LENGTH(req->input_buffer) != strlen(POST_DATA)) {
888 fprintf(stdout, "FAILED (length: %zu vs %zu)\n",
889 EVBUFFER_LENGTH(req->input_buffer), strlen(POST_DATA));
890 exit(1);
891 }
892
893 if (memcmp(EVBUFFER_DATA(req->input_buffer), POST_DATA,
894 strlen(POST_DATA))) {
895 fprintf(stdout, "FAILED (data)\n");
896 fprintf(stdout, "Got :%s\n", EVBUFFER_DATA(req->input_buffer));
897 fprintf(stdout, "Want:%s\n", POST_DATA);
898 exit(1);
899 }
900
901 evb = evbuffer_new();
902 evbuffer_add_printf(evb, "This is funny");
903
904 evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
905
906 evbuffer_free(evb);
907 }
908
909 void
910 http_postrequest_done(struct evhttp_request *req, void *arg)
911 {
912 const char *what = "This is funny";
913
914 if (req == NULL) {
915 fprintf(stderr, "FAILED (timeout)\n");
916 exit(1);
917 }
918
919 if (req->response_code != HTTP_OK) {
920
921 fprintf(stderr, "FAILED (response code)\n");
922 exit(1);
923 }
924
925 if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
926 fprintf(stderr, "FAILED (content type)\n");
927 exit(1);
928 }
929
930 if (EVBUFFER_LENGTH(req->input_buffer) != strlen(what)) {
931 fprintf(stderr, "FAILED (length %zu vs %zu)\n",
932 EVBUFFER_LENGTH(req->input_buffer), strlen(what));
933 exit(1);
934 }
935
936 if (memcmp(EVBUFFER_DATA(req->input_buffer), what, strlen(what)) != 0) {
937 fprintf(stderr, "FAILED (data)\n");
938 exit(1);
939 }
940
941 test_ok = 1;
942 event_loopexit(NULL);
943 }
944
945 static void
946 http_failure_readcb(struct bufferevent *bev, void *arg)
947 {
948 const char *what = "400 Bad Request";
949 if (evbuffer_find(bev->input, (const unsigned char*) what, strlen(what)) != NULL) {
950 test_ok = 2;
951 bufferevent_disable(bev, EV_READ);
952 event_loopexit(NULL);
953 }
954 }
955
956 /*
957 * Testing that the HTTP server can deal with a malformed request.
958 */
959 static void
960 http_failure_test(void)
961 {
962 struct bufferevent *bev;
963 int fd;
964 const char *http_request;
965 short port = -1;
966
967 test_ok = 0;
968 fprintf(stdout, "Testing Bad HTTP Request: ");
969
970 http = http_setup(&port, NULL);
971
972 fd = http_connect("127.0.0.1", port);
973
974 /* Stupid thing to send a request */
975 bev = bufferevent_new(fd, http_failure_readcb, http_writecb,
976 http_errorcb, NULL);
977
978 http_request = "illegal request\r\n";
979
980 bufferevent_write(bev, http_request, strlen(http_request));
981
982 event_dispatch();
983
984 bufferevent_free(bev);
985 EVUTIL_CLOSESOCKET(fd);
986
987 evhttp_free(http);
988
989 if (test_ok != 2) {
990 fprintf(stdout, "FAILED\n");
991 exit(1);
992 }
993
994 fprintf(stdout, "OK\n");
995 }
996
997 static void
998 close_detect_done(struct evhttp_request *req, void *arg)
999 {
1000 struct timeval tv;
1001 if (req == NULL || req->response_code != HTTP_OK) {
1002
1003 fprintf(stderr, "FAILED\n");
1004 exit(1);
1005 }
1006
1007 test_ok = 1;
1008
1009 timerclear(&tv);
1010 tv.tv_sec = 3; /* longer than the http time out */
1011
1012 event_loopexit(&tv);
1013 }
1014
1015 static void
1016 close_detect_launch(int fd, short what, void *arg)
1017 {
1018 struct evhttp_connection *evcon = arg;
1019 struct evhttp_request *req;
1020
1021 req = evhttp_request_new(close_detect_done, NULL);
1022
1023 /* Add the information that we care about */
1024 evhttp_add_header(req->output_headers, "Host", "somehost");
1025
1026 /* We give ownership of the request to the connection */
1027 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1028 fprintf(stdout, "FAILED\n");
1029 exit(1);
1030 }
1031 }
1032
1033 static void
1034 close_detect_cb(struct evhttp_request *req, void *arg)
1035 {
1036 struct evhttp_connection *evcon = arg;
1037 struct timeval tv;
1038
1039 if (req != NULL && req->response_code != HTTP_OK) {
1040
1041 fprintf(stderr, "FAILED\n");
1042 exit(1);
1043 }
1044
1045 timerclear(&tv);
1046 tv.tv_sec = 3; /* longer than the http time out */
1047
1048 /* launch a new request on the persistent connection in 6 seconds */
1049 event_once(-1, EV_TIMEOUT, close_detect_launch, evcon, &tv);
1050 }
1051
1052
1053 static void
1054 http_close_detection(int with_delay)
1055 {
1056 short port = -1;
1057 struct evhttp_connection *evcon = NULL;
1058 struct evhttp_request *req = NULL;
1059
1060 test_ok = 0;
1061 fprintf(stdout, "Testing Connection Close Detection%s: ",
1062 with_delay ? " (with delay)" : "");
1063
1064 http = http_setup(&port, NULL);
1065
1066 /* 2 second timeout */
1067 evhttp_set_timeout(http, 2);
1068
1069 evcon = evhttp_connection_new("127.0.0.1", port);
1070 if (evcon == NULL) {
1071 fprintf(stdout, "FAILED\n");
1072 exit(1);
1073 }
1074
1075 delayed_client = evcon;
1076
1077 /*
1078 * At this point, we want to schedule a request to the HTTP
1079 * server using our make request method.
1080 */
1081
1082 req = evhttp_request_new(close_detect_cb, evcon);
1083
1084 /* Add the information that we care about */
1085 evhttp_add_header(req->output_headers, "Host", "somehost");
1086
1087 /* We give ownership of the request to the connection */
1088 if (evhttp_make_request(evcon,
1089 req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
1090 fprintf(stdout, "FAILED\n");
1091 exit(1);
1092 }
1093
1094 event_dispatch();
1095
1096 if (test_ok != 1) {
1097 fprintf(stdout, "FAILED\n");
1098 exit(1);
1099 }
1100
1101 /* at this point, the http server should have no connection */
1102 if (TAILQ_FIRST(&http->connections) != NULL) {
1103 fprintf(stdout, "FAILED (left connections)\n");
1104 exit(1);
1105 }
1106
1107 evhttp_connection_free(evcon);
1108 evhttp_free(http);
1109
1110 fprintf(stdout, "OK\n");
1111 }
1112
1113 static void
1114 http_highport_test(void)
1115 {
1116 int i = -1;
1117 struct evhttp *myhttp = NULL;
1118
1119 fprintf(stdout, "Testing HTTP Server with high port: ");
1120
1121 /* Try a few different ports */
1122 for (i = 0; i < 50; ++i) {
1123 myhttp = evhttp_start("127.0.0.1", 65535 - i);
1124 if (myhttp != NULL) {
1125 fprintf(stdout, "OK\n");
1126 evhttp_free(myhttp);
1127 return;
1128 }
1129 }
1130
1131 fprintf(stdout, "FAILED\n");
1132 exit(1);
1133 }
1134
1135 static void
1136 http_bad_header_test(void)
1137 {
1138 struct evkeyvalq headers;
1139
1140 fprintf(stdout, "Testing HTTP Header filtering: ");
1141
1142 TAILQ_INIT(&headers);
1143
1144 if (evhttp_add_header(&headers, "One", "Two") != 0)
1145 goto fail;
1146
1147 if (evhttp_add_header(&headers, "One\r", "Two") != -1)
1148 goto fail;
1149 if (evhttp_add_header(&headers, "One", "Two") != 0)
1150 goto fail;
1151 if (evhttp_add_header(&headers, "One", "Two\r\n Three") != 0)
1152 goto fail;
1153 if (evhttp_add_header(&headers, "One\r", "Two") != -1)
1154 goto fail;
1155 if (evhttp_add_header(&headers, "One\n", "Two") != -1)
1156 goto fail;
1157 if (evhttp_add_header(&headers, "One", "Two\r") != -1)
1158 goto fail;
1159 if (evhttp_add_header(&headers, "One", "Two\n") != -1)
1160 goto fail;
1161
1162 evhttp_clear_headers(&headers);
1163
1164 fprintf(stdout, "OK\n");
1165 return;
1166 fail:
1167 fprintf(stdout, "FAILED\n");
1168 exit(1);
1169 }
1170
1171 static int validate_header(
1172 const struct evkeyvalq* headers,
1173 const char *key, const char *value)
1174 {
1175 const char *real_val = evhttp_find_header(headers, key);
1176 if (real_val == NULL)
1177 return (-1);
1178 if (strcmp(real_val, value) != 0)
1179 return (-1);
1180 return (0);
1181 }
1182
1183 static void
1184 http_parse_query_test(void)
1185 {
1186 struct evkeyvalq headers;
1187
1188 fprintf(stdout, "Testing HTTP query parsing: ");
1189
1190 TAILQ_INIT(&headers);
1191
1192 evhttp_parse_query("http://www.test.com/?q=test", &headers);
1193 if (validate_header(&headers, "q", "test") != 0)
1194 goto fail;
1195 evhttp_clear_headers(&headers);
1196
1197 evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
1198 if (validate_header(&headers, "q", "test") != 0)
1199 goto fail;
1200 if (validate_header(&headers, "foo", "bar") != 0)
1201 goto fail;
1202 evhttp_clear_headers(&headers);
1203
1204 evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
1205 if (validate_header(&headers, "q", "test foo") != 0)
1206 goto fail;
1207 evhttp_clear_headers(&headers);
1208
1209 evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
1210 if (validate_header(&headers, "q", "test\nfoo") != 0)
1211 goto fail;
1212 evhttp_clear_headers(&headers);
1213
1214 evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
1215 if (validate_header(&headers, "q", "test\rfoo") != 0)
1216 goto fail;
1217 evhttp_clear_headers(&headers);
1218
1219 fprintf(stdout, "OK\n");
1220 return;
1221 fail:
1222 fprintf(stdout, "FAILED\n");
1223 exit(1);
1224 }
1225
1226 static void
1227 http_base_test(void)
1228 {
1229 struct bufferevent *bev;
1230 int fd;
1231 const char *http_request;
1232 short port = -1;
1233
1234 test_ok = 0;
1235 fprintf(stdout, "Testing HTTP Server Event Base: ");
1236
1237 base = event_init();
1238
1239 /*
1240 * create another bogus base - which is being used by all subsequen
1241 * tests - yuck!
1242 */
1243 event_init();
1244
1245 http = http_setup(&port, base);
1246
1247 fd = http_connect("127.0.0.1", port);
1248
1249 /* Stupid thing to send a request */
1250 bev = bufferevent_new(fd, http_readcb, http_writecb,
1251 http_errorcb, NULL);
1252 bufferevent_base_set(base, bev);
1253
1254 http_request =
1255 "GET /test HTTP/1.1\r\n"
1256 "Host: somehost\r\n"
1257 "Connection: close\r\n"
1258 "\r\n";
1259
1260 bufferevent_write(bev, http_request, strlen(http_request));
1261
1262 event_base_dispatch(base);
1263
1264 bufferevent_free(bev);
1265 EVUTIL_CLOSESOCKET(fd);
1266
1267 evhttp_free(http);
1268
1269 event_base_free(base);
1270 base = NULL;
1271
1272 if (test_ok != 2) {
1273 fprintf(stdout, "FAILED\n");
1274 exit(1);
1275 }
1276
1277 fprintf(stdout, "OK\n");
1278 }
1279
1280 /*
1281 * the server is going to reply with chunked data.
1282 */
1283
1284 static void
1285 http_chunked_readcb(struct bufferevent *bev, void *arg)
1286 {
1287 /* nothing here */
1288 }
1289
1290 static void
1291 http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
1292 {
1293 if (!test_ok)
1294 goto out;
1295
1296 test_ok = -1;
1297
1298 if ((what & EVBUFFER_EOF) != 0) {
1299 struct evhttp_request *req = evhttp_request_new(NULL, NULL);
1300 const char *header;
1301 enum message_read_status done;
1302
1303 req->kind = EVHTTP_RESPONSE;
1304 done = evhttp_parse_firstline(req, EVBUFFER_INPUT(bev));
1305 if (done != ALL_DATA_READ)
1306 goto out;
1307
1308 done = evhttp_parse_headers(req, EVBUFFER_INPUT(bev));
1309 if (done != ALL_DATA_READ)
1310 goto out;
1311
1312 header = evhttp_find_header(req->input_headers, "Transfer-Encodi ng");
1313 if (header == NULL || strcmp(header, "chunked"))
1314 goto out;
1315
1316 header = evhttp_find_header(req->input_headers, "Connection");
1317 if (header == NULL || strcmp(header, "close"))
1318 goto out;
1319
1320 header = evbuffer_readline(EVBUFFER_INPUT(bev));
1321 if (header == NULL)
1322 goto out;
1323 /* 13 chars */
1324 if (strcmp(header, "d"))
1325 goto out;
1326 free((char*)header);
1327
1328 if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
1329 "This is funny", 13))
1330 goto out;
1331
1332 evbuffer_drain(EVBUFFER_INPUT(bev), 13 + 2);
1333
1334 header = evbuffer_readline(EVBUFFER_INPUT(bev));
1335 if (header == NULL)
1336 goto out;
1337 /* 18 chars */
1338 if (strcmp(header, "12"))
1339 goto out;
1340 free((char *)header);
1341
1342 if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
1343 "but not hilarious.", 18))
1344 goto out;
1345
1346 evbuffer_drain(EVBUFFER_INPUT(bev), 18 + 2);
1347
1348 header = evbuffer_readline(EVBUFFER_INPUT(bev));
1349 if (header == NULL)
1350 goto out;
1351 /* 8 chars */
1352 if (strcmp(header, "8"))
1353 goto out;
1354 free((char *)header);
1355
1356 if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
1357 "bwv 1052.", 8))
1358 goto out;
1359
1360 evbuffer_drain(EVBUFFER_INPUT(bev), 8 + 2);
1361
1362 header = evbuffer_readline(EVBUFFER_INPUT(bev));
1363 if (header == NULL)
1364 goto out;
1365 /* 0 chars */
1366 if (strcmp(header, "0"))
1367 goto out;
1368 free((char *)header);
1369
1370 test_ok = 2;
1371 }
1372
1373 out:
1374 event_loopexit(NULL);
1375 }
1376
1377 static void
1378 http_chunked_writecb(struct bufferevent *bev, void *arg)
1379 {
1380 if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(bev)) == 0) {
1381 /* enable reading of the reply */
1382 bufferevent_enable(bev, EV_READ);
1383 test_ok++;
1384 }
1385 }
1386
1387 static void
1388 http_chunked_request_done(struct evhttp_request *req, void *arg)
1389 {
1390 if (req->response_code != HTTP_OK) {
1391 fprintf(stderr, "FAILED\n");
1392 exit(1);
1393 }
1394
1395 if (evhttp_find_header(req->input_headers,
1396 "Transfer-Encoding") == NULL) {
1397 fprintf(stderr, "FAILED\n");
1398 exit(1);
1399 }
1400
1401 if (EVBUFFER_LENGTH(req->input_buffer) != 13 + 18 + 8) {
1402 fprintf(stderr, "FAILED\n");
1403 exit(1);
1404 }
1405
1406 if (strncmp((char *)EVBUFFER_DATA(req->input_buffer),
1407 "This is funnybut not hilarious.bwv 1052",
1408 13 + 18 + 8)) {
1409 fprintf(stderr, "FAILED\n");
1410 exit(1);
1411 }
1412
1413 test_ok = 1;
1414 event_loopexit(NULL);
1415 }
1416
1417 static void
1418 http_chunked_test(void)
1419 {
1420 struct bufferevent *bev;
1421 int fd;
1422 const char *http_request;
1423 short port = -1;
1424 struct timeval tv_start, tv_end;
1425 struct evhttp_connection *evcon = NULL;
1426 struct evhttp_request *req = NULL;
1427 int i;
1428
1429 test_ok = 0;
1430 fprintf(stdout, "Testing Chunked HTTP Reply: ");
1431
1432 http = http_setup(&port, NULL);
1433
1434 fd = http_connect("127.0.0.1", port);
1435
1436 /* Stupid thing to send a request */
1437 bev = bufferevent_new(fd,
1438 http_chunked_readcb, http_chunked_writecb,
1439 http_chunked_errorcb, NULL);
1440
1441 http_request =
1442 "GET /chunked HTTP/1.1\r\n"
1443 "Host: somehost\r\n"
1444 "Connection: close\r\n"
1445 "\r\n";
1446
1447 bufferevent_write(bev, http_request, strlen(http_request));
1448
1449 evutil_gettimeofday(&tv_start, NULL);
1450
1451 event_dispatch();
1452
1453 evutil_gettimeofday(&tv_end, NULL);
1454 evutil_timersub(&tv_end, &tv_start, &tv_end);
1455
1456 if (tv_end.tv_sec >= 1) {
1457 fprintf(stdout, "FAILED (time)\n");
1458 exit (1);
1459 }
1460
1461
1462 if (test_ok != 2) {
1463 fprintf(stdout, "FAILED\n");
1464 exit(1);
1465 }
1466
1467 /* now try again with the regular connection object */
1468 evcon = evhttp_connection_new("127.0.0.1", port);
1469 if (evcon == NULL) {
1470 fprintf(stdout, "FAILED\n");
1471 exit(1);
1472 }
1473
1474 /* make two requests to check the keepalive behavior */
1475 for (i = 0; i < 2; i++) {
1476 test_ok = 0;
1477 req = evhttp_request_new(http_chunked_request_done, NULL);
1478
1479 /* Add the information that we care about */
1480 evhttp_add_header(req->output_headers, "Host", "somehost");
1481
1482 /* We give ownership of the request to the connection */
1483 if (evhttp_make_request(evcon, req,
1484 EVHTTP_REQ_GET, "/chunked") == -1) {
1485 fprintf(stdout, "FAILED\n");
1486 exit(1);
1487 }
1488
1489 event_dispatch();
1490
1491 if (test_ok != 1) {
1492 fprintf(stdout, "FAILED\n");
1493 exit(1);
1494 }
1495 }
1496
1497 evhttp_connection_free(evcon);
1498 evhttp_free(http);
1499
1500 fprintf(stdout, "OK\n");
1501 }
1502
1503 static void
1504 http_multi_line_header_test(void)
1505 {
1506 struct bufferevent *bev;
1507 int fd;
1508 const char *http_start_request;
1509 short port = -1;
1510
1511 test_ok = 0;
1512 fprintf(stdout, "Testing HTTP Server with multi line: ");
1513
1514 http = http_setup(&port, NULL);
1515
1516 fd = http_connect("127.0.0.1", port);
1517
1518 /* Stupid thing to send a request */
1519 bev = bufferevent_new(fd, http_readcb, http_writecb,
1520 http_errorcb, NULL);
1521
1522 http_start_request =
1523 "GET /test HTTP/1.1\r\n"
1524 "Host: somehost\r\n"
1525 "Connection: close\r\n"
1526 "X-Multi: aaaaaaaa\r\n"
1527 " a\r\n"
1528 "\tEND\r\n"
1529 "X-Last: last\r\n"
1530 "\r\n";
1531
1532 bufferevent_write(bev, http_start_request, strlen(http_start_request));
1533
1534 event_dispatch();
1535
1536 bufferevent_free(bev);
1537 EVUTIL_CLOSESOCKET(fd);
1538
1539 evhttp_free(http);
1540
1541 if (test_ok != 4) {
1542 fprintf(stdout, "FAILED\n");
1543 exit(1);
1544 }
1545
1546 fprintf(stdout, "OK\n");
1547 }
1548
1549 static void
1550 http_request_bad(struct evhttp_request *req, void *arg)
1551 {
1552 if (req != NULL) {
1553 fprintf(stderr, "FAILED\n");
1554 exit(1);
1555 }
1556
1557 test_ok = 1;
1558 event_loopexit(NULL);
1559 }
1560
1561 static void
1562 http_negative_content_length_test(void)
1563 {
1564 short port = -1;
1565 struct evhttp_connection *evcon = NULL;
1566 struct evhttp_request *req = NULL;
1567
1568 test_ok = 0;
1569 fprintf(stdout, "Testing HTTP Negative Content Length: ");
1570
1571 http = http_setup(&port, NULL);
1572
1573 evcon = evhttp_connection_new("127.0.0.1", port);
1574 if (evcon == NULL) {
1575 fprintf(stdout, "FAILED\n");
1576 exit(1);
1577 }
1578
1579 /*
1580 * At this point, we want to schedule a request to the HTTP
1581 * server using our make request method.
1582 */
1583
1584 req = evhttp_request_new(http_request_bad, NULL);
1585
1586 /* Cause the response to have a negative content-length */
1587 evhttp_add_header(req->output_headers, "X-Negative", "makeitso");
1588
1589 /* We give ownership of the request to the connection */
1590 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
1591 fprintf(stdout, "FAILED\n");
1592 exit(1);
1593 }
1594
1595 event_dispatch();
1596
1597 evhttp_free(http);
1598
1599 if (test_ok != 1) {
1600 fprintf(stdout, "FAILED\n");
1601 exit(1);
1602 }
1603
1604 fprintf(stdout, "OK\n");
1605 }
1606
1607 /*
1608 * Testing client reset of server chunked connections
1609 */
1610
1611 struct terminate_state {
1612 struct evhttp_request *req;
1613 struct bufferevent *bev;
1614 int fd;
1615 } terminate_state;
1616
1617 static void
1618 terminate_chunked_trickle_cb(int fd, short events, void *arg)
1619 {
1620 struct terminate_state *state = arg;
1621 struct evbuffer *evb = evbuffer_new();
1622 struct timeval tv;
1623
1624 if (evhttp_request_get_connection(state->req) == NULL) {
1625 test_ok = 1;
1626 evhttp_request_free(state->req);
1627 event_loopexit(NULL);
1628 return;
1629 }
1630
1631 evbuffer_add_printf(evb, "%p", evb);
1632 evhttp_send_reply_chunk(state->req, evb);
1633 evbuffer_free(evb);
1634
1635 tv.tv_sec = 0;
1636 tv.tv_usec = 3000;
1637 event_once(-1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
1638 }
1639
1640 static void
1641 terminate_chunked_cb(struct evhttp_request *req, void *arg)
1642 {
1643 struct terminate_state *state = arg;
1644 struct timeval tv;
1645
1646 state->req = req;
1647
1648 evhttp_send_reply_start(req, HTTP_OK, "OK");
1649
1650 tv.tv_sec = 0;
1651 tv.tv_usec = 3000;
1652 event_once(-1, EV_TIMEOUT, terminate_chunked_trickle_cb, arg, &tv);
1653 }
1654
1655 static void
1656 terminate_chunked_client(int fd, short event, void *arg)
1657 {
1658 struct terminate_state *state = arg;
1659 bufferevent_free(state->bev);
1660 EVUTIL_CLOSESOCKET(state->fd);
1661 }
1662
1663 static void
1664 terminate_readcb(struct bufferevent *bev, void *arg)
1665 {
1666 /* just drop the data */
1667 evbuffer_drain(bev->output, -1);
1668 }
1669
1670
1671 static void
1672 http_terminate_chunked_test(void)
1673 {
1674 struct bufferevent *bev = NULL;
1675 struct timeval tv;
1676 const char *http_request;
1677 short port = -1;
1678 int fd = -1;
1679
1680 test_ok = 0;
1681 fprintf(stdout, "Testing Terminated Chunked Connection: ");
1682
1683 http = http_setup(&port, NULL);
1684 evhttp_del_cb(http, "/test");
1685 evhttp_set_cb(http, "/test", terminate_chunked_cb, &terminate_state);
1686
1687 fd = http_connect("127.0.0.1", port);
1688
1689 /* Stupid thing to send a request */
1690 bev = bufferevent_new(fd, terminate_readcb, http_writecb,
1691 http_errorcb, NULL);
1692
1693 terminate_state.fd = fd;
1694 terminate_state.bev = bev;
1695
1696 /* first half of the http request */
1697 http_request =
1698 "GET /test HTTP/1.1\r\n"
1699 "Host: some\r\n\r\n";
1700
1701 bufferevent_write(bev, http_request, strlen(http_request));
1702 evutil_timerclear(&tv);
1703 tv.tv_usec = 10000;
1704 event_once(-1, EV_TIMEOUT, terminate_chunked_client, &terminate_state,
1705 &tv);
1706
1707 event_dispatch();
1708
1709 if (test_ok != 1) {
1710 fprintf(stdout, "FAILED\n");
1711 exit(1);
1712 }
1713
1714 fprintf(stdout, "OK\n");
1715
1716 if (fd >= 0)
1717 EVUTIL_CLOSESOCKET(fd);
1718 if (http)
1719 evhttp_free(http);
1720 }
1721
1722 void
1723 http_suite(void)
1724 {
1725 http_base_test();
1726 http_bad_header_test();
1727 http_parse_query_test();
1728 http_basic_test();
1729 http_connection_test(0 /* not-persistent */);
1730 http_connection_test(1 /* persistent */);
1731 http_close_detection(0 /* without delay */);
1732 http_close_detection(1 /* with delay */);
1733 http_bad_request();
1734 http_post_test();
1735 http_failure_test();
1736 http_highport_test();
1737 http_dispatcher_test();
1738
1739 http_multi_line_header_test();
1740 http_negative_content_length_test();
1741
1742 http_chunked_test();
1743 http_terminate_chunked_test();
1744 }
OLDNEW
« no previous file with comments | « third_party/libevent/test/regress_dns.c ('k') | third_party/libevent/test/regress_rpc.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698