OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu> | 2 * Copyright (c) 2003-2006 Niels Provos <provos@citi.umich.edu> |
3 * All rights reserved. | 3 * All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 24 matching lines...) Expand all Loading... |
35 #endif | 35 #endif |
36 | 36 |
37 #include <sys/types.h> | 37 #include <sys/types.h> |
38 #include <sys/stat.h> | 38 #include <sys/stat.h> |
39 #ifdef HAVE_SYS_TIME_H | 39 #ifdef HAVE_SYS_TIME_H |
40 #include <sys/time.h> | 40 #include <sys/time.h> |
41 #endif | 41 #endif |
42 #include <sys/queue.h> | 42 #include <sys/queue.h> |
43 #ifndef WIN32 | 43 #ifndef WIN32 |
44 #include <sys/socket.h> | 44 #include <sys/socket.h> |
45 #include <sys/signal.h> | 45 #include <signal.h> |
46 #include <unistd.h> | 46 #include <unistd.h> |
47 #include <netdb.h> | 47 #include <netdb.h> |
48 #endif | 48 #endif |
49 #include <fcntl.h> | 49 #include <fcntl.h> |
50 #include <stdlib.h> | 50 #include <stdlib.h> |
51 #include <stdio.h> | 51 #include <stdio.h> |
52 #include <string.h> | 52 #include <string.h> |
53 #include <errno.h> | 53 #include <errno.h> |
54 | 54 |
55 #include "event.h" | 55 #include "event.h" |
56 #include "evhttp.h" | 56 #include "evhttp.h" |
57 #include "log.h" | 57 #include "log.h" |
58 #include "http-internal.h" | 58 #include "http-internal.h" |
59 | 59 |
60 extern int pair[]; | 60 extern int pair[]; |
61 extern int test_ok; | 61 extern int test_ok; |
62 | 62 |
63 static struct evhttp *http; | 63 static struct evhttp *http; |
64 /* set if a test needs to call loopexit on a base */ | 64 /* set if a test needs to call loopexit on a base */ |
65 static struct event_base *base; | 65 static struct event_base *base; |
66 | 66 |
67 void http_suite(void); | 67 void http_suite(void); |
68 | 68 |
69 void http_basic_cb(struct evhttp_request *req, void *arg); | 69 void http_basic_cb(struct evhttp_request *req, void *arg); |
70 static void http_chunked_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); | 71 void http_post_cb(struct evhttp_request *req, void *arg); |
72 void http_dispatcher_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); |
73 | 74 |
74 static struct evhttp * | 75 static struct evhttp * |
75 http_setup(short *pport, struct event_base *base) | 76 http_setup(short *pport, struct event_base *base) |
76 { | 77 { |
77 int i; | 78 int i; |
78 struct evhttp *myhttp; | 79 struct evhttp *myhttp; |
79 short port = -1; | 80 short port = -1; |
80 | 81 |
81 /* Try a few different ports */ | 82 /* Try a few different ports */ |
82 myhttp = evhttp_new(base); | 83 myhttp = evhttp_new(base); |
83 for (i = 0; i < 50; ++i) { | 84 for (i = 0; i < 50; ++i) { |
84 if (evhttp_bind_socket(myhttp, "127.0.0.1", 8080 + i) != -1) { | 85 if (evhttp_bind_socket(myhttp, "127.0.0.1", 8080 + i) != -1) { |
85 port = 8080 + i; | 86 port = 8080 + i; |
86 break; | 87 break; |
87 } | 88 } |
88 } | 89 } |
89 | 90 |
90 if (port == -1) | 91 if (port == -1) |
91 event_errx(1, "Could not start web server"); | 92 event_errx(1, "Could not start web server"); |
92 | 93 |
93 /* Register a callback for certain types of requests */ | 94 /* Register a callback for certain types of requests */ |
94 evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL); | 95 evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL); |
95 evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, NULL); | 96 evhttp_set_cb(myhttp, "/chunked", http_chunked_cb, NULL); |
96 evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL); | 97 evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL); |
| 98 evhttp_set_cb(myhttp, "/largedelay", http_large_delay_cb, NULL); |
97 evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL); | 99 evhttp_set_cb(myhttp, "/", http_dispatcher_cb, NULL); |
98 | 100 |
99 *pport = port; | 101 *pport = port; |
100 return (myhttp); | 102 return (myhttp); |
101 } | 103 } |
102 | 104 |
103 #ifndef NI_MAXSERV | 105 #ifndef NI_MAXSERV |
104 #define NI_MAXSERV 1024 | 106 #define NI_MAXSERV 1024 |
105 #endif | 107 #endif |
106 | 108 |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 evhttp_free(http); | 370 evhttp_free(http); |
369 | 371 |
370 if (test_ok != 5) { | 372 if (test_ok != 5) { |
371 fprintf(stdout, "FAILED\n"); | 373 fprintf(stdout, "FAILED\n"); |
372 exit(1); | 374 exit(1); |
373 } | 375 } |
374 | 376 |
375 fprintf(stdout, "OK\n"); | 377 fprintf(stdout, "OK\n"); |
376 } | 378 } |
377 | 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 |
378 void http_request_done(struct evhttp_request *, void *); | 405 void http_request_done(struct evhttp_request *, void *); |
379 void http_request_empty_done(struct evhttp_request *, void *); | 406 void http_request_empty_done(struct evhttp_request *, void *); |
380 | 407 |
381 static void | 408 static void |
382 http_connection_test(int persistent) | 409 http_connection_test(int persistent) |
383 { | 410 { |
384 short port = -1; | 411 short port = -1; |
385 struct evhttp_connection *evcon = NULL; | 412 struct evhttp_connection *evcon = NULL; |
386 struct evhttp_request *req = NULL; | 413 struct evhttp_request *req = NULL; |
387 | 414 |
(...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
812 fprintf(stdout, "FAILED\n"); | 839 fprintf(stdout, "FAILED\n"); |
813 exit(1); | 840 exit(1); |
814 } | 841 } |
815 | 842 |
816 fprintf(stdout, "OK\n"); | 843 fprintf(stdout, "OK\n"); |
817 } | 844 } |
818 | 845 |
819 static void | 846 static void |
820 close_detect_done(struct evhttp_request *req, void *arg) | 847 close_detect_done(struct evhttp_request *req, void *arg) |
821 { | 848 { |
| 849 struct timeval tv; |
822 if (req == NULL || req->response_code != HTTP_OK) { | 850 if (req == NULL || req->response_code != HTTP_OK) { |
823 | 851 |
824 fprintf(stderr, "FAILED\n"); | 852 fprintf(stderr, "FAILED\n"); |
825 exit(1); | 853 exit(1); |
826 } | 854 } |
827 | 855 |
828 test_ok = 1; | 856 test_ok = 1; |
829 » event_loopexit(NULL); | 857 |
| 858 » timerclear(&tv); |
| 859 » tv.tv_sec = 3; /* longer than the http time out */ |
| 860 |
| 861 » event_loopexit(&tv); |
830 } | 862 } |
831 | 863 |
832 static void | 864 static void |
833 close_detect_launch(int fd, short what, void *arg) | 865 close_detect_launch(int fd, short what, void *arg) |
834 { | 866 { |
835 struct evhttp_connection *evcon = arg; | 867 struct evhttp_connection *evcon = arg; |
836 struct evhttp_request *req; | 868 struct evhttp_request *req; |
837 | 869 |
838 req = evhttp_request_new(close_detect_done, NULL); | 870 req = evhttp_request_new(close_detect_done, NULL); |
839 | 871 |
840 /* Add the information that we care about */ | 872 /* Add the information that we care about */ |
841 evhttp_add_header(req->output_headers, "Host", "somehost"); | 873 evhttp_add_header(req->output_headers, "Host", "somehost"); |
842 | 874 |
843 /* We give ownership of the request to the connection */ | 875 /* We give ownership of the request to the connection */ |
844 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { | 876 if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) { |
845 fprintf(stdout, "FAILED\n"); | 877 fprintf(stdout, "FAILED\n"); |
846 exit(1); | 878 exit(1); |
847 } | 879 } |
848 } | 880 } |
849 | 881 |
850 static void | 882 static void |
851 close_detect_cb(struct evhttp_request *req, void *arg) | 883 close_detect_cb(struct evhttp_request *req, void *arg) |
852 { | 884 { |
853 struct evhttp_connection *evcon = arg; | 885 struct evhttp_connection *evcon = arg; |
854 struct timeval tv; | 886 struct timeval tv; |
855 | 887 |
856 » if (req->response_code != HTTP_OK) { | 888 » if (req != NULL && req->response_code != HTTP_OK) { |
857 | 889 |
858 fprintf(stderr, "FAILED\n"); | 890 fprintf(stderr, "FAILED\n"); |
859 exit(1); | 891 exit(1); |
860 } | 892 } |
861 | 893 |
862 timerclear(&tv); | 894 timerclear(&tv); |
863 tv.tv_sec = 3; /* longer than the http time out */ | 895 tv.tv_sec = 3; /* longer than the http time out */ |
864 | 896 |
865 /* launch a new request on the persistent connection in 6 seconds */ | 897 /* launch a new request on the persistent connection in 6 seconds */ |
866 event_once(-1, EV_TIMEOUT, close_detect_launch, evcon, &tv); | 898 event_once(-1, EV_TIMEOUT, close_detect_launch, evcon, &tv); |
867 } | 899 } |
868 | 900 |
869 | 901 |
870 static void | 902 static void |
871 http_close_detection(void) | 903 http_close_detection(int with_delay) |
872 { | 904 { |
873 short port = -1; | 905 short port = -1; |
874 struct evhttp_connection *evcon = NULL; | 906 struct evhttp_connection *evcon = NULL; |
875 struct evhttp_request *req = NULL; | 907 struct evhttp_request *req = NULL; |
876 | 908 |
877 test_ok = 0; | 909 test_ok = 0; |
878 » fprintf(stdout, "Testing Connection Close Detection: "); | 910 » fprintf(stdout, "Testing Connection Close Detection%s: ", |
| 911 » » with_delay ? " (with delay)" : ""); |
879 | 912 |
880 http = http_setup(&port, NULL); | 913 http = http_setup(&port, NULL); |
881 | 914 |
882 /* 2 second timeout */ | 915 /* 2 second timeout */ |
883 evhttp_set_timeout(http, 2); | 916 evhttp_set_timeout(http, 2); |
884 | 917 |
885 evcon = evhttp_connection_new("127.0.0.1", port); | 918 evcon = evhttp_connection_new("127.0.0.1", port); |
886 if (evcon == NULL) { | 919 if (evcon == NULL) { |
887 fprintf(stdout, "FAILED\n"); | 920 fprintf(stdout, "FAILED\n"); |
888 exit(1); | 921 exit(1); |
889 } | 922 } |
890 | 923 |
| 924 delayed_client = evcon; |
| 925 |
891 /* | 926 /* |
892 * At this point, we want to schedule a request to the HTTP | 927 * At this point, we want to schedule a request to the HTTP |
893 * server using our make request method. | 928 * server using our make request method. |
894 */ | 929 */ |
895 | 930 |
896 req = evhttp_request_new(close_detect_cb, evcon); | 931 req = evhttp_request_new(close_detect_cb, evcon); |
897 | 932 |
898 /* Add the information that we care about */ | 933 /* Add the information that we care about */ |
899 evhttp_add_header(req->output_headers, "Host", "somehost"); | 934 evhttp_add_header(req->output_headers, "Host", "somehost"); |
900 | 935 |
901 /* We give ownership of the request to the connection */ | 936 /* We give ownership of the request to the connection */ |
902 » 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) { |
903 fprintf(stdout, "FAILED\n"); | 939 fprintf(stdout, "FAILED\n"); |
904 exit(1); | 940 exit(1); |
905 } | 941 } |
906 | 942 |
907 event_dispatch(); | 943 event_dispatch(); |
908 | 944 |
909 if (test_ok != 1) { | 945 if (test_ok != 1) { |
910 fprintf(stdout, "FAILED\n"); | 946 fprintf(stdout, "FAILED\n"); |
911 exit(1); | 947 exit(1); |
912 } | 948 } |
913 | 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 |
914 evhttp_connection_free(evcon); | 956 evhttp_connection_free(evcon); |
915 evhttp_free(http); | 957 evhttp_free(http); |
916 | 958 |
917 fprintf(stdout, "OK\n"); | 959 fprintf(stdout, "OK\n"); |
918 } | 960 } |
919 | 961 |
920 static void | 962 static void |
921 http_highport_test(void) | 963 http_highport_test(void) |
922 { | 964 { |
923 int i = -1; | 965 int i = -1; |
(...skipping 22 matching lines...) Expand all Loading... |
946 | 988 |
947 fprintf(stdout, "Testing HTTP Header filtering: "); | 989 fprintf(stdout, "Testing HTTP Header filtering: "); |
948 | 990 |
949 TAILQ_INIT(&headers); | 991 TAILQ_INIT(&headers); |
950 | 992 |
951 if (evhttp_add_header(&headers, "One", "Two") != 0) | 993 if (evhttp_add_header(&headers, "One", "Two") != 0) |
952 goto fail; | 994 goto fail; |
953 | 995 |
954 if (evhttp_add_header(&headers, "One\r", "Two") != -1) | 996 if (evhttp_add_header(&headers, "One\r", "Two") != -1) |
955 goto fail; | 997 goto fail; |
956 | 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; |
957 if (evhttp_add_header(&headers, "One\n", "Two") != -1) | 1004 if (evhttp_add_header(&headers, "One\n", "Two") != -1) |
958 goto fail; | 1005 goto fail; |
959 | |
960 if (evhttp_add_header(&headers, "One", "Two\r") != -1) | 1006 if (evhttp_add_header(&headers, "One", "Two\r") != -1) |
961 goto fail; | 1007 goto fail; |
962 | |
963 if (evhttp_add_header(&headers, "One", "Two\n") != -1) | 1008 if (evhttp_add_header(&headers, "One", "Two\n") != -1) |
964 goto fail; | 1009 goto fail; |
965 | 1010 |
966 evhttp_clear_headers(&headers); | 1011 evhttp_clear_headers(&headers); |
967 | 1012 |
968 fprintf(stdout, "OK\n"); | 1013 fprintf(stdout, "OK\n"); |
969 return; | 1014 return; |
970 fail: | 1015 fail: |
971 fprintf(stdout, "FAILED\n"); | 1016 fprintf(stdout, "FAILED\n"); |
972 exit(1); | 1017 exit(1); |
973 } | 1018 } |
974 | 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 |
975 static void | 1075 static void |
976 http_base_test(void) | 1076 http_base_test(void) |
977 { | 1077 { |
978 struct bufferevent *bev; | 1078 struct bufferevent *bev; |
979 int fd; | 1079 int fd; |
980 const char *http_request; | 1080 const char *http_request; |
981 short port = -1; | 1081 short port = -1; |
982 | 1082 |
983 test_ok = 0; | 1083 test_ok = 0; |
984 fprintf(stdout, "Testing HTTP Server Event Base: "); | 1084 fprintf(stdout, "Testing HTTP Server Event Base: "); |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1351 } | 1451 } |
1352 | 1452 |
1353 fprintf(stdout, "OK\n"); | 1453 fprintf(stdout, "OK\n"); |
1354 } | 1454 } |
1355 | 1455 |
1356 void | 1456 void |
1357 http_suite(void) | 1457 http_suite(void) |
1358 { | 1458 { |
1359 http_base_test(); | 1459 http_base_test(); |
1360 http_bad_header_test(); | 1460 http_bad_header_test(); |
| 1461 http_parse_query_test(); |
1361 http_basic_test(); | 1462 http_basic_test(); |
1362 http_connection_test(0 /* not-persistent */); | 1463 http_connection_test(0 /* not-persistent */); |
1363 http_connection_test(1 /* persistent */); | 1464 http_connection_test(1 /* persistent */); |
1364 » http_close_detection(); | 1465 » http_close_detection(0 /* with delay */); |
| 1466 » http_close_detection(1 /* with delay */); |
1365 http_post_test(); | 1467 http_post_test(); |
1366 http_failure_test(); | 1468 http_failure_test(); |
1367 http_highport_test(); | 1469 http_highport_test(); |
1368 http_dispatcher_test(); | 1470 http_dispatcher_test(); |
1369 | 1471 |
1370 http_multi_line_header_test(); | 1472 http_multi_line_header_test(); |
1371 http_negative_content_length_test(); | 1473 http_negative_content_length_test(); |
1372 | 1474 |
1373 http_chunked_test(); | 1475 http_chunked_test(); |
1374 } | 1476 } |
OLD | NEW |