~ubuntu-branches/ubuntu/lucid/libevent/lucid

« back to all changes in this revision

Viewing changes to test/regress_http.c

  • Committer: Bazaar Package Importer
  • Author(s): Anibal Monsalve Salazar
  • Date: 2009-05-15 20:11:06 UTC
  • mfrom: (1.3.1 upstream) (5.2.1 sid)
  • Revision ID: james.westby@ubuntu.com-20090515201106-auauq7m2l4sej5n9
Tags: 1.4.11-stable-1
* New upstream release 
  - Fix a bug when removing a timeout from the heap
  - Remove the limit on size of HTTP headers by removing static buffers
  - Fix a nasty dangling pointer bug in epoll.c that could occur after
    epoll_recalc() 

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
#include <sys/queue.h>
43
43
#ifndef WIN32
44
44
#include <sys/socket.h>
45
 
#include <sys/signal.h>
 
45
#include <signal.h>
46
46
#include <unistd.h>
47
 
#endif
48
47
#include <netdb.h>
 
48
#endif
49
49
#include <fcntl.h>
50
50
#include <stdlib.h>
51
51
#include <stdio.h>
61
61
extern int test_ok;
62
62
 
63
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);
64
68
 
65
69
void http_basic_cb(struct evhttp_request *req, void *arg);
 
70
static void http_chunked_cb(struct evhttp_request *req, void *arg);
66
71
void http_post_cb(struct evhttp_request *req, void *arg);
67
72
void http_dispatcher_cb(struct evhttp_request *req, void *arg);
 
73
static void http_large_delay_cb(struct evhttp_request *req, void *arg);
68
74
 
69
 
struct evhttp *
70
 
http_setup(short *pport)
 
75
static struct evhttp *
 
76
http_setup(short *pport, struct event_base *base)
71
77
{
72
78
        int i;
73
79
        struct evhttp *myhttp;
74
80
        short port = -1;
75
81
 
76
82
        /* Try a few different ports */
 
83
        myhttp = evhttp_new(base);
77
84
        for (i = 0; i < 50; ++i) {
78
 
                myhttp = evhttp_start("127.0.0.1", 8080 + i);
79
 
                if (myhttp != NULL) {
 
85
                if (evhttp_bind_socket(myhttp, "127.0.0.1", 8080 + i) != -1) {
80
86
                        port = 8080 + i;
81
87
                        break;
82
88
                }
87
93
 
88
94
        /* Register a callback for certain types of requests */
89
95
        evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL);
 
96
        evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, NULL);
90
97
        evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL);
 
98
        evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, NULL);
91
99
        evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL);
92
100
 
93
101
        *pport = port;
94
102
        return (myhttp);
95
103
}
96
104
 
97
 
int
 
105
#ifndef NI_MAXSERV
 
106
#define NI_MAXSERV 1024
 
107
#endif
 
108
 
 
109
static int
98
110
http_connect(const char *address, u_short port)
99
111
{
100
112
        /* Stupid code for connecting */
 
113
#ifdef WIN32
 
114
        struct hostent *he;
 
115
        struct sockaddr_in sin;
 
116
#else
101
117
        struct addrinfo ai, *aitop;
102
118
        char strport[NI_MAXSERV];
 
119
#endif
 
120
        struct sockaddr *sa;
 
121
        int slen;
103
122
        int fd;
104
123
        
 
124
#ifdef WIN32
 
125
        if (!(he = gethostbyname(address))) {
 
126
                event_warn("gethostbyname");
 
127
        }
 
128
        memcpy(&sin.sin_addr, he->h_addr_list[0], he->h_length);
 
129
        sin.sin_family = AF_INET;
 
130
        sin.sin_port = htons(port);
 
131
        slen = sizeof(struct sockaddr_in);
 
132
        sa = (struct sockaddr*)&sin;
 
133
#else
105
134
        memset(&ai, 0, sizeof (ai));
106
135
        ai.ai_family = AF_INET;
107
136
        ai.ai_socktype = SOCK_STREAM;
110
139
                event_warn("getaddrinfo");
111
140
                return (-1);
112
141
        }
 
142
        sa = aitop->ai_addr;
 
143
        slen = aitop->ai_addrlen;
 
144
#endif
113
145
        
114
146
        fd = socket(AF_INET, SOCK_STREAM, 0);
115
147
        if (fd == -1)
116
148
                event_err(1, "socket failed");
117
149
 
118
 
        if (connect(fd, aitop->ai_addr, aitop->ai_addrlen) == -1)
 
150
        if (connect(fd, sa, slen) == -1)
119
151
                event_err(1, "connect failed");
120
152
 
 
153
#ifndef WIN32
121
154
        freeaddrinfo(aitop);
 
155
#endif
122
156
 
123
157
        return (fd);
124
158
}
125
159
 
126
 
void
 
160
static void
127
161
http_readcb(struct bufferevent *bev, void *arg)
128
162
{
129
163
        const char *what = "This is funny";
130
164
 
131
165
        event_debug(("%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
132
166
        
133
 
        if (evbuffer_find(bev->input, (const unsigned char*) what, strlen(what)) != NULL) {
 
167
        if (evbuffer_find(bev->input,
 
168
                (const unsigned char*) what, strlen(what)) != NULL) {
134
169
                struct evhttp_request *req = evhttp_request_new(NULL, NULL);
135
 
                int done;
 
170
                enum message_read_status done;
136
171
 
137
172
                req->kind = EVHTTP_RESPONSE;
138
 
                done = evhttp_parse_lines(req, bev->input);
 
173
                done = evhttp_parse_firstline(req, bev->input);
 
174
                if (done != ALL_DATA_READ)
 
175
                        goto out;
 
176
 
 
177
                done = evhttp_parse_headers(req, bev->input);
 
178
                if (done != ALL_DATA_READ)
 
179
                        goto out;
139
180
 
140
181
                if (done == 1 &&
141
182
                    evhttp_find_header(req->input_headers,
142
183
                        "Content-Type") != NULL)
143
184
                        test_ok++;
 
185
 
 
186
        out:
144
187
                evhttp_request_free(req);
145
188
                bufferevent_disable(bev, EV_READ);
146
 
                event_loopexit(NULL);
 
189
                if (base)
 
190
                        event_base_loopexit(base, NULL);
 
191
                else
 
192
                        event_loopexit(NULL);
147
193
        }
148
194
}
149
195
 
150
 
void
 
196
static void
151
197
http_writecb(struct bufferevent *bev, void *arg)
152
198
{
153
199
        if (EVBUFFER_LENGTH(bev->output) == 0) {
157
203
        }
158
204
}
159
205
 
160
 
void
 
206
static void
161
207
http_errorcb(struct bufferevent *bev, short what, void *arg)
162
208
{
163
209
        test_ok = -2;
167
213
void
168
214
http_basic_cb(struct evhttp_request *req, void *arg)
169
215
{
170
 
 
171
216
        struct evbuffer *evb = evbuffer_new();
 
217
        int empty = evhttp_find_header(req->input_headers, "Empty") != NULL;
172
218
        event_debug(("%s: called\n", __func__));
173
219
        evbuffer_add_printf(evb, "This is funny");
174
 
 
175
 
        evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
176
 
 
177
 
        evbuffer_free(evb);
178
 
}
179
 
 
180
 
void
 
220
        
 
221
        /* For multi-line headers test */
 
222
        {
 
223
                const char *multi =
 
224
                    evhttp_find_header(req->input_headers,"X-multi");
 
225
                if (multi) {
 
226
                        if (strcmp("END", multi + strlen(multi) - 3) == 0)
 
227
                                test_ok++;
 
228
                        if (evhttp_find_header(req->input_headers, "X-Last"))
 
229
                                test_ok++;
 
230
                }
 
231
        }
 
232
 
 
233
        /* injecting a bad content-length */
 
234
        if (evhttp_find_header(req->input_headers, "X-Negative"))
 
235
                evhttp_add_header(req->output_headers,
 
236
                    "Content-Length", "-100");
 
237
 
 
238
        /* allow sending of an empty reply */
 
239
        evhttp_send_reply(req, HTTP_OK, "Everything is fine",
 
240
            !empty ? evb : NULL);
 
241
 
 
242
        evbuffer_free(evb);
 
243
}
 
244
 
 
245
static char const* const CHUNKS[] = {
 
246
        "This is funny",
 
247
        "but not hilarious.",
 
248
        "bwv 1052"
 
249
};
 
250
 
 
251
struct chunk_req_state {
 
252
        struct evhttp_request *req;
 
253
        int i;
 
254
};
 
255
 
 
256
static void
 
257
http_chunked_trickle_cb(int fd, short events, void *arg)
 
258
{
 
259
        struct evbuffer *evb = evbuffer_new();
 
260
        struct chunk_req_state *state = arg;
 
261
        struct timeval when = { 0, 0 };
 
262
 
 
263
        evbuffer_add_printf(evb, "%s", CHUNKS[state->i]);
 
264
        evhttp_send_reply_chunk(state->req, evb);
 
265
        evbuffer_free(evb);
 
266
 
 
267
        if (++state->i < sizeof(CHUNKS)/sizeof(CHUNKS[0])) {
 
268
                event_once(-1, EV_TIMEOUT,
 
269
                    http_chunked_trickle_cb, state, &when);
 
270
        } else {
 
271
                evhttp_send_reply_end(state->req);
 
272
                free(state);
 
273
        }
 
274
}
 
275
 
 
276
static void
 
277
http_chunked_cb(struct evhttp_request *req, void *arg)
 
278
{
 
279
        struct timeval when = { 0, 0 };
 
280
        struct chunk_req_state *state = malloc(sizeof(struct chunk_req_state));
 
281
        event_debug(("%s: called\n", __func__));
 
282
 
 
283
        memset(state, 0, sizeof(struct chunk_req_state));
 
284
        state->req = req;
 
285
 
 
286
        /* generate a chunked reply */
 
287
        evhttp_send_reply_start(req, HTTP_OK, "Everything is fine");
 
288
 
 
289
        /* but trickle it across several iterations to ensure we're not
 
290
         * assuming it comes all at once */
 
291
        event_once(-1, EV_TIMEOUT, http_chunked_trickle_cb, state, &when);
 
292
}
 
293
 
 
294
static void
 
295
http_complete_write(int fd, short what, void *arg)
 
296
{
 
297
        struct bufferevent *bev = arg;
 
298
        const char *http_request = "host\r\n"
 
299
            "Connection: close\r\n"
 
300
            "\r\n";
 
301
        bufferevent_write(bev, http_request, strlen(http_request));
 
302
}
 
303
 
 
304
static void
181
305
http_basic_test(void)
182
306
{
 
307
        struct timeval tv;
183
308
        struct bufferevent *bev;
184
309
        int fd;
185
 
        char *http_request;
 
310
        const char *http_request;
186
311
        short port = -1;
187
312
 
188
313
        test_ok = 0;
189
314
        fprintf(stdout, "Testing Basic HTTP Server: ");
190
315
 
191
 
        http = http_setup(&port);
 
316
        http = http_setup(&port, NULL);
 
317
 
 
318
        /* bind to a second socket */
 
319
        if (evhttp_bind_socket(http, "127.0.0.1", port + 1) == -1) {
 
320
                fprintf(stdout, "FAILED (bind)\n");
 
321
                exit(1);
 
322
        }
192
323
        
193
324
        fd = http_connect("127.0.0.1", port);
194
325
 
196
327
        bev = bufferevent_new(fd, http_readcb, http_writecb,
197
328
            http_errorcb, NULL);
198
329
 
 
330
        /* first half of the http request */
 
331
        http_request =
 
332
            "GET /test HTTP/1.1\r\n"
 
333
            "Host: some";
 
334
 
 
335
        bufferevent_write(bev, http_request, strlen(http_request));
 
336
        timerclear(&tv);
 
337
        tv.tv_usec = 10000;
 
338
        event_once(-1, EV_TIMEOUT, http_complete_write, bev, &tv);
 
339
        
 
340
        event_dispatch();
 
341
 
 
342
        if (test_ok != 3) {
 
343
                fprintf(stdout, "FAILED\n");
 
344
                exit(1);
 
345
        }
 
346
 
 
347
        /* connect to the second port */
 
348
        bufferevent_free(bev);
 
349
        EVUTIL_CLOSESOCKET(fd);
 
350
 
 
351
        fd = http_connect("127.0.0.1", port + 1);
 
352
 
 
353
        /* Stupid thing to send a request */
 
354
        bev = bufferevent_new(fd, http_readcb, http_writecb,
 
355
            http_errorcb, NULL);
 
356
 
199
357
        http_request =
200
358
            "GET /test HTTP/1.1\r\n"
201
359
            "Host: somehost\r\n"
207
365
        event_dispatch();
208
366
 
209
367
        bufferevent_free(bev);
210
 
        close(fd);
 
368
        EVUTIL_CLOSESOCKET(fd);
211
369
 
212
370
        evhttp_free(http);
213
371
        
214
 
        if (test_ok != 2) {
 
372
        if (test_ok != 5) {
215
373
                fprintf(stdout, "FAILED\n");
216
374
                exit(1);
217
375
        }
218
 
        
 
376
 
219
377
        fprintf(stdout, "OK\n");
220
378
}
221
379
 
 
380
static struct evhttp_connection *delayed_client;
 
381
 
 
382
static void
 
383
http_delay_reply(int fd, short what, void *arg)
 
384
{
 
385
        struct evhttp_request *req = arg;
 
386
 
 
387
        evhttp_send_reply(req, HTTP_OK, "Everything is fine", NULL);
 
388
 
 
389
        ++test_ok;
 
390
}
 
391
 
 
392
static void
 
393
http_large_delay_cb(struct evhttp_request *req, void *arg)
 
394
{
 
395
        struct timeval tv;
 
396
        timerclear(&tv);
 
397
        tv.tv_sec = 3;
 
398
 
 
399
        event_once(-1, EV_TIMEOUT, http_delay_reply, req, &tv);
 
400
 
 
401
        /* here we close the client connection which will cause an EOF */
 
402
        evhttp_connection_fail(delayed_client, EVCON_HTTP_EOF);
 
403
}
 
404
 
222
405
void http_request_done(struct evhttp_request *, void *);
 
406
void http_request_empty_done(struct evhttp_request *, void *);
223
407
 
224
 
void
 
408
static void
225
409
http_connection_test(int persistent)
226
410
{
227
411
        short port = -1;
232
416
        fprintf(stdout, "Testing Request Connection Pipeline %s: ",
233
417
            persistent ? "(persistent)" : "");
234
418
 
235
 
        http = http_setup(&port);
 
419
        http = http_setup(&port, NULL);
236
420
 
237
421
        evcon = evhttp_connection_new("127.0.0.1", port);
238
422
        if (evcon == NULL) {
286
470
 
287
471
        event_dispatch();
288
472
 
 
473
        /* make another request: request empty reply */
 
474
        test_ok = 0;
 
475
        
 
476
        req = evhttp_request_new(http_request_empty_done, NULL);
 
477
 
 
478
        /* Add the information that we care about */
 
479
        evhttp_add_header(req->output_headers, "Empty", "itis");
 
480
 
 
481
        /* We give ownership of the request to the connection */
 
482
        if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
 
483
                fprintf(stdout, "FAILED\n");
 
484
                exit(1);
 
485
        }
 
486
 
 
487
        event_dispatch();
 
488
 
 
489
        if (test_ok != 1) {
 
490
                fprintf(stdout, "FAILED\n");
 
491
                exit(1);
 
492
        }
 
493
 
289
494
        evhttp_connection_free(evcon);
290
495
        evhttp_free(http);
291
496
        
298
503
        const char *what = "This is funny";
299
504
 
300
505
        if (req->response_code != HTTP_OK) {
301
 
        
302
506
                fprintf(stderr, "FAILED\n");
303
507
                exit(1);
304
508
        }
322
526
        event_loopexit(NULL);
323
527
}
324
528
 
 
529
/* test date header and content length */
 
530
 
 
531
void
 
532
http_request_empty_done(struct evhttp_request *req, void *arg)
 
533
{
 
534
        if (req->response_code != HTTP_OK) {
 
535
                fprintf(stderr, "FAILED\n");
 
536
                exit(1);
 
537
        }
 
538
 
 
539
        if (evhttp_find_header(req->input_headers, "Date") == NULL) {
 
540
                fprintf(stderr, "FAILED\n");
 
541
                exit(1);
 
542
        }
 
543
 
 
544
        
 
545
        if (evhttp_find_header(req->input_headers, "Content-Length") == NULL) {
 
546
                fprintf(stderr, "FAILED\n");
 
547
                exit(1);
 
548
        }
 
549
 
 
550
        if (strcmp(evhttp_find_header(req->input_headers, "Content-Length"),
 
551
                "0")) {
 
552
                fprintf(stderr, "FAILED\n");
 
553
                exit(1);
 
554
        }
 
555
 
 
556
        if (EVBUFFER_LENGTH(req->input_buffer) != 0) {
 
557
                fprintf(stderr, "FAILED\n");
 
558
                exit(1);
 
559
        }
 
560
 
 
561
        test_ok = 1;
 
562
        event_loopexit(NULL);
 
563
}
 
564
 
325
565
/*
326
566
 * HTTP DISPATCHER test
327
567
 */
339
579
        evbuffer_free(evb);
340
580
}
341
581
 
342
 
void
 
582
static void
343
583
http_dispatcher_test_done(struct evhttp_request *req, void *arg)
344
584
{
345
585
        const char *what = "DISPATCHER_TEST";
369
609
        event_loopexit(NULL);
370
610
}
371
611
 
372
 
void
 
612
static void
373
613
http_dispatcher_test(void)
374
614
{
375
615
        short port = -1;
379
619
        test_ok = 0;
380
620
        fprintf(stdout, "Testing HTTP Dispatcher: ");
381
621
 
382
 
        http = http_setup(&port);
 
622
        http = http_setup(&port, NULL);
383
623
 
384
624
        evcon = evhttp_connection_new("127.0.0.1", port);
385
625
        if (evcon == NULL) {
387
627
                exit(1);
388
628
        }
389
629
 
 
630
        /* also bind to local host */
 
631
        evhttp_connection_set_local_address(evcon, "127.0.0.1");
 
632
 
390
633
        /*
391
634
         * At this point, we want to schedule an HTTP GET request
392
635
         * server using our make request method.
427
670
 
428
671
#define POST_DATA "Okay.  Not really printf"
429
672
 
430
 
void
 
673
static void
431
674
http_post_test(void)
432
675
{
433
676
        short port = -1;
437
680
        test_ok = 0;
438
681
        fprintf(stdout, "Testing HTTP POST Request: ");
439
682
 
440
 
        http = http_setup(&port);
 
683
        http = http_setup(&port, NULL);
441
684
 
442
685
        evcon = evhttp_connection_new("127.0.0.1", port);
443
686
        if (evcon == NULL) {
548
791
        event_loopexit(NULL);
549
792
}
550
793
 
551
 
void
 
794
static void
552
795
http_failure_readcb(struct bufferevent *bev, void *arg)
553
796
{
554
797
        const char *what = "400 Bad Request";
562
805
/*
563
806
 * Testing that the HTTP server can deal with a malformed request.
564
807
 */
565
 
void
 
808
static void
566
809
http_failure_test(void)
567
810
{
568
811
        struct bufferevent *bev;
569
812
        int fd;
570
 
        char *http_request;
 
813
        const char *http_request;
571
814
        short port = -1;
572
815
 
573
816
        test_ok = 0;
574
817
        fprintf(stdout, "Testing Bad HTTP Request: ");
575
818
 
576
 
        http = http_setup(&port);
 
819
        http = http_setup(&port, NULL);
577
820
        
578
821
        fd = http_connect("127.0.0.1", port);
579
822
 
588
831
        event_dispatch();
589
832
 
590
833
        bufferevent_free(bev);
591
 
        close(fd);
 
834
        EVUTIL_CLOSESOCKET(fd);
592
835
 
593
836
        evhttp_free(http);
594
837
        
603
846
static void
604
847
close_detect_done(struct evhttp_request *req, void *arg)
605
848
{
 
849
        struct timeval tv;
606
850
        if (req == NULL || req->response_code != HTTP_OK) {
607
851
        
608
852
                fprintf(stderr, "FAILED\n");
610
854
        }
611
855
 
612
856
        test_ok = 1;
613
 
        event_loopexit(NULL);
 
857
 
 
858
        timerclear(&tv);
 
859
        tv.tv_sec = 3;   /* longer than the http time out */
 
860
 
 
861
        event_loopexit(&tv);
614
862
}
615
863
 
616
864
static void
637
885
        struct evhttp_connection *evcon = arg;
638
886
        struct timeval tv;
639
887
 
640
 
        if (req->response_code != HTTP_OK) {
 
888
        if (req != NULL && req->response_code != HTTP_OK) {
641
889
        
642
890
                fprintf(stderr, "FAILED\n");
643
891
                exit(1);
651
899
}
652
900
 
653
901
 
654
 
void
655
 
http_close_detection()
 
902
static void
 
903
http_close_detection(int with_delay)
656
904
{
657
905
        short port = -1;
658
906
        struct evhttp_connection *evcon = NULL;
659
907
        struct evhttp_request *req = NULL;
660
908
        
661
909
        test_ok = 0;
662
 
        fprintf(stdout, "Testing Connection Close Detection: ");
 
910
        fprintf(stdout, "Testing Connection Close Detection%s: ",
 
911
                with_delay ? " (with delay)" : "");
663
912
 
664
 
        http = http_setup(&port);
 
913
        http = http_setup(&port, NULL);
665
914
 
666
915
        /* 2 second timeout */
667
916
        evhttp_set_timeout(http, 2);
672
921
                exit(1);
673
922
        }
674
923
 
 
924
        delayed_client = evcon;
 
925
 
675
926
        /*
676
927
         * At this point, we want to schedule a request to the HTTP
677
928
         * server using our make request method.
683
934
        evhttp_add_header(req->output_headers, "Host", "somehost");
684
935
 
685
936
        /* We give ownership of the request to the connection */
686
 
        if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
 
937
        if (evhttp_make_request(evcon,
 
938
            req, EVHTTP_REQ_GET, with_delay ? "/largedelay" : "/test") == -1) {
687
939
                fprintf(stdout, "FAILED\n");
688
940
                exit(1);
689
941
        }
695
947
                exit(1);
696
948
        }
697
949
 
 
950
        /* at this point, the http server should have no connection */
 
951
        if (TAILQ_FIRST(&http->connections) != NULL) {
 
952
                fprintf(stdout, "FAILED (left connections)\n");
 
953
                exit(1);
 
954
        }
 
955
 
698
956
        evhttp_connection_free(evcon);
699
957
        evhttp_free(http);
700
958
        
701
959
        fprintf(stdout, "OK\n");
702
960
}
703
961
 
704
 
void
 
962
static void
705
963
http_highport_test(void)
706
964
{
707
965
        int i = -1;
723
981
        exit(1);
724
982
}
725
983
 
726
 
void
727
 
http_bad_header_test()
 
984
static void
 
985
http_bad_header_test(void)
728
986
{
729
987
        struct evkeyvalq headers;
730
988
 
737
995
        
738
996
        if (evhttp_add_header(&headers, "One\r", "Two") != -1)
739
997
                goto fail;
740
 
 
 
998
        if (evhttp_add_header(&headers, "One", "Two") != 0)
 
999
                goto fail;
 
1000
        if (evhttp_add_header(&headers, "One", "Two\r\n Three") != 0)
 
1001
                goto fail;
 
1002
        if (evhttp_add_header(&headers, "One\r", "Two") != -1)
 
1003
                goto fail;
741
1004
        if (evhttp_add_header(&headers, "One\n", "Two") != -1)
742
1005
                goto fail;
743
 
 
744
1006
        if (evhttp_add_header(&headers, "One", "Two\r") != -1)
745
1007
                goto fail;
746
 
 
747
1008
        if (evhttp_add_header(&headers, "One", "Two\n") != -1)
748
1009
                goto fail;
749
1010
 
750
 
        fprintf(stdout, "OK\n");
751
 
        return;
752
 
fail:
753
 
        fprintf(stdout, "FAILED\n");
754
 
        exit(1);
 
1011
        evhttp_clear_headers(&headers);
 
1012
 
 
1013
        fprintf(stdout, "OK\n");
 
1014
        return;
 
1015
fail:
 
1016
        fprintf(stdout, "FAILED\n");
 
1017
        exit(1);
 
1018
}
 
1019
 
 
1020
static int validate_header(
 
1021
        const struct evkeyvalq* headers,
 
1022
        const char *key, const char *value) 
 
1023
{
 
1024
        const char *real_val = evhttp_find_header(headers, key);
 
1025
        if (real_val == NULL)
 
1026
                return (-1);
 
1027
        if (strcmp(real_val, value) != 0)
 
1028
                return (-1);
 
1029
        return (0);
 
1030
}
 
1031
 
 
1032
static void
 
1033
http_parse_query_test(void)
 
1034
{
 
1035
        struct evkeyvalq headers;
 
1036
 
 
1037
        fprintf(stdout, "Testing HTTP query parsing: ");
 
1038
 
 
1039
        TAILQ_INIT(&headers);
 
1040
        
 
1041
        evhttp_parse_query("http://www.test.com/?q=test", &headers);
 
1042
        if (validate_header(&headers, "q", "test") != 0)
 
1043
                goto fail;
 
1044
        evhttp_clear_headers(&headers);
 
1045
 
 
1046
        evhttp_parse_query("http://www.test.com/?q=test&foo=bar", &headers);
 
1047
        if (validate_header(&headers, "q", "test") != 0)
 
1048
                goto fail;
 
1049
        if (validate_header(&headers, "foo", "bar") != 0)
 
1050
                goto fail;
 
1051
        evhttp_clear_headers(&headers);
 
1052
 
 
1053
        evhttp_parse_query("http://www.test.com/?q=test+foo", &headers);
 
1054
        if (validate_header(&headers, "q", "test foo") != 0)
 
1055
                goto fail;
 
1056
        evhttp_clear_headers(&headers);
 
1057
 
 
1058
        evhttp_parse_query("http://www.test.com/?q=test%0Afoo", &headers);
 
1059
        if (validate_header(&headers, "q", "test\nfoo") != 0)
 
1060
                goto fail;
 
1061
        evhttp_clear_headers(&headers);
 
1062
 
 
1063
        evhttp_parse_query("http://www.test.com/?q=test%0Dfoo", &headers);
 
1064
        if (validate_header(&headers, "q", "test\rfoo") != 0)
 
1065
                goto fail;
 
1066
        evhttp_clear_headers(&headers);
 
1067
 
 
1068
        fprintf(stdout, "OK\n");
 
1069
        return;
 
1070
fail:
 
1071
        fprintf(stdout, "FAILED\n");
 
1072
        exit(1);
 
1073
}
 
1074
 
 
1075
static void
 
1076
http_base_test(void)
 
1077
{
 
1078
        struct bufferevent *bev;
 
1079
        int fd;
 
1080
        const char *http_request;
 
1081
        short port = -1;
 
1082
 
 
1083
        test_ok = 0;
 
1084
        fprintf(stdout, "Testing HTTP Server Event Base: ");
 
1085
 
 
1086
        base = event_init();
 
1087
 
 
1088
        /* 
 
1089
         * create another bogus base - which is being used by all subsequen
 
1090
         * tests - yuck!
 
1091
         */
 
1092
        event_init();
 
1093
 
 
1094
        http = http_setup(&port, base);
 
1095
        
 
1096
        fd = http_connect("127.0.0.1", port);
 
1097
 
 
1098
        /* Stupid thing to send a request */
 
1099
        bev = bufferevent_new(fd, http_readcb, http_writecb,
 
1100
            http_errorcb, NULL);
 
1101
        bufferevent_base_set(base, bev);
 
1102
 
 
1103
        http_request =
 
1104
            "GET /test HTTP/1.1\r\n"
 
1105
            "Host: somehost\r\n"
 
1106
            "Connection: close\r\n"
 
1107
            "\r\n";
 
1108
 
 
1109
        bufferevent_write(bev, http_request, strlen(http_request));
 
1110
        
 
1111
        event_base_dispatch(base);
 
1112
 
 
1113
        bufferevent_free(bev);
 
1114
        EVUTIL_CLOSESOCKET(fd);
 
1115
 
 
1116
        evhttp_free(http);
 
1117
 
 
1118
        event_base_free(base);
 
1119
        base = NULL;
 
1120
        
 
1121
        if (test_ok != 2) {
 
1122
                fprintf(stdout, "FAILED\n");
 
1123
                exit(1);
 
1124
        }
 
1125
        
 
1126
        fprintf(stdout, "OK\n");
 
1127
}
 
1128
 
 
1129
/*
 
1130
 * the server is going to reply with chunked data.
 
1131
 */
 
1132
 
 
1133
static void
 
1134
http_chunked_readcb(struct bufferevent *bev, void *arg)
 
1135
{
 
1136
        /* nothing here */
 
1137
}
 
1138
 
 
1139
static void
 
1140
http_chunked_errorcb(struct bufferevent *bev, short what, void *arg)
 
1141
{
 
1142
        if (!test_ok)
 
1143
                goto out;
 
1144
 
 
1145
        test_ok = -1;
 
1146
 
 
1147
        if ((what & EVBUFFER_EOF) != 0) {
 
1148
                struct evhttp_request *req = evhttp_request_new(NULL, NULL);
 
1149
                const char *header;
 
1150
                enum message_read_status done;
 
1151
                
 
1152
                req->kind = EVHTTP_RESPONSE;
 
1153
                done = evhttp_parse_firstline(req, EVBUFFER_INPUT(bev));
 
1154
                if (done != ALL_DATA_READ)
 
1155
                        goto out;
 
1156
 
 
1157
                done = evhttp_parse_headers(req, EVBUFFER_INPUT(bev));
 
1158
                if (done != ALL_DATA_READ)
 
1159
                        goto out;
 
1160
 
 
1161
                header = evhttp_find_header(req->input_headers, "Transfer-Encoding");
 
1162
                if (header == NULL || strcmp(header, "chunked"))
 
1163
                        goto out;
 
1164
 
 
1165
                header = evhttp_find_header(req->input_headers, "Connection");
 
1166
                if (header == NULL || strcmp(header, "close"))
 
1167
                        goto out;
 
1168
 
 
1169
                header = evbuffer_readline(EVBUFFER_INPUT(bev));
 
1170
                if (header == NULL)
 
1171
                        goto out;
 
1172
                /* 13 chars */
 
1173
                if (strcmp(header, "d"))
 
1174
                        goto out;
 
1175
                free((char*)header);
 
1176
 
 
1177
                if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
 
1178
                        "This is funny", 13))
 
1179
                        goto out;
 
1180
 
 
1181
                evbuffer_drain(EVBUFFER_INPUT(bev), 13 + 2);
 
1182
 
 
1183
                header = evbuffer_readline(EVBUFFER_INPUT(bev));
 
1184
                if (header == NULL)
 
1185
                        goto out;
 
1186
                /* 18 chars */
 
1187
                if (strcmp(header, "12"))
 
1188
                        goto out;
 
1189
                free((char *)header);
 
1190
 
 
1191
                if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
 
1192
                        "but not hilarious.", 18))
 
1193
                        goto out;
 
1194
 
 
1195
                evbuffer_drain(EVBUFFER_INPUT(bev), 18 + 2);
 
1196
 
 
1197
                header = evbuffer_readline(EVBUFFER_INPUT(bev));
 
1198
                if (header == NULL)
 
1199
                        goto out;
 
1200
                /* 8 chars */
 
1201
                if (strcmp(header, "8"))
 
1202
                        goto out;
 
1203
                free((char *)header);
 
1204
 
 
1205
                if (strncmp((char *)EVBUFFER_DATA(EVBUFFER_INPUT(bev)),
 
1206
                        "bwv 1052.", 8))
 
1207
                        goto out;
 
1208
 
 
1209
                evbuffer_drain(EVBUFFER_INPUT(bev), 8 + 2);
 
1210
 
 
1211
                header = evbuffer_readline(EVBUFFER_INPUT(bev));
 
1212
                if (header == NULL)
 
1213
                        goto out;
 
1214
                /* 0 chars */
 
1215
                if (strcmp(header, "0"))
 
1216
                        goto out;
 
1217
                free((char *)header);
 
1218
 
 
1219
                test_ok = 2;
 
1220
        }
 
1221
 
 
1222
out:
 
1223
        event_loopexit(NULL);
 
1224
}
 
1225
 
 
1226
static void
 
1227
http_chunked_writecb(struct bufferevent *bev, void *arg)
 
1228
{
 
1229
        if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(bev)) == 0) {
 
1230
                /* enable reading of the reply */
 
1231
                bufferevent_enable(bev, EV_READ);
 
1232
                test_ok++;
 
1233
        }
 
1234
}
 
1235
 
 
1236
static void
 
1237
http_chunked_request_done(struct evhttp_request *req, void *arg)
 
1238
{
 
1239
        if (req->response_code != HTTP_OK) {
 
1240
                fprintf(stderr, "FAILED\n");
 
1241
                exit(1);
 
1242
        }
 
1243
 
 
1244
        if (evhttp_find_header(req->input_headers,
 
1245
                "Transfer-Encoding") == NULL) {
 
1246
                fprintf(stderr, "FAILED\n");
 
1247
                exit(1);
 
1248
        }
 
1249
 
 
1250
        if (EVBUFFER_LENGTH(req->input_buffer) != 13 + 18 + 8) {
 
1251
                fprintf(stderr, "FAILED\n");
 
1252
                exit(1);
 
1253
        }
 
1254
 
 
1255
        if (strncmp((char *)EVBUFFER_DATA(req->input_buffer),
 
1256
                "This is funnybut not hilarious.bwv 1052",
 
1257
                13 + 18 + 8)) {
 
1258
                fprintf(stderr, "FAILED\n");
 
1259
                exit(1);
 
1260
        }
 
1261
        
 
1262
        test_ok = 1;
 
1263
        event_loopexit(NULL);
 
1264
}
 
1265
 
 
1266
static void
 
1267
http_chunked_test(void)
 
1268
{
 
1269
        struct bufferevent *bev;
 
1270
        int fd;
 
1271
        const char *http_request;
 
1272
        short port = -1;
 
1273
        struct timeval tv_start, tv_end;
 
1274
        struct evhttp_connection *evcon = NULL;
 
1275
        struct evhttp_request *req = NULL;
 
1276
        int i;
 
1277
 
 
1278
        test_ok = 0;
 
1279
        fprintf(stdout, "Testing Chunked HTTP Reply: ");
 
1280
 
 
1281
        http = http_setup(&port, NULL);
 
1282
 
 
1283
        fd = http_connect("127.0.0.1", port);
 
1284
 
 
1285
        /* Stupid thing to send a request */
 
1286
        bev = bufferevent_new(fd, 
 
1287
            http_chunked_readcb, http_chunked_writecb,
 
1288
            http_chunked_errorcb, NULL);
 
1289
 
 
1290
        http_request =
 
1291
            "GET /chunked HTTP/1.1\r\n"
 
1292
            "Host: somehost\r\n"
 
1293
            "Connection: close\r\n"
 
1294
            "\r\n";
 
1295
 
 
1296
        bufferevent_write(bev, http_request, strlen(http_request));
 
1297
 
 
1298
        evutil_gettimeofday(&tv_start, NULL);
 
1299
        
 
1300
        event_dispatch();
 
1301
 
 
1302
        evutil_gettimeofday(&tv_end, NULL);
 
1303
        evutil_timersub(&tv_end, &tv_start, &tv_end);
 
1304
 
 
1305
        if (tv_end.tv_sec >= 1) {
 
1306
                fprintf(stdout, "FAILED (time)\n");
 
1307
                exit (1);
 
1308
        }
 
1309
 
 
1310
 
 
1311
        if (test_ok != 2) {
 
1312
                fprintf(stdout, "FAILED\n");
 
1313
                exit(1);
 
1314
        }
 
1315
 
 
1316
        /* now try again with the regular connection object */
 
1317
        evcon = evhttp_connection_new("127.0.0.1", port);
 
1318
        if (evcon == NULL) {
 
1319
                fprintf(stdout, "FAILED\n");
 
1320
                exit(1);
 
1321
        }
 
1322
 
 
1323
        /* make two requests to check the keepalive behavior */
 
1324
        for (i = 0; i < 2; i++) {
 
1325
                test_ok = 0;
 
1326
                req = evhttp_request_new(http_chunked_request_done, NULL);
 
1327
 
 
1328
                /* Add the information that we care about */
 
1329
                evhttp_add_header(req->output_headers, "Host", "somehost");
 
1330
 
 
1331
                /* We give ownership of the request to the connection */
 
1332
                if (evhttp_make_request(evcon, req,
 
1333
                        EVHTTP_REQ_GET, "/chunked") == -1) {
 
1334
                        fprintf(stdout, "FAILED\n");
 
1335
                        exit(1);
 
1336
                }
 
1337
 
 
1338
                event_dispatch();
 
1339
 
 
1340
                if (test_ok != 1) {
 
1341
                        fprintf(stdout, "FAILED\n");
 
1342
                        exit(1);
 
1343
                }
 
1344
        }
 
1345
 
 
1346
        evhttp_connection_free(evcon);
 
1347
        evhttp_free(http);
 
1348
        
 
1349
        fprintf(stdout, "OK\n");
 
1350
}
 
1351
 
 
1352
static void
 
1353
http_multi_line_header_test(void)
 
1354
{
 
1355
        struct bufferevent *bev;
 
1356
        int fd;
 
1357
        const char *http_start_request;
 
1358
        short port = -1;
 
1359
        
 
1360
        test_ok = 0;
 
1361
        fprintf(stdout, "Testing HTTP Server with multi line: ");
 
1362
 
 
1363
        http = http_setup(&port, NULL);
 
1364
        
 
1365
        fd = http_connect("127.0.0.1", port);
 
1366
 
 
1367
        /* Stupid thing to send a request */
 
1368
        bev = bufferevent_new(fd, http_readcb, http_writecb,
 
1369
            http_errorcb, NULL);
 
1370
 
 
1371
        http_start_request =
 
1372
            "GET /test HTTP/1.1\r\n"
 
1373
            "Host: somehost\r\n"
 
1374
            "Connection: close\r\n"
 
1375
            "X-Multi:  aaaaaaaa\r\n"
 
1376
            " a\r\n"
 
1377
            "\tEND\r\n"
 
1378
            "X-Last: last\r\n"
 
1379
            "\r\n";
 
1380
                
 
1381
        bufferevent_write(bev, http_start_request, strlen(http_start_request));
 
1382
 
 
1383
        event_dispatch();
 
1384
        
 
1385
        bufferevent_free(bev);
 
1386
        EVUTIL_CLOSESOCKET(fd);
 
1387
 
 
1388
        evhttp_free(http);
 
1389
 
 
1390
        if (test_ok != 4) {
 
1391
                fprintf(stdout, "FAILED\n");
 
1392
                exit(1);
 
1393
        }
 
1394
        
 
1395
        fprintf(stdout, "OK\n");
 
1396
}
 
1397
 
 
1398
static void
 
1399
http_request_bad(struct evhttp_request *req, void *arg)
 
1400
{
 
1401
        if (req != NULL) {
 
1402
                fprintf(stderr, "FAILED\n");
 
1403
                exit(1);
 
1404
        }
 
1405
 
 
1406
        test_ok = 1;
 
1407
        event_loopexit(NULL);
 
1408
}
 
1409
 
 
1410
static void
 
1411
http_negative_content_length_test(void)
 
1412
{
 
1413
        short port = -1;
 
1414
        struct evhttp_connection *evcon = NULL;
 
1415
        struct evhttp_request *req = NULL;
 
1416
        
 
1417
        test_ok = 0;
 
1418
        fprintf(stdout, "Testing HTTP Negative Content Length: ");
 
1419
 
 
1420
        http = http_setup(&port, NULL);
 
1421
 
 
1422
        evcon = evhttp_connection_new("127.0.0.1", port);
 
1423
        if (evcon == NULL) {
 
1424
                fprintf(stdout, "FAILED\n");
 
1425
                exit(1);
 
1426
        }
 
1427
 
 
1428
        /*
 
1429
         * At this point, we want to schedule a request to the HTTP
 
1430
         * server using our make request method.
 
1431
         */
 
1432
 
 
1433
        req = evhttp_request_new(http_request_bad, NULL);
 
1434
 
 
1435
        /* Cause the response to have a negative content-length */
 
1436
        evhttp_add_header(req->output_headers, "X-Negative", "makeitso");
 
1437
 
 
1438
        /* We give ownership of the request to the connection */
 
1439
        if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
 
1440
                fprintf(stdout, "FAILED\n");
 
1441
                exit(1);
 
1442
        }
 
1443
 
 
1444
        event_dispatch();
 
1445
 
 
1446
        evhttp_free(http);
 
1447
 
 
1448
        if (test_ok != 1) {
 
1449
                fprintf(stdout, "FAILED\n");
 
1450
                exit(1);
 
1451
        }
 
1452
 
 
1453
        fprintf(stdout, "OK\n");
755
1454
}
756
1455
 
757
1456
void
758
1457
http_suite(void)
759
1458
{
 
1459
        http_base_test();
760
1460
        http_bad_header_test();
 
1461
        http_parse_query_test();
761
1462
        http_basic_test();
762
1463
        http_connection_test(0 /* not-persistent */);
763
1464
        http_connection_test(1 /* persistent */);
764
 
        http_close_detection();
 
1465
        http_close_detection(0 /* with delay */);
 
1466
        http_close_detection(1 /* with delay */);
765
1467
        http_post_test();
766
1468
        http_failure_test();
767
1469
        http_highport_test();
768
1470
        http_dispatcher_test();
 
1471
 
 
1472
        http_multi_line_header_test();
 
1473
        http_negative_content_length_test();
 
1474
 
 
1475
        http_chunked_test();
769
1476
}