Annotation of embedaddon/libevent/test/regress_http.c, revision 1.1.1.1
1.1 misho 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; charset=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)) != NULL) {
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-Encoding");
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>