Annotation of embedaddon/libevent/test/regress_http.c, revision 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>