aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2019-10-26 18:52:53 +0200
committerChristian Grothoff <christian@grothoff.org>2019-10-26 18:52:53 +0200
commit5e5dbf980de763480f7957f64af78bbb2159d9a0 (patch)
treec769f03c3d7b78df899023ff4366042670ca23f8
parentb8516d23ba11cf3a94fcbf2ea228ea0456354017 (diff)
downloadlibmicrohttpd-5e5dbf980de763480f7957f64af78bbb2159d9a0.tar.gz
libmicrohttpd-5e5dbf980de763480f7957f64af78bbb2159d9a0.zip
add tests for empty reply in HTTPS
-rw-r--r--src/examples/.gitignore2
-rw-r--r--src/examples/Makefile.am9
-rw-r--r--src/examples/minimal_example_empty_tls.c150
-rw-r--r--src/microhttpd/mhd_send.c23
-rw-r--r--src/testcurl/.gitignore1
-rw-r--r--src/testcurl/https/test_https_get.c156
-rw-r--r--src/testcurl/https/tls_test_common.c61
-rw-r--r--src/testcurl/test_get.c20
-rw-r--r--src/testcurl/test_get_empty.c941
9 files changed, 1331 insertions, 32 deletions
diff --git a/src/examples/.gitignore b/src/examples/.gitignore
index 9da24b59..7fa3e9b8 100644
--- a/src/examples/.gitignore
+++ b/src/examples/.gitignore
@@ -35,3 +35,5 @@ upgrade_example
35/timeout 35/timeout
36http_chunked_compression 36http_chunked_compression
37http_compression 37http_compression
38minimal_example_empty
39minimal_example_empty_tls
diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am
index 7ffddff5..5dcee4d2 100644
--- a/src/examples/Makefile.am
+++ b/src/examples/Makefile.am
@@ -39,7 +39,9 @@ EXTRA_DIST = msgs_i18n.c
39noinst_EXTRA_DIST = msgs_i18n.c 39noinst_EXTRA_DIST = msgs_i18n.c
40 40
41if ENABLE_HTTPS 41if ENABLE_HTTPS
42noinst_PROGRAMS += https_fileserver_example 42noinst_PROGRAMS += \
43 https_fileserver_example \
44 minimal_example_empty_tls
43endif 45endif
44if HAVE_POSTPROCESSOR 46if HAVE_POSTPROCESSOR
45noinst_PROGRAMS += \ 47noinst_PROGRAMS += \
@@ -89,6 +91,11 @@ minimal_example_empty_SOURCES = \
89minimal_example_empty_LDADD = \ 91minimal_example_empty_LDADD = \
90 $(top_builddir)/src/microhttpd/libmicrohttpd.la 92 $(top_builddir)/src/microhttpd/libmicrohttpd.la
91 93
94minimal_example_empty_tls_SOURCES = \
95 minimal_example_empty_tls.c
96minimal_example_empty_tls_LDADD = \
97 $(top_builddir)/src/microhttpd/libmicrohttpd.la
98
92upgrade_example_SOURCES = \ 99upgrade_example_SOURCES = \
93 upgrade_example.c 100 upgrade_example.c
94upgrade_example_CFLAGS = \ 101upgrade_example_CFLAGS = \
diff --git a/src/examples/minimal_example_empty_tls.c b/src/examples/minimal_example_empty_tls.c
new file mode 100644
index 00000000..e3daca5f
--- /dev/null
+++ b/src/examples/minimal_example_empty_tls.c
@@ -0,0 +1,150 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007 Christian Grothoff (and other contributing authors)
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19/**
20 * @file minimal_example_empty_ssl.c
21 * @brief minimal example for how to use libmicrohttpd
22 * @author Christian Grothoff
23 */
24
25#include "platform.h"
26#include <microhttpd.h>
27
28
29static int
30ahc_echo (void *cls,
31 struct MHD_Connection *connection,
32 const char *url,
33 const char *method,
34 const char *version,
35 const char *upload_data,
36 size_t *upload_data_size,
37 void **ptr)
38{
39 static int aptr;
40 struct MHD_Response *response;
41 int ret;
42
43 (void) url; /* Unused. Silent compiler warning. */
44 (void) version; /* Unused. Silent compiler warning. */
45 (void) upload_data; /* Unused. Silent compiler warning. */
46 (void) upload_data_size; /* Unused. Silent compiler warning. */
47
48 if (0 != strcmp (method, "GET"))
49 return MHD_NO; /* unexpected method */
50 if (&aptr != *ptr)
51 {
52 /* do never respond on first call */
53 *ptr = &aptr;
54 return MHD_YES;
55 }
56 *ptr = NULL; /* reset when done */
57 response = MHD_create_response_from_buffer (0,
58 NULL,
59 MHD_RESPMEM_PERSISTENT);
60 ret = MHD_queue_response (connection,
61 MHD_HTTP_NO_CONTENT,
62 response);
63 MHD_destroy_response (response);
64 return ret;
65}
66
67
68/* test server key */
69const char srv_signed_key_pem[] = "-----BEGIN RSA PRIVATE KEY-----\n"
70 "MIIEowIBAAKCAQEAvfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW\n"
71 "+K03KwEku55QvnUndwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8IL\n"
72 "q4sw32vo0fbMu5BZF49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ0\n"
73 "20Q5EAAEseD1YtWCIpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6\n"
74 "QYGGh1QmHRPAy3CBII6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6x\n"
75 "yoOl204xuekZOaG9RUPId74Rtmwfi1TLbBzo2wIDAQABAoIBADu09WSICNq5cMe4\n"
76 "+NKCLlgAT1NiQpLls1gKRbDhKiHU9j8QWNvWWkJWrCya4QdUfLCfeddCMeiQmv3K\n"
77 "lJMvDs+5OjJSHFoOsGiuW2Ias7IjnIojaJalfBml6frhJ84G27IXmdz6gzOiTIer\n"
78 "DjeAgcwBaKH5WwIay2TxIaScl7AwHBauQkrLcyb4hTmZuQh6ArVIN6+pzoVuORXM\n"
79 "bpeNWl2l/HSN3VtUN6aCAKbN/X3o0GavCCMn5Fa85uJFsab4ss/uP+2PusU71+zP\n"
80 "sBm6p/2IbGvF5k3VPDA7X5YX61sukRjRBihY8xSnNYx1UcoOsX6AiPnbhifD8+xQ\n"
81 "Tlf8oJUCgYEA0BTfzqNpr9Wxw5/QXaSdw7S/0eP5a0C/nwURvmfSzuTD4equzbEN\n"
82 "d+dI/s2JMxrdj/I4uoAfUXRGaabevQIjFzC9uyE3LaOyR2zhuvAzX+vVcs6bSXeU\n"
83 "pKpCAcN+3Z3evMaX2f+z/nfSUAl2i4J2R+/LQAWJW4KwRky/m+cxpfUCgYEA6bN1\n"
84 "b73bMgM8wpNt6+fcmS+5n0iZihygQ2U2DEud8nZJL4Nrm1dwTnfZfJBnkGj6+0Q0\n"
85 "cOwj2KS0/wcEdJBP0jucU4v60VMhp75AQeHqidIde0bTViSRo3HWKXHBIFGYoU3T\n"
86 "LyPyKndbqsOObnsFXHn56Nwhr2HLf6nw4taGQY8CgYBoSW36FLCNbd6QGvLFXBGt\n"
87 "2lMhEM8az/K58kJ4WXSwOLtr6MD/WjNT2tkcy0puEJLm6BFCd6A6pLn9jaKou/92\n"
88 "SfltZjJPb3GUlp9zn5tAAeSSi7YMViBrfuFiHObij5LorefBXISLjuYbMwL03MgH\n"
89 "Ocl2JtA2ywMp2KFXs8GQWQKBgFyIVv5ogQrbZ0pvj31xr9HjqK6d01VxIi+tOmpB\n"
90 "4ocnOLEcaxX12BzprW55ytfOCVpF1jHD/imAhb3YrHXu0fwe6DXYXfZV4SSG2vB7\n"
91 "IB9z14KBN5qLHjNGFpMQXHSMek+b/ftTU0ZnPh9uEM5D3YqRLVd7GcdUhHvG8P8Q\n"
92 "C9aXAoGBAJtID6h8wOGMP0XYX5YYnhlC7dOLfk8UYrzlp3xhqVkzKthTQTj6wx9R\n"
93 "GtC4k7U1ki8oJsfcIlBNXd768fqDVWjYju5rzShMpo8OCTS6ipAblKjCxPPVhIpv\n"
94 "tWPlbSn1qj6wylstJ5/3Z+ZW5H4wIKp5jmLiioDhcP0L/Ex3Zx8O\n"
95 "-----END RSA PRIVATE KEY-----\n";
96
97/* test server CA signed certificates */
98const char srv_signed_cert_pem[] = "-----BEGIN CERTIFICATE-----\n"
99 "MIIDGzCCAgWgAwIBAgIES0KCvTALBgkqhkiG9w0BAQUwFzEVMBMGA1UEAxMMdGVz\n"
100 "dF9jYV9jZXJ0MB4XDTEwMDEwNTAwMDcyNVoXDTQ1MDMxMjAwMDcyNVowFzEVMBMG\n"
101 "A1UEAxMMdGVzdF9jYV9jZXJ0MIIBHzALBgkqhkiG9w0BAQEDggEOADCCAQkCggEA\n"
102 "vfTdv+3fgvVTKRnP/HVNG81cr8TrUP/iiyuve/THMzvFXhCW+K03KwEku55QvnUn\n"
103 "dwBfU/ROzLlv+5hotgiDRNFT3HxurmhouySBrJNJv7qWp8ILq4sw32vo0fbMu5BZ\n"
104 "F49bUXK9L3kW2PdhTtSQPWHEzNrCxO+YgCilKHkY3vQNfdJ020Q5EAAEseD1YtWC\n"
105 "IpRvJzYlZMpjYB1ubTl24kwrgOKUJYKqM4jmF4DVQp4oOK/6QYGGh1QmHRPAy3CB\n"
106 "II6sbb+sZT9cAqU6GYQVB35lm4XAgibXV6KgmpVxVQQ69U6xyoOl204xuekZOaG9\n"
107 "RUPId74Rtmwfi1TLbBzo2wIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM\n"
108 "MAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHIAAwHQYDVR0OBBYEFOFi4ilKOP1d\n"
109 "XHlWCMwmVKr7mgy8MB8GA1UdIwQYMBaAFP2olB4s2T/xuoQ5pT2RKojFwZo2MAsG\n"
110 "CSqGSIb3DQEBBQOCAQEAHVWPxazupbOkG7Did+dY9z2z6RjTzYvurTtEKQgzM2Vz\n"
111 "GQBA+3pZ3c5mS97fPIs9hZXfnQeelMeZ2XP1a+9vp35bJjZBBhVH+pqxjCgiUflg\n"
112 "A3Zqy0XwwVCgQLE2HyaU3DLUD/aeIFK5gJaOSdNTXZLv43K8kl4cqDbMeRpVTbkt\n"
113 "YmG4AyEOYRNKGTqMEJXJoxD5E3rBUNrVI/XyTjYrulxbNPcMWEHKNeeqWpKDYTFo\n"
114 "Bb01PCthGXiq/4A2RLAFosadzRa8SBpoSjPPfZ0b2w4MJpReHqKbR5+T2t6hzml6\n"
115 "4ToyOKPDmamiTuN5KzLN3cw7DQlvWMvqSOChPLnA3Q==\n"
116 "-----END CERTIFICATE-----\n";
117
118
119int
120main (int argc,
121 char *const *argv)
122{
123 struct MHD_Daemon *d;
124
125 if (argc != 2)
126 {
127 printf ("%s PORT\n", argv[0]);
128 return 1;
129 }
130 d = MHD_start_daemon (/* MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, */
131 MHD_USE_AUTO | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
132 | MHD_USE_TLS,
133 /* MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_POLL, */
134 /* MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG | MHD_USE_POLL, */
135 /* MHD_USE_THREAD_PER_CONNECTION | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG, */
136 atoi (argv[1]),
137 NULL, NULL, &ahc_echo, NULL,
138 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120,
139 MHD_OPTION_STRICT_FOR_CLIENT, (int) 1,
140 /* Optionally, the gnutls_load_file() can be used to
141 load the key and the certificate from file. */
142 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
143 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
144 MHD_OPTION_END);
145 if (d == NULL)
146 return 1;
147 (void) getc (stdin);
148 MHD_stop_daemon (d);
149 return 0;
150}
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c
index e50be96e..db621cb2 100644
--- a/src/microhttpd/mhd_send.c
+++ b/src/microhttpd/mhd_send.c
@@ -240,7 +240,8 @@ MHD_send_on_connection_ (struct MHD_Connection *connection,
240 ssize_t ret; 240 ssize_t ret;
241 241
242 /* error handling from send_param_adapter() */ 242 /* error handling from send_param_adapter() */
243 if ((MHD_INVALID_SOCKET == s) || (MHD_CONNECTION_CLOSED == connection->state)) 243 if ( (MHD_INVALID_SOCKET == s) ||
244 (MHD_CONNECTION_CLOSED == connection->state) )
244 { 245 {
245 return MHD_ERR_NOTCONN_; 246 return MHD_ERR_NOTCONN_;
246 } 247 }
@@ -382,10 +383,22 @@ MHD_send_on_connection2_ (struct MHD_Connection *connection,
382{ 383{
383#ifdef HTTPS_SUPPORT 384#ifdef HTTPS_SUPPORT
384 if (0 != (connection->daemon->options & MHD_USE_TLS)) 385 if (0 != (connection->daemon->options & MHD_USE_TLS))
385 return MHD_send_on_connection_ (connection, 386 {
386 header, 387 ssize_t ret;
387 header_size, 388
388 MHD_SSO_HDR_CORK); 389 ret = MHD_send_on_connection_ (connection,
390 header,
391 header_size,
392 MHD_SSO_HDR_CORK);
393 if ( (ret == header_size) &&
394 (0 == buffer_size) &&
395 connection->sk_cork_on)
396 {
397 (void) gnutls_record_uncork (connection->tls_session, 0);
398 connection->sk_cork_on = false;
399 }
400 return ret;
401 }
389#endif 402#endif
390#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV) 403#if defined(HAVE_SENDMSG) || defined(HAVE_WRITEV)
391 MHD_socket s = connection->socket_fd; 404 MHD_socket s = connection->socket_fd;
diff --git a/src/testcurl/.gitignore b/src/testcurl/.gitignore
index 800bdffe..52457fa4 100644
--- a/src/testcurl/.gitignore
+++ b/src/testcurl/.gitignore
@@ -108,3 +108,4 @@ test_large_put_inc11
108test_delete 108test_delete
109test_digestauth_sha256 109test_digestauth_sha256
110perf_get_concurrent11 110perf_get_concurrent11
111test_get_empty
diff --git a/src/testcurl/https/test_https_get.c b/src/testcurl/https/test_https_get.c
index 17248bf7..8f62e46c 100644
--- a/src/testcurl/https/test_https_get.c
+++ b/src/testcurl/https/test_https_get.c
@@ -37,6 +37,10 @@
37extern const char srv_signed_cert_pem[]; 37extern const char srv_signed_cert_pem[];
38extern const char srv_signed_key_pem[]; 38extern const char srv_signed_key_pem[];
39 39
40
41static int global_port;
42
43
40/* perform a HTTP GET request via SSL/TLS */ 44/* perform a HTTP GET request via SSL/TLS */
41static int 45static int
42test_secure_get (FILE *test_fd, 46test_secure_get (FILE *test_fd,
@@ -55,7 +59,8 @@ test_secure_get (FILE *test_fd,
55 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION 59 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
56 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS 60 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_TLS
57 | MHD_USE_ERROR_LOG, port, 61 | MHD_USE_ERROR_LOG, port,
58 NULL, NULL, &http_ahc, NULL, 62 NULL, NULL,
63 &http_ahc, NULL,
59 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem, 64 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
60 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem, 65 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
61 MHD_OPTION_END); 66 MHD_OPTION_END);
@@ -76,13 +81,156 @@ test_secure_get (FILE *test_fd,
76 port = (int) dinfo->port; 81 port = (int) dinfo->port;
77 } 82 }
78 83
79 ret = test_https_transfer (test_fd, port, cipher_suite, proto_version); 84 ret = test_https_transfer (test_fd,
85 port,
86 cipher_suite,
87 proto_version);
80 88
81 MHD_stop_daemon (d); 89 MHD_stop_daemon (d);
82 return ret; 90 return ret;
83} 91}
84 92
85 93
94static int
95ahc_empty (void *cls,
96 struct MHD_Connection *connection,
97 const char *url,
98 const char *method,
99 const char *version,
100 const char *upload_data,
101 size_t *upload_data_size,
102 void **unused)
103{
104 static int ptr;
105 struct MHD_Response *response;
106 int ret;
107 (void) cls;
108 (void) url;
109 (void) url;
110 (void) version; /* Unused. Silent compiler warning. */
111 (void) upload_data;
112 (void) upload_data_size; /* Unused. Silent compiler warning. */
113
114 if (0 != strcasecmp ("GET",
115 method))
116 return MHD_NO; /* unexpected method */
117 if (&ptr != *unused)
118 {
119 *unused = &ptr;
120 return MHD_YES;
121 }
122 *unused = NULL;
123 response = MHD_create_response_from_buffer (0,
124 NULL,
125 MHD_RESPMEM_PERSISTENT);
126 ret = MHD_queue_response (connection,
127 MHD_HTTP_OK,
128 response);
129 MHD_destroy_response (response);
130 if (ret == MHD_NO)
131 {
132 fprintf (stderr, "Failed to queue response.\n");
133 _exit (20);
134 }
135 return ret;
136}
137
138
139static int
140curlExcessFound (CURL *c,
141 curl_infotype type,
142 char *data,
143 size_t size,
144 void *cls)
145{
146 static const char *excess_found = "Excess found";
147 const size_t str_size = strlen (excess_found);
148 (void) c; /* Unused. Silence compiler warning. */
149
150 if ((CURLINFO_TEXT == type)
151 &&(size >= str_size)
152 &&(0 == strncmp (excess_found, data, str_size)))
153 *(int *) cls = 1;
154 return 0;
155}
156
157
158static int
159testEmptyGet (int poll_flag)
160{
161 struct MHD_Daemon *d;
162 CURL *c;
163 char buf[2048];
164 struct CBC cbc;
165 CURLcode errornum;
166 int excess_found = 0;
167
168
169 if ( (0 == global_port) &&
170 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
171 {
172 global_port = 1225;
173
174 }
175
176 cbc.buf = buf;
177 cbc.size = 2048;
178 cbc.pos = 0;
179 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
180 | poll_flag | MHD_USE_TLS,
181 global_port, NULL, NULL,
182 &ahc_empty, NULL,
183 MHD_OPTION_HTTPS_MEM_KEY, srv_signed_key_pem,
184 MHD_OPTION_HTTPS_MEM_CERT, srv_signed_cert_pem,
185 MHD_OPTION_END);
186 if (d == NULL)
187 return 4194304;
188 if (0 == global_port)
189 {
190 const union MHD_DaemonInfo *dinfo;
191 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
192 if ((NULL == dinfo) ||(0 == dinfo->port) )
193 {
194 MHD_stop_daemon (d); return 32;
195 }
196 global_port = (int) dinfo->port;
197 }
198 c = curl_easy_init ();
199 curl_easy_setopt (c, CURLOPT_URL, "https://127.0.0.1/");
200 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port);
201 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
202 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
203 curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, &curlExcessFound);
204 curl_easy_setopt (c, CURLOPT_DEBUGDATA, &excess_found);
205 curl_easy_setopt (c, CURLOPT_VERBOSE, 1L);
206 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
207 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
208 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
209 curl_easy_setopt (c, CURLOPT_SSL_VERIFYPEER, 0L);
210 curl_easy_setopt (c, CURLOPT_SSL_VERIFYHOST, 0L);
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, 1L);
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 8388608;
223 }
224 curl_easy_cleanup (c);
225 MHD_stop_daemon (d);
226 if (cbc.pos != 0)
227 return 16777216;
228 if (excess_found)
229 return 33554432;
230 return 0;
231}
232
233
86int 234int
87main (int argc, char *const *argv) 235main (int argc, char *const *argv)
88{ 236{
@@ -109,11 +257,9 @@ main (int argc, char *const *argv)
109 { 257 {
110 aes256_sha_tlsv1 = "rsa_aes_256_sha"; 258 aes256_sha_tlsv1 = "rsa_aes_256_sha";
111 } 259 }
112
113 errorCount += 260 errorCount +=
114 test_secure_get (NULL, aes256_sha_tlsv1, CURL_SSLVERSION_TLSv1); 261 test_secure_get (NULL, aes256_sha_tlsv1, CURL_SSLVERSION_TLSv1);
115 print_test_result (errorCount, argv[0]); 262 errorCount += testEmptyGet (0);
116
117 curl_global_cleanup (); 263 curl_global_cleanup ();
118 264
119 return errorCount != 0 ? 1 : 0; 265 return errorCount != 0 ? 1 : 0;
diff --git a/src/testcurl/https/tls_test_common.c b/src/testcurl/https/tls_test_common.c
index eb7cb14c..9d988451 100644
--- a/src/testcurl/https/tls_test_common.c
+++ b/src/testcurl/https/tls_test_common.c
@@ -62,7 +62,8 @@ setup_ca_cert ()
62 */ 62 */
63int 63int
64test_daemon_get (void *cls, 64test_daemon_get (void *cls,
65 const char *cipher_suite, int proto_version, 65 const char *cipher_suite,
66 int proto_version,
66 int port, 67 int port,
67 int ver_peer) 68 int ver_peer)
68{ 69{
@@ -71,7 +72,7 @@ test_daemon_get (void *cls,
71 CURLcode errornum; 72 CURLcode errornum;
72 char url[255]; 73 char url[255];
73 size_t len; 74 size_t len;
74 (void) cls; /* Unused. Silent compiler warning. */ 75 (void) cls; /* Unused. Silence compiler warning. */
75 76
76 len = strlen (test_data); 77 len = strlen (test_data);
77 if (NULL == (cbc.buf = malloc (sizeof (char) * len))) 78 if (NULL == (cbc.buf = malloc (sizeof (char) * len)))
@@ -138,20 +139,29 @@ test_daemon_get (void *cls,
138 139
139 140
140void 141void
141print_test_result (int test_outcome, char *test_name) 142print_test_result (int test_outcome,
143 char *test_name)
142{ 144{
143 if (test_outcome != 0) 145 if (test_outcome != 0)
144 fprintf (stderr, "running test: %s [fail: %u]\n", test_name, (unsigned 146 fprintf (stderr,
145 int) 147 "running test: %s [fail: %u]\n",
148 test_name, (unsigned
149 int)
146 test_outcome); 150 test_outcome);
147#if 0 151#if 0
148 else 152 else
149 fprintf (stdout, "running test: %s [pass]\n", test_name); 153 fprintf (stdout,
154 "running test: %s [pass]\n",
155 test_name);
150#endif 156#endif
151} 157}
152 158
159
153size_t 160size_t
154copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 161copyBuffer (void *ptr,
162 size_t size,
163 size_t nmemb,
164 void *ctx)
155{ 165{
156 struct CBC *cbc = ctx; 166 struct CBC *cbc = ctx;
157 167
@@ -162,13 +172,19 @@ copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
162 return size * nmemb; 172 return size * nmemb;
163} 173}
164 174
175
165/** 176/**
166 * HTTP access handler call back 177 * HTTP access handler call back
167 */ 178 */
168int 179int
169http_ahc (void *cls, struct MHD_Connection *connection, 180http_ahc (void *cls,
170 const char *url, const char *method, const char *version, 181 struct MHD_Connection *connection,
171 const char *upload_data, size_t *upload_data_size, void **ptr) 182 const char *url,
183 const char *method,
184 const char *version,
185 const char *upload_data,
186 size_t *upload_data_size,
187 void **ptr)
172{ 188{
173 static int aptr; 189 static int aptr;
174 struct MHD_Response *response; 190 struct MHD_Response *response;
@@ -193,15 +209,26 @@ http_ahc (void *cls, struct MHD_Connection *connection,
193 return ret; 209 return ret;
194} 210}
195 211
212
196/* HTTP access handler call back */ 213/* HTTP access handler call back */
197int 214int
198http_dummy_ahc (void *cls, struct MHD_Connection *connection, 215http_dummy_ahc (void *cls,
199 const char *url, const char *method, const char *version, 216 struct MHD_Connection *connection,
200 const char *upload_data, size_t *upload_data_size, 217 const char *url,
218 const char *method,
219 const char *version,
220 const char *upload_data,
221 size_t *upload_data_size,
201 void **ptr) 222 void **ptr)
202{ 223{
203 (void) cls; (void) connection; (void) url; (void) method; (void) version; /* Unused. Silent compiler warning. */ 224 (void) cls;
204 (void) upload_data; (void) upload_data_size; (void) ptr; /* Unused. Silent compiler warning. */ 225 (void) connection;
226 (void) url;
227 (void) method;
228 (void) version; /* Unused. Silent compiler warning. */
229 (void) upload_data;
230 (void) upload_data_size;
231 (void) ptr; /* Unused. Silent compiler warning. */
205 return 0; 232 return 0;
206} 233}
207 234
@@ -215,7 +242,9 @@ http_dummy_ahc (void *cls, struct MHD_Connection *connection,
215 */ 242 */
216/* TODO have test wrap consider a NULL cbc */ 243/* TODO have test wrap consider a NULL cbc */
217int 244int
218send_curl_req (char *url, struct CBC *cbc, const char *cipher_suite, 245send_curl_req (char *url,
246 struct CBC *cbc,
247 const char *cipher_suite,
219 int proto_version) 248 int proto_version)
220{ 249{
221 CURL *c; 250 CURL *c;
diff --git a/src/testcurl/test_get.c b/src/testcurl/test_get.c
index dee5a9c1..09cae5f6 100644
--- a/src/testcurl/test_get.c
+++ b/src/testcurl/test_get.c
@@ -719,14 +719,19 @@ ahc_empty (void *cls,
719 const char *url, 719 const char *url,
720 const char *method, 720 const char *method,
721 const char *version, 721 const char *version,
722 const char *upload_data, size_t *upload_data_size, 722 const char *upload_data,
723 size_t *upload_data_size,
723 void **unused) 724 void **unused)
724{ 725{
725 static int ptr; 726 static int ptr;
726 struct MHD_Response *response; 727 struct MHD_Response *response;
727 int ret; 728 int ret;
728 (void) cls; (void) url; (void) url; (void) version; /* Unused. Silent compiler warning. */ 729 (void) cls;
729 (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 730 (void) url;
731 (void) url;
732 (void) version; /* Unused. Silent compiler warning. */
733 (void) upload_data;
734 (void) upload_data_size; /* Unused. Silent compiler warning. */
730 735
731 if (0 != strcasecmp ("GET", method)) 736 if (0 != strcasecmp ("GET", method))
732 return MHD_NO; /* unexpected method */ 737 return MHD_NO; /* unexpected method */
@@ -739,7 +744,9 @@ ahc_empty (void *cls,
739 response = MHD_create_response_from_buffer (0, 744 response = MHD_create_response_from_buffer (0,
740 NULL, 745 NULL,
741 MHD_RESPMEM_PERSISTENT); 746 MHD_RESPMEM_PERSISTENT);
742 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 747 ret = MHD_queue_response (connection,
748 MHD_HTTP_OK,
749 response);
743 MHD_destroy_response (response); 750 MHD_destroy_response (response);
744 if (ret == MHD_NO) 751 if (ret == MHD_NO)
745 { 752 {
@@ -751,7 +758,10 @@ ahc_empty (void *cls,
751 758
752 759
753static int 760static int
754curlExcessFound (CURL *c, curl_infotype type, char *data, size_t size, 761curlExcessFound (CURL *c,
762 curl_infotype type,
763 char *data,
764 size_t size,
755 void *cls) 765 void *cls)
756{ 766{
757 static const char *excess_found = "Excess found"; 767 static const char *excess_found = "Excess found";
diff --git a/src/testcurl/test_get_empty.c b/src/testcurl/test_get_empty.c
new file mode 100644
index 00000000..0fffb37d
--- /dev/null
+++ b/src/testcurl/test_get_empty.c
@@ -0,0 +1,941 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007, 2009, 2011, 2019 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 * @file test_get_empty.c
22 * @brief Testcase for libmicrohttpd GET operations returning an empty body
23 * @author Christian Grothoff
24 */
25#include "MHD_config.h"
26#include "platform.h"
27#include <curl/curl.h>
28#include <microhttpd.h>
29#include <stdlib.h>
30#include <string.h>
31#include <time.h>
32#include "test_helpers.h"
33#include "mhd_sockets.h" /* only macros used */
34
35
36#define EXPECTED_URI_PATH "/hello_world?a=%26&b=c"
37
38#ifdef _WIN32
39#ifndef WIN32_LEAN_AND_MEAN
40#define WIN32_LEAN_AND_MEAN 1
41#endif /* !WIN32_LEAN_AND_MEAN */
42#include <windows.h>
43#endif
44
45#ifndef WINDOWS
46#include <unistd.h>
47#include <sys/socket.h>
48#endif
49
50#if defined(CPU_COUNT) && (CPU_COUNT + 0) < 2
51#undef CPU_COUNT
52#endif
53#if ! defined(CPU_COUNT)
54#define CPU_COUNT 2
55#endif
56
57static int oneone;
58static int global_port;
59
60struct CBC
61{
62 char *buf;
63 size_t pos;
64 size_t size;
65};
66
67
68static size_t
69copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx)
70{
71 struct CBC *cbc = ctx;
72
73 if (cbc->pos + size * nmemb > cbc->size)
74 return 0; /* overflow */
75 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
76 cbc->pos += size * nmemb;
77 return size * nmemb;
78}
79
80
81static void *
82log_cb (void *cls,
83 const char *uri,
84 struct MHD_Connection *con)
85{
86 (void) cls;
87 (void) con;
88 if (0 != strcmp (uri,
89 EXPECTED_URI_PATH))
90 {
91 fprintf (stderr,
92 "Wrong URI: `%s'\n",
93 uri);
94 _exit (22);
95 }
96 return NULL;
97}
98
99
100static int
101ahc_echo (void *cls,
102 struct MHD_Connection *connection,
103 const char *url,
104 const char *method,
105 const char *version,
106 const char *upload_data, size_t *upload_data_size,
107 void **unused)
108{
109 static int ptr;
110 const char *me = cls;
111 struct MHD_Response *response;
112 int ret;
113 (void) version;
114 (void) upload_data;
115 (void) upload_data_size; /* Unused. Silence compiler warning. */
116
117 if (0 != strcasecmp (me, method))
118 return MHD_NO; /* unexpected method */
119 if (&ptr != *unused)
120 {
121 *unused = &ptr;
122 return MHD_YES;
123 }
124 *unused = NULL;
125 response = MHD_create_response_from_buffer (0,
126 NULL,
127 MHD_RESPMEM_PERSISTENT);
128 ret = MHD_queue_response (connection,
129 MHD_HTTP_NO_CONTENT,
130 response);
131 MHD_destroy_response (response);
132 if (ret == MHD_NO)
133 {
134 fprintf (stderr, "Failed to queue response.\n");
135 _exit (19);
136 }
137 return ret;
138}
139
140
141static int
142testInternalGet (int poll_flag)
143{
144 struct MHD_Daemon *d;
145 CURL *c;
146 char buf[2048];
147 struct CBC cbc;
148 CURLcode errornum;
149
150 if ( (0 == global_port) &&
151 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
152 {
153 global_port = 1220;
154 if (oneone)
155 global_port += 20;
156 }
157
158 cbc.buf = buf;
159 cbc.size = 2048;
160 cbc.pos = 0;
161 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
162 | poll_flag,
163 global_port, NULL, NULL,
164 &ahc_echo, "GET",
165 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
166 MHD_OPTION_END);
167 if (d == NULL)
168 return 1;
169 if (0 == global_port)
170 {
171 const union MHD_DaemonInfo *dinfo;
172 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
173 if ((NULL == dinfo) ||(0 == dinfo->port) )
174 {
175 MHD_stop_daemon (d); return 32;
176 }
177 global_port = (int) dinfo->port;
178 }
179 c = curl_easy_init ();
180 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
181 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port);
182 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
183 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
184 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
185 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
186 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
187 if (oneone)
188 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
189 else
190 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
191 /* NOTE: use of CONNECTTIMEOUT without also
192 setting NOSIGNAL results in really weird
193 crashes on my system!*/
194 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
195 if (CURLE_OK != (errornum = curl_easy_perform (c)))
196 {
197 fprintf (stderr,
198 "curl_easy_perform failed: `%s'\n",
199 curl_easy_strerror (errornum));
200 curl_easy_cleanup (c);
201 MHD_stop_daemon (d);
202 return 2;
203 }
204 curl_easy_cleanup (c);
205 MHD_stop_daemon (d);
206 if (cbc.pos != 0)
207 return 4;
208 return 0;
209}
210
211
212static int
213testMultithreadedGet (int poll_flag)
214{
215 struct MHD_Daemon *d;
216 CURL *c;
217 char buf[2048];
218 struct CBC cbc;
219 CURLcode errornum;
220
221 if ( (0 == global_port) &&
222 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
223 {
224 global_port = 1221;
225 if (oneone)
226 global_port += 20;
227 }
228
229 cbc.buf = buf;
230 cbc.size = 2048;
231 cbc.pos = 0;
232 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
233 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
234 | poll_flag,
235 global_port, NULL, NULL,
236 &ahc_echo, "GET",
237 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
238 MHD_OPTION_END);
239 if (d == NULL)
240 return 16;
241 if (0 == global_port)
242 {
243 const union MHD_DaemonInfo *dinfo;
244 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
245 if ((NULL == dinfo) ||(0 == dinfo->port) )
246 {
247 MHD_stop_daemon (d); return 32;
248 }
249 global_port = (int) dinfo->port;
250 }
251 c = curl_easy_init ();
252 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
253 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port);
254 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
255 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
256 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
257 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
258 if (oneone)
259 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
260 else
261 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
262 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
263 /* NOTE: use of CONNECTTIMEOUT without also
264 setting NOSIGNAL results in really weird
265 crashes on my system! */
266 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
267 if (CURLE_OK != (errornum = curl_easy_perform (c)))
268 {
269 fprintf (stderr,
270 "curl_easy_perform failed: `%s'\n",
271 curl_easy_strerror (errornum));
272 curl_easy_cleanup (c);
273 MHD_stop_daemon (d);
274 return 32;
275 }
276 curl_easy_cleanup (c);
277 MHD_stop_daemon (d);
278 if (cbc.pos != 0)
279 return 64;
280 return 0;
281}
282
283
284static int
285testMultithreadedPoolGet (int poll_flag)
286{
287 struct MHD_Daemon *d;
288 CURL *c;
289 char buf[2048];
290 struct CBC cbc;
291 CURLcode errornum;
292
293 if ( (0 == global_port) &&
294 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
295 {
296 global_port = 1222;
297 if (oneone)
298 global_port += 20;
299 }
300
301 cbc.buf = buf;
302 cbc.size = 2048;
303 cbc.pos = 0;
304 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
305 | poll_flag,
306 global_port, NULL, NULL,
307 &ahc_echo, "GET",
308 MHD_OPTION_THREAD_POOL_SIZE, CPU_COUNT,
309 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
310 MHD_OPTION_END);
311 if (d == NULL)
312 return 16;
313 if (0 == global_port)
314 {
315 const union MHD_DaemonInfo *dinfo;
316 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
317 if ((NULL == dinfo) ||(0 == dinfo->port) )
318 {
319 MHD_stop_daemon (d); return 32;
320 }
321 global_port = (int) dinfo->port;
322 }
323 c = curl_easy_init ();
324 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
325 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port);
326 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
327 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
328 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
329 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
330 if (oneone)
331 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
332 else
333 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
334 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
335 /* NOTE: use of CONNECTTIMEOUT without also
336 setting NOSIGNAL results in really weird
337 crashes on my system!*/
338 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
339 if (CURLE_OK != (errornum = curl_easy_perform (c)))
340 {
341 fprintf (stderr,
342 "curl_easy_perform failed: `%s'\n",
343 curl_easy_strerror (errornum));
344 curl_easy_cleanup (c);
345 MHD_stop_daemon (d);
346 return 32;
347 }
348 curl_easy_cleanup (c);
349 MHD_stop_daemon (d);
350 if (cbc.pos != 0)
351 return 64;
352 return 0;
353}
354
355
356static int
357testExternalGet ()
358{
359 struct MHD_Daemon *d;
360 CURL *c;
361 char buf[2048];
362 struct CBC cbc;
363 CURLM *multi;
364 CURLMcode mret;
365 fd_set rs;
366 fd_set ws;
367 fd_set es;
368 MHD_socket maxsock;
369 int maxposixs;
370 int running;
371 struct CURLMsg *msg;
372 time_t start;
373 struct timeval tv;
374
375 if ( (0 == global_port) &&
376 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
377 {
378 global_port = 1223;
379 if (oneone)
380 global_port += 20;
381 }
382
383 multi = NULL;
384 cbc.buf = buf;
385 cbc.size = 2048;
386 cbc.pos = 0;
387 d = MHD_start_daemon (MHD_USE_ERROR_LOG,
388 global_port, NULL, NULL,
389 &ahc_echo, "GET",
390 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
391 MHD_OPTION_END);
392 if (d == NULL)
393 return 256;
394 if (0 == global_port)
395 {
396 const union MHD_DaemonInfo *dinfo;
397 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
398 if ((NULL == dinfo) ||(0 == dinfo->port) )
399 {
400 MHD_stop_daemon (d); return 32;
401 }
402 global_port = (int) dinfo->port;
403 }
404 c = curl_easy_init ();
405 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
406 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port);
407 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
408 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
409 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
410 if (oneone)
411 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
412 else
413 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
414 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
415 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
416 /* NOTE: use of CONNECTTIMEOUT without also
417 setting NOSIGNAL results in really weird
418 crashes on my system! */
419 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
420
421
422 multi = curl_multi_init ();
423 if (multi == NULL)
424 {
425 curl_easy_cleanup (c);
426 MHD_stop_daemon (d);
427 return 512;
428 }
429 mret = curl_multi_add_handle (multi, c);
430 if (mret != CURLM_OK)
431 {
432 curl_multi_cleanup (multi);
433 curl_easy_cleanup (c);
434 MHD_stop_daemon (d);
435 return 1024;
436 }
437 start = time (NULL);
438 while ((time (NULL) - start < 5) && (multi != NULL))
439 {
440 maxsock = MHD_INVALID_SOCKET;
441 maxposixs = -1;
442 FD_ZERO (&rs);
443 FD_ZERO (&ws);
444 FD_ZERO (&es);
445 curl_multi_perform (multi, &running);
446 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
447 if (mret != CURLM_OK)
448 {
449 curl_multi_remove_handle (multi, c);
450 curl_multi_cleanup (multi);
451 curl_easy_cleanup (c);
452 MHD_stop_daemon (d);
453 return 2048;
454 }
455 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock))
456 {
457 curl_multi_remove_handle (multi, c);
458 curl_multi_cleanup (multi);
459 curl_easy_cleanup (c);
460 MHD_stop_daemon (d);
461 return 4096;
462 }
463 tv.tv_sec = 0;
464 tv.tv_usec = 1000;
465#ifdef MHD_POSIX_SOCKETS
466 if (maxsock > maxposixs)
467 maxposixs = maxsock;
468#endif /* MHD_POSIX_SOCKETS */
469 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv))
470 {
471#ifdef MHD_POSIX_SOCKETS
472 if (EINTR != errno)
473 abort ();
474#else
475 if ((WSAEINVAL != WSAGetLastError ()) ||(0 != rs.fd_count) ||(0 !=
476 ws.fd_count)
477 ||(0 != es.fd_count) )
478 _exit (99);
479 Sleep (1000);
480#endif
481 }
482 curl_multi_perform (multi, &running);
483 if (running == 0)
484 {
485 msg = curl_multi_info_read (multi, &running);
486 if (msg == NULL)
487 break;
488 if (msg->msg == CURLMSG_DONE)
489 {
490 if (msg->data.result != CURLE_OK)
491 printf ("%s failed at %s:%d: `%s'\n",
492 "curl_multi_perform",
493 __FILE__,
494 __LINE__, curl_easy_strerror (msg->data.result));
495 curl_multi_remove_handle (multi, c);
496 curl_multi_cleanup (multi);
497 curl_easy_cleanup (c);
498 c = NULL;
499 multi = NULL;
500 }
501 }
502 MHD_run (d);
503 }
504 if (multi != NULL)
505 {
506 curl_multi_remove_handle (multi, c);
507 curl_easy_cleanup (c);
508 curl_multi_cleanup (multi);
509 }
510 MHD_stop_daemon (d);
511 if (cbc.pos != 0)
512 return 8192;
513 return 0;
514}
515
516
517static int
518testUnknownPortGet (int poll_flag)
519{
520 struct MHD_Daemon *d;
521 const union MHD_DaemonInfo *di;
522 CURL *c;
523 char buf[2048];
524 struct CBC cbc;
525 CURLcode errornum;
526 int port;
527
528 struct sockaddr_in addr;
529 socklen_t addr_len = sizeof(addr);
530 memset (&addr, 0, sizeof(addr));
531 addr.sin_family = AF_INET;
532 addr.sin_port = 0;
533 addr.sin_addr.s_addr = INADDR_ANY;
534
535 cbc.buf = buf;
536 cbc.size = 2048;
537 cbc.pos = 0;
538 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
539 | poll_flag,
540 0, NULL, NULL, &ahc_echo, "GET",
541 MHD_OPTION_SOCK_ADDR, &addr,
542 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
543 MHD_OPTION_END);
544 if (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
545 {
546 di = MHD_get_daemon_info (d, MHD_DAEMON_INFO_LISTEN_FD);
547 if (di == NULL)
548 return 65536;
549
550 if (0 != getsockname (di->listen_fd, (struct sockaddr *) &addr, &addr_len))
551 return 131072;
552
553 if (addr.sin_family != AF_INET)
554 return 26214;
555 port = (int) ntohs (addr.sin_port);
556 }
557 else
558 {
559 const union MHD_DaemonInfo *dinfo;
560 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
561 if ((NULL == dinfo) ||(0 == dinfo->port) )
562 {
563 MHD_stop_daemon (d); return 32;
564 }
565 port = (int) dinfo->port;
566 }
567
568 snprintf (buf,
569 sizeof(buf),
570 "http://127.0.0.1:%d%s",
571 port,
572 EXPECTED_URI_PATH);
573
574 c = curl_easy_init ();
575 curl_easy_setopt (c, CURLOPT_URL, buf);
576 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
577 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
578 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
579 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
580 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
581 if (oneone)
582 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
583 else
584 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
585 /* NOTE: use of CONNECTTIMEOUT without also
586 setting NOSIGNAL results in really weird
587 crashes on my system! */
588 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
589 if (CURLE_OK != (errornum = curl_easy_perform (c)))
590 {
591 fprintf (stderr,
592 "curl_easy_perform failed: `%s'\n",
593 curl_easy_strerror (errornum));
594 curl_easy_cleanup (c);
595 MHD_stop_daemon (d);
596 return 524288;
597 }
598 curl_easy_cleanup (c);
599 MHD_stop_daemon (d);
600 if (cbc.pos != 0)
601 return 1048576;
602 return 0;
603}
604
605
606static int
607testStopRace (int poll_flag)
608{
609 struct sockaddr_in sin;
610 MHD_socket fd;
611 struct MHD_Daemon *d;
612
613 if ( (0 == global_port) &&
614 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
615 {
616 global_port = 1224;
617 if (oneone)
618 global_port += 20;
619 }
620
621 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION
622 | MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
623 | poll_flag,
624 global_port, NULL, NULL,
625 &ahc_echo, "GET",
626 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
627 MHD_OPTION_END);
628 if (d == NULL)
629 return 16;
630 if (0 == global_port)
631 {
632 const union MHD_DaemonInfo *dinfo;
633 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
634 if ((NULL == dinfo) ||(0 == dinfo->port) )
635 {
636 MHD_stop_daemon (d); return 32;
637 }
638 global_port = (int) dinfo->port;
639 }
640
641 fd = socket (PF_INET, SOCK_STREAM, 0);
642 if (fd == MHD_INVALID_SOCKET)
643 {
644 fprintf (stderr, "socket error\n");
645 return 256;
646 }
647
648 memset (&sin, 0, sizeof(sin));
649 sin.sin_family = AF_INET;
650 sin.sin_port = htons (global_port);
651 sin.sin_addr.s_addr = htonl (0x7f000001);
652
653 if (connect (fd, (struct sockaddr *) (&sin), sizeof(sin)) < 0)
654 {
655 fprintf (stderr, "connect error\n");
656 MHD_socket_close_chk_ (fd);
657 return 512;
658 }
659
660 /* printf("Waiting\n"); */
661 /* Let the thread get going. */
662 usleep (500000);
663
664 /* printf("Stopping daemon\n"); */
665 MHD_stop_daemon (d);
666
667 MHD_socket_close_chk_ (fd);
668
669 /* printf("good\n"); */
670 return 0;
671}
672
673
674static int
675ahc_empty (void *cls,
676 struct MHD_Connection *connection,
677 const char *url,
678 const char *method,
679 const char *version,
680 const char *upload_data, size_t *upload_data_size,
681 void **unused)
682{
683 static int ptr;
684 struct MHD_Response *response;
685 int ret;
686 (void) cls;
687 (void) url;
688 (void) url;
689 (void) version; /* Unused. Silence compiler warning. */
690 (void) upload_data;
691 (void) upload_data_size; /* Unused. Silent compiler warning. */
692
693 if (0 != strcasecmp ("GET", method))
694 return MHD_NO; /* unexpected method */
695 if (&ptr != *unused)
696 {
697 *unused = &ptr;
698 return MHD_YES;
699 }
700 *unused = NULL;
701 response = MHD_create_response_from_buffer (0,
702 NULL,
703 MHD_RESPMEM_PERSISTENT);
704 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
705 MHD_destroy_response (response);
706 if (ret == MHD_NO)
707 {
708 fprintf (stderr, "Failed to queue response.\n");
709 _exit (20);
710 }
711 return ret;
712}
713
714
715static int
716curlExcessFound (CURL *c, curl_infotype type, char *data, size_t size,
717 void *cls)
718{
719 static const char *excess_found = "Excess found";
720 const size_t str_size = strlen (excess_found);
721 (void) c; /* Unused. Silent compiler warning. */
722
723 if ((CURLINFO_TEXT == type)
724 &&(size >= str_size)
725 &&(0 == strncmp (excess_found, data, str_size)))
726 *(int *) cls = 1;
727 return 0;
728}
729
730
731static int
732testEmptyGet (int poll_flag)
733{
734 struct MHD_Daemon *d;
735 CURL *c;
736 char buf[2048];
737 struct CBC cbc;
738 CURLcode errornum;
739 int excess_found = 0;
740
741 if ( (0 == global_port) &&
742 (MHD_NO == MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) )
743 {
744 global_port = 1225;
745 if (oneone)
746 global_port += 20;
747 }
748
749 cbc.buf = buf;
750 cbc.size = 2048;
751 cbc.pos = 0;
752 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_ERROR_LOG
753 | poll_flag,
754 global_port, NULL, NULL,
755 &ahc_empty, NULL,
756 MHD_OPTION_URI_LOG_CALLBACK, &log_cb, NULL,
757 MHD_OPTION_END);
758 if (d == NULL)
759 return 4194304;
760 if (0 == global_port)
761 {
762 const union MHD_DaemonInfo *dinfo;
763 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT);
764 if ((NULL == dinfo) ||(0 == dinfo->port) )
765 {
766 MHD_stop_daemon (d); return 32;
767 }
768 global_port = (int) dinfo->port;
769 }
770 c = curl_easy_init ();
771 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1" EXPECTED_URI_PATH);
772 curl_easy_setopt (c, CURLOPT_PORT, (long) global_port);
773 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
774 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
775 curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION, &curlExcessFound);
776 curl_easy_setopt (c, CURLOPT_DEBUGDATA, &excess_found);
777 curl_easy_setopt (c, CURLOPT_VERBOSE, 1L);
778 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
779 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
780 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L);
781 if (oneone)
782 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
783 else
784 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
785 /* NOTE: use of CONNECTTIMEOUT without also
786 setting NOSIGNAL results in really weird
787 crashes on my system!*/
788 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L);
789 if (CURLE_OK != (errornum = curl_easy_perform (c)))
790 {
791 fprintf (stderr,
792 "curl_easy_perform failed: `%s'\n",
793 curl_easy_strerror (errornum));
794 curl_easy_cleanup (c);
795 MHD_stop_daemon (d);
796 return 8388608;
797 }
798 curl_easy_cleanup (c);
799 MHD_stop_daemon (d);
800 if (cbc.pos != 0)
801 return 16777216;
802 if (excess_found)
803 return 33554432;
804 return 0;
805}
806
807
808int
809main (int argc, char *const *argv)
810{
811 unsigned int errorCount = 0;
812 unsigned int test_result = 0;
813 int verbose = 0;
814
815 if ((NULL == argv)||(0 == argv[0]))
816 return 99;
817 oneone = has_in_name (argv[0], "11");
818 verbose = has_param (argc, argv, "-v") || has_param (argc, argv, "--verbose");
819 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
820 return 2;
821 global_port = 0;
822 test_result = testExternalGet ();
823 if (test_result)
824 fprintf (stderr, "FAILED: testExternalGet () - %u.\n", test_result);
825 else if (verbose)
826 printf ("PASSED: testExternalGet ().\n");
827 errorCount += test_result;
828 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_THREADS))
829 {
830 test_result += testInternalGet (0);
831 if (test_result)
832 fprintf (stderr, "FAILED: testInternalGet (0) - %u.\n", test_result);
833 else if (verbose)
834 printf ("PASSED: testInternalGet (0).\n");
835 errorCount += test_result;
836 test_result += testMultithreadedGet (0);
837 if (test_result)
838 fprintf (stderr, "FAILED: testMultithreadedGet (0) - %u.\n", test_result);
839 else if (verbose)
840 printf ("PASSED: testMultithreadedGet (0).\n");
841 errorCount += test_result;
842 test_result += testMultithreadedPoolGet (0);
843 if (test_result)
844 fprintf (stderr, "FAILED: testMultithreadedPoolGet (0) - %u.\n",
845 test_result);
846 else if (verbose)
847 printf ("PASSED: testMultithreadedPoolGet (0).\n");
848 errorCount += test_result;
849 test_result += testUnknownPortGet (0);
850 if (test_result)
851 fprintf (stderr, "FAILED: testUnknownPortGet (0) - %u.\n", test_result);
852 else if (verbose)
853 printf ("PASSED: testUnknownPortGet (0).\n");
854 errorCount += test_result;
855 test_result += testEmptyGet (0);
856 if (test_result)
857 fprintf (stderr, "FAILED: testEmptyGet (0) - %u.\n", test_result);
858 else if (verbose)
859 printf ("PASSED: testEmptyGet (0).\n");
860 errorCount += test_result;
861 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_POLL))
862 {
863 test_result += testInternalGet (MHD_USE_POLL);
864 if (test_result)
865 fprintf (stderr, "FAILED: testInternalGet (MHD_USE_POLL) - %u.\n",
866 test_result);
867 else if (verbose)
868 printf ("PASSED: testInternalGet (MHD_USE_POLL).\n");
869 errorCount += test_result;
870 test_result += testMultithreadedGet (MHD_USE_POLL);
871 if (test_result)
872 fprintf (stderr, "FAILED: testMultithreadedGet (MHD_USE_POLL) - %u.\n",
873 test_result);
874 else if (verbose)
875 printf ("PASSED: testMultithreadedGet (MHD_USE_POLL).\n");
876 errorCount += test_result;
877 test_result += testMultithreadedPoolGet (MHD_USE_POLL);
878 if (test_result)
879 fprintf (stderr,
880 "FAILED: testMultithreadedPoolGet (MHD_USE_POLL) - %u.\n",
881 test_result);
882 else if (verbose)
883 printf ("PASSED: testMultithreadedPoolGet (MHD_USE_POLL).\n");
884 errorCount += test_result;
885 test_result += testUnknownPortGet (MHD_USE_POLL);
886 if (test_result)
887 fprintf (stderr, "FAILED: testUnknownPortGet (MHD_USE_POLL) - %u.\n",
888 test_result);
889 else if (verbose)
890 printf ("PASSED: testUnknownPortGet (MHD_USE_POLL).\n");
891 errorCount += test_result;
892 test_result += testEmptyGet (MHD_USE_POLL);
893 if (test_result)
894 fprintf (stderr, "FAILED: testEmptyGet (MHD_USE_POLL) - %u.\n",
895 test_result);
896 else if (verbose)
897 printf ("PASSED: testEmptyGet (MHD_USE_POLL).\n");
898 errorCount += test_result;
899 }
900 if (MHD_YES == MHD_is_feature_supported (MHD_FEATURE_EPOLL))
901 {
902 test_result += testInternalGet (MHD_USE_EPOLL);
903 if (test_result)
904 fprintf (stderr, "FAILED: testInternalGet (MHD_USE_EPOLL) - %u.\n",
905 test_result);
906 else if (verbose)
907 printf ("PASSED: testInternalGet (MHD_USE_EPOLL).\n");
908 errorCount += test_result;
909 test_result += testMultithreadedPoolGet (MHD_USE_EPOLL);
910 if (test_result)
911 fprintf (stderr,
912 "FAILED: testMultithreadedPoolGet (MHD_USE_EPOLL) - %u.\n",
913 test_result);
914 else if (verbose)
915 printf ("PASSED: testMultithreadedPoolGet (MHD_USE_EPOLL).\n");
916 errorCount += test_result;
917 test_result += testUnknownPortGet (MHD_USE_EPOLL);
918 if (test_result)
919 fprintf (stderr, "FAILED: testUnknownPortGet (MHD_USE_EPOLL) - %u.\n",
920 test_result);
921 else if (verbose)
922 printf ("PASSED: testUnknownPortGet (MHD_USE_EPOLL).\n");
923 errorCount += test_result;
924 test_result += testEmptyGet (MHD_USE_EPOLL);
925 if (test_result)
926 fprintf (stderr, "FAILED: testEmptyGet (MHD_USE_EPOLL) - %u.\n",
927 test_result);
928 else if (verbose)
929 printf ("PASSED: testEmptyGet (MHD_USE_EPOLL).\n");
930 errorCount += test_result;
931 }
932 }
933 if (0 != errorCount)
934 fprintf (stderr,
935 "Error (code: %u)\n",
936 errorCount);
937 else if (verbose)
938 printf ("All tests passed.\n");
939 curl_global_cleanup ();
940 return errorCount != 0; /* 0 == pass */
941}