diff options
Diffstat (limited to 'src/testzzuf')
-rw-r--r-- | src/testzzuf/Makefile.am | 125 | ||||
-rw-r--r-- | src/testzzuf/daemontest.c | 163 | ||||
-rw-r--r-- | src/testzzuf/daemontest_get.c | 330 | ||||
-rw-r--r-- | src/testzzuf/daemontest_get_chunked.c | 364 | ||||
-rw-r--r-- | src/testzzuf/daemontest_large_put.c | 404 | ||||
-rw-r--r-- | src/testzzuf/daemontest_long_header.c | 240 | ||||
-rw-r--r-- | src/testzzuf/daemontest_put.c | 375 | ||||
-rw-r--r-- | src/testzzuf/daemontest_put_chunked.c | 383 |
8 files changed, 2384 insertions, 0 deletions
diff --git a/src/testzzuf/Makefile.am b/src/testzzuf/Makefile.am new file mode 100644 index 00000000..b48b75be --- /dev/null +++ b/src/testzzuf/Makefile.am | |||
@@ -0,0 +1,125 @@ | |||
1 | SUBDIRS = . | ||
2 | |||
3 | INCLUDES = -I$(top_srcdir)/src/include | ||
4 | |||
5 | check_PROGRAMS = \ | ||
6 | postprocessor_test \ | ||
7 | daemontest \ | ||
8 | daemontest_get \ | ||
9 | daemontest_post \ | ||
10 | daemontest_postform \ | ||
11 | daemontest_post_loop \ | ||
12 | daemontest_put \ | ||
13 | daemontest_large_put \ | ||
14 | daemontest_get11 \ | ||
15 | daemontest_post11 \ | ||
16 | daemontest_postform11 \ | ||
17 | daemontest_post_loop11 \ | ||
18 | daemontest_put11 \ | ||
19 | daemontest_large_put11 \ | ||
20 | daemontest_long_header \ | ||
21 | daemontest_get_chunked \ | ||
22 | daemontest_put_chunked | ||
23 | |||
24 | TESTS = $(check_PROGRAMS) | ||
25 | |||
26 | daemontest_SOURCES = \ | ||
27 | daemontest.c | ||
28 | daemontest_LDADD = \ | ||
29 | $(top_builddir)/src/daemon/libmicrohttpd.la | ||
30 | |||
31 | postprocessor_test_SOURCES = \ | ||
32 | postprocessor_test.c | ||
33 | postprocessor_test_LDADD = \ | ||
34 | $(top_builddir)/src/daemon/libmicrohttpd.la | ||
35 | |||
36 | daemontest_get_SOURCES = \ | ||
37 | daemontest_get.c | ||
38 | daemontest_get_LDADD = \ | ||
39 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
40 | @LIBCURL@ | ||
41 | |||
42 | daemontest_get_chunked_SOURCES = \ | ||
43 | daemontest_get_chunked.c | ||
44 | daemontest_get_chunked_LDADD = \ | ||
45 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
46 | @LIBCURL@ | ||
47 | |||
48 | daemontest_post_SOURCES = \ | ||
49 | daemontest_post.c | ||
50 | daemontest_post_LDADD = \ | ||
51 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
52 | @LIBCURL@ | ||
53 | |||
54 | daemontest_postform_SOURCES = \ | ||
55 | daemontest_postform.c | ||
56 | daemontest_postform_LDADD = \ | ||
57 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
58 | @LIBCURL@ | ||
59 | |||
60 | daemontest_post_loop_SOURCES = \ | ||
61 | daemontest_post_loop.c | ||
62 | daemontest_post_loop_LDADD = \ | ||
63 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
64 | @LIBCURL@ | ||
65 | |||
66 | daemontest_put_SOURCES = \ | ||
67 | daemontest_put.c | ||
68 | daemontest_put_LDADD = \ | ||
69 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
70 | @LIBCURL@ | ||
71 | |||
72 | daemontest_put_chunked_SOURCES = \ | ||
73 | daemontest_put_chunked.c | ||
74 | daemontest_put_chunked_LDADD = \ | ||
75 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
76 | @LIBCURL@ | ||
77 | |||
78 | daemontest_get11_SOURCES = \ | ||
79 | daemontest_get.c | ||
80 | daemontest_get11_LDADD = \ | ||
81 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
82 | @LIBCURL@ | ||
83 | |||
84 | daemontest_post11_SOURCES = \ | ||
85 | daemontest_post.c | ||
86 | daemontest_post11_LDADD = \ | ||
87 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
88 | @LIBCURL@ | ||
89 | |||
90 | daemontest_postform11_SOURCES = \ | ||
91 | daemontest_postform.c | ||
92 | daemontest_postform11_LDADD = \ | ||
93 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
94 | @LIBCURL@ | ||
95 | |||
96 | daemontest_post_loop11_SOURCES = \ | ||
97 | daemontest_post_loop.c | ||
98 | daemontest_post_loop11_LDADD = \ | ||
99 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
100 | @LIBCURL@ | ||
101 | |||
102 | daemontest_put11_SOURCES = \ | ||
103 | daemontest_put.c | ||
104 | daemontest_put11_LDADD = \ | ||
105 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
106 | @LIBCURL@ | ||
107 | |||
108 | |||
109 | daemontest_large_put_SOURCES = \ | ||
110 | daemontest_large_put.c | ||
111 | daemontest_large_put_LDADD = \ | ||
112 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
113 | @LIBCURL@ | ||
114 | |||
115 | daemontest_large_put11_SOURCES = \ | ||
116 | daemontest_large_put.c | ||
117 | daemontest_large_put11_LDADD = \ | ||
118 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
119 | @LIBCURL@ | ||
120 | |||
121 | daemontest_long_header_SOURCES = \ | ||
122 | daemontest_long_header.c | ||
123 | daemontest_long_header_LDADD = \ | ||
124 | $(top_builddir)/src/daemon/libmicrohttpd.la \ | ||
125 | @LIBCURL@ | ||
diff --git a/src/testzzuf/daemontest.c b/src/testzzuf/daemontest.c new file mode 100644 index 00000000..8048b438 --- /dev/null +++ b/src/testzzuf/daemontest.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | (C) 2007 Christian Grothoff | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file daemontest.c | ||
23 | * @brief Testcase for libmicrohttpd starts and stops | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "config.h" | ||
28 | #include "microhttpd.h" | ||
29 | #include <stdlib.h> | ||
30 | #include <string.h> | ||
31 | #include <stdio.h> | ||
32 | |||
33 | #ifndef WINDOWS | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | |||
38 | static int | ||
39 | testStartError () | ||
40 | { | ||
41 | struct MHD_Daemon *d; | ||
42 | |||
43 | d = MHD_start_daemon (MHD_USE_DEBUG, 0, NULL, NULL, NULL, NULL); | ||
44 | if (d != NULL) | ||
45 | return 1; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static int | ||
50 | apc_nothing (void *cls, const struct sockaddr *addr, socklen_t addrlen) | ||
51 | { | ||
52 | return MHD_NO; | ||
53 | } | ||
54 | |||
55 | static int | ||
56 | apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen) | ||
57 | { | ||
58 | return MHD_YES; | ||
59 | } | ||
60 | |||
61 | static int | ||
62 | ahc_nothing (void *cls, | ||
63 | struct MHD_Connection *connection, | ||
64 | const char *url, | ||
65 | const char *method, | ||
66 | const char *version, | ||
67 | const char *upload_data, unsigned int *upload_data_size, | ||
68 | void **unused) | ||
69 | { | ||
70 | return MHD_NO; | ||
71 | } | ||
72 | |||
73 | static int | ||
74 | testStartStop () | ||
75 | { | ||
76 | struct MHD_Daemon *d; | ||
77 | |||
78 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, | ||
79 | 1080, | ||
80 | &apc_nothing, | ||
81 | NULL, &ahc_nothing, NULL, MHD_OPTION_END); | ||
82 | if (d == NULL) | ||
83 | return 2; | ||
84 | MHD_stop_daemon (d); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int | ||
89 | testExternalRun () | ||
90 | { | ||
91 | struct MHD_Daemon *d; | ||
92 | fd_set rs; | ||
93 | int maxfd; | ||
94 | int i; | ||
95 | |||
96 | d = MHD_start_daemon (MHD_USE_DEBUG, | ||
97 | 1081, | ||
98 | &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END); | ||
99 | |||
100 | if (d == NULL) | ||
101 | return 4; | ||
102 | i = 0; | ||
103 | while (i < 15) | ||
104 | { | ||
105 | maxfd = 0; | ||
106 | FD_ZERO (&rs); | ||
107 | MHD_get_fdset (d, &rs, &rs, &rs, &maxfd); | ||
108 | if (MHD_run (d) == MHD_NO) | ||
109 | { | ||
110 | MHD_stop_daemon (d); | ||
111 | return 8; | ||
112 | } | ||
113 | i++; | ||
114 | } | ||
115 | MHD_stop_daemon (d); | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int | ||
120 | testThread () | ||
121 | { | ||
122 | struct MHD_Daemon *d; | ||
123 | d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_SELECT_INTERNALLY, | ||
124 | 1082, | ||
125 | &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END); | ||
126 | |||
127 | if (d == NULL) | ||
128 | return 16; | ||
129 | if (MHD_run (d) != MHD_NO) | ||
130 | return 32; | ||
131 | MHD_stop_daemon (d); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int | ||
136 | testMultithread () | ||
137 | { | ||
138 | struct MHD_Daemon *d; | ||
139 | d = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_THREAD_PER_CONNECTION, | ||
140 | 1083, | ||
141 | &apc_all, NULL, &ahc_nothing, NULL, MHD_OPTION_END); | ||
142 | |||
143 | if (d == NULL) | ||
144 | return 64; | ||
145 | if (MHD_run (d) != MHD_NO) | ||
146 | return 128; | ||
147 | MHD_stop_daemon (d); | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | int | ||
152 | main (int argc, char *const *argv) | ||
153 | { | ||
154 | unsigned int errorCount = 0; | ||
155 | errorCount += testStartError (); | ||
156 | errorCount += testStartStop (); | ||
157 | errorCount += testExternalRun (); | ||
158 | errorCount += testThread (); | ||
159 | errorCount += testMultithread (); | ||
160 | if (errorCount != 0) | ||
161 | fprintf (stderr, "Error (code: %u)\n", errorCount); | ||
162 | return errorCount != 0; /* 0 == pass */ | ||
163 | } | ||
diff --git a/src/testzzuf/daemontest_get.c b/src/testzzuf/daemontest_get.c new file mode 100644 index 00000000..2d5729c1 --- /dev/null +++ b/src/testzzuf/daemontest_get.c | |||
@@ -0,0 +1,330 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | (C) 2007 Christian Grothoff | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file daemontest_get.c | ||
23 | * @brief Testcase for libmicrohttpd GET operations | ||
24 | * TODO: test parsing of query | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include "config.h" | ||
29 | #include <curl/curl.h> | ||
30 | #include <microhttpd.h> | ||
31 | #include <stdlib.h> | ||
32 | #include <string.h> | ||
33 | #include <time.h> | ||
34 | |||
35 | #ifndef WINDOWS | ||
36 | #include <unistd.h> | ||
37 | #endif | ||
38 | |||
39 | static int oneone; | ||
40 | |||
41 | struct CBC | ||
42 | { | ||
43 | char *buf; | ||
44 | size_t pos; | ||
45 | size_t size; | ||
46 | }; | ||
47 | |||
48 | static size_t | ||
49 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
50 | { | ||
51 | struct CBC *cbc = ctx; | ||
52 | |||
53 | if (cbc->pos + size * nmemb > cbc->size) | ||
54 | return 0; /* overflow */ | ||
55 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
56 | cbc->pos += size * nmemb; | ||
57 | return size * nmemb; | ||
58 | } | ||
59 | |||
60 | static int | ||
61 | ahc_echo (void *cls, | ||
62 | struct MHD_Connection *connection, | ||
63 | const char *url, | ||
64 | const char *method, | ||
65 | const char *version, | ||
66 | const char *upload_data, unsigned int *upload_data_size, | ||
67 | void **unused) | ||
68 | { | ||
69 | static int ptr; | ||
70 | const char *me = cls; | ||
71 | struct MHD_Response *response; | ||
72 | int ret; | ||
73 | |||
74 | if (0 != strcmp (me, method)) | ||
75 | return MHD_NO; /* unexpected method */ | ||
76 | if (&ptr != *unused) | ||
77 | { | ||
78 | *unused = &ptr; | ||
79 | return MHD_YES; | ||
80 | } | ||
81 | *unused = NULL; | ||
82 | response = MHD_create_response_from_data (strlen (url), | ||
83 | (void *) url, MHD_NO, MHD_YES); | ||
84 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
85 | MHD_destroy_response (response); | ||
86 | if (ret == MHD_NO) | ||
87 | abort (); | ||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | |||
92 | static int | ||
93 | testInternalGet () | ||
94 | { | ||
95 | struct MHD_Daemon *d; | ||
96 | CURL *c; | ||
97 | char buf[2048]; | ||
98 | struct CBC cbc; | ||
99 | CURLcode errornum; | ||
100 | |||
101 | cbc.buf = buf; | ||
102 | cbc.size = 2048; | ||
103 | cbc.pos = 0; | ||
104 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, | ||
105 | 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); | ||
106 | if (d == NULL) | ||
107 | return 1; | ||
108 | c = curl_easy_init (); | ||
109 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world"); | ||
110 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
111 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
112 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
113 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
114 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
115 | if (oneone) | ||
116 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
117 | else | ||
118 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
119 | // NOTE: use of CONNECTTIMEOUT without also | ||
120 | // setting NOSIGNAL results in really weird | ||
121 | // crashes on my system! | ||
122 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
123 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
124 | { | ||
125 | fprintf (stderr, | ||
126 | "curl_easy_perform failed: `%s'\n", | ||
127 | curl_easy_strerror (errornum)); | ||
128 | curl_easy_cleanup (c); | ||
129 | MHD_stop_daemon (d); | ||
130 | return 2; | ||
131 | } | ||
132 | curl_easy_cleanup (c); | ||
133 | MHD_stop_daemon (d); | ||
134 | if (cbc.pos != strlen ("/hello_world")) | ||
135 | return 4; | ||
136 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
137 | return 8; | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static int | ||
142 | testMultithreadedGet () | ||
143 | { | ||
144 | struct MHD_Daemon *d; | ||
145 | CURL *c; | ||
146 | char buf[2048]; | ||
147 | struct CBC cbc; | ||
148 | CURLcode errornum; | ||
149 | |||
150 | cbc.buf = buf; | ||
151 | cbc.size = 2048; | ||
152 | cbc.pos = 0; | ||
153 | d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, | ||
154 | 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); | ||
155 | if (d == NULL) | ||
156 | return 16; | ||
157 | c = curl_easy_init (); | ||
158 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); | ||
159 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
160 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
161 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
162 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
163 | if (oneone) | ||
164 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
165 | else | ||
166 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
167 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
168 | // NOTE: use of CONNECTTIMEOUT without also | ||
169 | // setting NOSIGNAL results in really weird | ||
170 | // crashes on my system! | ||
171 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
172 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
173 | { | ||
174 | fprintf (stderr, | ||
175 | "curl_easy_perform failed: `%s'\n", | ||
176 | curl_easy_strerror (errornum)); | ||
177 | curl_easy_cleanup (c); | ||
178 | MHD_stop_daemon (d); | ||
179 | return 32; | ||
180 | } | ||
181 | curl_easy_cleanup (c); | ||
182 | MHD_stop_daemon (d); | ||
183 | if (cbc.pos != strlen ("/hello_world")) | ||
184 | return 64; | ||
185 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
186 | return 128; | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | |||
191 | static int | ||
192 | testExternalGet () | ||
193 | { | ||
194 | struct MHD_Daemon *d; | ||
195 | CURL *c; | ||
196 | char buf[2048]; | ||
197 | struct CBC cbc; | ||
198 | CURLM *multi; | ||
199 | CURLMcode mret; | ||
200 | fd_set rs; | ||
201 | fd_set ws; | ||
202 | fd_set es; | ||
203 | int max; | ||
204 | int running; | ||
205 | struct CURLMsg *msg; | ||
206 | time_t start; | ||
207 | struct timeval tv; | ||
208 | |||
209 | multi = NULL; | ||
210 | cbc.buf = buf; | ||
211 | cbc.size = 2048; | ||
212 | cbc.pos = 0; | ||
213 | d = MHD_start_daemon (MHD_USE_DEBUG, | ||
214 | 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); | ||
215 | if (d == NULL) | ||
216 | return 256; | ||
217 | c = curl_easy_init (); | ||
218 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); | ||
219 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
220 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
221 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
222 | if (oneone) | ||
223 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
224 | else | ||
225 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
226 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
227 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
228 | // NOTE: use of CONNECTTIMEOUT without also | ||
229 | // setting NOSIGNAL results in really weird | ||
230 | // crashes on my system! | ||
231 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
232 | |||
233 | |||
234 | multi = curl_multi_init (); | ||
235 | if (multi == NULL) | ||
236 | { | ||
237 | curl_easy_cleanup (c); | ||
238 | MHD_stop_daemon (d); | ||
239 | return 512; | ||
240 | } | ||
241 | mret = curl_multi_add_handle (multi, c); | ||
242 | if (mret != CURLM_OK) | ||
243 | { | ||
244 | curl_multi_cleanup (multi); | ||
245 | curl_easy_cleanup (c); | ||
246 | MHD_stop_daemon (d); | ||
247 | return 1024; | ||
248 | } | ||
249 | start = time (NULL); | ||
250 | while ((time (NULL) - start < 5) && (multi != NULL)) | ||
251 | { | ||
252 | max = 0; | ||
253 | FD_ZERO (&rs); | ||
254 | FD_ZERO (&ws); | ||
255 | FD_ZERO (&es); | ||
256 | curl_multi_perform (multi, &running); | ||
257 | mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); | ||
258 | if (mret != CURLM_OK) | ||
259 | { | ||
260 | curl_multi_remove_handle (multi, c); | ||
261 | curl_multi_cleanup (multi); | ||
262 | curl_easy_cleanup (c); | ||
263 | MHD_stop_daemon (d); | ||
264 | return 2048; | ||
265 | } | ||
266 | if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) | ||
267 | { | ||
268 | curl_multi_remove_handle (multi, c); | ||
269 | curl_multi_cleanup (multi); | ||
270 | curl_easy_cleanup (c); | ||
271 | MHD_stop_daemon (d); | ||
272 | return 4096; | ||
273 | } | ||
274 | tv.tv_sec = 0; | ||
275 | tv.tv_usec = 1000; | ||
276 | select (max + 1, &rs, &ws, &es, &tv); | ||
277 | curl_multi_perform (multi, &running); | ||
278 | if (running == 0) | ||
279 | { | ||
280 | msg = curl_multi_info_read (multi, &running); | ||
281 | if (msg == NULL) | ||
282 | break; | ||
283 | if (msg->msg == CURLMSG_DONE) | ||
284 | { | ||
285 | if (msg->data.result != CURLE_OK) | ||
286 | printf ("%s failed at %s:%d: `%s'\n", | ||
287 | "curl_multi_perform", | ||
288 | __FILE__, | ||
289 | __LINE__, curl_easy_strerror (msg->data.result)); | ||
290 | curl_multi_remove_handle (multi, c); | ||
291 | curl_multi_cleanup (multi); | ||
292 | curl_easy_cleanup (c); | ||
293 | c = NULL; | ||
294 | multi = NULL; | ||
295 | } | ||
296 | } | ||
297 | MHD_run (d); | ||
298 | } | ||
299 | if (multi != NULL) | ||
300 | { | ||
301 | curl_multi_remove_handle (multi, c); | ||
302 | curl_easy_cleanup (c); | ||
303 | curl_multi_cleanup (multi); | ||
304 | } | ||
305 | MHD_stop_daemon (d); | ||
306 | if (cbc.pos != strlen ("/hello_world")) | ||
307 | return 8192; | ||
308 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
309 | return 16384; | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | |||
314 | |||
315 | int | ||
316 | main (int argc, char *const *argv) | ||
317 | { | ||
318 | unsigned int errorCount = 0; | ||
319 | |||
320 | oneone = NULL != strstr (argv[0], "11"); | ||
321 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
322 | return 2; | ||
323 | errorCount += testInternalGet (); | ||
324 | errorCount += testMultithreadedGet (); | ||
325 | errorCount += testExternalGet (); | ||
326 | if (errorCount != 0) | ||
327 | fprintf (stderr, "Error (code: %u)\n", errorCount); | ||
328 | curl_global_cleanup (); | ||
329 | return errorCount != 0; /* 0 == pass */ | ||
330 | } | ||
diff --git a/src/testzzuf/daemontest_get_chunked.c b/src/testzzuf/daemontest_get_chunked.c new file mode 100644 index 00000000..4b2739cf --- /dev/null +++ b/src/testzzuf/daemontest_get_chunked.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | (C) 2007 Christian Grothoff | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file daemontest_get_chunked.c | ||
23 | * @brief Testcase for libmicrohttpd GET operations with chunked content encoding | ||
24 | * TODO: | ||
25 | * - how to test that chunking was actually used? | ||
26 | * - use CURLOPT_HEADERFUNCTION to validate | ||
27 | * footer was sent | ||
28 | * @author Christian Grothoff | ||
29 | */ | ||
30 | |||
31 | #include "config.h" | ||
32 | #include <curl/curl.h> | ||
33 | #include <microhttpd.h> | ||
34 | #include <stdlib.h> | ||
35 | #include <string.h> | ||
36 | #include <time.h> | ||
37 | |||
38 | #ifndef WINDOWS | ||
39 | #include <unistd.h> | ||
40 | #endif | ||
41 | |||
42 | struct CBC | ||
43 | { | ||
44 | char *buf; | ||
45 | size_t pos; | ||
46 | size_t size; | ||
47 | }; | ||
48 | |||
49 | static size_t | ||
50 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
51 | { | ||
52 | struct CBC *cbc = ctx; | ||
53 | |||
54 | if (cbc->pos + size * nmemb > cbc->size) | ||
55 | return 0; /* overflow */ | ||
56 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
57 | cbc->pos += size * nmemb; | ||
58 | return size * nmemb; | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * MHD content reader callback that returns | ||
63 | * data in chunks. | ||
64 | */ | ||
65 | static int | ||
66 | crc (void *cls, size_t pos, char *buf, int max) | ||
67 | { | ||
68 | struct MHD_Response **responseptr = cls; | ||
69 | |||
70 | if (pos == 128 * 10) | ||
71 | { | ||
72 | MHD_add_response_header (*responseptr, "Footer", "working"); | ||
73 | return -1; /* end of stream */ | ||
74 | } | ||
75 | if (max < 128) | ||
76 | abort (); /* should not happen in this testcase... */ | ||
77 | memset (buf, 'A' + (pos / 128), 128); | ||
78 | return 128; | ||
79 | } | ||
80 | |||
81 | /** | ||
82 | * Dummy function that does nothing. | ||
83 | */ | ||
84 | static void | ||
85 | crcf (void *ptr) | ||
86 | { | ||
87 | free (ptr); | ||
88 | } | ||
89 | |||
90 | static int | ||
91 | ahc_echo (void *cls, | ||
92 | struct MHD_Connection *connection, | ||
93 | const char *url, | ||
94 | const char *method, | ||
95 | const char *version, | ||
96 | const char *upload_data, unsigned int *upload_data_size, void **ptr) | ||
97 | { | ||
98 | static int aptr; | ||
99 | const char *me = cls; | ||
100 | struct MHD_Response *response; | ||
101 | struct MHD_Response **responseptr; | ||
102 | int ret; | ||
103 | |||
104 | if (0 != strcmp (me, method)) | ||
105 | return MHD_NO; /* unexpected method */ | ||
106 | if (&aptr != *ptr) | ||
107 | { | ||
108 | /* do never respond on first call */ | ||
109 | *ptr = &aptr; | ||
110 | return MHD_YES; | ||
111 | } | ||
112 | responseptr = malloc (sizeof (struct MHD_Response *)); | ||
113 | response = MHD_create_response_from_callback (-1, | ||
114 | 1024, | ||
115 | &crc, responseptr, &crcf); | ||
116 | *responseptr = response; | ||
117 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
118 | MHD_destroy_response (response); | ||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | static int | ||
123 | validate (struct CBC cbc, int ebase) | ||
124 | { | ||
125 | int i; | ||
126 | char buf[128]; | ||
127 | |||
128 | if (cbc.pos != 128 * 10) | ||
129 | return ebase; | ||
130 | |||
131 | for (i = 0; i < 10; i++) | ||
132 | { | ||
133 | memset (buf, 'A' + i, 128); | ||
134 | if (0 != memcmp (buf, &cbc.buf[i * 128], 128)) | ||
135 | { | ||
136 | fprintf (stderr, | ||
137 | "Got `%.*s'\nWant `%.*s'\n", | ||
138 | 128, buf, 128, &cbc.buf[i * 128]); | ||
139 | return ebase * 2; | ||
140 | } | ||
141 | } | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int | ||
146 | testInternalGet () | ||
147 | { | ||
148 | struct MHD_Daemon *d; | ||
149 | CURL *c; | ||
150 | char buf[2048]; | ||
151 | struct CBC cbc; | ||
152 | CURLcode errornum; | ||
153 | |||
154 | cbc.buf = buf; | ||
155 | cbc.size = 2048; | ||
156 | cbc.pos = 0; | ||
157 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, | ||
158 | 1080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); | ||
159 | if (d == NULL) | ||
160 | return 1; | ||
161 | c = curl_easy_init (); | ||
162 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); | ||
163 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
164 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
165 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
166 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
167 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
168 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
169 | // NOTE: use of CONNECTTIMEOUT without also | ||
170 | // setting NOSIGNAL results in really weird | ||
171 | // crashes on my system! | ||
172 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
173 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
174 | { | ||
175 | fprintf (stderr, | ||
176 | "curl_easy_perform failed: `%s'\n", | ||
177 | curl_easy_strerror (errornum)); | ||
178 | curl_easy_cleanup (c); | ||
179 | MHD_stop_daemon (d); | ||
180 | return 2; | ||
181 | } | ||
182 | curl_easy_cleanup (c); | ||
183 | MHD_stop_daemon (d); | ||
184 | return validate (cbc, 4); | ||
185 | } | ||
186 | |||
187 | static int | ||
188 | testMultithreadedGet () | ||
189 | { | ||
190 | struct MHD_Daemon *d; | ||
191 | CURL *c; | ||
192 | char buf[2048]; | ||
193 | struct CBC cbc; | ||
194 | CURLcode errornum; | ||
195 | |||
196 | cbc.buf = buf; | ||
197 | cbc.size = 2048; | ||
198 | cbc.pos = 0; | ||
199 | d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, | ||
200 | 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); | ||
201 | if (d == NULL) | ||
202 | return 16; | ||
203 | c = curl_easy_init (); | ||
204 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); | ||
205 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
206 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
207 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
208 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
209 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
210 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
211 | // NOTE: use of CONNECTTIMEOUT without also | ||
212 | // setting NOSIGNAL results in really weird | ||
213 | // crashes on my system! | ||
214 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
215 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
216 | { | ||
217 | fprintf (stderr, | ||
218 | "curl_easy_perform failed: `%s'\n", | ||
219 | curl_easy_strerror (errornum)); | ||
220 | curl_easy_cleanup (c); | ||
221 | MHD_stop_daemon (d); | ||
222 | return 32; | ||
223 | } | ||
224 | curl_easy_cleanup (c); | ||
225 | MHD_stop_daemon (d); | ||
226 | return validate (cbc, 64); | ||
227 | } | ||
228 | |||
229 | |||
230 | static int | ||
231 | testExternalGet () | ||
232 | { | ||
233 | struct MHD_Daemon *d; | ||
234 | CURL *c; | ||
235 | char buf[2048]; | ||
236 | struct CBC cbc; | ||
237 | CURLM *multi; | ||
238 | CURLMcode mret; | ||
239 | fd_set rs; | ||
240 | fd_set ws; | ||
241 | fd_set es; | ||
242 | int max; | ||
243 | int running; | ||
244 | struct CURLMsg *msg; | ||
245 | time_t start; | ||
246 | struct timeval tv; | ||
247 | |||
248 | multi = NULL; | ||
249 | cbc.buf = buf; | ||
250 | cbc.size = 2048; | ||
251 | cbc.pos = 0; | ||
252 | d = MHD_start_daemon (MHD_USE_DEBUG, | ||
253 | 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); | ||
254 | if (d == NULL) | ||
255 | return 256; | ||
256 | c = curl_easy_init (); | ||
257 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); | ||
258 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
259 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
260 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
261 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
262 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
263 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 5L); | ||
264 | // NOTE: use of CONNECTTIMEOUT without also | ||
265 | // setting NOSIGNAL results in really weird | ||
266 | // crashes on my system! | ||
267 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
268 | |||
269 | |||
270 | multi = curl_multi_init (); | ||
271 | if (multi == NULL) | ||
272 | { | ||
273 | curl_easy_cleanup (c); | ||
274 | MHD_stop_daemon (d); | ||
275 | return 512; | ||
276 | } | ||
277 | mret = curl_multi_add_handle (multi, c); | ||
278 | if (mret != CURLM_OK) | ||
279 | { | ||
280 | curl_multi_cleanup (multi); | ||
281 | curl_easy_cleanup (c); | ||
282 | MHD_stop_daemon (d); | ||
283 | return 1024; | ||
284 | } | ||
285 | start = time (NULL); | ||
286 | while ((time (NULL) - start < 5) && (multi != NULL)) | ||
287 | { | ||
288 | max = 0; | ||
289 | FD_ZERO (&rs); | ||
290 | FD_ZERO (&ws); | ||
291 | FD_ZERO (&es); | ||
292 | curl_multi_perform (multi, &running); | ||
293 | mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); | ||
294 | if (mret != CURLM_OK) | ||
295 | { | ||
296 | curl_multi_remove_handle (multi, c); | ||
297 | curl_multi_cleanup (multi); | ||
298 | curl_easy_cleanup (c); | ||
299 | MHD_stop_daemon (d); | ||
300 | return 2048; | ||
301 | } | ||
302 | if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) | ||
303 | { | ||
304 | curl_multi_remove_handle (multi, c); | ||
305 | curl_multi_cleanup (multi); | ||
306 | curl_easy_cleanup (c); | ||
307 | MHD_stop_daemon (d); | ||
308 | return 4096; | ||
309 | } | ||
310 | tv.tv_sec = 0; | ||
311 | tv.tv_usec = 1000; | ||
312 | select (max + 1, &rs, &ws, &es, &tv); | ||
313 | curl_multi_perform (multi, &running); | ||
314 | if (running == 0) | ||
315 | { | ||
316 | msg = curl_multi_info_read (multi, &running); | ||
317 | if (msg == NULL) | ||
318 | break; | ||
319 | if (msg->msg == CURLMSG_DONE) | ||
320 | { | ||
321 | if (msg->data.result != CURLE_OK) | ||
322 | printf ("%s failed at %s:%d: `%s'\n", | ||
323 | "curl_multi_perform", | ||
324 | __FILE__, | ||
325 | __LINE__, curl_easy_strerror (msg->data.result)); | ||
326 | curl_multi_remove_handle (multi, c); | ||
327 | curl_multi_cleanup (multi); | ||
328 | curl_easy_cleanup (c); | ||
329 | c = NULL; | ||
330 | multi = NULL; | ||
331 | } | ||
332 | } | ||
333 | MHD_run (d); | ||
334 | } | ||
335 | if (multi != NULL) | ||
336 | { | ||
337 | curl_multi_remove_handle (multi, c); | ||
338 | curl_easy_cleanup (c); | ||
339 | curl_multi_cleanup (multi); | ||
340 | } | ||
341 | MHD_stop_daemon (d); | ||
342 | return validate (cbc, 8192); | ||
343 | } | ||
344 | |||
345 | |||
346 | |||
347 | int | ||
348 | main (int argc, char *const *argv) | ||
349 | { | ||
350 | unsigned int errorCount = 0; | ||
351 | |||
352 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
353 | return 2; | ||
354 | errorCount += testInternalGet (); | ||
355 | if (0) | ||
356 | { | ||
357 | errorCount += testMultithreadedGet (); | ||
358 | errorCount += testExternalGet (); | ||
359 | } | ||
360 | if (errorCount != 0) | ||
361 | fprintf (stderr, "Error (code: %u)\n", errorCount); | ||
362 | curl_global_cleanup (); | ||
363 | return errorCount != 0; /* 0 == pass */ | ||
364 | } | ||
diff --git a/src/testzzuf/daemontest_large_put.c b/src/testzzuf/daemontest_large_put.c new file mode 100644 index 00000000..b0c7bf37 --- /dev/null +++ b/src/testzzuf/daemontest_large_put.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | (C) 2007 Christian Grothoff | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file daemontest_put.c | ||
23 | * @brief Testcase for libmicrohttpd PUT operations | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "config.h" | ||
28 | #include <curl/curl.h> | ||
29 | #include <microhttpd.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <string.h> | ||
32 | #include <time.h> | ||
33 | |||
34 | #ifndef WINDOWS | ||
35 | #include <unistd.h> | ||
36 | #endif | ||
37 | |||
38 | static int oneone; | ||
39 | |||
40 | /** | ||
41 | * Do not make this much larger since we will hit the | ||
42 | * MHD default buffer limit and the test code is not | ||
43 | * written for incremental upload processing... | ||
44 | */ | ||
45 | #define PUT_SIZE (512 * 1024) | ||
46 | |||
47 | static char *put_buffer; | ||
48 | |||
49 | struct CBC | ||
50 | { | ||
51 | char *buf; | ||
52 | size_t pos; | ||
53 | size_t size; | ||
54 | }; | ||
55 | |||
56 | static size_t | ||
57 | putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) | ||
58 | { | ||
59 | unsigned int *pos = ptr; | ||
60 | unsigned int wrt; | ||
61 | |||
62 | wrt = size * nmemb; | ||
63 | if (wrt > PUT_SIZE - (*pos)) | ||
64 | wrt = PUT_SIZE - (*pos); | ||
65 | memcpy (stream, &put_buffer[*pos], wrt); | ||
66 | (*pos) += wrt; | ||
67 | return wrt; | ||
68 | } | ||
69 | |||
70 | static size_t | ||
71 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
72 | { | ||
73 | struct CBC *cbc = ctx; | ||
74 | |||
75 | if (cbc->pos + size * nmemb > cbc->size) | ||
76 | return 0; /* overflow */ | ||
77 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
78 | cbc->pos += size * nmemb; | ||
79 | return size * nmemb; | ||
80 | } | ||
81 | |||
82 | static int | ||
83 | ahc_echo (void *cls, | ||
84 | struct MHD_Connection *connection, | ||
85 | const char *url, | ||
86 | const char *method, | ||
87 | const char *version, | ||
88 | const char *upload_data, unsigned int *upload_data_size, | ||
89 | void **unused) | ||
90 | { | ||
91 | int *done = cls; | ||
92 | struct MHD_Response *response; | ||
93 | int ret; | ||
94 | |||
95 | if (0 != strcmp ("PUT", method)) | ||
96 | return MHD_NO; /* unexpected method */ | ||
97 | if ((*done) == 0) | ||
98 | { | ||
99 | if (*upload_data_size != PUT_SIZE) | ||
100 | { | ||
101 | #if 0 | ||
102 | fprintf (stderr, | ||
103 | "Waiting for more data (%u/%u)...\n", | ||
104 | *upload_data_size, PUT_SIZE); | ||
105 | #endif | ||
106 | return MHD_YES; /* not yet ready */ | ||
107 | } | ||
108 | if (0 == memcmp (upload_data, put_buffer, PUT_SIZE)) | ||
109 | { | ||
110 | *upload_data_size = 0; | ||
111 | } | ||
112 | else | ||
113 | { | ||
114 | printf ("Invalid upload data!\n"); | ||
115 | return MHD_NO; | ||
116 | } | ||
117 | *done = 1; | ||
118 | return MHD_YES; | ||
119 | } | ||
120 | response = MHD_create_response_from_data (strlen (url), | ||
121 | (void *) url, MHD_NO, MHD_YES); | ||
122 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
123 | MHD_destroy_response (response); | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | |||
128 | static int | ||
129 | testInternalPut () | ||
130 | { | ||
131 | struct MHD_Daemon *d; | ||
132 | CURL *c; | ||
133 | struct CBC cbc; | ||
134 | unsigned int pos = 0; | ||
135 | int done_flag = 0; | ||
136 | CURLcode errornum; | ||
137 | char buf[2048]; | ||
138 | |||
139 | cbc.buf = buf; | ||
140 | cbc.size = 2048; | ||
141 | cbc.pos = 0; | ||
142 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, | ||
143 | 1080, | ||
144 | NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); | ||
145 | if (d == NULL) | ||
146 | return 1; | ||
147 | c = curl_easy_init (); | ||
148 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); | ||
149 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
150 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
151 | curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); | ||
152 | curl_easy_setopt (c, CURLOPT_READDATA, &pos); | ||
153 | curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); | ||
154 | curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); | ||
155 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
156 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
157 | if (oneone) | ||
158 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
159 | else | ||
160 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
161 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
162 | // NOTE: use of CONNECTTIMEOUT without also | ||
163 | // setting NOSIGNAL results in really weird | ||
164 | // crashes on my system! | ||
165 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
166 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
167 | { | ||
168 | fprintf (stderr, | ||
169 | "curl_easy_perform failed: `%s'\n", | ||
170 | curl_easy_strerror (errornum)); | ||
171 | curl_easy_cleanup (c); | ||
172 | MHD_stop_daemon (d); | ||
173 | return 2; | ||
174 | } | ||
175 | curl_easy_cleanup (c); | ||
176 | MHD_stop_daemon (d); | ||
177 | if (cbc.pos != strlen ("/hello_world")) | ||
178 | return 4; | ||
179 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
180 | return 8; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int | ||
185 | testMultithreadedPut () | ||
186 | { | ||
187 | struct MHD_Daemon *d; | ||
188 | CURL *c; | ||
189 | struct CBC cbc; | ||
190 | unsigned int pos = 0; | ||
191 | int done_flag = 0; | ||
192 | CURLcode errornum; | ||
193 | char buf[2048]; | ||
194 | |||
195 | cbc.buf = buf; | ||
196 | cbc.size = 2048; | ||
197 | cbc.pos = 0; | ||
198 | d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, | ||
199 | 1081, | ||
200 | NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); | ||
201 | if (d == NULL) | ||
202 | { | ||
203 | free (cbc.buf); | ||
204 | return 16; | ||
205 | } | ||
206 | c = curl_easy_init (); | ||
207 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); | ||
208 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
209 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
210 | curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); | ||
211 | curl_easy_setopt (c, CURLOPT_READDATA, &pos); | ||
212 | curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); | ||
213 | curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); | ||
214 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
215 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
216 | if (oneone) | ||
217 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
218 | else | ||
219 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
220 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
221 | // NOTE: use of CONNECTTIMEOUT without also | ||
222 | // setting NOSIGNAL results in really weird | ||
223 | // crashes on my system! | ||
224 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
225 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
226 | { | ||
227 | fprintf (stderr, | ||
228 | "curl_easy_perform failed: `%s'\n", | ||
229 | curl_easy_strerror (errornum)); | ||
230 | curl_easy_cleanup (c); | ||
231 | MHD_stop_daemon (d); | ||
232 | return 32; | ||
233 | } | ||
234 | curl_easy_cleanup (c); | ||
235 | MHD_stop_daemon (d); | ||
236 | if (cbc.pos != strlen ("/hello_world")) | ||
237 | { | ||
238 | fprintf (stderr, "Got invalid response `%.*s'\n", cbc.pos, cbc.buf); | ||
239 | return 64; | ||
240 | } | ||
241 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
242 | return 128; | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | |||
247 | static int | ||
248 | testExternalPut () | ||
249 | { | ||
250 | struct MHD_Daemon *d; | ||
251 | CURL *c; | ||
252 | struct CBC cbc; | ||
253 | CURLM *multi; | ||
254 | CURLMcode mret; | ||
255 | fd_set rs; | ||
256 | fd_set ws; | ||
257 | fd_set es; | ||
258 | int max; | ||
259 | int running; | ||
260 | struct CURLMsg *msg; | ||
261 | time_t start; | ||
262 | struct timeval tv; | ||
263 | unsigned int pos = 0; | ||
264 | int done_flag = 0; | ||
265 | char buf[2048]; | ||
266 | |||
267 | cbc.buf = buf; | ||
268 | cbc.size = 2048; | ||
269 | cbc.pos = 0; | ||
270 | multi = NULL; | ||
271 | d = MHD_start_daemon (MHD_USE_DEBUG, | ||
272 | 1082, | ||
273 | NULL, NULL, &ahc_echo, &done_flag, | ||
274 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
275 | PUT_SIZE * 4, MHD_OPTION_END); | ||
276 | if (d == NULL) | ||
277 | return 256; | ||
278 | c = curl_easy_init (); | ||
279 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); | ||
280 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
281 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
282 | curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); | ||
283 | curl_easy_setopt (c, CURLOPT_READDATA, &pos); | ||
284 | curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); | ||
285 | curl_easy_setopt (c, CURLOPT_INFILESIZE, (long) PUT_SIZE); | ||
286 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
287 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
288 | if (oneone) | ||
289 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
290 | else | ||
291 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
292 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
293 | // NOTE: use of CONNECTTIMEOUT without also | ||
294 | // setting NOSIGNAL results in really weird | ||
295 | // crashes on my system! | ||
296 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
297 | |||
298 | |||
299 | multi = curl_multi_init (); | ||
300 | if (multi == NULL) | ||
301 | { | ||
302 | curl_easy_cleanup (c); | ||
303 | MHD_stop_daemon (d); | ||
304 | return 512; | ||
305 | } | ||
306 | mret = curl_multi_add_handle (multi, c); | ||
307 | if (mret != CURLM_OK) | ||
308 | { | ||
309 | curl_multi_cleanup (multi); | ||
310 | curl_easy_cleanup (c); | ||
311 | MHD_stop_daemon (d); | ||
312 | return 1024; | ||
313 | } | ||
314 | start = time (NULL); | ||
315 | while ((time (NULL) - start < 5) && (multi != NULL)) | ||
316 | { | ||
317 | max = 0; | ||
318 | FD_ZERO (&rs); | ||
319 | FD_ZERO (&ws); | ||
320 | FD_ZERO (&es); | ||
321 | curl_multi_perform (multi, &running); | ||
322 | mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); | ||
323 | if (mret != CURLM_OK) | ||
324 | { | ||
325 | curl_multi_remove_handle (multi, c); | ||
326 | curl_multi_cleanup (multi); | ||
327 | curl_easy_cleanup (c); | ||
328 | MHD_stop_daemon (d); | ||
329 | return 2048; | ||
330 | } | ||
331 | if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) | ||
332 | { | ||
333 | curl_multi_remove_handle (multi, c); | ||
334 | curl_multi_cleanup (multi); | ||
335 | curl_easy_cleanup (c); | ||
336 | MHD_stop_daemon (d); | ||
337 | return 4096; | ||
338 | } | ||
339 | tv.tv_sec = 0; | ||
340 | tv.tv_usec = 1000; | ||
341 | select (max + 1, &rs, &ws, &es, &tv); | ||
342 | curl_multi_perform (multi, &running); | ||
343 | if (running == 0) | ||
344 | { | ||
345 | msg = curl_multi_info_read (multi, &running); | ||
346 | if (msg == NULL) | ||
347 | break; | ||
348 | if (msg->msg == CURLMSG_DONE) | ||
349 | { | ||
350 | if (msg->data.result != CURLE_OK) | ||
351 | printf ("%s failed at %s:%d: `%s'\n", | ||
352 | "curl_multi_perform", | ||
353 | __FILE__, | ||
354 | __LINE__, curl_easy_strerror (msg->data.result)); | ||
355 | curl_multi_remove_handle (multi, c); | ||
356 | curl_multi_cleanup (multi); | ||
357 | curl_easy_cleanup (c); | ||
358 | c = NULL; | ||
359 | multi = NULL; | ||
360 | } | ||
361 | } | ||
362 | MHD_run (d); | ||
363 | } | ||
364 | if (multi != NULL) | ||
365 | { | ||
366 | curl_multi_remove_handle (multi, c); | ||
367 | curl_easy_cleanup (c); | ||
368 | curl_multi_cleanup (multi); | ||
369 | } | ||
370 | MHD_stop_daemon (d); | ||
371 | if (cbc.pos != strlen ("/hello_world")) | ||
372 | { | ||
373 | fprintf (stderr, "Got invalid response `%.*s'\n", cbc.pos, cbc.buf); | ||
374 | return 8192; | ||
375 | } | ||
376 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
377 | return 16384; | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | |||
382 | |||
383 | int | ||
384 | main (int argc, char *const *argv) | ||
385 | { | ||
386 | unsigned int errorCount = 0; | ||
387 | |||
388 | oneone = NULL != strstr (argv[0], "11"); | ||
389 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
390 | return 2; | ||
391 | put_buffer = malloc (PUT_SIZE); | ||
392 | memset (put_buffer, 1, PUT_SIZE); | ||
393 | if (0) | ||
394 | { | ||
395 | errorCount += testInternalPut (); | ||
396 | errorCount += testMultithreadedPut (); | ||
397 | } | ||
398 | errorCount += testExternalPut (); | ||
399 | free (put_buffer); | ||
400 | if (errorCount != 0) | ||
401 | fprintf (stderr, "Error (code: %u)\n", errorCount); | ||
402 | curl_global_cleanup (); | ||
403 | return errorCount != 0; /* 0 == pass */ | ||
404 | } | ||
diff --git a/src/testzzuf/daemontest_long_header.c b/src/testzzuf/daemontest_long_header.c new file mode 100644 index 00000000..385b9776 --- /dev/null +++ b/src/testzzuf/daemontest_long_header.c | |||
@@ -0,0 +1,240 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | (C) 2007 Christian Grothoff | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file daemontest_long_header.c | ||
23 | * @brief Testcase for libmicrohttpd handling of very long headers | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "config.h" | ||
28 | #include <curl/curl.h> | ||
29 | #include <microhttpd.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <string.h> | ||
32 | #include <time.h> | ||
33 | |||
34 | #ifndef WINDOWS | ||
35 | #include <unistd.h> | ||
36 | #endif | ||
37 | |||
38 | /** | ||
39 | * We will set the memory available per connection to | ||
40 | * half of this value, so the actual value does not have | ||
41 | * to be big at all... | ||
42 | */ | ||
43 | #define VERY_LONG (1024*10) | ||
44 | |||
45 | static int oneone; | ||
46 | |||
47 | static int | ||
48 | apc_all (void *cls, const struct sockaddr *addr, socklen_t addrlen) | ||
49 | { | ||
50 | return MHD_YES; | ||
51 | } | ||
52 | |||
53 | struct CBC | ||
54 | { | ||
55 | char *buf; | ||
56 | size_t pos; | ||
57 | size_t size; | ||
58 | }; | ||
59 | |||
60 | static size_t | ||
61 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
62 | { | ||
63 | return size * nmemb; | ||
64 | } | ||
65 | |||
66 | static int | ||
67 | ahc_echo (void *cls, | ||
68 | struct MHD_Connection *connection, | ||
69 | const char *url, | ||
70 | const char *method, | ||
71 | const char *version, | ||
72 | const char *upload_data, unsigned int *upload_data_size, | ||
73 | void **unused) | ||
74 | { | ||
75 | const char *me = cls; | ||
76 | struct MHD_Response *response; | ||
77 | int ret; | ||
78 | |||
79 | if (0 != strcmp (me, method)) | ||
80 | return MHD_NO; /* unexpected method */ | ||
81 | response = MHD_create_response_from_data (strlen (url), | ||
82 | (void *) url, MHD_NO, MHD_YES); | ||
83 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
84 | MHD_destroy_response (response); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | |||
89 | static int | ||
90 | testLongUrlGet () | ||
91 | { | ||
92 | struct MHD_Daemon *d; | ||
93 | CURL *c; | ||
94 | char buf[2048]; | ||
95 | struct CBC cbc; | ||
96 | char *url; | ||
97 | long code; | ||
98 | |||
99 | cbc.buf = buf; | ||
100 | cbc.size = 2048; | ||
101 | cbc.pos = 0; | ||
102 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , | ||
103 | 1080, | ||
104 | &apc_all, | ||
105 | NULL, | ||
106 | &ahc_echo, | ||
107 | "GET", | ||
108 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
109 | VERY_LONG / 2, MHD_OPTION_END); | ||
110 | if (d == NULL) | ||
111 | return 1; | ||
112 | c = curl_easy_init (); | ||
113 | url = malloc (VERY_LONG); | ||
114 | memset (url, 'a', VERY_LONG); | ||
115 | url[VERY_LONG - 1] = '\0'; | ||
116 | memcpy (url, "http://localhost:1080/", strlen ("http://localhost:1080/")); | ||
117 | curl_easy_setopt (c, CURLOPT_URL, url); | ||
118 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
119 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
120 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
121 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
122 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
123 | if (oneone) | ||
124 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
125 | else | ||
126 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
127 | // NOTE: use of CONNECTTIMEOUT without also | ||
128 | // setting NOSIGNAL results in really weird | ||
129 | // crashes on my system! | ||
130 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
131 | if (CURLE_OK == curl_easy_perform (c)) | ||
132 | { | ||
133 | curl_easy_cleanup (c); | ||
134 | MHD_stop_daemon (d); | ||
135 | free (url); | ||
136 | return 2; | ||
137 | } | ||
138 | if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code)) | ||
139 | { | ||
140 | curl_easy_cleanup (c); | ||
141 | MHD_stop_daemon (d); | ||
142 | free (url); | ||
143 | return 4; | ||
144 | } | ||
145 | curl_easy_cleanup (c); | ||
146 | MHD_stop_daemon (d); | ||
147 | free (url); | ||
148 | if (code != MHD_HTTP_REQUEST_URI_TOO_LONG) | ||
149 | return 8; | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | |||
154 | static int | ||
155 | testLongHeaderGet () | ||
156 | { | ||
157 | struct MHD_Daemon *d; | ||
158 | CURL *c; | ||
159 | char buf[2048]; | ||
160 | struct CBC cbc; | ||
161 | char *url; | ||
162 | long code; | ||
163 | struct curl_slist *header = NULL; | ||
164 | |||
165 | cbc.buf = buf; | ||
166 | cbc.size = 2048; | ||
167 | cbc.pos = 0; | ||
168 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY /* | MHD_USE_DEBUG */ , | ||
169 | 1080, | ||
170 | &apc_all, | ||
171 | NULL, | ||
172 | &ahc_echo, | ||
173 | "GET", | ||
174 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
175 | VERY_LONG / 2, MHD_OPTION_END); | ||
176 | if (d == NULL) | ||
177 | return 16; | ||
178 | c = curl_easy_init (); | ||
179 | url = malloc (VERY_LONG); | ||
180 | memset (url, 'a', VERY_LONG); | ||
181 | url[VERY_LONG - 1] = '\0'; | ||
182 | url[VERY_LONG / 2] = ':'; | ||
183 | url[VERY_LONG / 2 + 1] = ':'; | ||
184 | header = curl_slist_append (header, url); | ||
185 | |||
186 | curl_easy_setopt (c, CURLOPT_HTTPHEADER, header); | ||
187 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); | ||
188 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
189 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
190 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
191 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
192 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
193 | if (oneone) | ||
194 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
195 | else | ||
196 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
197 | // NOTE: use of CONNECTTIMEOUT without also | ||
198 | // setting NOSIGNAL results in really weird | ||
199 | // crashes on my system! | ||
200 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
201 | if (CURLE_OK == curl_easy_perform (c)) | ||
202 | { | ||
203 | curl_easy_cleanup (c); | ||
204 | MHD_stop_daemon (d); | ||
205 | curl_slist_free_all (header); | ||
206 | free (url); | ||
207 | return 32; | ||
208 | } | ||
209 | if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code)) | ||
210 | { | ||
211 | curl_slist_free_all (header); | ||
212 | curl_easy_cleanup (c); | ||
213 | MHD_stop_daemon (d); | ||
214 | free (url); | ||
215 | return 64; | ||
216 | } | ||
217 | curl_slist_free_all (header); | ||
218 | curl_easy_cleanup (c); | ||
219 | MHD_stop_daemon (d); | ||
220 | free (url); | ||
221 | if (code != MHD_HTTP_REQUEST_ENTITY_TOO_LARGE) | ||
222 | return 128; | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | int | ||
227 | main (int argc, char *const *argv) | ||
228 | { | ||
229 | unsigned int errorCount = 0; | ||
230 | |||
231 | oneone = NULL != strstr (argv[0], "11"); | ||
232 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
233 | return 2; | ||
234 | errorCount += testLongUrlGet (); | ||
235 | errorCount += testLongHeaderGet (); | ||
236 | if (errorCount != 0) | ||
237 | fprintf (stderr, "Error (code: %u)\n", errorCount); | ||
238 | curl_global_cleanup (); | ||
239 | return errorCount != 0; /* 0 == pass */ | ||
240 | } | ||
diff --git a/src/testzzuf/daemontest_put.c b/src/testzzuf/daemontest_put.c new file mode 100644 index 00000000..e1f89402 --- /dev/null +++ b/src/testzzuf/daemontest_put.c | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | (C) 2007 Christian Grothoff | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file daemontest_put.c | ||
23 | * @brief Testcase for libmicrohttpd PUT operations | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "config.h" | ||
28 | #include <curl/curl.h> | ||
29 | #include <microhttpd.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <string.h> | ||
32 | #include <time.h> | ||
33 | |||
34 | #ifndef WINDOWS | ||
35 | #include <unistd.h> | ||
36 | #endif | ||
37 | |||
38 | static int oneone; | ||
39 | |||
40 | struct CBC | ||
41 | { | ||
42 | char *buf; | ||
43 | size_t pos; | ||
44 | size_t size; | ||
45 | }; | ||
46 | |||
47 | static size_t | ||
48 | putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) | ||
49 | { | ||
50 | unsigned int *pos = ptr; | ||
51 | unsigned int wrt; | ||
52 | |||
53 | wrt = size * nmemb; | ||
54 | if (wrt > 8 - (*pos)) | ||
55 | wrt = 8 - (*pos); | ||
56 | memcpy (stream, &("Hello123"[*pos]), wrt); | ||
57 | (*pos) += wrt; | ||
58 | return wrt; | ||
59 | } | ||
60 | |||
61 | static size_t | ||
62 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
63 | { | ||
64 | struct CBC *cbc = ctx; | ||
65 | |||
66 | if (cbc->pos + size * nmemb > cbc->size) | ||
67 | return 0; /* overflow */ | ||
68 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
69 | cbc->pos += size * nmemb; | ||
70 | return size * nmemb; | ||
71 | } | ||
72 | |||
73 | static int | ||
74 | ahc_echo (void *cls, | ||
75 | struct MHD_Connection *connection, | ||
76 | const char *url, | ||
77 | const char *method, | ||
78 | const char *version, | ||
79 | const char *upload_data, unsigned int *upload_data_size, | ||
80 | void **unused) | ||
81 | { | ||
82 | int *done = cls; | ||
83 | struct MHD_Response *response; | ||
84 | int ret; | ||
85 | |||
86 | if (0 != strcmp ("PUT", method)) | ||
87 | return MHD_NO; /* unexpected method */ | ||
88 | if ((*done) == 0) | ||
89 | { | ||
90 | if (*upload_data_size != 8) | ||
91 | return MHD_YES; /* not yet ready */ | ||
92 | if (0 == memcmp (upload_data, "Hello123", 8)) | ||
93 | { | ||
94 | *upload_data_size = 0; | ||
95 | } | ||
96 | else | ||
97 | { | ||
98 | printf ("Invalid upload data `%8s'!\n", upload_data); | ||
99 | return MHD_NO; | ||
100 | } | ||
101 | *done = 1; | ||
102 | return MHD_YES; | ||
103 | } | ||
104 | response = MHD_create_response_from_data (strlen (url), | ||
105 | (void *) url, MHD_NO, MHD_YES); | ||
106 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
107 | MHD_destroy_response (response); | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | |||
112 | static int | ||
113 | testInternalPut () | ||
114 | { | ||
115 | struct MHD_Daemon *d; | ||
116 | CURL *c; | ||
117 | char buf[2048]; | ||
118 | struct CBC cbc; | ||
119 | unsigned int pos = 0; | ||
120 | int done_flag = 0; | ||
121 | CURLcode errornum; | ||
122 | |||
123 | cbc.buf = buf; | ||
124 | cbc.size = 2048; | ||
125 | cbc.pos = 0; | ||
126 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, | ||
127 | 1080, | ||
128 | NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); | ||
129 | if (d == NULL) | ||
130 | return 1; | ||
131 | c = curl_easy_init (); | ||
132 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1080/hello_world"); | ||
133 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
134 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
135 | curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); | ||
136 | curl_easy_setopt (c, CURLOPT_READDATA, &pos); | ||
137 | curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); | ||
138 | curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); | ||
139 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
140 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
141 | if (oneone) | ||
142 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
143 | else | ||
144 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
145 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
146 | // NOTE: use of CONNECTTIMEOUT without also | ||
147 | // setting NOSIGNAL results in really weird | ||
148 | // crashes on my system! | ||
149 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
150 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
151 | { | ||
152 | fprintf (stderr, | ||
153 | "curl_easy_perform failed: `%s'\n", | ||
154 | curl_easy_strerror (errornum)); | ||
155 | curl_easy_cleanup (c); | ||
156 | MHD_stop_daemon (d); | ||
157 | return 2; | ||
158 | } | ||
159 | curl_easy_cleanup (c); | ||
160 | MHD_stop_daemon (d); | ||
161 | if (cbc.pos != strlen ("/hello_world")) | ||
162 | return 4; | ||
163 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
164 | return 8; | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int | ||
169 | testMultithreadedPut () | ||
170 | { | ||
171 | struct MHD_Daemon *d; | ||
172 | CURL *c; | ||
173 | char buf[2048]; | ||
174 | struct CBC cbc; | ||
175 | unsigned int pos = 0; | ||
176 | int done_flag = 0; | ||
177 | CURLcode errornum; | ||
178 | |||
179 | cbc.buf = buf; | ||
180 | cbc.size = 2048; | ||
181 | cbc.pos = 0; | ||
182 | d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, | ||
183 | 1081, | ||
184 | NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); | ||
185 | if (d == NULL) | ||
186 | return 16; | ||
187 | c = curl_easy_init (); | ||
188 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world"); | ||
189 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
190 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
191 | curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); | ||
192 | curl_easy_setopt (c, CURLOPT_READDATA, &pos); | ||
193 | curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); | ||
194 | curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); | ||
195 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
196 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
197 | if (oneone) | ||
198 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
199 | else | ||
200 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
201 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
202 | // NOTE: use of CONNECTTIMEOUT without also | ||
203 | // setting NOSIGNAL results in really weird | ||
204 | // crashes on my system! | ||
205 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
206 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
207 | { | ||
208 | fprintf (stderr, | ||
209 | "curl_easy_perform failed: `%s'\n", | ||
210 | curl_easy_strerror (errornum)); | ||
211 | curl_easy_cleanup (c); | ||
212 | MHD_stop_daemon (d); | ||
213 | return 32; | ||
214 | } | ||
215 | curl_easy_cleanup (c); | ||
216 | MHD_stop_daemon (d); | ||
217 | if (cbc.pos != strlen ("/hello_world")) | ||
218 | return 64; | ||
219 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
220 | return 128; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | |||
226 | static int | ||
227 | testExternalPut () | ||
228 | { | ||
229 | struct MHD_Daemon *d; | ||
230 | CURL *c; | ||
231 | char buf[2048]; | ||
232 | struct CBC cbc; | ||
233 | CURLM *multi; | ||
234 | CURLMcode mret; | ||
235 | fd_set rs; | ||
236 | fd_set ws; | ||
237 | fd_set es; | ||
238 | int max; | ||
239 | int running; | ||
240 | struct CURLMsg *msg; | ||
241 | time_t start; | ||
242 | struct timeval tv; | ||
243 | unsigned int pos = 0; | ||
244 | int done_flag = 0; | ||
245 | |||
246 | multi = NULL; | ||
247 | cbc.buf = buf; | ||
248 | cbc.size = 2048; | ||
249 | cbc.pos = 0; | ||
250 | d = MHD_start_daemon (MHD_USE_DEBUG, | ||
251 | 1082, | ||
252 | NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); | ||
253 | if (d == NULL) | ||
254 | return 256; | ||
255 | c = curl_easy_init (); | ||
256 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world"); | ||
257 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
258 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
259 | curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); | ||
260 | curl_easy_setopt (c, CURLOPT_READDATA, &pos); | ||
261 | curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); | ||
262 | curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); | ||
263 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
264 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
265 | if (oneone) | ||
266 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
267 | else | ||
268 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
269 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
270 | // NOTE: use of CONNECTTIMEOUT without also | ||
271 | // setting NOSIGNAL results in really weird | ||
272 | // crashes on my system! | ||
273 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
274 | |||
275 | |||
276 | multi = curl_multi_init (); | ||
277 | if (multi == NULL) | ||
278 | { | ||
279 | curl_easy_cleanup (c); | ||
280 | MHD_stop_daemon (d); | ||
281 | return 512; | ||
282 | } | ||
283 | mret = curl_multi_add_handle (multi, c); | ||
284 | if (mret != CURLM_OK) | ||
285 | { | ||
286 | curl_multi_cleanup (multi); | ||
287 | curl_easy_cleanup (c); | ||
288 | MHD_stop_daemon (d); | ||
289 | return 1024; | ||
290 | } | ||
291 | start = time (NULL); | ||
292 | while ((time (NULL) - start < 5) && (multi != NULL)) | ||
293 | { | ||
294 | max = 0; | ||
295 | FD_ZERO (&rs); | ||
296 | FD_ZERO (&ws); | ||
297 | FD_ZERO (&es); | ||
298 | curl_multi_perform (multi, &running); | ||
299 | mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); | ||
300 | if (mret != CURLM_OK) | ||
301 | { | ||
302 | curl_multi_remove_handle (multi, c); | ||
303 | curl_multi_cleanup (multi); | ||
304 | curl_easy_cleanup (c); | ||
305 | MHD_stop_daemon (d); | ||
306 | return 2048; | ||
307 | } | ||
308 | if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) | ||
309 | { | ||
310 | curl_multi_remove_handle (multi, c); | ||
311 | curl_multi_cleanup (multi); | ||
312 | curl_easy_cleanup (c); | ||
313 | MHD_stop_daemon (d); | ||
314 | return 4096; | ||
315 | } | ||
316 | tv.tv_sec = 0; | ||
317 | tv.tv_usec = 1000; | ||
318 | select (max + 1, &rs, &ws, &es, &tv); | ||
319 | curl_multi_perform (multi, &running); | ||
320 | if (running == 0) | ||
321 | { | ||
322 | msg = curl_multi_info_read (multi, &running); | ||
323 | if (msg == NULL) | ||
324 | break; | ||
325 | if (msg->msg == CURLMSG_DONE) | ||
326 | { | ||
327 | if (msg->data.result != CURLE_OK) | ||
328 | printf ("%s failed at %s:%d: `%s'\n", | ||
329 | "curl_multi_perform", | ||
330 | __FILE__, | ||
331 | __LINE__, curl_easy_strerror (msg->data.result)); | ||
332 | curl_multi_remove_handle (multi, c); | ||
333 | curl_multi_cleanup (multi); | ||
334 | curl_easy_cleanup (c); | ||
335 | c = NULL; | ||
336 | multi = NULL; | ||
337 | } | ||
338 | } | ||
339 | MHD_run (d); | ||
340 | } | ||
341 | if (multi != NULL) | ||
342 | { | ||
343 | curl_multi_remove_handle (multi, c); | ||
344 | curl_easy_cleanup (c); | ||
345 | curl_multi_cleanup (multi); | ||
346 | } | ||
347 | MHD_stop_daemon (d); | ||
348 | if (cbc.pos != strlen ("/hello_world")) | ||
349 | return 8192; | ||
350 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
351 | return 16384; | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | |||
356 | |||
357 | int | ||
358 | main (int argc, char *const *argv) | ||
359 | { | ||
360 | unsigned int errorCount = 0; | ||
361 | |||
362 | oneone = NULL != strstr (argv[0], "11"); | ||
363 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
364 | return 2; | ||
365 | errorCount += testInternalPut (); | ||
366 | if (0) | ||
367 | { | ||
368 | errorCount += testMultithreadedPut (); | ||
369 | errorCount += testExternalPut (); | ||
370 | } | ||
371 | if (errorCount != 0) | ||
372 | fprintf (stderr, "Error (code: %u)\n", errorCount); | ||
373 | curl_global_cleanup (); | ||
374 | return errorCount != 0; /* 0 == pass */ | ||
375 | } | ||
diff --git a/src/testzzuf/daemontest_put_chunked.c b/src/testzzuf/daemontest_put_chunked.c new file mode 100644 index 00000000..0cc3eb8f --- /dev/null +++ b/src/testzzuf/daemontest_put_chunked.c | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | (C) 2007 Christian Grothoff | ||
4 | |||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with libmicrohttpd; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file daemontest_put_chunked.c | ||
23 | * @brief Testcase for libmicrohttpd PUT operations with chunked encoding | ||
24 | * for the upload data | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include "config.h" | ||
29 | #include <curl/curl.h> | ||
30 | #include <microhttpd.h> | ||
31 | #include <stdlib.h> | ||
32 | #include <string.h> | ||
33 | #include <time.h> | ||
34 | |||
35 | #ifndef WINDOWS | ||
36 | #include <unistd.h> | ||
37 | #endif | ||
38 | |||
39 | struct CBC | ||
40 | { | ||
41 | char *buf; | ||
42 | size_t pos; | ||
43 | size_t size; | ||
44 | }; | ||
45 | |||
46 | static size_t | ||
47 | putBuffer (void *stream, size_t size, size_t nmemb, void *ptr) | ||
48 | { | ||
49 | unsigned int *pos = ptr; | ||
50 | unsigned int wrt; | ||
51 | |||
52 | wrt = size * nmemb; | ||
53 | if (wrt > 8 - (*pos)) | ||
54 | wrt = 8 - (*pos); | ||
55 | if (wrt > 4) | ||
56 | wrt = 4; /* only send half at first => force multiple chunks! */ | ||
57 | memcpy (stream, &("Hello123"[*pos]), wrt); | ||
58 | (*pos) += wrt; | ||
59 | return wrt; | ||
60 | } | ||
61 | |||
62 | static size_t | ||
63 | copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) | ||
64 | { | ||
65 | struct CBC *cbc = ctx; | ||
66 | |||
67 | if (cbc->pos + size * nmemb > cbc->size) | ||
68 | return 0; /* overflow */ | ||
69 | memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); | ||
70 | cbc->pos += size * nmemb; | ||
71 | return size * nmemb; | ||
72 | } | ||
73 | |||
74 | static int | ||
75 | ahc_echo (void *cls, | ||
76 | struct MHD_Connection *connection, | ||
77 | const char *url, | ||
78 | const char *method, | ||
79 | const char *version, | ||
80 | const char *upload_data, unsigned int *upload_data_size, | ||
81 | void **unused) | ||
82 | { | ||
83 | int *done = cls; | ||
84 | struct MHD_Response *response; | ||
85 | int ret; | ||
86 | int have; | ||
87 | |||
88 | if (0 != strcmp ("PUT", method)) | ||
89 | return MHD_NO; /* unexpected method */ | ||
90 | if ((*done) < 8) | ||
91 | { | ||
92 | have = *upload_data_size; | ||
93 | if (have + *done > 8) | ||
94 | { | ||
95 | printf ("Invalid upload data `%8s'!\n", upload_data); | ||
96 | return MHD_NO; | ||
97 | } | ||
98 | if (0 == memcmp (upload_data, &"Hello123"[*done], have)) | ||
99 | { | ||
100 | *done += have; | ||
101 | *upload_data_size = 0; | ||
102 | } | ||
103 | else | ||
104 | { | ||
105 | printf ("Invalid upload data `%8s'!\n", upload_data); | ||
106 | return MHD_NO; | ||
107 | } | ||
108 | #if 0 | ||
109 | fprintf (stderr, "Not ready for response: %u/%u\n", *done, 8); | ||
110 | #endif | ||
111 | return MHD_YES; | ||
112 | } | ||
113 | response = MHD_create_response_from_data (strlen (url), | ||
114 | (void *) url, MHD_NO, MHD_YES); | ||
115 | ret = MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
116 | MHD_destroy_response (response); | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | |||
121 | static int | ||
122 | testInternalPut () | ||
123 | { | ||
124 | struct MHD_Daemon *d; | ||
125 | CURL *c; | ||
126 | char buf[2048]; | ||
127 | struct CBC cbc; | ||
128 | unsigned int pos = 0; | ||
129 | int done_flag = 0; | ||
130 | CURLcode errornum; | ||
131 | |||
132 | cbc.buf = buf; | ||
133 | cbc.size = 2048; | ||
134 | cbc.pos = 0; | ||
135 | d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG, | ||
136 | 11080, | ||
137 | NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); | ||
138 | if (d == NULL) | ||
139 | return 1; | ||
140 | c = curl_easy_init (); | ||
141 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world"); | ||
142 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
143 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
144 | curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); | ||
145 | curl_easy_setopt (c, CURLOPT_READDATA, &pos); | ||
146 | curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); | ||
147 | /* | ||
148 | // by not giving the file size, we force chunking! | ||
149 | curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); | ||
150 | */ | ||
151 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
152 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
153 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
154 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
155 | // NOTE: use of CONNECTTIMEOUT without also | ||
156 | // setting NOSIGNAL results in really weird | ||
157 | // crashes on my system! | ||
158 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
159 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
160 | { | ||
161 | fprintf (stderr, | ||
162 | "curl_easy_perform failed: `%s'\n", | ||
163 | curl_easy_strerror (errornum)); | ||
164 | curl_easy_cleanup (c); | ||
165 | MHD_stop_daemon (d); | ||
166 | return 2; | ||
167 | } | ||
168 | curl_easy_cleanup (c); | ||
169 | MHD_stop_daemon (d); | ||
170 | if (cbc.pos != strlen ("/hello_world")) | ||
171 | return 4; | ||
172 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
173 | return 8; | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int | ||
178 | testMultithreadedPut () | ||
179 | { | ||
180 | struct MHD_Daemon *d; | ||
181 | CURL *c; | ||
182 | char buf[2048]; | ||
183 | struct CBC cbc; | ||
184 | unsigned int pos = 0; | ||
185 | int done_flag = 0; | ||
186 | CURLcode errornum; | ||
187 | |||
188 | cbc.buf = buf; | ||
189 | cbc.size = 2048; | ||
190 | cbc.pos = 0; | ||
191 | d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG, | ||
192 | 11081, | ||
193 | NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); | ||
194 | if (d == NULL) | ||
195 | return 16; | ||
196 | c = curl_easy_init (); | ||
197 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11081/hello_world"); | ||
198 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
199 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
200 | curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); | ||
201 | curl_easy_setopt (c, CURLOPT_READDATA, &pos); | ||
202 | curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); | ||
203 | /* | ||
204 | // by not giving the file size, we force chunking! | ||
205 | curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); | ||
206 | */ | ||
207 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
208 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
209 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
210 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
211 | // NOTE: use of CONNECTTIMEOUT without also | ||
212 | // setting NOSIGNAL results in really weird | ||
213 | // crashes on my system! | ||
214 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
215 | if (CURLE_OK != (errornum = curl_easy_perform (c))) | ||
216 | { | ||
217 | fprintf (stderr, | ||
218 | "curl_easy_perform failed: `%s'\n", | ||
219 | curl_easy_strerror (errornum)); | ||
220 | curl_easy_cleanup (c); | ||
221 | MHD_stop_daemon (d); | ||
222 | return 32; | ||
223 | } | ||
224 | curl_easy_cleanup (c); | ||
225 | MHD_stop_daemon (d); | ||
226 | if (cbc.pos != strlen ("/hello_world")) | ||
227 | return 64; | ||
228 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
229 | return 128; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | |||
235 | static int | ||
236 | testExternalPut () | ||
237 | { | ||
238 | struct MHD_Daemon *d; | ||
239 | CURL *c; | ||
240 | char buf[2048]; | ||
241 | struct CBC cbc; | ||
242 | CURLM *multi; | ||
243 | CURLMcode mret; | ||
244 | fd_set rs; | ||
245 | fd_set ws; | ||
246 | fd_set es; | ||
247 | int max; | ||
248 | int running; | ||
249 | struct CURLMsg *msg; | ||
250 | time_t start; | ||
251 | struct timeval tv; | ||
252 | unsigned int pos = 0; | ||
253 | int done_flag = 0; | ||
254 | |||
255 | multi = NULL; | ||
256 | cbc.buf = buf; | ||
257 | cbc.size = 2048; | ||
258 | cbc.pos = 0; | ||
259 | d = MHD_start_daemon (MHD_USE_DEBUG, | ||
260 | 11082, | ||
261 | NULL, NULL, &ahc_echo, &done_flag, MHD_OPTION_END); | ||
262 | if (d == NULL) | ||
263 | return 256; | ||
264 | c = curl_easy_init (); | ||
265 | curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11082/hello_world"); | ||
266 | curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, ©Buffer); | ||
267 | curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc); | ||
268 | curl_easy_setopt (c, CURLOPT_READFUNCTION, &putBuffer); | ||
269 | curl_easy_setopt (c, CURLOPT_READDATA, &pos); | ||
270 | curl_easy_setopt (c, CURLOPT_UPLOAD, 1L); | ||
271 | /* | ||
272 | // by not giving the file size, we force chunking! | ||
273 | curl_easy_setopt (c, CURLOPT_INFILESIZE_LARGE, (curl_off_t) 8L); | ||
274 | */ | ||
275 | curl_easy_setopt (c, CURLOPT_FAILONERROR, 1); | ||
276 | curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); | ||
277 | curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); | ||
278 | curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L); | ||
279 | // NOTE: use of CONNECTTIMEOUT without also | ||
280 | // setting NOSIGNAL results in really weird | ||
281 | // crashes on my system! | ||
282 | curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1); | ||
283 | |||
284 | |||
285 | multi = curl_multi_init (); | ||
286 | if (multi == NULL) | ||
287 | { | ||
288 | curl_easy_cleanup (c); | ||
289 | MHD_stop_daemon (d); | ||
290 | return 512; | ||
291 | } | ||
292 | mret = curl_multi_add_handle (multi, c); | ||
293 | if (mret != CURLM_OK) | ||
294 | { | ||
295 | curl_multi_cleanup (multi); | ||
296 | curl_easy_cleanup (c); | ||
297 | MHD_stop_daemon (d); | ||
298 | return 1024; | ||
299 | } | ||
300 | start = time (NULL); | ||
301 | while ((time (NULL) - start < 5) && (multi != NULL)) | ||
302 | { | ||
303 | max = 0; | ||
304 | FD_ZERO (&rs); | ||
305 | FD_ZERO (&ws); | ||
306 | FD_ZERO (&es); | ||
307 | curl_multi_perform (multi, &running); | ||
308 | mret = curl_multi_fdset (multi, &rs, &ws, &es, &max); | ||
309 | if (mret != CURLM_OK) | ||
310 | { | ||
311 | curl_multi_remove_handle (multi, c); | ||
312 | curl_multi_cleanup (multi); | ||
313 | curl_easy_cleanup (c); | ||
314 | MHD_stop_daemon (d); | ||
315 | return 2048; | ||
316 | } | ||
317 | if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) | ||
318 | { | ||
319 | curl_multi_remove_handle (multi, c); | ||
320 | curl_multi_cleanup (multi); | ||
321 | curl_easy_cleanup (c); | ||
322 | MHD_stop_daemon (d); | ||
323 | return 4096; | ||
324 | } | ||
325 | tv.tv_sec = 0; | ||
326 | tv.tv_usec = 1000; | ||
327 | select (max + 1, &rs, &ws, &es, &tv); | ||
328 | curl_multi_perform (multi, &running); | ||
329 | if (running == 0) | ||
330 | { | ||
331 | msg = curl_multi_info_read (multi, &running); | ||
332 | if (msg == NULL) | ||
333 | break; | ||
334 | if (msg->msg == CURLMSG_DONE) | ||
335 | { | ||
336 | if (msg->data.result != CURLE_OK) | ||
337 | printf ("%s failed at %s:%d: `%s'\n", | ||
338 | "curl_multi_perform", | ||
339 | __FILE__, | ||
340 | __LINE__, curl_easy_strerror (msg->data.result)); | ||
341 | curl_multi_remove_handle (multi, c); | ||
342 | curl_multi_cleanup (multi); | ||
343 | curl_easy_cleanup (c); | ||
344 | c = NULL; | ||
345 | multi = NULL; | ||
346 | } | ||
347 | } | ||
348 | MHD_run (d); | ||
349 | } | ||
350 | if (multi != NULL) | ||
351 | { | ||
352 | curl_multi_remove_handle (multi, c); | ||
353 | curl_easy_cleanup (c); | ||
354 | curl_multi_cleanup (multi); | ||
355 | } | ||
356 | MHD_stop_daemon (d); | ||
357 | if (cbc.pos != strlen ("/hello_world")) | ||
358 | return 8192; | ||
359 | if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) | ||
360 | return 16384; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | |||
365 | |||
366 | int | ||
367 | main (int argc, char *const *argv) | ||
368 | { | ||
369 | unsigned int errorCount = 0; | ||
370 | |||
371 | if (0 != curl_global_init (CURL_GLOBAL_WIN32)) | ||
372 | return 2; | ||
373 | errorCount += testInternalPut (); | ||
374 | if (0) | ||
375 | { | ||
376 | errorCount += testMultithreadedPut (); | ||
377 | errorCount += testExternalPut (); | ||
378 | } | ||
379 | if (errorCount != 0) | ||
380 | fprintf (stderr, "Error (code: %u)\n", errorCount); | ||
381 | curl_global_cleanup (); | ||
382 | return errorCount != 0; /* 0 == pass */ | ||
383 | } | ||