aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-11-28 18:53:02 +0300
committerEvgeny Grin (Karlson2k) <k2k@narod.ru>2022-12-19 18:13:44 +0300
commit38b46a2fd1cf24270e6deab2bb64c381938b95a9 (patch)
treef073f991f6fe0d5de829eb79a85d490d909079be
parent2a71dbd38f47cb067e61b681d7ac5dd39d26b754 (diff)
downloadlibmicrohttpd-38b46a2fd1cf24270e6deab2bb64c381938b95a9.tar.gz
libmicrohttpd-38b46a2fd1cf24270e6deab2bb64c381938b95a9.zip
test_parse_cookies: rewritten
Reused the same connection with the server. Added more flexible checks.
-rw-r--r--src/testcurl/Makefile.am8
-rw-r--r--src/testcurl/test_parse_cookies.c1445
2 files changed, 1062 insertions, 391 deletions
diff --git a/src/testcurl/Makefile.am b/src/testcurl/Makefile.am
index cc685d3b..010ec2ef 100644
--- a/src/testcurl/Makefile.am
+++ b/src/testcurl/Makefile.am
@@ -145,7 +145,7 @@ check_PROGRAMS = \
145if ENABLE_COOKIE 145if ENABLE_COOKIE
146check_PROGRAMS += \ 146check_PROGRAMS += \
147 test_parse_cookies \ 147 test_parse_cookies \
148 test_parse_cookies_invalid 148 test_parse_cookies_nonstrict
149endif 149endif
150 150
151if HEAVY_TESTS 151if HEAVY_TESTS
@@ -468,10 +468,10 @@ test_process_headers_SOURCES = \
468 test_process_headers.c mhd_has_in_name.h 468 test_process_headers.c mhd_has_in_name.h
469 469
470test_parse_cookies_SOURCES = \ 470test_parse_cookies_SOURCES = \
471 test_parse_cookies.c mhd_has_in_name.h 471 test_parse_cookies.c mhd_has_in_name.h mhd_has_param.h
472 472
473test_parse_cookies_invalid_SOURCES = \ 473test_parse_cookies_nonstrict_SOURCES = \
474 test_parse_cookies.c mhd_has_in_name.h 474 $(test_parse_cookies_SOURCES)
475 475
476test_process_arguments_SOURCES = \ 476test_process_arguments_SOURCES = \
477 test_process_arguments.c mhd_has_in_name.h 477 test_process_arguments.c mhd_has_in_name.h
diff --git a/src/testcurl/test_parse_cookies.c b/src/testcurl/test_parse_cookies.c
index d02a2b76..987ddbf4 100644
--- a/src/testcurl/test_parse_cookies.c
+++ b/src/testcurl/test_parse_cookies.c
@@ -1,14 +1,14 @@
1/* 1/*
2 This file is part of libmicrohttpd 2 This file is part of GNU libmicrohttpd
3 Copyright (C) 2007 Christian Grothoff 3 Copyright (C) 2007 Christian Grothoff
4 Copyright (C) 2014-2022 Evgeny Grin (Karlson2k) 4 Copyright (C) 2016-2022 Evgeny Grin (Karlson2k)
5 5
6 libmicrohttpd is free software; you can redistribute it and/or modify 6 GNU libmicrohttpd is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published 7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 3, or (at your 8 by the Free Software Foundation; either version 2, or (at your
9 option) any later version. 9 option) any later version.
10 10
11 libmicrohttpd is distributed in the hope that it will be useful, but 11 GNU libmicrohttpd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of 12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details. 14 General Public License for more details.
@@ -22,522 +22,1193 @@
22/** 22/**
23 * @file test_parse_cookies.c 23 * @file test_parse_cookies.c
24 * @brief Testcase for HTTP cookie parsing 24 * @brief Testcase for HTTP cookie parsing
25 * @author Christian Grothoff
26 * @author Karlson2k (Evgeny Grin) 25 * @author Karlson2k (Evgeny Grin)
26 * @author Christian Grothoff
27 */ 27 */
28 28
29#include "MHD_config.h" 29#include "mhd_options.h"
30#include "platform.h" 30#include "platform.h"
31#include <curl/curl.h> 31#include <curl/curl.h>
32#include <microhttpd.h> 32#include <microhttpd.h>
33#include <stdlib.h> 33#include <stdlib.h>
34#include <stdio.h>
35#include <string.h> 34#include <string.h>
36#include <time.h> 35#include <time.h>
37#include "mhd_has_in_name.h"
38 36
39#ifndef WINDOWS 37#ifndef _WIN32
38#include <sys/socket.h>
40#include <unistd.h> 39#include <unistd.h>
41#endif 40#endif
42 41
43static int use_invalid; 42#include "mhd_has_param.h"
43#include "mhd_has_in_name.h"
44 44
45struct CBC 45#ifndef MHD_STATICSTR_LEN_
46{ 46/**
47 char *buf; 47 * Determine length of static string / macro strings at compile time.
48 size_t pos; 48 */
49 size_t size; 49#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
50}; 50#endif /* ! MHD_STATICSTR_LEN_ */
51 51
52static size_t 52#ifndef CURL_VERSION_BITS
53copyBuffer (void *ptr, size_t size, size_t nmemb, void *ctx) 53#define CURL_VERSION_BITS(x,y,z) ((x) << 16 | (y) << 8 | (z))
54#endif /* ! CURL_VERSION_BITS */
55#ifndef CURL_AT_LEAST_VERSION
56#define CURL_AT_LEAST_VERSION(x,y,z) \
57 (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS (x, y, z))
58#endif /* ! CURL_AT_LEAST_VERSION */
59
60#ifndef _MHD_INSTRMACRO
61/* Quoted macro parameter */
62#define _MHD_INSTRMACRO(a) #a
63#endif /* ! _MHD_INSTRMACRO */
64#ifndef _MHD_STRMACRO
65/* Quoted expanded macro parameter */
66#define _MHD_STRMACRO(a) _MHD_INSTRMACRO (a)
67#endif /* ! _MHD_STRMACRO */
68
69#if defined(HAVE___FUNC__)
70#define externalErrorExit(ignore) \
71 _externalErrorExit_func (NULL, __func__, __LINE__)
72#define externalErrorExitDesc(errDesc) \
73 _externalErrorExit_func (errDesc, __func__, __LINE__)
74#define libcurlErrorExit(ignore) \
75 _libcurlErrorExit_func (NULL, __func__, __LINE__)
76#define libcurlErrorExitDesc(errDesc) \
77 _libcurlErrorExit_func (errDesc, __func__, __LINE__)
78#define mhdErrorExit(ignore) \
79 _mhdErrorExit_func (NULL, __func__, __LINE__)
80#define mhdErrorExitDesc(errDesc) \
81 _mhdErrorExit_func (errDesc, __func__, __LINE__)
82#define checkCURLE_OK(libcurlcall) \
83 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \
84 __func__, __LINE__)
85#elif defined(HAVE___FUNCTION__)
86#define externalErrorExit(ignore) \
87 _externalErrorExit_func (NULL, __FUNCTION__, __LINE__)
88#define externalErrorExitDesc(errDesc) \
89 _externalErrorExit_func (errDesc, __FUNCTION__, __LINE__)
90#define libcurlErrorExit(ignore) \
91 _libcurlErrorExit_func (NULL, __FUNCTION__, __LINE__)
92#define libcurlErrorExitDesc(errDesc) \
93 _libcurlErrorExit_func (errDesc, __FUNCTION__, __LINE__)
94#define mhdErrorExit(ignore) \
95 _mhdErrorExit_func (NULL, __FUNCTION__, __LINE__)
96#define mhdErrorExitDesc(errDesc) \
97 _mhdErrorExit_func (errDesc, __FUNCTION__, __LINE__)
98#define checkCURLE_OK(libcurlcall) \
99 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), \
100 __FUNCTION__, __LINE__)
101#else
102#define externalErrorExit(ignore) _externalErrorExit_func (NULL, NULL, __LINE__)
103#define externalErrorExitDesc(errDesc) \
104 _externalErrorExit_func (errDesc, NULL, __LINE__)
105#define libcurlErrorExit(ignore) _libcurlErrorExit_func (NULL, NULL, __LINE__)
106#define libcurlErrorExitDesc(errDesc) \
107 _libcurlErrorExit_func (errDesc, NULL, __LINE__)
108#define mhdErrorExit(ignore) _mhdErrorExit_func (NULL, NULL, __LINE__)
109#define mhdErrorExitDesc(errDesc) _mhdErrorExit_func (errDesc, NULL, __LINE__)
110#define checkCURLE_OK(libcurlcall) \
111 _checkCURLE_OK_func ((libcurlcall), _MHD_STRMACRO (libcurlcall), NULL, \
112 __LINE__)
113#endif
114
115
116_MHD_NORETURN static void
117_externalErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
54{ 118{
55 struct CBC *cbc = ctx; 119 fflush (stdout);
120 if ((NULL != errDesc) && (0 != errDesc[0]))
121 fprintf (stderr, "%s", errDesc);
122 else
123 fprintf (stderr, "System or external library call failed");
124 if ((NULL != funcName) && (0 != funcName[0]))
125 fprintf (stderr, " in %s", funcName);
126 if (0 < lineNum)
127 fprintf (stderr, " at line %d", lineNum);
56 128
57 if (cbc->pos + size * nmemb > cbc->size) 129 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
58 return 0; /* overflow */ 130 strerror (errno));
59 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb); 131#ifdef MHD_WINSOCK_SOCKETS
60 cbc->pos += size * nmemb; 132 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
61 return size * nmemb; 133#endif /* MHD_WINSOCK_SOCKETS */
134 fflush (stderr);
135 exit (99);
62} 136}
63 137
64 138
65static enum MHD_Result 139static char libcurl_errbuf[CURL_ERROR_SIZE] = "";
66ahc_echo (void *cls, 140
67 struct MHD_Connection *connection, 141_MHD_NORETURN static void
68 const char *url, 142_libcurlErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
69 const char *method,
70 const char *version,
71 const char *upload_data, size_t *upload_data_size,
72 void **req_cls)
73{ 143{
74 static int ptr; 144 fflush (stdout);
75 const int *puse_invalid = cls; 145 if ((NULL != errDesc) && (0 != errDesc[0]))
76 struct MHD_Response *response; 146 fprintf (stderr, "%s", errDesc);
77 enum MHD_Result ret; 147 else
78 const char *hdr; 148 fprintf (stderr, "CURL library call failed");
79 (void) version; (void) upload_data; (void) upload_data_size; /* Unused. Silent compiler warning. */ 149 if ((NULL != funcName) && (0 != funcName[0]))
150 fprintf (stderr, " in %s", funcName);
151 if (0 < lineNum)
152 fprintf (stderr, " at line %d", lineNum);
80 153
81 if (0 != strcmp (MHD_HTTP_METHOD_GET, method)) 154 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
82 return MHD_NO; /* unexpected method */ 155 strerror (errno));
83 if (&ptr != *req_cls) 156#ifdef MHD_WINSOCK_SOCKETS
84 { 157 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
85 *req_cls = &ptr; 158#endif /* MHD_WINSOCK_SOCKETS */
86 return MHD_YES; 159 if (0 != libcurl_errbuf[0])
87 } 160 fprintf (stderr, "Last libcurl error description: %s\n", libcurl_errbuf);
88 *req_cls = NULL;
89 161
90 if (! *puse_invalid) 162 fflush (stderr);
91 { 163 exit (99);
92 hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name1"); 164}
93 if ((hdr == NULL) || (0 != strcmp (hdr, "var1"))) 165
94 { 166
95 fprintf (stderr, "'name1' cookie decoded incorrectly.\n"); 167_MHD_NORETURN static void
96 exit (11); 168_mhdErrorExit_func (const char *errDesc, const char *funcName, int lineNum)
97 } 169{
98 hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name2"); 170 fflush (stdout);
99 if ((hdr == NULL) || (0 != strcmp (hdr, "var2"))) 171 if ((NULL != errDesc) && (0 != errDesc[0]))
100 { 172 fprintf (stderr, "%s", errDesc);
101 fprintf (stderr, "'name2' cookie decoded incorrectly.\n");
102 exit (11);
103 }
104 hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name3");
105 if ((hdr == NULL) || (0 != strcmp (hdr, "")))
106 {
107 fprintf (stderr, "'name3' cookie decoded incorrectly.\n");
108 exit (11);
109 }
110 hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name4");
111 if ((hdr == NULL) || (0 != strcmp (hdr, "var4 with spaces")))
112 {
113 fprintf (stderr, "'name4' cookie decoded incorrectly.\n");
114 exit (11);
115 }
116 hdr = MHD_lookup_connection_value (connection, MHD_COOKIE_KIND, "name5");
117 if ((hdr == NULL) || (0 != strcmp (hdr, "var_with_=_char")))
118 {
119 fprintf (stderr, "'name5' cookie decoded incorrectly.\n");
120 exit (11);
121 }
122 if (5 != MHD_get_connection_values_n (connection, MHD_COOKIE_KIND,
123 NULL, NULL))
124 {
125 fprintf (stderr, "The total number of cookie is not five.\n");
126 exit (12);
127 }
128 }
129 else 173 else
130 { 174 fprintf (stderr, "MHD unexpected error");
131 if (0 != MHD_get_connection_values_n (connection, MHD_COOKIE_KIND, 175 if ((NULL != funcName) && (0 != funcName[0]))
132 NULL, NULL)) 176 fprintf (stderr, " in %s", funcName);
133 { 177 if (0 < lineNum)
134 fprintf (stderr, "The total number of cookie is not zero.\n"); 178 fprintf (stderr, " at line %d", lineNum);
135 exit (12); 179
136 } 180 fprintf (stderr, ".\nLast errno value: %d (%s)\n", (int) errno,
137 } 181 strerror (errno));
138 response = MHD_create_response_from_buffer_copy (strlen (url), 182#ifdef MHD_WINSOCK_SOCKETS
139 url); 183 fprintf (stderr, "WSAGetLastError() value: %d\n", (int) WSAGetLastError ());
140 ret = MHD_queue_response (connection, MHD_HTTP_OK, response); 184#endif /* MHD_WINSOCK_SOCKETS */
141 MHD_destroy_response (response); 185
142 if (ret == MHD_NO) 186 fflush (stderr);
143 abort (); 187 exit (8);
144 return ret;
145} 188}
146 189
147 190
148/* Re-use the same port for all checks */ 191/* Could be increased to facilitate debugging */
149static uint16_t port; 192#define TIMEOUTS_VAL 5
150 193
151static unsigned int 194#define EXPECTED_URI_BASE_PATH "/"
152testExternalGet (int test_number) 195
196#define URL_SCHEME "http:/" "/"
197
198#define URL_HOST "127.0.0.1"
199
200#define URL_SCHEME_HOST URL_SCHEME URL_HOST
201
202#define PAGE \
203 "<html><head><title>libmicrohttpd test page</title></head>" \
204 "<body>Success!</body></html>"
205
206
207#ifndef MHD_STATICSTR_LEN_
208/**
209 * Determine length of static string / macro strings at compile time.
210 */
211#define MHD_STATICSTR_LEN_(macro) (sizeof(macro) / sizeof(char) - 1)
212#endif /* ! MHD_STATICSTR_LEN_ */
213
214
215struct strct_str_len
153{ 216{
154 struct MHD_Daemon *d; 217 const char *str;
155 CURL *c; 218 const size_t len;
156 char buf[2048]; 219};
157 struct CBC cbc;
158 CURLM *multi;
159 CURLMcode mret;
160 fd_set rs;
161 fd_set ws;
162 fd_set es;
163 MHD_socket maxsock;
164#ifdef MHD_WINSOCK_SOCKETS
165 int maxposixs; /* Max socket number unused on W32 */
166#else /* MHD_POSIX_SOCKETS */
167#define maxposixs maxsock
168#endif /* MHD_POSIX_SOCKETS */
169 int running;
170 struct CURLMsg *msg;
171 time_t start;
172 struct timeval tv;
173 220
174 multi = NULL; 221#define STR_LEN_(str) {str, MHD_STATICSTR_LEN_(str)}
175 cbc.buf = buf; 222#define STR_NULL_ {NULL, 0}
176 cbc.size = 2048; 223
177 cbc.pos = 0; 224struct strct_cookie
178 d = MHD_start_daemon (MHD_USE_ERROR_LOG, 225{
179 port, NULL, NULL, &ahc_echo, &use_invalid, 226 struct strct_str_len name;
180 MHD_OPTION_END); 227 struct strct_str_len value;
181 if (d == NULL) 228};
182 return 256; 229
183 if (0 == port) 230#define COOKIE_(name,value) {STR_LEN_(name), STR_LEN_(value)}
231#define COOKIE_NULL {STR_NULL_, STR_NULL_}
232
233struct strct_test_data
234{
235 unsigned int line_num;
236 const char *header_str;
237 unsigned int num_cookies_non_strict;
238 unsigned int num_cookies_strict;
239 struct strct_cookie cookies[5];
240};
241
242static const struct strct_test_data test_data[] = {
184 { 243 {
185 const union MHD_DaemonInfo *dinfo; 244 __LINE__,
186 dinfo = MHD_get_daemon_info (d, MHD_DAEMON_INFO_BIND_PORT); 245 "name1=var1; name2=var2; name3=; " \
187 if ((NULL == dinfo) || (0 == dinfo->port) ) 246 "name4=\"var4 with spaces\"; " \
247 "name5=var_with_=_char",
248 5,
249 0,
188 { 250 {
189 MHD_stop_daemon (d); return 32; 251 COOKIE_ ("name1", "var1"),
252 COOKIE_ ("name2", "var2"),
253 COOKIE_ ("name3", ""),
254 COOKIE_ ("name4", "var4 with spaces"),
255 COOKIE_ ("name5", "var_with_=_char")
190 } 256 }
191 port = dinfo->port; 257 },
192 }
193 c = curl_easy_init ();
194 curl_easy_setopt (c, CURLOPT_URL, "http://127.0.0.1/hello_world");
195 curl_easy_setopt (c, CURLOPT_PORT, (long) port);
196 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
197 curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
198 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1L);
199 if (! use_invalid)
200 { 258 {
201 if (0 == test_number) 259 __LINE__,
260 "name1=var1;name2=var2;name3=;" \
261 "name4=\"var4 with spaces\";" \
262 "name5=var_with_=_char",
263 5,
264 0,
202 { 265 {
203 curl_easy_setopt (c, CURLOPT_COOKIE, 266 COOKIE_ ("name1", "var1"),
204 "name1=var1; name2=var2; name3=; " \ 267 COOKIE_ ("name2", "var2"),
205 "name4=\"var4 with spaces\"; " \ 268 COOKIE_ ("name3", ""),
206 "name5=var_with_=_char"); 269 COOKIE_ ("name4", "var4 with spaces"),
270 COOKIE_ ("name5", "var_with_=_char")
207 } 271 }
208 else if (1 == test_number) 272 },
273 {
274 __LINE__,
275 "name1=var1; name2=var2; name3=; " \
276 "name4=\"var4 with spaces\"; " \
277 "name5=var_with_=_char\t \t",
278 5,
279 0,
209 { 280 {
210 curl_easy_setopt (c, CURLOPT_COOKIE, 281 COOKIE_ ("name1", "var1"),
211 "name1=var1;name2=var2;name3=;" \ 282 COOKIE_ ("name2", "var2"),
212 "name4=\"var4 with spaces\";" \ 283 COOKIE_ ("name3", ""),
213 "name5=var_with_=_char"); 284 COOKIE_ ("name4", "var4 with spaces"),
285 COOKIE_ ("name5", "var_with_=_char")
214 } 286 }
215 else if (2 == test_number) 287 },
288 {
289 __LINE__,
290 "name1=var1;;name2=var2;;name3=;;" \
291 "name4=\"var4 with spaces\";;" \
292 "name5=var_with_=_char;\t \t",
293 5,
294 0,
216 { 295 {
217 curl_easy_setopt (c, CURLOPT_COOKIE, 296 COOKIE_ ("name1", "var1"),
218 "name1=var1; name2=var2; name3=; " \ 297 COOKIE_ ("name2", "var2"),
219 "name4=\"var4 with spaces\"; " \ 298 COOKIE_ ("name3", ""),
220 "name5=var_with_=_char\t \t"); 299 COOKIE_ ("name4", "var4 with spaces"),
300 COOKIE_ ("name5", "var_with_=_char")
221 } 301 }
222 else if (3 == test_number) 302 },
303 {
304 __LINE__,
305 "name3=; name1=var1; name2=var2; " \
306 "name5=var_with_=_char;" \
307 "name4=\"var4 with spaces\"",
308 5,
309 0,
223 { 310 {
224 curl_easy_setopt (c, CURLOPT_COOKIE, 311 COOKIE_ ("name1", "var1"),
225 "name1=var1;;name2=var2;;name3=;;" \ 312 COOKIE_ ("name2", "var2"),
226 "name4=\"var4 with spaces\";;" \ 313 COOKIE_ ("name3", ""),
227 "name5=var_with_=_char;\t \t"); 314 COOKIE_ ("name4", "var4 with spaces"),
315 COOKIE_ ("name5", "var_with_=_char")
228 } 316 }
229 else if (4 == test_number) 317 },
318 {
319 __LINE__,
320 "name2=var2; name1=var1; " \
321 "name5=var_with_=_char; name3=; " \
322 "name4=\"var4 with spaces\";",
323 5,
324 0,
230 { 325 {
231 curl_easy_setopt (c, CURLOPT_COOKIE, 326 COOKIE_ ("name1", "var1"),
232 "name1=var1 ;name2=var2 ;name3= ;" \ 327 COOKIE_ ("name2", "var2"),
233 "name4=\"var4 with spaces\" ;" \ 328 COOKIE_ ("name3", ""),
234 "name5=var_with_=_char ;"); 329 COOKIE_ ("name4", "var4 with spaces"),
330 COOKIE_ ("name5", "var_with_=_char")
235 } 331 }
236 else if (5 == test_number) 332 },
333 {
334 __LINE__,
335 "name2=var2; name1=var1; " \
336 "name5=var_with_=_char; " \
337 "name4=\"var4 with spaces\"; name3=",
338 5,
339 0,
237 { 340 {
238 curl_easy_setopt (c, CURLOPT_COOKIE, 341 COOKIE_ ("name1", "var1"),
239 "name3=; name1=var1; name2=var2; " \ 342 COOKIE_ ("name2", "var2"),
240 "name5=var_with_=_char;" \ 343 COOKIE_ ("name3", ""),
241 "name4=\"var4 with spaces\""); 344 COOKIE_ ("name4", "var4 with spaces"),
345 COOKIE_ ("name5", "var_with_=_char")
242 } 346 }
243 else if (6 == test_number) 347 },
348 {
349 __LINE__,
350 "name2=var2; name1=var1; " \
351 "name4=\"var4 with spaces\"; " \
352 "name5=var_with_=_char; name3=;",
353 5,
354 0,
244 { 355 {
245 curl_easy_setopt (c, CURLOPT_COOKIE, 356 COOKIE_ ("name1", "var1"),
246 "name2=var2; name1=var1; " \ 357 COOKIE_ ("name2", "var2"),
247 "name5=var_with_=_char; name3=; " \ 358 COOKIE_ ("name3", ""),
248 "name4=\"var4 with spaces\";"); 359 COOKIE_ ("name4", "var4 with spaces"),
360 COOKIE_ ("name5", "var_with_=_char")
249 } 361 }
250 else if (7 == test_number) 362 },
363 {
364 __LINE__,
365 ";;;;;;;;name1=var1; name2=var2; name3=; " \
366 "name4=\"var4 with spaces\"; " \
367 "name5=var_with_=_char",
368 5,
369 0,
251 { 370 {
252 curl_easy_setopt (c, CURLOPT_COOKIE, 371 COOKIE_ ("name1", "var1"),
253 "name2=var2; name1=var1; " \ 372 COOKIE_ ("name2", "var2"),
254 "name5=var_with_=_char; " \ 373 COOKIE_ ("name3", ""),
255 "name4=\"var4 with spaces\"; name3="); 374 COOKIE_ ("name4", "var4 with spaces"),
375 COOKIE_ ("name5", "var_with_=_char")
256 } 376 }
257 else if (8 == test_number) 377 },
378 {
379 __LINE__,
380 "name1=var1; name2=var2; name3=; " \
381 "name4=\"var4 with spaces\"; ; ; ; ; " \
382 "name5=var_with_=_char",
383 5,
384 0,
258 { 385 {
259 curl_easy_setopt (c, CURLOPT_COOKIE, 386 COOKIE_ ("name1", "var1"),
260 "name2=var2; name1=var1; " \ 387 COOKIE_ ("name2", "var2"),
261 "name4=\"var4 with spaces\"; " \ 388 COOKIE_ ("name3", ""),
262 "name5=var_with_=_char; name3=;"); 389 COOKIE_ ("name4", "var4 with spaces"),
390 COOKIE_ ("name5", "var_with_=_char")
263 } 391 }
264 else if (9 == test_number) 392 },
393 {
394 __LINE__,
395 "name1=var1; name2=var2; name3=; " \
396 "name4=\"var4 with spaces\"; " \
397 "name5=var_with_=_char;;;;;;;;",
398 5,
399 0,
265 { 400 {
266 curl_easy_setopt (c, CURLOPT_COOKIE, 401 COOKIE_ ("name1", "var1"),
267 ";;;;;;;;name1=var1; name2=var2; name3=; " \ 402 COOKIE_ ("name2", "var2"),
268 "name4=\"var4 with spaces\"; " \ 403 COOKIE_ ("name3", ""),
269 "name5=var_with_=_char"); 404 COOKIE_ ("name4", "var4 with spaces"),
405 COOKIE_ ("name5", "var_with_=_char")
270 } 406 }
271 else if (10 == test_number) 407 },
408 {
409 __LINE__,
410 "name1=var1; name2=var2; " \
411 "name4=\"var4 with spaces\"" \
412 "name5=var_with_=_char; ; ; ; ; name3=",
413 5,
414 0,
272 { 415 {
273 curl_easy_setopt (c, CURLOPT_COOKIE, 416 COOKIE_ ("name1", "var1"),
274 "name1=var1; name2=var2; name3=; " \ 417 COOKIE_ ("name2", "var2"),
275 "name4=\"var4 with spaces\"; ; ; ; ; " \ 418 COOKIE_ ("name3", ""),
276 "name5=var_with_=_char"); 419 COOKIE_ ("name4", "var4 with spaces"),
420 COOKIE_ ("name5", "var_with_=_char")
277 } 421 }
278 else if (11 == test_number) 422 },
423 {
424 __LINE__,
425 "name5=var_with_=_char ;" \
426 "name1=var1; name2=var2; name3=; " \
427 "name4=\"var4 with spaces\" ",
428 5,
429 0,
279 { 430 {
280 curl_easy_setopt (c, CURLOPT_COOKIE, 431 COOKIE_ ("name1", "var1"),
281 "name1=var1; name2=var2; name3=; " \ 432 COOKIE_ ("name2", "var2"),
282 "name4=\"var4 with spaces\"; " \ 433 COOKIE_ ("name3", ""),
283 "name5=var_with_=_char;;;;;;;;"); 434 COOKIE_ ("name4", "var4 with spaces"),
435 COOKIE_ ("name5", "var_with_=_char")
284 } 436 }
285 else if (12 == test_number) 437 },
438 {
439 __LINE__,
440 "name5=var_with_=_char; name4=\"var4 with spaces\";" \
441 "name1=var1; name2=var2; name3=",
442 5,
443 0,
286 { 444 {
287 curl_easy_setopt (c, CURLOPT_COOKIE, 445 COOKIE_ ("name1", "var1"),
288 "name1=var1; name2=var2; " \ 446 COOKIE_ ("name2", "var2"),
289 "name4=\"var4 with spaces\"" \ 447 COOKIE_ ("name3", ""),
290 "name5=var_with_=_char; ; ; ; ; name3="); 448 COOKIE_ ("name4", "var4 with spaces"),
449 COOKIE_ ("name5", "var_with_=_char")
291 } 450 }
292 else if (13 == test_number) 451 },
452 {
453 __LINE__,
454 "",
455 0,
456 0,
293 { 457 {
294 curl_easy_setopt (c, CURLOPT_COOKIE, 458 COOKIE_NULL,
295 "name5=var_with_=_char ;" \ 459 COOKIE_NULL,
296 "name1=var1; name2=var2; name3=; " \ 460 COOKIE_NULL,
297 "name4=\"var4 with spaces\" "); 461 COOKIE_NULL,
462 COOKIE_NULL
298 } 463 }
299 else if (14 == test_number) 464 },
465 {
466 __LINE__,
467 " ",
468 0,
469 0,
300 { 470 {
301 curl_easy_setopt (c, CURLOPT_COOKIE, 471 COOKIE_NULL,
302 "name5=var_with_=_char; name4=\"var4 with spaces\";" \ 472 COOKIE_NULL,
303 "name1=var1; name2=var2; name3="); 473 COOKIE_NULL,
474 COOKIE_NULL,
475 COOKIE_NULL
304 } 476 }
305 } 477 },
306 else
307 { 478 {
308 if (0 == test_number) 479 __LINE__,
480 "\t",
481 0,
482 0,
309 { 483 {
310 (void) 0; /* No cookie */ 484 COOKIE_NULL,
485 COOKIE_NULL,
486 COOKIE_NULL,
487 COOKIE_NULL,
488 COOKIE_NULL
311 } 489 }
312 else if (1 == test_number) 490 },
491 {
492 __LINE__,
493 "var=,",
494 0,
495 0,
313 { 496 {
314 curl_easy_setopt (c, CURLOPT_COOKIE, 497 COOKIE_NULL,
315 ""); 498 COOKIE_NULL,
499 COOKIE_NULL,
500 COOKIE_NULL,
501 COOKIE_NULL
316 } 502 }
317 else if (2 == test_number) 503 },
504 {
505 __LINE__,
506 "var=\"\\ \"",
507 0,
508 0,
318 { 509 {
319 curl_easy_setopt (c, CURLOPT_COOKIE, 510 COOKIE_NULL,
320 " "); 511 COOKIE_NULL,
512 COOKIE_NULL,
513 COOKIE_NULL,
514 COOKIE_NULL
321 } 515 }
322 else if (3 == test_number) 516 },
517 {
518 __LINE__,
519 "var=value space",
520 0,
521 0,
323 { 522 {
324 curl_easy_setopt (c, CURLOPT_COOKIE, 523 COOKIE_NULL,
325 "\t"); 524 COOKIE_NULL,
525 COOKIE_NULL,
526 COOKIE_NULL,
527 COOKIE_NULL
326 } 528 }
327 else if (4 == test_number) 529 },
530 {
531 __LINE__,
532 "var=value\ttab",
533 0,
534 0,
328 { 535 {
329 curl_easy_setopt (c, CURLOPT_COOKIE, 536 COOKIE_NULL,
330 "var=,"); 537 COOKIE_NULL,
538 COOKIE_NULL,
539 COOKIE_NULL,
540 COOKIE_NULL
331 } 541 }
332 else if (5 == test_number) 542 },
543 {
544 __LINE__,
545 "=",
546 0,
547 0,
333 { 548 {
334 curl_easy_setopt (c, CURLOPT_COOKIE, 549 COOKIE_NULL,
335 "var=\"\\ \""); 550 COOKIE_NULL,
551 COOKIE_NULL,
552 COOKIE_NULL,
553 COOKIE_NULL
336 } 554 }
337 else if (6 == test_number) 555 },
556 {
557 __LINE__,
558 "====",
559 0,
560 0,
338 { 561 {
339 curl_easy_setopt (c, CURLOPT_COOKIE, 562 COOKIE_NULL,
340 "var=value space"); 563 COOKIE_NULL,
564 COOKIE_NULL,
565 COOKIE_NULL,
566 COOKIE_NULL
341 } 567 }
342 else if (7 == test_number) 568 },
569 {
570 __LINE__,
571 ";=",
572 0,
573 0,
343 { 574 {
344 curl_easy_setopt (c, CURLOPT_COOKIE, 575 COOKIE_NULL,
345 "var=value\ttab"); 576 COOKIE_NULL,
577 COOKIE_NULL,
578 COOKIE_NULL,
579 COOKIE_NULL
346 } 580 }
347 else if (8 == test_number) 581 },
582 {
583 __LINE__,
584 "var",
585 0,
586 0,
348 { 587 {
349 curl_easy_setopt (c, CURLOPT_COOKIE, 588 COOKIE_NULL,
350 "="); 589 COOKIE_NULL,
590 COOKIE_NULL,
591 COOKIE_NULL,
592 COOKIE_NULL
351 } 593 }
352 else if (9 == test_number) 594 },
595 {
596 __LINE__,
597 "=;",
598 0,
599 0,
353 { 600 {
354 curl_easy_setopt (c, CURLOPT_COOKIE, 601 COOKIE_NULL,
355 "===="); 602 COOKIE_NULL,
603 COOKIE_NULL,
604 COOKIE_NULL,
605 COOKIE_NULL
356 } 606 }
357 else if (10 == test_number) 607 },
608 {
609 __LINE__,
610 "= ;",
611 0,
612 0,
613 {
614 COOKIE_NULL,
615 COOKIE_NULL,
616 COOKIE_NULL,
617 COOKIE_NULL,
618 COOKIE_NULL
619 }
620 },
621 {
622 __LINE__,
623 ";= ;",
624 0,
625 0,
358 { 626 {
359 curl_easy_setopt (c, CURLOPT_COOKIE, 627 COOKIE_NULL,
360 ";="); 628 COOKIE_NULL,
629 COOKIE_NULL,
630 COOKIE_NULL,
631 COOKIE_NULL
361 } 632 }
362 else if (11 == test_number) 633 }
634};
635
636/* Global parameters */
637static int verbose;
638static int oneone; /**< If false use HTTP/1.0 for requests*/
639static int use_non_strict;
640
641static void
642test_global_init (void)
643{
644 libcurl_errbuf[0] = 0;
645
646 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
647 externalErrorExit ();
648}
649
650
651static void
652test_global_cleanup (void)
653{
654 curl_global_cleanup ();
655}
656
657
658struct CBC
659{
660 char *buf;
661 size_t pos;
662 size_t size;
663};
664
665
666static size_t
667copyBuffer (void *ptr,
668 size_t size,
669 size_t nmemb,
670 void *ctx)
671{
672 struct CBC *cbc = ctx;
673
674 if (cbc->pos + size * nmemb > cbc->size)
675 return 0; /* overflow */
676 memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
677 cbc->pos += size * nmemb;
678 return size * nmemb;
679}
680
681
682struct ahc_cls_type
683{
684 const char *rq_method;
685 const char *rq_url;
686 const struct strct_test_data *check;
687};
688
689
690static enum MHD_Result
691ahcCheck (void *cls,
692 struct MHD_Connection *connection,
693 const char *url,
694 const char *method,
695 const char *version,
696 const char *upload_data, size_t *upload_data_size,
697 void **req_cls)
698{
699 static int marker;
700 struct MHD_Response *response;
701 enum MHD_Result ret;
702 struct ahc_cls_type *const param = (struct ahc_cls_type *) cls;
703 const unsigned int expected_num_cookies =
704 use_non_strict ? param->check->num_cookies_non_strict :
705 param->check->num_cookies_strict;
706 unsigned int i;
707 int cookie_failed;
708
709 if (NULL == param)
710 mhdErrorExitDesc ("cls parameter is NULL");
711
712 if (oneone)
713 {
714 if (0 != strcmp (version, MHD_HTTP_VERSION_1_1))
715 mhdErrorExitDesc ("Unexpected HTTP version");
716 }
717 else
718 {
719 if (0 != strcmp (version, MHD_HTTP_VERSION_1_0))
720 mhdErrorExitDesc ("Unexpected HTTP version");
721 }
722
723 if (0 != strcmp (url, param->rq_url))
724 mhdErrorExitDesc ("Unexpected URI");
725
726 if (NULL != upload_data)
727 mhdErrorExitDesc ("'upload_data' is not NULL");
728
729 if (NULL == upload_data_size)
730 mhdErrorExitDesc ("'upload_data_size' pointer is NULL");
731
732 if (0 != *upload_data_size)
733 mhdErrorExitDesc ("'*upload_data_size' value is not zero");
734
735 if (0 != strcmp (param->rq_method, method))
736 mhdErrorExitDesc ("Unexpected request method");
737
738 cookie_failed = 0;
739 for (i = 0; i < expected_num_cookies; ++i)
740 {
741 const char *cookie_val;
742 size_t cookie_val_len;
743 const struct strct_cookie *const cookie_data = param->check->cookies + i;
744 if (NULL == cookie_data->name.str)
745 externalErrorExitDesc ("Broken test data");
746 if (NULL == cookie_data->value.str)
747 externalErrorExitDesc ("Broken test data");
748
749 cookie_val =
750 MHD_lookup_connection_value (connection,
751 MHD_COOKIE_KIND,
752 cookie_data->name.str);
753 if (cookie_val == NULL)
363 { 754 {
364 curl_easy_setopt (c, CURLOPT_COOKIE, 755 fprintf (stderr, "'%s' cookie not found.\n",
365 "var"); 756 cookie_data->name.str);
757 cookie_failed = 1;
366 } 758 }
367 else if (12 == test_number) 759 else if (0 != strcmp (cookie_val,
760 cookie_data->value.str))
368 { 761 {
369 curl_easy_setopt (c, CURLOPT_COOKIE, 762 fprintf (stderr, "'%s' cookie decoded incorrectly.\n"
370 "=;"); 763 "Expected: %s\nGot: %s\n",
764 cookie_data->name.str,
765 cookie_data->value.str,
766 cookie_val);
767 cookie_failed = 1;
371 } 768 }
372 else if (13 == test_number) 769 else if (MHD_YES !=
770 MHD_lookup_connection_value_n (connection,
771 MHD_COOKIE_KIND,
772 cookie_data->name.str,
773 cookie_data->name.len,
774 &cookie_val, &cookie_val_len))
373 { 775 {
374 curl_easy_setopt (c, CURLOPT_COOKIE, 776 fprintf (stderr, "'%s' (length %lu) cookie not found.\n",
375 "= ;"); 777 cookie_data->name.str,
778 (unsigned long) cookie_data->name.len);
779 cookie_failed = 1;
376 } 780 }
377 else if (14 == test_number) 781 else
378 { 782 {
379 curl_easy_setopt (c, CURLOPT_COOKIE, 783 if (cookie_data->value.len != cookie_val_len)
380 ";= ;"); 784 {
785 fprintf (stderr, "'%s' (length %lu) cookie has wrong value length.\n"
786 "Expected: %lu\nGot: %lu\n",
787 cookie_data->name.str,
788 (unsigned long) cookie_data->name.len,
789 (unsigned long) cookie_data->value.len,
790 (unsigned long) cookie_val_len);
791 cookie_failed = 1;
792 }
793 else if (0 != memcmp (cookie_val, cookie_data->value.str, cookie_val_len))
794 {
795 fprintf (stderr, "'%s' (length %lu) cookie has wrong value.\n"
796 "Expected: %.*s\nGot: %.*s\n",
797 cookie_data->name.str,
798 (unsigned long) cookie_data->name.len,
799 (int) cookie_data->value.len, cookie_data->value.str,
800 (int) cookie_val_len, cookie_val);
801 cookie_failed = 1;
802 }
381 } 803 }
382 } 804 }
805 if (((int) expected_num_cookies) !=
806 MHD_get_connection_values_n (connection, MHD_COOKIE_KIND, NULL, NULL))
807 {
808 fprintf (stderr, "Wrong total number of cookies.\n"
809 "Expected: %u\nGot: %d\n",
810 expected_num_cookies,
811 MHD_get_connection_values_n (connection, MHD_COOKIE_KIND, NULL,
812 NULL));
813 cookie_failed = 1;
814 }
815 if (cookie_failed)
816 return MHD_NO; /* Break connection */
817
818 if (&marker != *req_cls)
819 {
820 *req_cls = &marker;
821 return MHD_YES;
822 }
823 *req_cls = NULL;
824
825 response =
826 MHD_create_response_from_buffer_static (MHD_STATICSTR_LEN_ (PAGE),
827 PAGE);
828 if (NULL == response)
829 mhdErrorExitDesc ("Failed to create response");
830
831 ret = MHD_queue_response (connection,
832 MHD_HTTP_OK,
833 response);
834 MHD_destroy_response (response);
835 if (MHD_YES != ret)
836 mhdErrorExitDesc ("Failed to queue response");
383 837
384 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); 838 return ret;
385 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L); 839}
386 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 150L); 840
387 /* NOTE: use of CONNECTTIMEOUT without also 841
388 setting NOSIGNAL results in really weird 842static int
389 crashes on my system! */ 843libcurl_debug_cb (CURL *handle,
390 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L); 844 curl_infotype type,
845 char *data,
846 size_t size,
847 void *userptr)
848{
849 static const char excess_mark[] = "Excess found";
850 static const size_t excess_mark_len = MHD_STATICSTR_LEN_ (excess_mark);
391 851
852 (void) handle;
853 (void) userptr;
392 854
393 multi = curl_multi_init (); 855#ifdef _DEBUG
394 if (multi == NULL) 856 switch (type)
395 { 857 {
396 curl_easy_cleanup (c); 858 case CURLINFO_TEXT:
397 MHD_stop_daemon (d); 859 fprintf (stderr, "* %.*s", (int) size, data);
398 return 512; 860 break;
861 case CURLINFO_HEADER_IN:
862 fprintf (stderr, "< %.*s", (int) size, data);
863 break;
864 case CURLINFO_HEADER_OUT:
865 fprintf (stderr, "> %.*s", (int) size, data);
866 break;
867 case CURLINFO_DATA_IN:
868#if 0
869 fprintf (stderr, "<| %.*s\n", (int) size, data);
870#endif
871 break;
872 case CURLINFO_DATA_OUT:
873 case CURLINFO_SSL_DATA_IN:
874 case CURLINFO_SSL_DATA_OUT:
875 case CURLINFO_END:
876 default:
877 break;
878 }
879#endif /* _DEBUG */
880 if (CURLINFO_TEXT == type)
881 {
882 if ((size >= excess_mark_len) &&
883 (0 == memcmp (data, excess_mark, excess_mark_len)))
884 mhdErrorExitDesc ("Extra data has been detected in MHD reply");
399 } 885 }
400 mret = curl_multi_add_handle (multi, c); 886 return 0;
401 if (mret != CURLM_OK) 887}
888
889
890static CURL *
891setupCURL (void *cbc, uint16_t port)
892{
893 CURL *c;
894
895 c = curl_easy_init ();
896 if (NULL == c)
897 libcurlErrorExitDesc ("curl_easy_init() failed");
898
899 if ((CURLE_OK != curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1L)) ||
900 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEFUNCTION,
901 &copyBuffer)) ||
902 (CURLE_OK != curl_easy_setopt (c, CURLOPT_WRITEDATA, cbc)) ||
903 (CURLE_OK != curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT,
904 ((long) TIMEOUTS_VAL))) ||
905 (CURLE_OK != curl_easy_setopt (c, CURLOPT_HTTP_VERSION,
906 (oneone) ?
907 CURL_HTTP_VERSION_1_1 :
908 CURL_HTTP_VERSION_1_0)) ||
909 (CURLE_OK != curl_easy_setopt (c, CURLOPT_TIMEOUT,
910 ((long) TIMEOUTS_VAL))) ||
911 (CURLE_OK != curl_easy_setopt (c, CURLOPT_ERRORBUFFER,
912 libcurl_errbuf)) ||
913 (CURLE_OK != curl_easy_setopt (c, CURLOPT_FAILONERROR, 0L)) ||
914#ifdef _DEBUG
915 (CURLE_OK != curl_easy_setopt (c, CURLOPT_VERBOSE, 1L)) ||
916#endif /* _DEBUG */
917 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEBUGFUNCTION,
918 &libcurl_debug_cb)) ||
919#if CURL_AT_LEAST_VERSION (7, 19, 4)
920 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PROTOCOLS, CURLPROTO_HTTP)) ||
921#endif /* CURL_AT_LEAST_VERSION (7, 19, 4) */
922#if CURL_AT_LEAST_VERSION (7, 45, 0)
923 (CURLE_OK != curl_easy_setopt (c, CURLOPT_DEFAULT_PROTOCOL, "http")) ||
924#endif /* CURL_AT_LEAST_VERSION (7, 45, 0) */
925 (CURLE_OK != curl_easy_setopt (c, CURLOPT_PORT, ((long) port))))
926 libcurlErrorExitDesc ("curl_easy_setopt() failed");
927
928 if (CURLE_OK !=
929 curl_easy_setopt (c, CURLOPT_URL,
930 URL_SCHEME_HOST EXPECTED_URI_BASE_PATH))
931 libcurlErrorExitDesc ("Cannot set request URL");
932
933 return c;
934}
935
936
937static CURLcode
938performQueryExternal (struct MHD_Daemon *d, CURL *c, CURLM **multi_reuse)
939{
940 CURLM *multi;
941 time_t start;
942 struct timeval tv;
943 CURLcode ret;
944
945 ret = CURLE_FAILED_INIT; /* will be replaced with real result */
946 if (NULL != *multi_reuse)
947 multi = *multi_reuse;
948 else
402 { 949 {
403 curl_multi_cleanup (multi); 950 multi = curl_multi_init ();
404 curl_easy_cleanup (c); 951 if (multi == NULL)
405 MHD_stop_daemon (d); 952 libcurlErrorExitDesc ("curl_multi_init() failed");
406 return 1024; 953 *multi_reuse = multi;
407 } 954 }
955 if (CURLM_OK != curl_multi_add_handle (multi, c))
956 libcurlErrorExitDesc ("curl_multi_add_handle() failed");
957
408 start = time (NULL); 958 start = time (NULL);
409 while ((time (NULL) - start < 5) && (multi != NULL)) 959 while (time (NULL) - start <= TIMEOUTS_VAL)
410 { 960 {
411 maxsock = MHD_INVALID_SOCKET; 961 fd_set rs;
412 maxposixs = -1; 962 fd_set ws;
963 fd_set es;
964 MHD_socket maxMhdSk;
965 int maxCurlSk;
966 int running;
967
968 maxMhdSk = MHD_INVALID_SOCKET;
969 maxCurlSk = -1;
413 FD_ZERO (&rs); 970 FD_ZERO (&rs);
414 FD_ZERO (&ws); 971 FD_ZERO (&ws);
415 FD_ZERO (&es); 972 FD_ZERO (&es);
416 curl_multi_perform (multi, &running); 973 if (NULL != multi)
417 mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs);
418 if (mret != CURLM_OK)
419 { 974 {
420 curl_multi_remove_handle (multi, c); 975 curl_multi_perform (multi, &running);
421 curl_multi_cleanup (multi); 976 if (0 == running)
422 curl_easy_cleanup (c); 977 {
423 MHD_stop_daemon (d); 978 struct CURLMsg *msg;
424 return 2048; 979 int msgLeft;
980 int totalMsgs = 0;
981 do
982 {
983 msg = curl_multi_info_read (multi, &msgLeft);
984 if (NULL == msg)
985 libcurlErrorExitDesc ("curl_multi_info_read() failed");
986 totalMsgs++;
987 if (CURLMSG_DONE == msg->msg)
988 ret = msg->data.result;
989 } while (msgLeft > 0);
990 if (1 != totalMsgs)
991 {
992 fprintf (stderr,
993 "curl_multi_info_read returned wrong "
994 "number of results (%d).\n",
995 totalMsgs);
996 externalErrorExit ();
997 }
998 curl_multi_remove_handle (multi, c);
999 multi = NULL;
1000 }
1001 else
1002 {
1003 if (CURLM_OK != curl_multi_fdset (multi, &rs, &ws, &es, &maxCurlSk))
1004 libcurlErrorExitDesc ("curl_multi_fdset() failed");
1005 }
425 } 1006 }
426 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) 1007 if (NULL == multi)
427 { 1008 { /* libcurl has finished, check whether MHD still needs to perform cleanup */
428 curl_multi_remove_handle (multi, c); 1009 if (0 != MHD_get_timeout64s (d))
429 curl_multi_cleanup (multi); 1010 break; /* MHD finished as well */
430 curl_easy_cleanup (c);
431 MHD_stop_daemon (d);
432 return 4096;
433 } 1011 }
1012 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxMhdSk))
1013 mhdErrorExitDesc ("MHD_get_fdset() failed");
434 tv.tv_sec = 0; 1014 tv.tv_sec = 0;
435 tv.tv_usec = 1000; 1015 tv.tv_usec = 200000;
436 if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) 1016 if (0 == MHD_get_timeout64s (d))
1017 tv.tv_usec = 0;
1018 else
1019 {
1020 long curl_to = -1;
1021 curl_multi_timeout (multi, &curl_to);
1022 if (0 == curl_to)
1023 tv.tv_usec = 0;
1024 }
1025#ifdef MHD_POSIX_SOCKETS
1026 if (maxMhdSk > maxCurlSk)
1027 maxCurlSk = maxMhdSk;
1028#endif /* MHD_POSIX_SOCKETS */
1029 if (-1 == select (maxCurlSk + 1, &rs, &ws, &es, &tv))
437 { 1030 {
438#ifdef MHD_POSIX_SOCKETS 1031#ifdef MHD_POSIX_SOCKETS
439 if (EINTR != errno) 1032 if (EINTR != errno)
440 { 1033 externalErrorExitDesc ("Unexpected select() error");
441 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n",
442 (int) errno, __LINE__);
443 fflush (stderr);
444 exit (99);
445 }
446#else 1034#else
447 if ((WSAEINVAL != WSAGetLastError ()) || 1035 if ((WSAEINVAL != WSAGetLastError ()) ||
448 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) ) 1036 (0 != rs.fd_count) || (0 != ws.fd_count) || (0 != es.fd_count) )
449 { 1037 externalErrorExitDesc ("Unexpected select() error");
450 fprintf (stderr, "Unexpected select() error: %d. Line: %d\n", 1038 Sleep ((unsigned long) tv.tv_usec / 1000);
451 (int) WSAGetLastError (), __LINE__);
452 fflush (stderr);
453 exit (99);
454 }
455 Sleep (1);
456#endif 1039#endif
457 } 1040 }
458 curl_multi_perform (multi, &running); 1041 if (MHD_YES != MHD_run_from_select (d, &rs, &ws, &es))
459 if (0 == running) 1042 mhdErrorExitDesc ("MHD_run_from_select() failed");
460 { 1043 }
461 int pending; 1044
462 int curl_fine = 0; 1045 return ret;
463 while (NULL != (msg = curl_multi_info_read (multi, &pending))) 1046}
464 { 1047
465 if (msg->msg == CURLMSG_DONE) 1048
466 { 1049/**
467 if (msg->data.result == CURLE_OK) 1050 * Check request result
468 curl_fine = 1; 1051 * @param curl_code the CURL easy return code
469 else 1052 * @param pcbc the pointer struct CBC
470 { 1053 * @return non-zero if success, zero if failed
471 fprintf (stderr, 1054 */
472 "%s failed at %s:%d: `%s'\n", 1055static unsigned int
473 "curl_multi_perform", 1056check_result (CURLcode curl_code, CURL *c, long expected_code,
474 __FILE__, 1057 struct CBC *pcbc)
475 __LINE__, curl_easy_strerror (msg->data.result)); 1058{
476 abort (); 1059 long code;
477 } 1060 unsigned int ret;
478 } 1061
479 } 1062 if (CURLE_OK != curl_code)
480 if (! curl_fine) 1063 {
481 { 1064 fflush (stdout);
482 fprintf (stderr, "libcurl haven't returned OK code\n"); 1065 if (0 != libcurl_errbuf[0])
483 abort (); 1066 fprintf (stderr, "Request failed. "
484 } 1067 "libcurl error: '%s'.\n"
485 curl_multi_remove_handle (multi, c); 1068 "libcurl error description: '%s'.\n",
486 curl_multi_cleanup (multi); 1069 curl_easy_strerror (curl_code),
487 curl_easy_cleanup (c); 1070 libcurl_errbuf);
488 c = NULL; 1071 else
489 multi = NULL; 1072 fprintf (stderr, "Request failed. "
490 } 1073 "libcurl error: '%s'.\n",
491 MHD_run (d); 1074 curl_easy_strerror (curl_code));
1075 fflush (stderr);
1076 return 0;
492 } 1077 }
493 if (multi != NULL) 1078
1079 if (CURLE_OK != curl_easy_getinfo (c, CURLINFO_RESPONSE_CODE, &code))
1080 libcurlErrorExit ();
1081
1082 ret = 1;
1083 if (expected_code != code)
494 { 1084 {
495 curl_multi_remove_handle (multi, c); 1085 fprintf (stderr, "The response has wrong HTTP code: %ld\tExpected: %ld.\n",
496 curl_easy_cleanup (c); 1086 code, expected_code);
497 curl_multi_cleanup (multi); 1087 ret = 0;
498 } 1088 }
499 MHD_stop_daemon (d); 1089 else if (verbose)
500 if (cbc.pos != strlen ("/hello_world")) 1090 printf ("The response has expected HTTP code: %ld\n", expected_code);
501 return 8192; 1091
502 if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) 1092 if (pcbc->pos != MHD_STATICSTR_LEN_ (PAGE))
503 return 16384; 1093 {
504 return 0; 1094 fprintf (stderr, "Got %u bytes ('%.*s'), expected %u bytes. ",
1095 (unsigned) pcbc->pos, (int) pcbc->pos, pcbc->buf,
1096 (unsigned) MHD_STATICSTR_LEN_ (PAGE));
1097 mhdErrorExitDesc ("Wrong returned data length");
1098 }
1099 if (0 != memcmp (PAGE, pcbc->buf, pcbc->pos))
1100 {
1101 fprintf (stderr, "Got invalid response '%.*s'. ",
1102 (int) pcbc->pos, pcbc->buf);
1103 mhdErrorExitDesc ("Wrong returned data");
1104 }
1105 fflush (stderr);
1106 fflush (stdout);
1107
1108 return ret;
505} 1109}
506 1110
507 1111
508int 1112static unsigned int
509main (int argc, char *const *argv) 1113testExternalPolling (void)
510{ 1114{
511 unsigned int errorCount = 0; 1115 struct MHD_Daemon *d;
512 (void) argc; /* Unused. Silent compiler warning. */ 1116 uint16_t port;
1117 struct CBC cbc;
1118 struct ahc_cls_type ahc_param;
1119 char buf[2048];
1120 CURL *c;
1121 CURLM *multi_reuse;
1122 size_t i;
1123 int failed = 0;
513 1124
514 if ((NULL == argv) || (0 == argv[0]))
515 return 99;
516 use_invalid = has_in_name (argv[0], "_invalid");
517 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
518 return 2;
519 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT)) 1125 if (MHD_NO != MHD_is_feature_supported (MHD_FEATURE_AUTODETECT_BIND_PORT))
520 port = 0; 1126 port = 0;
521 else 1127 else
1128 port = 1340 + oneone ? 0 : 1 + use_non_strict ? 0 : 2;
1129
1130 d = MHD_start_daemon (MHD_USE_ERROR_LOG,
1131 port, NULL, NULL,
1132 &ahcCheck, &ahc_param,
1133 MHD_OPTION_STRICT_FOR_CLIENT,
1134 (int) (use_non_strict ? 0 : 1),
1135 MHD_OPTION_END);
1136 if (d == NULL)
1137 return 1;
1138 if (0 == port)
522 { 1139 {
523 port = 1340; 1140 const union MHD_DaemonInfo *dinfo;
524 if (use_invalid) 1141
525 port += 5; 1142 dinfo = MHD_get_daemon_info (d,
1143 MHD_DAEMON_INFO_BIND_PORT);
1144 if ( (NULL == dinfo) ||
1145 (0 == dinfo->port) )
1146 mhdErrorExitDesc ("MHD_get_daemon_info() failed");
1147 port = dinfo->port;
526 } 1148 }
527 errorCount += testExternalGet (0); 1149
528 errorCount += testExternalGet (1); 1150 ahc_param.rq_method = MHD_HTTP_METHOD_GET;
529 errorCount += testExternalGet (2); 1151 ahc_param.rq_url = EXPECTED_URI_BASE_PATH;
530 errorCount += testExternalGet (3); 1152 cbc.buf = buf;
531 errorCount += testExternalGet (4); 1153 cbc.size = sizeof (buf);
532 errorCount += testExternalGet (5); 1154 memset (cbc.buf, 0, cbc.size);
533 errorCount += testExternalGet (6); 1155 c = setupCURL (&cbc, port);
534 errorCount += testExternalGet (7); 1156 multi_reuse = NULL;
535 errorCount += testExternalGet (8); 1157 for (i = 0; i < sizeof(test_data) / sizeof(test_data[0]); ++i)
536 errorCount += testExternalGet (9); 1158 {
537 errorCount += testExternalGet (10); 1159 cbc.pos = 0;
538 errorCount += testExternalGet (11); 1160 ahc_param.check = test_data + i;
1161 if (CURLE_OK !=
1162 curl_easy_setopt (c, CURLOPT_COOKIE,
1163 ahc_param.check->header_str))
1164 libcurlErrorExitDesc ("Cannot set request cookies");
1165
1166 if (check_result (performQueryExternal (d, c, &multi_reuse), c,
1167 MHD_HTTP_OK, &cbc))
1168 {
1169 if (verbose)
1170 printf ("Got expected response for the check at line %u.\n",
1171 test_data[i].line_num);
1172 fflush (stdout);
1173 }
1174 else
1175 {
1176 fprintf (stderr, "FAILED request for the check at line %u.\n",
1177 test_data[i].line_num);
1178 fflush (stderr);
1179 failed = 1;
1180 }
1181 }
1182
1183 curl_easy_cleanup (c);
1184 if (NULL != multi_reuse)
1185 curl_multi_cleanup (multi_reuse);
1186
1187 MHD_stop_daemon (d);
1188 return failed ? 1 : 0;
1189}
1190
1191
1192int
1193main (int argc, char *const *argv)
1194{
1195 unsigned int errorCount = 0;
1196
1197 /* Test type and test parameters */
1198 verbose = ! (has_param (argc, argv, "-q") ||
1199 has_param (argc, argv, "--quiet") ||
1200 has_param (argc, argv, "-s") ||
1201 has_param (argc, argv, "--silent"));
1202 oneone = ! has_in_name (argv[0], "10");
1203 use_non_strict = has_in_name (argv[0], "_nonstrict");
1204
1205 test_global_init ();
1206
1207 errorCount += testExternalPolling ();
539 if (errorCount != 0) 1208 if (errorCount != 0)
540 fprintf (stderr, "Error (code: %u)\n", errorCount); 1209 fprintf (stderr, "Error (code: %u)\n", errorCount);
541 curl_global_cleanup (); 1210
1211 test_global_cleanup ();
1212
542 return (0 == errorCount) ? 0 : 1; /* 0 == pass */ 1213 return (0 == errorCount) ? 0 : 1; /* 0 == pass */
543} 1214}