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>