diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-09-04 15:05:41 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-09-04 15:05:41 +0000 |
commit | 39bc8f5c76f844e56a04d5993ccfee9f2b41d17e (patch) | |
tree | c52459a1ca25accef1565de668d95fd9f0cffed5 | |
parent | 1f2539eed6da8dcf7f4f1ede8ab14c278f9b0c5e (diff) | |
download | libmicrohttpd-39bc8f5c76f844e56a04d5993ccfee9f2b41d17e.tar.gz libmicrohttpd-39bc8f5c76f844e56a04d5993ccfee9f2b41d17e.zip |
factor out shared test logic, test with external select as well
-rw-r--r-- | src/microhttpd/Makefile.am | 2 | ||||
-rw-r--r-- | src/microhttpd/test_upgrade.c | 380 | ||||
-rw-r--r-- | src/microhttpd/test_upgrade_common.c | 451 | ||||
-rw-r--r-- | src/microhttpd/test_upgrade_ssl.c | 383 |
4 files changed, 524 insertions, 692 deletions
diff --git a/src/microhttpd/Makefile.am b/src/microhttpd/Makefile.am index b60ff81e..13c2fa65 100644 --- a/src/microhttpd/Makefile.am +++ b/src/microhttpd/Makefile.am | |||
@@ -8,6 +8,8 @@ AM_CFLAGS = $(HIDDEN_VISIBILITY_CFLAGS) | |||
8 | lib_LTLIBRARIES = \ | 8 | lib_LTLIBRARIES = \ |
9 | libmicrohttpd.la | 9 | libmicrohttpd.la |
10 | 10 | ||
11 | EXTRA_DIST = test_upgrade_common.c | ||
12 | |||
11 | noinst_DATA = | 13 | noinst_DATA = |
12 | MOSTLYCLEANFILES = | 14 | MOSTLYCLEANFILES = |
13 | 15 | ||
diff --git a/src/microhttpd/test_upgrade.c b/src/microhttpd/test_upgrade.c index c6005407..91b85b1e 100644 --- a/src/microhttpd/test_upgrade.c +++ b/src/microhttpd/test_upgrade.c | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | 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 | 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 | 7 | by the Free Software Foundation; either version 3, or (at your |
8 | option) any later version. | 8 | option) any later version. |
9 | 9 | ||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | 10 | libmicrohttpd is distributed in the hope that it will be useful, but |
@@ -39,337 +39,18 @@ | |||
39 | #include <netinet/in.h> | 39 | #include <netinet/in.h> |
40 | #include <netinet/ip.h> | 40 | #include <netinet/ip.h> |
41 | #include "mhd_sockets.h" | 41 | #include "mhd_sockets.h" |
42 | #include "test_upgrade_common.c" | ||
42 | 43 | ||
43 | 44 | ||
44 | /** | 45 | /** |
45 | * Thread we use to run the interaction with the upgraded socket. | 46 | * Test upgrading a connection. |
46 | */ | ||
47 | static pthread_t pt; | ||
48 | |||
49 | /** | ||
50 | * Will be set to the upgraded socket. | ||
51 | */ | ||
52 | static MHD_socket usock; | ||
53 | |||
54 | /** | ||
55 | * Thread we use to run the interaction with the upgraded socket. | ||
56 | */ | ||
57 | static pthread_t pt_client; | ||
58 | |||
59 | |||
60 | /** | ||
61 | * Change itc FD options to be non-blocking. | ||
62 | * | ||
63 | * @param fd the FD to manipulate | ||
64 | * @return non-zero if succeeded, zero otherwise | ||
65 | */ | ||
66 | static void | ||
67 | make_blocking (MHD_socket fd) | ||
68 | { | ||
69 | int flags; | ||
70 | |||
71 | flags = fcntl (fd, F_GETFL); | ||
72 | if (-1 == flags) | ||
73 | return; | ||
74 | if ((flags & ~O_NONBLOCK) != flags) | ||
75 | fcntl (fd, F_SETFL, flags & ~O_NONBLOCK); | ||
76 | } | ||
77 | |||
78 | |||
79 | static void | ||
80 | send_all (MHD_socket sock, | ||
81 | const char *text) | ||
82 | { | ||
83 | size_t len = strlen (text); | ||
84 | ssize_t ret; | ||
85 | |||
86 | make_blocking (sock); | ||
87 | for (size_t off = 0; off < len; off += ret) | ||
88 | { | ||
89 | ret = write (sock, | ||
90 | &text[off], | ||
91 | len - off); | ||
92 | if (-1 == ret) | ||
93 | { | ||
94 | if (EAGAIN == errno) | ||
95 | { | ||
96 | ret = 0; | ||
97 | continue; | ||
98 | } | ||
99 | abort (); | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Read character-by-character until we | ||
107 | * get '\r\n\r\n'. | ||
108 | */ | ||
109 | static void | ||
110 | recv_hdr (MHD_socket sock) | ||
111 | { | ||
112 | unsigned int i; | ||
113 | char next; | ||
114 | char c; | ||
115 | ssize_t ret; | ||
116 | |||
117 | make_blocking (sock); | ||
118 | next = '\r'; | ||
119 | i = 0; | ||
120 | while (i < 4) | ||
121 | { | ||
122 | ret = read (sock, | ||
123 | &c, | ||
124 | 1); | ||
125 | if (-1 == ret) | ||
126 | { | ||
127 | if (EAGAIN == errno) | ||
128 | { | ||
129 | ret = 0; | ||
130 | continue; | ||
131 | } | ||
132 | abort (); | ||
133 | } | ||
134 | if (0 == ret) | ||
135 | continue; | ||
136 | if (c == next) | ||
137 | { | ||
138 | i++; | ||
139 | if (next == '\r') | ||
140 | next = '\n'; | ||
141 | else | ||
142 | next = '\r'; | ||
143 | continue; | ||
144 | } | ||
145 | if (c == '\r') | ||
146 | { | ||
147 | i = 1; | ||
148 | next = '\n'; | ||
149 | continue; | ||
150 | } | ||
151 | i = 0; | ||
152 | next = '\r'; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | |||
157 | static void | ||
158 | recv_all (MHD_socket sock, | ||
159 | const char *text) | ||
160 | { | ||
161 | size_t len = strlen (text); | ||
162 | char buf[len]; | ||
163 | ssize_t ret; | ||
164 | |||
165 | make_blocking (sock); | ||
166 | for (size_t off = 0; off < len; off += ret) | ||
167 | { | ||
168 | ret = read (sock, | ||
169 | &buf[off], | ||
170 | len - off); | ||
171 | if (-1 == ret) | ||
172 | { | ||
173 | if (EAGAIN == errno) | ||
174 | { | ||
175 | ret = 0; | ||
176 | continue; | ||
177 | } | ||
178 | abort (); | ||
179 | } | ||
180 | } | ||
181 | if (0 != strncmp (text, buf, len)) | ||
182 | abort(); | ||
183 | } | ||
184 | |||
185 | |||
186 | /** | ||
187 | * Main function for the thread that runs the interaction with | ||
188 | * the upgraded socket. | ||
189 | * | ||
190 | * @param cls the handle for the upgrade | ||
191 | */ | ||
192 | static void * | ||
193 | run_usock (void *cls) | ||
194 | { | ||
195 | struct MHD_UpgradeResponseHandle *urh = cls; | ||
196 | |||
197 | send_all (usock, | ||
198 | "Hello"); | ||
199 | recv_all (usock, | ||
200 | "World"); | ||
201 | send_all (usock, | ||
202 | "Finished"); | ||
203 | MHD_upgrade_action (urh, | ||
204 | MHD_UPGRADE_ACTION_CLOSE); | ||
205 | return NULL; | ||
206 | } | ||
207 | |||
208 | |||
209 | /** | ||
210 | * Main function for the thread that runs the client-side of the | ||
211 | * interaction with the upgraded socket. | ||
212 | * | ||
213 | * @param cls the client socket | ||
214 | */ | ||
215 | static void * | ||
216 | run_usock_client (void *cls) | ||
217 | { | ||
218 | MHD_socket *sock = cls; | ||
219 | |||
220 | send_all (*sock, | ||
221 | "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n"); | ||
222 | recv_hdr (*sock); | ||
223 | recv_all (*sock, | ||
224 | "Hello"); | ||
225 | send_all (*sock, | ||
226 | "World"); | ||
227 | recv_all (*sock, | ||
228 | "Finished"); | ||
229 | MHD_socket_close_ (*sock); | ||
230 | return NULL; | ||
231 | } | ||
232 | |||
233 | |||
234 | /** | ||
235 | * Function called after a protocol "upgrade" response was sent | ||
236 | * successfully and the socket should now be controlled by some | ||
237 | * protocol other than HTTP. | ||
238 | * | ||
239 | * Any data received on the socket will be made available in | ||
240 | * 'data_in'. The function should update 'data_in_size' to | ||
241 | * reflect the number of bytes consumed from 'data_in' (the remaining | ||
242 | * bytes will be made available in the next call to the handler). | ||
243 | * | ||
244 | * Any data that should be transmitted on the socket should be | ||
245 | * stored in 'data_out'. '*data_out_size' is initially set to | ||
246 | * the available buffer space in 'data_out'. It should be set to | ||
247 | * the number of bytes stored in 'data_out' (which can be zero). | ||
248 | * | ||
249 | * The return value is a BITMASK that indicates how the function | ||
250 | * intends to interact with the event loop. It can request to be | ||
251 | * notified for reading, writing, request to UNCORK the send buffer | ||
252 | * (which MHD is allowed to ignore, if it is not possible to uncork on | ||
253 | * the local platform), to wait for the 'external' select loop to | ||
254 | * trigger another round. It is also possible to specify "no events" | ||
255 | * to terminate the connection; in this case, the | ||
256 | * #MHD_RequestCompletedCallback will be called and all resources of | ||
257 | * the connection will be released. | ||
258 | * | 47 | * |
259 | * Except when in 'thread-per-connection' mode, implementations | 48 | * @param flags which event loop style should be tested |
260 | * of this function should never block (as it will still be called | 49 | * @param pool size of the thread pool, 0 to disable |
261 | * from within the main event loop). | ||
262 | * | ||
263 | * @param cls closure, whatever was given to #MHD_create_response_for_upgrade(). | ||
264 | * @param connection original HTTP connection handle, | ||
265 | * giving the function a last chance | ||
266 | * to inspect the original HTTP request | ||
267 | * @param con_cls last value left in `*con_cls` in the `MHD_AccessHandlerCallback` | ||
268 | * @param extra_in if we happened to have read bytes after the | ||
269 | * HTTP header already (because the client sent | ||
270 | * more than the HTTP header of the request before | ||
271 | * we sent the upgrade response), | ||
272 | * these are the extra bytes already read from @a sock | ||
273 | * by MHD. The application should treat these as if | ||
274 | * it had read them from @a sock. | ||
275 | * @param extra_in_size number of bytes in @a extra_in | ||
276 | * @param sock socket to use for bi-directional communication | ||
277 | * with the client. For HTTPS, this may not be a socket | ||
278 | * that is directly connected to the client and thus certain | ||
279 | * operations (TCP-specific setsockopt(), getsockopt(), etc.) | ||
280 | * may not work as expected (as the socket could be from a | ||
281 | * socketpair() or a TCP-loopback) | ||
282 | * @param urh argument for #MHD_upgrade_action()s on this @a connection. | ||
283 | * Applications must eventually use this function to perform the | ||
284 | * close() action on the @a sock. | ||
285 | */ | ||
286 | static void | ||
287 | upgrade_cb (void *cls, | ||
288 | struct MHD_Connection *connection, | ||
289 | void *con_cls, | ||
290 | const char *extra_in, | ||
291 | size_t extra_in_size, | ||
292 | MHD_socket sock, | ||
293 | struct MHD_UpgradeResponseHandle *urh) | ||
294 | { | ||
295 | usock = sock; | ||
296 | if (0 != extra_in_size) | ||
297 | abort (); | ||
298 | pthread_create (&pt, | ||
299 | NULL, | ||
300 | &run_usock, | ||
301 | urh); | ||
302 | } | ||
303 | |||
304 | |||
305 | /** | ||
306 | * A client has requested the given url using the given method | ||
307 | * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, | ||
308 | * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback | ||
309 | * must call MHD callbacks to provide content to give back to the | ||
310 | * client and return an HTTP status code (i.e. #MHD_HTTP_OK, | ||
311 | * #MHD_HTTP_NOT_FOUND, etc.). | ||
312 | * | ||
313 | * @param cls argument given together with the function | ||
314 | * pointer when the handler was registered with MHD | ||
315 | * @param url the requested url | ||
316 | * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, | ||
317 | * #MHD_HTTP_METHOD_PUT, etc.) | ||
318 | * @param version the HTTP version string (i.e. | ||
319 | * #MHD_HTTP_VERSION_1_1) | ||
320 | * @param upload_data the data being uploaded (excluding HEADERS, | ||
321 | * for a POST that fits into memory and that is encoded | ||
322 | * with a supported encoding, the POST data will NOT be | ||
323 | * given in upload_data and is instead available as | ||
324 | * part of #MHD_get_connection_values; very large POST | ||
325 | * data *will* be made available incrementally in | ||
326 | * @a upload_data) | ||
327 | * @param upload_data_size set initially to the size of the | ||
328 | * @a upload_data provided; the method must update this | ||
329 | * value to the number of bytes NOT processed; | ||
330 | * @param con_cls pointer that the callback can set to some | ||
331 | * address and that will be preserved by MHD for future | ||
332 | * calls for this request; since the access handler may | ||
333 | * be called many times (i.e., for a PUT/POST operation | ||
334 | * with plenty of upload data) this allows the application | ||
335 | * to easily associate some request-specific state. | ||
336 | * If necessary, this state can be cleaned up in the | ||
337 | * global #MHD_RequestCompletedCallback (which | ||
338 | * can be set with the #MHD_OPTION_NOTIFY_COMPLETED). | ||
339 | * Initially, `*con_cls` will be NULL. | ||
340 | * @return #MHD_YES if the connection was handled successfully, | ||
341 | * #MHD_NO if the socket must be closed due to a serios | ||
342 | * error while handling the request | ||
343 | */ | 50 | */ |
344 | static int | 51 | static int |
345 | ahc_upgrade (void *cls, | 52 | test_upgrade (int flags, |
346 | struct MHD_Connection *connection, | 53 | unsigned int pool) |
347 | const char *url, | ||
348 | const char *method, | ||
349 | const char *version, | ||
350 | const char *upload_data, | ||
351 | size_t *upload_data_size, | ||
352 | void **con_cls) | ||
353 | { | ||
354 | struct MHD_Response *resp; | ||
355 | int ret; | ||
356 | |||
357 | resp = MHD_create_response_for_upgrade (&upgrade_cb, | ||
358 | NULL); | ||
359 | MHD_add_response_header (resp, | ||
360 | MHD_HTTP_HEADER_UPGRADE, | ||
361 | "Hello World Protocol"); | ||
362 | ret = MHD_queue_response (connection, | ||
363 | MHD_HTTP_SWITCHING_PROTOCOLS, | ||
364 | resp); | ||
365 | MHD_destroy_response (resp); | ||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | |||
370 | static int | ||
371 | test_upgrade_internal (int flags, | ||
372 | unsigned int pool) | ||
373 | { | 54 | { |
374 | struct MHD_Daemon *d; | 55 | struct MHD_Daemon *d; |
375 | MHD_socket sock; | 56 | MHD_socket sock; |
@@ -399,7 +80,9 @@ test_upgrade_internal (int flags, | |||
399 | NULL, | 80 | NULL, |
400 | &run_usock_client, | 81 | &run_usock_client, |
401 | &sock); | 82 | &sock); |
402 | 83 | if (0 == (flags & (MHD_USE_SELECT_INTERNALLY | | |
84 | MHD_USE_THREAD_PER_CONNECTION)) ) | ||
85 | run_mhd_loop (d, flags); | ||
403 | pthread_join (pt_client, | 86 | pthread_join (pt_client, |
404 | NULL); | 87 | NULL); |
405 | pthread_join (pt, | 88 | pthread_join (pt, |
@@ -415,27 +98,36 @@ main (int argc, | |||
415 | { | 98 | { |
416 | int error_count = 0; | 99 | int error_count = 0; |
417 | 100 | ||
418 | error_count += test_upgrade_internal (MHD_USE_THREAD_PER_CONNECTION, | 101 | /* try external select */ |
419 | 0); | 102 | error_count += test_upgrade (0, |
420 | error_count += test_upgrade_internal (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL, | 103 | 0); |
421 | 0); | 104 | |
422 | error_count += test_upgrade_internal (MHD_USE_SELECT_INTERNALLY, | 105 | /* Test thread-per-connection */ |
423 | 0); | 106 | error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION, |
424 | error_count += test_upgrade_internal (MHD_USE_SELECT_INTERNALLY, | 107 | 0); |
425 | 2); | 108 | error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL, |
109 | 0); | ||
110 | |||
111 | /* Test different event loops, with and without thread pool */ | ||
112 | error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY, | ||
113 | 0); | ||
114 | error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY, | ||
115 | 2); | ||
426 | #ifdef HAVE_POLL | 116 | #ifdef HAVE_POLL |
427 | error_count += test_upgrade_internal (MHD_USE_POLL_INTERNALLY, | 117 | error_count += test_upgrade (MHD_USE_POLL_INTERNALLY, |
428 | 0); | 118 | 0); |
429 | error_count += test_upgrade_internal (MHD_USE_POLL_INTERNALLY, | 119 | error_count += test_upgrade (MHD_USE_POLL_INTERNALLY, |
430 | 2); | 120 | 2); |
431 | #endif | 121 | #endif |
432 | #ifdef EPOLL_SUPPORT | 122 | #ifdef EPOLL_SUPPORT |
433 | error_count += test_upgrade_internal (MHD_USE_EPOLL_INTERNALLY, | 123 | error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY, |
434 | 0); | 124 | 0); |
435 | error_count += test_upgrade_internal (MHD_USE_EPOLL_INTERNALLY, | 125 | error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY, |
436 | 2); | 126 | 2); |
437 | #endif | 127 | #endif |
438 | if (error_count != 0) | 128 | |
129 | /* report result */ | ||
130 | if (0 != error_count) | ||
439 | fprintf (stderr, | 131 | fprintf (stderr, |
440 | "Error (code: %u)\n", | 132 | "Error (code: %u)\n", |
441 | error_count); | 133 | error_count); |
diff --git a/src/microhttpd/test_upgrade_common.c b/src/microhttpd/test_upgrade_common.c new file mode 100644 index 00000000..9985ef5e --- /dev/null +++ b/src/microhttpd/test_upgrade_common.c | |||
@@ -0,0 +1,451 @@ | |||
1 | /* | ||
2 | This file is part of libmicrohttpd | ||
3 | Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file test_upgrade_common.c | ||
23 | * @brief Shared logic for testcases for libmicrohttpd upgrading a connection | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | |||
28 | /** | ||
29 | * Thread we use to run the interaction with the upgraded socket. | ||
30 | */ | ||
31 | static pthread_t pt; | ||
32 | |||
33 | /** | ||
34 | * Will be set to the upgraded socket. | ||
35 | */ | ||
36 | static MHD_socket usock; | ||
37 | |||
38 | /** | ||
39 | * Thread we use to run the interaction with the upgraded socket. | ||
40 | */ | ||
41 | static pthread_t pt_client; | ||
42 | |||
43 | /** | ||
44 | * Flag set to 1 once the test is finished. | ||
45 | */ | ||
46 | static int done; | ||
47 | |||
48 | /** | ||
49 | * Change itc FD options to be non-blocking. | ||
50 | * | ||
51 | * @param fd the FD to manipulate | ||
52 | * @return non-zero if succeeded, zero otherwise | ||
53 | */ | ||
54 | static void | ||
55 | make_blocking (MHD_socket fd) | ||
56 | { | ||
57 | int flags; | ||
58 | |||
59 | flags = fcntl (fd, F_GETFL); | ||
60 | if (-1 == flags) | ||
61 | return; | ||
62 | if ((flags & ~O_NONBLOCK) != flags) | ||
63 | fcntl (fd, F_SETFL, flags & ~O_NONBLOCK); | ||
64 | } | ||
65 | |||
66 | |||
67 | static void | ||
68 | send_all (MHD_socket sock, | ||
69 | const char *text) | ||
70 | { | ||
71 | size_t len = strlen (text); | ||
72 | ssize_t ret; | ||
73 | |||
74 | make_blocking (sock); | ||
75 | for (size_t off = 0; off < len; off += ret) | ||
76 | { | ||
77 | ret = write (sock, | ||
78 | &text[off], | ||
79 | len - off); | ||
80 | if (-1 == ret) | ||
81 | { | ||
82 | if (EAGAIN == errno) | ||
83 | { | ||
84 | ret = 0; | ||
85 | continue; | ||
86 | } | ||
87 | abort (); | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
92 | |||
93 | /** | ||
94 | * Read character-by-character until we | ||
95 | * get '\r\n\r\n'. | ||
96 | */ | ||
97 | static void | ||
98 | recv_hdr (MHD_socket sock) | ||
99 | { | ||
100 | unsigned int i; | ||
101 | char next; | ||
102 | char c; | ||
103 | ssize_t ret; | ||
104 | |||
105 | make_blocking (sock); | ||
106 | next = '\r'; | ||
107 | i = 0; | ||
108 | while (i < 4) | ||
109 | { | ||
110 | ret = read (sock, | ||
111 | &c, | ||
112 | 1); | ||
113 | if (-1 == ret) | ||
114 | { | ||
115 | if (EAGAIN == errno) | ||
116 | { | ||
117 | ret = 0; | ||
118 | continue; | ||
119 | } | ||
120 | abort (); | ||
121 | } | ||
122 | if (0 == ret) | ||
123 | continue; | ||
124 | if (c == next) | ||
125 | { | ||
126 | i++; | ||
127 | if (next == '\r') | ||
128 | next = '\n'; | ||
129 | else | ||
130 | next = '\r'; | ||
131 | continue; | ||
132 | } | ||
133 | if (c == '\r') | ||
134 | { | ||
135 | i = 1; | ||
136 | next = '\n'; | ||
137 | continue; | ||
138 | } | ||
139 | i = 0; | ||
140 | next = '\r'; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | |||
145 | static void | ||
146 | recv_all (MHD_socket sock, | ||
147 | const char *text) | ||
148 | { | ||
149 | size_t len = strlen (text); | ||
150 | char buf[len]; | ||
151 | ssize_t ret; | ||
152 | |||
153 | make_blocking (sock); | ||
154 | for (size_t off = 0; off < len; off += ret) | ||
155 | { | ||
156 | ret = read (sock, | ||
157 | &buf[off], | ||
158 | len - off); | ||
159 | if (-1 == ret) | ||
160 | { | ||
161 | if (EAGAIN == errno) | ||
162 | { | ||
163 | ret = 0; | ||
164 | continue; | ||
165 | } | ||
166 | abort (); | ||
167 | } | ||
168 | } | ||
169 | if (0 != strncmp (text, buf, len)) | ||
170 | abort(); | ||
171 | } | ||
172 | |||
173 | |||
174 | /** | ||
175 | * Main function for the thread that runs the interaction with | ||
176 | * the upgraded socket. | ||
177 | * | ||
178 | * @param cls the handle for the upgrade | ||
179 | */ | ||
180 | static void * | ||
181 | run_usock (void *cls) | ||
182 | { | ||
183 | struct MHD_UpgradeResponseHandle *urh = cls; | ||
184 | |||
185 | send_all (usock, | ||
186 | "Hello"); | ||
187 | recv_all (usock, | ||
188 | "World"); | ||
189 | send_all (usock, | ||
190 | "Finished"); | ||
191 | MHD_upgrade_action (urh, | ||
192 | MHD_UPGRADE_ACTION_CLOSE); | ||
193 | return NULL; | ||
194 | } | ||
195 | |||
196 | |||
197 | /** | ||
198 | * Main function for the thread that runs the client-side of the | ||
199 | * interaction with the upgraded socket. | ||
200 | * | ||
201 | * @param cls the client socket | ||
202 | */ | ||
203 | static void * | ||
204 | run_usock_client (void *cls) | ||
205 | { | ||
206 | MHD_socket *sock = cls; | ||
207 | |||
208 | send_all (*sock, | ||
209 | "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n"); | ||
210 | recv_hdr (*sock); | ||
211 | recv_all (*sock, | ||
212 | "Hello"); | ||
213 | send_all (*sock, | ||
214 | "World"); | ||
215 | recv_all (*sock, | ||
216 | "Finished"); | ||
217 | MHD_socket_close_ (*sock); | ||
218 | done = 1; | ||
219 | return NULL; | ||
220 | } | ||
221 | |||
222 | |||
223 | /** | ||
224 | * Function called after a protocol "upgrade" response was sent | ||
225 | * successfully and the socket should now be controlled by some | ||
226 | * protocol other than HTTP. | ||
227 | * | ||
228 | * Any data received on the socket will be made available in | ||
229 | * 'data_in'. The function should update 'data_in_size' to | ||
230 | * reflect the number of bytes consumed from 'data_in' (the remaining | ||
231 | * bytes will be made available in the next call to the handler). | ||
232 | * | ||
233 | * Any data that should be transmitted on the socket should be | ||
234 | * stored in 'data_out'. '*data_out_size' is initially set to | ||
235 | * the available buffer space in 'data_out'. It should be set to | ||
236 | * the number of bytes stored in 'data_out' (which can be zero). | ||
237 | * | ||
238 | * The return value is a BITMASK that indicates how the function | ||
239 | * intends to interact with the event loop. It can request to be | ||
240 | * notified for reading, writing, request to UNCORK the send buffer | ||
241 | * (which MHD is allowed to ignore, if it is not possible to uncork on | ||
242 | * the local platform), to wait for the 'external' select loop to | ||
243 | * trigger another round. It is also possible to specify "no events" | ||
244 | * to terminate the connection; in this case, the | ||
245 | * #MHD_RequestCompletedCallback will be called and all resources of | ||
246 | * the connection will be released. | ||
247 | * | ||
248 | * Except when in 'thread-per-connection' mode, implementations | ||
249 | * of this function should never block (as it will still be called | ||
250 | * from within the main event loop). | ||
251 | * | ||
252 | * @param cls closure, whatever was given to #MHD_create_response_for_upgrade(). | ||
253 | * @param connection original HTTP connection handle, | ||
254 | * giving the function a last chance | ||
255 | * to inspect the original HTTP request | ||
256 | * @param con_cls last value left in `*con_cls` in the `MHD_AccessHandlerCallback` | ||
257 | * @param extra_in if we happened to have read bytes after the | ||
258 | * HTTP header already (because the client sent | ||
259 | * more than the HTTP header of the request before | ||
260 | * we sent the upgrade response), | ||
261 | * these are the extra bytes already read from @a sock | ||
262 | * by MHD. The application should treat these as if | ||
263 | * it had read them from @a sock. | ||
264 | * @param extra_in_size number of bytes in @a extra_in | ||
265 | * @param sock socket to use for bi-directional communication | ||
266 | * with the client. For HTTPS, this may not be a socket | ||
267 | * that is directly connected to the client and thus certain | ||
268 | * operations (TCP-specific setsockopt(), getsockopt(), etc.) | ||
269 | * may not work as expected (as the socket could be from a | ||
270 | * socketpair() or a TCP-loopback) | ||
271 | * @param urh argument for #MHD_upgrade_action()s on this @a connection. | ||
272 | * Applications must eventually use this function to perform the | ||
273 | * close() action on the @a sock. | ||
274 | */ | ||
275 | static void | ||
276 | upgrade_cb (void *cls, | ||
277 | struct MHD_Connection *connection, | ||
278 | void *con_cls, | ||
279 | const char *extra_in, | ||
280 | size_t extra_in_size, | ||
281 | MHD_socket sock, | ||
282 | struct MHD_UpgradeResponseHandle *urh) | ||
283 | { | ||
284 | usock = sock; | ||
285 | if (0 != extra_in_size) | ||
286 | abort (); | ||
287 | pthread_create (&pt, | ||
288 | NULL, | ||
289 | &run_usock, | ||
290 | urh); | ||
291 | } | ||
292 | |||
293 | |||
294 | /** | ||
295 | * A client has requested the given url using the given method | ||
296 | * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, | ||
297 | * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback | ||
298 | * must call MHD callbacks to provide content to give back to the | ||
299 | * client and return an HTTP status code (i.e. #MHD_HTTP_OK, | ||
300 | * #MHD_HTTP_NOT_FOUND, etc.). | ||
301 | * | ||
302 | * @param cls argument given together with the function | ||
303 | * pointer when the handler was registered with MHD | ||
304 | * @param url the requested url | ||
305 | * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, | ||
306 | * #MHD_HTTP_METHOD_PUT, etc.) | ||
307 | * @param version the HTTP version string (i.e. | ||
308 | * #MHD_HTTP_VERSION_1_1) | ||
309 | * @param upload_data the data being uploaded (excluding HEADERS, | ||
310 | * for a POST that fits into memory and that is encoded | ||
311 | * with a supported encoding, the POST data will NOT be | ||
312 | * given in upload_data and is instead available as | ||
313 | * part of #MHD_get_connection_values; very large POST | ||
314 | * data *will* be made available incrementally in | ||
315 | * @a upload_data) | ||
316 | * @param upload_data_size set initially to the size of the | ||
317 | * @a upload_data provided; the method must update this | ||
318 | * value to the number of bytes NOT processed; | ||
319 | * @param con_cls pointer that the callback can set to some | ||
320 | * address and that will be preserved by MHD for future | ||
321 | * calls for this request; since the access handler may | ||
322 | * be called many times (i.e., for a PUT/POST operation | ||
323 | * with plenty of upload data) this allows the application | ||
324 | * to easily associate some request-specific state. | ||
325 | * If necessary, this state can be cleaned up in the | ||
326 | * global #MHD_RequestCompletedCallback (which | ||
327 | * can be set with the #MHD_OPTION_NOTIFY_COMPLETED). | ||
328 | * Initially, `*con_cls` will be NULL. | ||
329 | * @return #MHD_YES if the connection was handled successfully, | ||
330 | * #MHD_NO if the socket must be closed due to a serios | ||
331 | * error while handling the request | ||
332 | */ | ||
333 | static int | ||
334 | ahc_upgrade (void *cls, | ||
335 | struct MHD_Connection *connection, | ||
336 | const char *url, | ||
337 | const char *method, | ||
338 | const char *version, | ||
339 | const char *upload_data, | ||
340 | size_t *upload_data_size, | ||
341 | void **con_cls) | ||
342 | { | ||
343 | struct MHD_Response *resp; | ||
344 | int ret; | ||
345 | |||
346 | resp = MHD_create_response_for_upgrade (&upgrade_cb, | ||
347 | NULL); | ||
348 | MHD_add_response_header (resp, | ||
349 | MHD_HTTP_HEADER_UPGRADE, | ||
350 | "Hello World Protocol"); | ||
351 | ret = MHD_queue_response (connection, | ||
352 | MHD_HTTP_SWITCHING_PROTOCOLS, | ||
353 | resp); | ||
354 | MHD_destroy_response (resp); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | |||
359 | /** | ||
360 | * Run the MHD external event loop using select. | ||
361 | * | ||
362 | * @param daemon daemon to run it for | ||
363 | * @param flags the flags the daemon was started with | ||
364 | */ | ||
365 | static void | ||
366 | run_mhd_select_loop (struct MHD_Daemon *daemon) | ||
367 | { | ||
368 | fd_set rs; | ||
369 | fd_set ws; | ||
370 | fd_set es; | ||
371 | MHD_socket max_fd; | ||
372 | MHD_UNSIGNED_LONG_LONG to; | ||
373 | struct timeval tv; | ||
374 | |||
375 | while (! done) | ||
376 | { | ||
377 | FD_ZERO (&rs); | ||
378 | FD_ZERO (&ws); | ||
379 | FD_ZERO (&es); | ||
380 | max_fd = -1; | ||
381 | to = 1000; | ||
382 | |||
383 | if (MHD_YES != | ||
384 | MHD_get_fdset (daemon, | ||
385 | &rs, | ||
386 | &ws, | ||
387 | &es, | ||
388 | &max_fd)) | ||
389 | abort (); | ||
390 | MHD_get_timeout (daemon, | ||
391 | &to); | ||
392 | tv.tv_sec = to / 1000; | ||
393 | tv.tv_usec = 1000 * (to % 1000); | ||
394 | select (max_fd + 1, | ||
395 | &rs, | ||
396 | &ws, | ||
397 | &es, | ||
398 | &tv); | ||
399 | MHD_run_from_select (daemon, | ||
400 | &rs, | ||
401 | &ws, | ||
402 | &es); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | |||
407 | /** | ||
408 | * Run the MHD external event loop using select. | ||
409 | * | ||
410 | * @param daemon daemon to run it for | ||
411 | * @param flags the flags the daemon was started with | ||
412 | */ | ||
413 | static void | ||
414 | run_mhd_poll_loop (struct MHD_Daemon *daemon) | ||
415 | { | ||
416 | abort (); // not implemented | ||
417 | } | ||
418 | |||
419 | |||
420 | /** | ||
421 | * Run the MHD external event loop using select. | ||
422 | * | ||
423 | * @param daemon daemon to run it for | ||
424 | * @param flags the flags the daemon was started with | ||
425 | */ | ||
426 | static void | ||
427 | run_mhd_epoll_loop (struct MHD_Daemon *daemon) | ||
428 | { | ||
429 | abort (); // not implemented | ||
430 | } | ||
431 | |||
432 | |||
433 | /** | ||
434 | * Run the MHD external event loop using select. | ||
435 | * | ||
436 | * @param daemon daemon to run it for | ||
437 | * @param flags the flags the daemon was started with | ||
438 | */ | ||
439 | static void | ||
440 | run_mhd_loop (struct MHD_Daemon *daemon, | ||
441 | int flags) | ||
442 | { | ||
443 | if (0 != (flags & MHD_USE_POLL)) | ||
444 | run_mhd_poll_loop (daemon); | ||
445 | #if EPOLL_SUPPORT | ||
446 | else if (0 != (flags & MHD_USE_EPOLL)) | ||
447 | run_mhd_epoll_loop (daemon); | ||
448 | #endif | ||
449 | else | ||
450 | run_mhd_select_loop (daemon); | ||
451 | } | ||
diff --git a/src/microhttpd/test_upgrade_ssl.c b/src/microhttpd/test_upgrade_ssl.c index 26fd53fa..91d22daf 100644 --- a/src/microhttpd/test_upgrade_ssl.c +++ b/src/microhttpd/test_upgrade_ssl.c | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | libmicrohttpd is free software; you can redistribute it and/or modify | 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 | 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 | 7 | by the Free Software Foundation; either version 3, or (at your |
8 | option) any later version. | 8 | option) any later version. |
9 | 9 | ||
10 | libmicrohttpd is distributed in the hope that it will be useful, but | 10 | libmicrohttpd is distributed in the hope that it will be useful, but |
@@ -40,26 +40,12 @@ | |||
40 | #include <netinet/ip.h> | 40 | #include <netinet/ip.h> |
41 | #include <pthread.h> | 41 | #include <pthread.h> |
42 | #include "mhd_sockets.h" | 42 | #include "mhd_sockets.h" |
43 | #include "test_upgrade_common.c" | ||
43 | 44 | ||
44 | #include "../testcurl/https/tls_test_keys.h" | 45 | #include "../testcurl/https/tls_test_keys.h" |
45 | 46 | ||
46 | 47 | ||
47 | /** | 48 | /** |
48 | * Thread we use to run the interaction with the upgraded socket. | ||
49 | */ | ||
50 | static pthread_t pt; | ||
51 | |||
52 | /** | ||
53 | * Will be set to the upgraded socket. | ||
54 | */ | ||
55 | static MHD_socket usock; | ||
56 | |||
57 | /** | ||
58 | * Thread we use to run the interaction with the upgraded socket. | ||
59 | */ | ||
60 | static pthread_t pt_client; | ||
61 | |||
62 | /** | ||
63 | * Fork child that connects via OpenSSL to our @a port. Allows us to | 49 | * Fork child that connects via OpenSSL to our @a port. Allows us to |
64 | * talk to our port over a socket in @a sp without having to worry | 50 | * talk to our port over a socket in @a sp without having to worry |
65 | * about TLS. | 51 | * about TLS. |
@@ -109,322 +95,14 @@ openssl_connect (int *sock, | |||
109 | 95 | ||
110 | 96 | ||
111 | /** | 97 | /** |
112 | * Change itc FD options to be non-blocking. | 98 | * Test upgrading a connection. |
113 | * | ||
114 | * @param fd the FD to manipulate | ||
115 | * @return non-zero if succeeded, zero otherwise | ||
116 | */ | ||
117 | static void | ||
118 | make_blocking (MHD_socket fd) | ||
119 | { | ||
120 | int flags; | ||
121 | |||
122 | flags = fcntl (fd, F_GETFL); | ||
123 | if (-1 == flags) | ||
124 | return; | ||
125 | if ((flags & ~O_NONBLOCK) != flags) | ||
126 | fcntl (fd, F_SETFL, flags & ~O_NONBLOCK); | ||
127 | } | ||
128 | |||
129 | |||
130 | static void | ||
131 | send_all (MHD_socket sock, | ||
132 | const char *text) | ||
133 | { | ||
134 | size_t len = strlen (text); | ||
135 | ssize_t ret; | ||
136 | |||
137 | make_blocking (sock); | ||
138 | for (size_t off = 0; off < len; off += ret) | ||
139 | { | ||
140 | ret = write (sock, | ||
141 | &text[off], | ||
142 | len - off); | ||
143 | if (-1 == ret) | ||
144 | { | ||
145 | if (EAGAIN == errno) | ||
146 | { | ||
147 | ret = 0; | ||
148 | continue; | ||
149 | } | ||
150 | abort (); | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Read character-by-character until we | ||
158 | * get '\r\n\r\n'. | ||
159 | */ | ||
160 | static void | ||
161 | recv_hdr (MHD_socket sock) | ||
162 | { | ||
163 | unsigned int i; | ||
164 | char next; | ||
165 | char c; | ||
166 | ssize_t ret; | ||
167 | |||
168 | make_blocking (sock); | ||
169 | next = '\r'; | ||
170 | i = 0; | ||
171 | while (i < 4) | ||
172 | { | ||
173 | ret = read (sock, | ||
174 | &c, | ||
175 | 1); | ||
176 | if (0 == ret) | ||
177 | abort (); /* this is fatal */ | ||
178 | if (-1 == ret) | ||
179 | { | ||
180 | if (EAGAIN == errno) | ||
181 | { | ||
182 | ret = 0; | ||
183 | continue; | ||
184 | } | ||
185 | abort (); | ||
186 | } | ||
187 | if (0 == ret) | ||
188 | continue; | ||
189 | if (c == next) | ||
190 | { | ||
191 | i++; | ||
192 | if (next == '\r') | ||
193 | next = '\n'; | ||
194 | else | ||
195 | next = '\r'; | ||
196 | continue; | ||
197 | } | ||
198 | if (c == '\r') | ||
199 | { | ||
200 | i = 1; | ||
201 | next = '\n'; | ||
202 | continue; | ||
203 | } | ||
204 | i = 0; | ||
205 | next = '\r'; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | |||
210 | static void | ||
211 | recv_all (MHD_socket sock, | ||
212 | const char *text) | ||
213 | { | ||
214 | size_t len = strlen (text); | ||
215 | char buf[len]; | ||
216 | ssize_t ret; | ||
217 | |||
218 | make_blocking (sock); | ||
219 | for (size_t off = 0; off < len; off += ret) | ||
220 | { | ||
221 | ret = read (sock, | ||
222 | &buf[off], | ||
223 | len - off); | ||
224 | if (0 == ret) | ||
225 | abort (); /* this is fatal */ | ||
226 | if (-1 == ret) | ||
227 | { | ||
228 | if (EAGAIN == errno) | ||
229 | { | ||
230 | ret = 0; | ||
231 | continue; | ||
232 | } | ||
233 | abort (); | ||
234 | } | ||
235 | } | ||
236 | if (0 != strncmp (text, buf, len)) | ||
237 | abort(); | ||
238 | } | ||
239 | |||
240 | |||
241 | /** | ||
242 | * Main function for the thread that runs the interaction with | ||
243 | * the upgraded socket. | ||
244 | * | ||
245 | * @param cls the handle for the upgrade | ||
246 | */ | ||
247 | static void * | ||
248 | run_usock (void *cls) | ||
249 | { | ||
250 | struct MHD_UpgradeResponseHandle *urh = cls; | ||
251 | |||
252 | send_all (usock, | ||
253 | "Hello"); | ||
254 | recv_all (usock, | ||
255 | "World"); | ||
256 | send_all (usock, | ||
257 | "Finished"); | ||
258 | MHD_upgrade_action (urh, | ||
259 | MHD_UPGRADE_ACTION_CLOSE); | ||
260 | return NULL; | ||
261 | } | ||
262 | |||
263 | |||
264 | /** | ||
265 | * Main function for the thread that runs the client-side of the | ||
266 | * interaction with the upgraded socket. | ||
267 | * | ||
268 | * @param cls the client socket | ||
269 | */ | ||
270 | static void * | ||
271 | run_usock_client (void *cls) | ||
272 | { | ||
273 | MHD_socket *sock = cls; | ||
274 | |||
275 | send_all (*sock, | ||
276 | "GET / HTTP/1.1\r\nConnection: Upgrade\r\n\r\n"); | ||
277 | recv_hdr (*sock); | ||
278 | recv_all (*sock, | ||
279 | "Hello"); | ||
280 | send_all (*sock, | ||
281 | "World"); | ||
282 | recv_all (*sock, | ||
283 | "Finished"); | ||
284 | MHD_socket_close_ (*sock); | ||
285 | return NULL; | ||
286 | } | ||
287 | |||
288 | |||
289 | /** | ||
290 | * Function called after a protocol "upgrade" response was sent | ||
291 | * successfully and the socket should now be controlled by some | ||
292 | * protocol other than HTTP. | ||
293 | * | ||
294 | * Any data received on the socket will be made available in | ||
295 | * 'data_in'. The function should update 'data_in_size' to | ||
296 | * reflect the number of bytes consumed from 'data_in' (the remaining | ||
297 | * bytes will be made available in the next call to the handler). | ||
298 | * | ||
299 | * Any data that should be transmitted on the socket should be | ||
300 | * stored in 'data_out'. '*data_out_size' is initially set to | ||
301 | * the available buffer space in 'data_out'. It should be set to | ||
302 | * the number of bytes stored in 'data_out' (which can be zero). | ||
303 | * | ||
304 | * The return value is a BITMASK that indicates how the function | ||
305 | * intends to interact with the event loop. It can request to be | ||
306 | * notified for reading, writing, request to UNCORK the send buffer | ||
307 | * (which MHD is allowed to ignore, if it is not possible to uncork on | ||
308 | * the local platform), to wait for the 'external' select loop to | ||
309 | * trigger another round. It is also possible to specify "no events" | ||
310 | * to terminate the connection; in this case, the | ||
311 | * #MHD_RequestCompletedCallback will be called and all resources of | ||
312 | * the connection will be released. | ||
313 | * | ||
314 | * Except when in 'thread-per-connection' mode, implementations | ||
315 | * of this function should never block (as it will still be called | ||
316 | * from within the main event loop). | ||
317 | * | ||
318 | * @param cls closure, whatever was given to #MHD_create_response_for_upgrade(). | ||
319 | * @param connection original HTTP connection handle, | ||
320 | * giving the function a last chance | ||
321 | * to inspect the original HTTP request | ||
322 | * @param con_cls last value left in `*con_cls` in the `MHD_AccessHandlerCallback` | ||
323 | * @param extra_in if we happened to have read bytes after the | ||
324 | * HTTP header already (because the client sent | ||
325 | * more than the HTTP header of the request before | ||
326 | * we sent the upgrade response), | ||
327 | * these are the extra bytes already read from @a sock | ||
328 | * by MHD. The application should treat these as if | ||
329 | * it had read them from @a sock. | ||
330 | * @param extra_in_size number of bytes in @a extra_in | ||
331 | * @param sock socket to use for bi-directional communication | ||
332 | * with the client. For HTTPS, this may not be a socket | ||
333 | * that is directly connected to the client and thus certain | ||
334 | * operations (TCP-specific setsockopt(), getsockopt(), etc.) | ||
335 | * may not work as expected (as the socket could be from a | ||
336 | * socketpair() or a TCP-loopback) | ||
337 | * @param urh argument for #MHD_upgrade_action()s on this @a connection. | ||
338 | * Applications must eventually use this function to perform the | ||
339 | * close() action on the @a sock. | ||
340 | */ | ||
341 | static void | ||
342 | upgrade_cb (void *cls, | ||
343 | struct MHD_Connection *connection, | ||
344 | void *con_cls, | ||
345 | const char *extra_in, | ||
346 | size_t extra_in_size, | ||
347 | MHD_socket sock, | ||
348 | struct MHD_UpgradeResponseHandle *urh) | ||
349 | { | ||
350 | usock = sock; | ||
351 | if (0 != extra_in_size) | ||
352 | abort (); | ||
353 | pthread_create (&pt, | ||
354 | NULL, | ||
355 | &run_usock, | ||
356 | urh); | ||
357 | } | ||
358 | |||
359 | |||
360 | /** | ||
361 | * A client has requested the given url using the given method | ||
362 | * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, | ||
363 | * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback | ||
364 | * must call MHD callbacks to provide content to give back to the | ||
365 | * client and return an HTTP status code (i.e. #MHD_HTTP_OK, | ||
366 | * #MHD_HTTP_NOT_FOUND, etc.). | ||
367 | * | 99 | * |
368 | * @param cls argument given together with the function | 100 | * @param flags which event loop style should be tested |
369 | * pointer when the handler was registered with MHD | 101 | * @param pool size of the thread pool, 0 to disable |
370 | * @param url the requested url | ||
371 | * @param method the HTTP method used (#MHD_HTTP_METHOD_GET, | ||
372 | * #MHD_HTTP_METHOD_PUT, etc.) | ||
373 | * @param version the HTTP version string (i.e. | ||
374 | * #MHD_HTTP_VERSION_1_1) | ||
375 | * @param upload_data the data being uploaded (excluding HEADERS, | ||
376 | * for a POST that fits into memory and that is encoded | ||
377 | * with a supported encoding, the POST data will NOT be | ||
378 | * given in upload_data and is instead available as | ||
379 | * part of #MHD_get_connection_values; very large POST | ||
380 | * data *will* be made available incrementally in | ||
381 | * @a upload_data) | ||
382 | * @param upload_data_size set initially to the size of the | ||
383 | * @a upload_data provided; the method must update this | ||
384 | * value to the number of bytes NOT processed; | ||
385 | * @param con_cls pointer that the callback can set to some | ||
386 | * address and that will be preserved by MHD for future | ||
387 | * calls for this request; since the access handler may | ||
388 | * be called many times (i.e., for a PUT/POST operation | ||
389 | * with plenty of upload data) this allows the application | ||
390 | * to easily associate some request-specific state. | ||
391 | * If necessary, this state can be cleaned up in the | ||
392 | * global #MHD_RequestCompletedCallback (which | ||
393 | * can be set with the #MHD_OPTION_NOTIFY_COMPLETED). | ||
394 | * Initially, `*con_cls` will be NULL. | ||
395 | * @return #MHD_YES if the connection was handled successfully, | ||
396 | * #MHD_NO if the socket must be closed due to a serios | ||
397 | * error while handling the request | ||
398 | */ | 102 | */ |
399 | static int | 103 | static int |
400 | ahc_upgrade (void *cls, | 104 | test_upgrade (int flags, |
401 | struct MHD_Connection *connection, | 105 | unsigned int pool) |
402 | const char *url, | ||
403 | const char *method, | ||
404 | const char *version, | ||
405 | const char *upload_data, | ||
406 | size_t *upload_data_size, | ||
407 | void **con_cls) | ||
408 | { | ||
409 | struct MHD_Response *resp; | ||
410 | int ret; | ||
411 | |||
412 | resp = MHD_create_response_for_upgrade (&upgrade_cb, | ||
413 | NULL); | ||
414 | MHD_add_response_header (resp, | ||
415 | MHD_HTTP_HEADER_UPGRADE, | ||
416 | "Hello World Protocol"); | ||
417 | ret = MHD_queue_response (connection, | ||
418 | MHD_HTTP_SWITCHING_PROTOCOLS, | ||
419 | resp); | ||
420 | MHD_destroy_response (resp); | ||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | |||
425 | static int | ||
426 | test_upgrade_internal (int flags, | ||
427 | unsigned int pool) | ||
428 | { | 106 | { |
429 | struct MHD_Daemon *d; | 107 | struct MHD_Daemon *d; |
430 | MHD_socket sock; | 108 | MHD_socket sock; |
@@ -452,9 +130,14 @@ test_upgrade_internal (int flags, | |||
452 | NULL, | 130 | NULL, |
453 | &run_usock_client, | 131 | &run_usock_client, |
454 | &sock); | 132 | &sock); |
455 | 133 | if (0 == (flags & (MHD_USE_SELECT_INTERNALLY | | |
134 | MHD_USE_THREAD_PER_CONNECTION)) ) | ||
135 | run_mhd_loop (d, flags); | ||
456 | pthread_join (pt_client, | 136 | pthread_join (pt_client, |
457 | NULL); | 137 | NULL); |
138 | if (0 == (flags & (MHD_USE_SELECT_INTERNALLY | | ||
139 | MHD_USE_THREAD_PER_CONNECTION)) ) | ||
140 | run_mhd_loop (d, flags); | ||
458 | pthread_join (pt, | 141 | pthread_join (pt, |
459 | NULL); | 142 | NULL); |
460 | waitpid (pid, | 143 | waitpid (pid, |
@@ -474,30 +157,34 @@ main (int argc, | |||
474 | if (0 != system ("openssl version 1> /dev/null")) | 157 | if (0 != system ("openssl version 1> /dev/null")) |
475 | return 77; /* openssl not available, can't run the test */ | 158 | return 77; /* openssl not available, can't run the test */ |
476 | 159 | ||
160 | /* try external select */ | ||
161 | error_count += test_upgrade (0, | ||
162 | 0); | ||
163 | |||
477 | /* Test thread-per-connection */ | 164 | /* Test thread-per-connection */ |
478 | error_count += test_upgrade_internal (MHD_USE_THREAD_PER_CONNECTION, | 165 | error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION, |
479 | 0); | 166 | 0); |
480 | error_count += test_upgrade_internal (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL, | 167 | error_count += test_upgrade (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_POLL, |
481 | 0); | 168 | 0); |
482 | 169 | ||
483 | /* Test different event loops, with and without thread pool */ | 170 | /* Test different event loops, with and without thread pool */ |
484 | error_count += test_upgrade_internal (MHD_USE_SELECT_INTERNALLY, | 171 | error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY, |
485 | 0); | 172 | 0); |
486 | error_count += test_upgrade_internal (MHD_USE_SELECT_INTERNALLY, | 173 | error_count += test_upgrade (MHD_USE_SELECT_INTERNALLY, |
487 | 2); | 174 | 2); |
488 | #ifdef HAVE_POLL | 175 | #ifdef HAVE_POLL |
489 | error_count += test_upgrade_internal (MHD_USE_POLL_INTERNALLY, | 176 | error_count += test_upgrade (MHD_USE_POLL_INTERNALLY, |
490 | 0); | 177 | 0); |
491 | error_count += test_upgrade_internal (MHD_USE_POLL_INTERNALLY, | 178 | error_count += test_upgrade (MHD_USE_POLL_INTERNALLY, |
492 | 2); | 179 | 2); |
493 | #endif | 180 | #endif |
494 | #ifdef EPOLL_SUPPORT | 181 | #ifdef EPOLL_SUPPORT |
495 | error_count += test_upgrade_internal (MHD_USE_EPOLL_INTERNALLY | | 182 | error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY | |
496 | MHD_USE_TLS_EPOLL_UPGRADE, | 183 | MHD_USE_TLS_EPOLL_UPGRADE, |
497 | 0); | 184 | 0); |
498 | error_count += test_upgrade_internal (MHD_USE_EPOLL_INTERNALLY | | 185 | error_count += test_upgrade (MHD_USE_EPOLL_INTERNALLY | |
499 | MHD_USE_TLS_EPOLL_UPGRADE, | 186 | MHD_USE_TLS_EPOLL_UPGRADE, |
500 | 2); | 187 | 2); |
501 | #endif | 188 | #endif |
502 | 189 | ||
503 | /* report result */ | 190 | /* report result */ |