1 /* Copyright (c) 2015-2018 the Civetweb developers
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  * copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  * THE SOFTWARE.
20  */
21 
22 #ifdef _MSC_VER
23 #ifndef _CRT_SECURE_NO_WARNINGS
24 #define _CRT_SECURE_NO_WARNINGS
25 #endif
26 #endif
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 
31 #include "public_func.h"
32 #include <civetweb.h>
33 
34 /* This unit test file uses the excellent Check unit testing library.
35  * The API documentation is available here:
36  * http://check.sourceforge.net/doc/check_html/index.html
37  */
38 
START_TEST(test_mg_version)39 START_TEST(test_mg_version)
40 {
41 	const char *ver = mg_version();
42 	unsigned major = 0, minor = 0;
43 	unsigned feature_files, feature_https, feature_cgi, feature_ipv6,
44 	    feature_websocket, feature_lua, feature_duktape, feature_caching;
45 	unsigned expect_files = 0, expect_https = 0, expect_cgi = 0,
46 	         expect_ipv6 = 0, expect_websocket = 0, expect_lua = 0,
47 	         expect_duktape = 0, expect_caching = 0;
48 	int ret, len;
49 	char *buf;
50 	struct mg_context *ctx = NULL;
51 
52 	ck_assert(ver != NULL);
53 	ck_assert_str_eq(ver, CIVETWEB_VERSION);
54 
55 	/* check structure of version string */
56 	ret = sscanf(ver, "%u.%u", &major, &minor);
57 	ck_assert_int_eq(ret, 2);
58 	ck_assert_uint_ge(major, 1);
59 	if (major == 1) {
60 		ck_assert_uint_ge(minor, 8); /* current version is 1.8 */
61 	}
62 
63 	/* check feature */
64 	feature_files = mg_check_feature(1);
65 	feature_https = mg_check_feature(2);
66 	feature_cgi = mg_check_feature(4);
67 	feature_ipv6 = mg_check_feature(8);
68 	feature_websocket = mg_check_feature(16);
69 	feature_lua = mg_check_feature(32);
70 	feature_duktape = mg_check_feature(64);
71 	feature_caching = mg_check_feature(128);
72 
73 #if !defined(NO_FILES)
74 	expect_files = 1;
75 #endif
76 #if !defined(NO_SSL)
77 	expect_https = 1;
78 #endif
79 #if !defined(NO_CGI)
80 	expect_cgi = 1;
81 #endif
82 #if defined(USE_IPV6)
83 	expect_ipv6 = 1;
84 #endif
85 #if defined(USE_WEBSOCKET)
86 	expect_websocket = 1;
87 #endif
88 #if defined(USE_LUA)
89 	expect_lua = 1;
90 #endif
91 #if defined(USE_DUKTAPE)
92 	expect_duktape = 1;
93 #endif
94 #if !defined(NO_CACHING)
95 	expect_caching = 1;
96 #endif
97 
98 	ck_assert_uint_eq(expect_files, !!feature_files);
99 	ck_assert_uint_eq(expect_https, !!feature_https);
100 	ck_assert_uint_eq(expect_cgi, !!feature_cgi);
101 	ck_assert_uint_eq(expect_ipv6, !!feature_ipv6);
102 	ck_assert_uint_eq(expect_websocket, !!feature_websocket);
103 	ck_assert_uint_eq(expect_lua, !!feature_lua);
104 	ck_assert_uint_eq(expect_duktape, !!feature_duktape);
105 	ck_assert_uint_eq(expect_caching, !!feature_caching);
106 
107 	/* get system information */
108 	len = mg_get_system_info(NULL, 0);
109 	ck_assert_int_gt(len, 0);
110 	buf = (char *)malloc((unsigned)len + 1);
111 	ck_assert(buf != NULL);
112 	ret = mg_get_system_info(buf, len + 1);
113 	ck_assert_int_eq(len, ret);
114 	ret = (int)strlen(buf);
115 	ck_assert_int_eq(len, ret);
116 	free(buf);
117 
118 #if defined(USE_SERVER_STATS)
119 	/* get context information for NULL */
120 	len = mg_get_context_info(ctx, NULL, 0);
121 	ck_assert_int_gt(len, 0);
122 	buf = (char *)malloc((unsigned)len + 100);
123 	ck_assert(buf != NULL);
124 	ret = mg_get_context_info(ctx, buf, len + 100);
125 	ck_assert_int_gt(ret, 0);
126 	len = (int)strlen(buf);
127 	ck_assert_int_eq(len, ret);
128 	free(buf);
129 
130 	/* get context information for simple ctx */
131 	ctx = mg_start(NULL, NULL, NULL);
132 	len = mg_get_context_info(ctx, NULL, 0);
133 	ck_assert_int_gt(len, 0);
134 	buf = (char *)malloc((unsigned)len + 100);
135 	ck_assert(buf != NULL);
136 	ret = mg_get_context_info(ctx, buf, len + 100);
137 	ck_assert_int_gt(ret, 0);
138 	len = (int)strlen(buf);
139 	ck_assert_int_eq(len, ret);
140 	free(buf);
141 	mg_stop(ctx);
142 #else
143 	len = mg_get_context_info(ctx, NULL, 0);
144 	ck_assert_int_eq(len, 0);
145 #endif
146 }
147 END_TEST
148 
149 
START_TEST(test_mg_get_valid_options)150 START_TEST(test_mg_get_valid_options)
151 {
152 	int i, j, len;
153 	char c;
154 	const struct mg_option *default_options = mg_get_valid_options();
155 
156 	ck_assert(default_options != NULL);
157 
158 	for (i = 0; default_options[i].name != NULL; i++) {
159 
160 		/* every option has a name */
161 		ck_assert(default_options[i].name != NULL);
162 
163 		/* every option has a valie type >0 and <= the highest currently known
164 		 * option type (currently 9 = MG_CONFIG_TYPE_YES_NO_OPTIONAL) */
165 		ck_assert(((int)default_options[i].type) > 0);
166 		ck_assert(((int)default_options[i].type) < 10);
167 
168 		/* options start with a lowercase letter (a-z) */
169 		c = default_options[i].name[0];
170 		ck_assert((c >= 'a') && (c <= 'z'));
171 
172 		/* check some reasonable length (this is not a permanent spec
173 		 * for min/max option name lengths) */
174 		len = (int)strlen(default_options[i].name);
175 		ck_assert_int_ge(len, 8);
176 		ck_assert_int_lt(len, 40);
177 
178 		/* check valid characters (lower case or underscore) */
179 		for (j = 0; j < len; j++) {
180 			c = default_options[i].name[j];
181 			ck_assert(((c >= 'a') && (c <= 'z')) || (c == '_'));
182 		}
183 	}
184 
185 	ck_assert(i > 0);
186 }
187 END_TEST
188 
189 
START_TEST(test_mg_get_builtin_mime_type)190 START_TEST(test_mg_get_builtin_mime_type)
191 {
192 	ck_assert_str_eq(mg_get_builtin_mime_type("x.txt"), "text/plain");
193 	ck_assert_str_eq(mg_get_builtin_mime_type("x.html"), "text/html");
194 	ck_assert_str_eq(mg_get_builtin_mime_type("x.HTML"), "text/html");
195 	ck_assert_str_eq(mg_get_builtin_mime_type("x.hTmL"), "text/html");
196 	ck_assert_str_eq(mg_get_builtin_mime_type("/abc/def/ghi.htm"), "text/html");
197 	ck_assert_str_eq(mg_get_builtin_mime_type("x.unknown_extention_xyz"),
198 	                 "text/plain");
199 }
200 END_TEST
201 
202 
START_TEST(test_mg_strncasecmp)203 START_TEST(test_mg_strncasecmp)
204 {
205 	/* equal */
206 	ck_assert(mg_strncasecmp("abc", "abc", 3) == 0);
207 
208 	/* equal, since only 3 letters are compared */
209 	ck_assert(mg_strncasecmp("abc", "abcd", 3) == 0);
210 
211 	/* not equal, since now all 4 letters are compared */
212 	ck_assert(mg_strncasecmp("abc", "abcd", 4) != 0);
213 
214 	/* equal, since we do not care about cases */
215 	ck_assert(mg_strncasecmp("a", "A", 1) == 0);
216 
217 	/* a < b */
218 	ck_assert(mg_strncasecmp("A", "B", 1) < 0);
219 	ck_assert(mg_strncasecmp("A", "b", 1) < 0);
220 	ck_assert(mg_strncasecmp("a", "B", 1) < 0);
221 	ck_assert(mg_strncasecmp("a", "b", 1) < 0);
222 	ck_assert(mg_strncasecmp("b", "A", 1) > 0);
223 	ck_assert(mg_strncasecmp("B", "A", 1) > 0);
224 	ck_assert(mg_strncasecmp("b", "a", 1) > 0);
225 	ck_assert(mg_strncasecmp("B", "a", 1) > 0);
226 
227 	ck_assert(mg_strncasecmp("xAx", "xBx", 3) < 0);
228 	ck_assert(mg_strncasecmp("xAx", "xbx", 3) < 0);
229 	ck_assert(mg_strncasecmp("xax", "xBx", 3) < 0);
230 	ck_assert(mg_strncasecmp("xax", "xbx", 3) < 0);
231 	ck_assert(mg_strncasecmp("xbx", "xAx", 3) > 0);
232 	ck_assert(mg_strncasecmp("xBx", "xAx", 3) > 0);
233 	ck_assert(mg_strncasecmp("xbx", "xax", 3) > 0);
234 	ck_assert(mg_strncasecmp("xBx", "xax", 3) > 0);
235 }
236 END_TEST
237 
238 
START_TEST(test_mg_get_cookie)239 START_TEST(test_mg_get_cookie)
240 {
241 	char buf[32];
242 	int ret;
243 	const char *longcookie = "key1=1; key2=2; key3; key4=4; key5=; key6; "
244 	                         "key7=this+is+it; key8=8; key9";
245 
246 	/* invalid result buffer */
247 	ret = mg_get_cookie("", "notfound", NULL, 999);
248 	ck_assert_int_eq(ret, -2);
249 
250 	/* zero size result buffer */
251 	ret = mg_get_cookie("", "notfound", buf, 0);
252 	ck_assert_int_eq(ret, -2);
253 
254 	/* too small result buffer */
255 	ret = mg_get_cookie("key=toooooooooolong", "key", buf, 4);
256 	ck_assert_int_eq(ret, -3);
257 
258 	/* key not found in string */
259 	ret = mg_get_cookie("", "notfound", buf, sizeof(buf));
260 	ck_assert_int_eq(ret, -1);
261 
262 	ret = mg_get_cookie(longcookie, "notfound", buf, sizeof(buf));
263 	ck_assert_int_eq(ret, -1);
264 
265 	/* key not found in string */
266 	ret = mg_get_cookie("key1=1; key2=2; key3=3", "notfound", buf, sizeof(buf));
267 	ck_assert_int_eq(ret, -1);
268 
269 	/* keys are found as first, middle and last key */
270 	memset(buf, 77, sizeof(buf));
271 	ret = mg_get_cookie("key1=1; key2=2; key3=3", "key1", buf, sizeof(buf));
272 	ck_assert_int_eq(ret, 1);
273 	ck_assert_str_eq("1", buf);
274 
275 	memset(buf, 77, sizeof(buf));
276 	ret = mg_get_cookie("key1=1; key2=2; key3=3", "key2", buf, sizeof(buf));
277 	ck_assert_int_eq(ret, 1);
278 	ck_assert_str_eq("2", buf);
279 
280 	memset(buf, 77, sizeof(buf));
281 	ret = mg_get_cookie("key1=1; key2=2; key3=3", "key3", buf, sizeof(buf));
282 	ck_assert_int_eq(ret, 1);
283 	ck_assert_str_eq("3", buf);
284 
285 	/* longer value in the middle of a longer string */
286 	memset(buf, 77, sizeof(buf));
287 	ret = mg_get_cookie(longcookie, "key7", buf, sizeof(buf));
288 	ck_assert_int_eq(ret, 10);
289 	ck_assert_str_eq("this+is+it", buf);
290 
291 	/* key with = but without value in the middle of a longer string */
292 	memset(buf, 77, sizeof(buf));
293 	ret = mg_get_cookie(longcookie, "key5", buf, sizeof(buf));
294 	ck_assert_int_eq(ret, 0);
295 	ck_assert_str_eq("", buf);
296 
297 	/* key without = and without value in the middle of a longer string */
298 	memset(buf, 77, sizeof(buf));
299 	ret = mg_get_cookie(longcookie, "key6", buf, sizeof(buf));
300 	ck_assert_int_eq(ret, -1);
301 	/* TODO: mg_get_cookie and mg_get_var(2) should have the same behavior */
302 }
303 END_TEST
304 
305 
START_TEST(test_mg_get_var)306 START_TEST(test_mg_get_var)
307 {
308 	char buf[32];
309 	int ret;
310 	const char *shortquery = "key1=1&key2=2&key3=3";
311 	const char *longquery = "key1=1&key2=2&key3&key4=4&key5=&key6&"
312 	                        "key7=this+is+it&key8=8&key9&&key10=&&"
313 	                        "key7=that+is+it&key12=12";
314 
315 	/* invalid result buffer */
316 	ret = mg_get_var2("", 0, "notfound", NULL, 999, 0);
317 	ck_assert_int_eq(ret, -2);
318 
319 	/* zero size result buffer */
320 	ret = mg_get_var2("", 0, "notfound", buf, 0, 0);
321 	ck_assert_int_eq(ret, -2);
322 
323 	/* too small result buffer */
324 	ret = mg_get_var2("key=toooooooooolong", 19, "key", buf, 4, 0);
325 	/* ck_assert_int_eq(ret, -3);
326 	   --> TODO: mg_get_cookie returns -3, mg_get_var -2. This should be
327 	   unified. */
328 	ck_assert(ret < 0);
329 
330 	/* key not found in string */
331 	ret = mg_get_var2("", 0, "notfound", buf, sizeof(buf), 0);
332 	ck_assert_int_eq(ret, -1);
333 
334 	ret = mg_get_var2(
335 	    longquery, strlen(longquery), "notfound", buf, sizeof(buf), 0);
336 	ck_assert_int_eq(ret, -1);
337 
338 	/* key not found in string */
339 	ret = mg_get_var2(
340 	    shortquery, strlen(shortquery), "notfound", buf, sizeof(buf), 0);
341 	ck_assert_int_eq(ret, -1);
342 
343 	/* key not found in string */
344 	ret = mg_get_var2("key1=1&key2=2&key3=3&notfound=here",
345 	                  strlen(shortquery),
346 	                  "notfound",
347 	                  buf,
348 	                  sizeof(buf),
349 	                  0);
350 	ck_assert_int_eq(ret, -1);
351 
352 	/* key not found in string */
353 	ret = mg_get_var2(
354 	    shortquery, strlen(shortquery), "key1", buf, sizeof(buf), 1);
355 	ck_assert_int_eq(ret, -1);
356 
357 	/* keys are found as first, middle and last key */
358 	memset(buf, 77, sizeof(buf));
359 	ret = mg_get_var2(
360 	    shortquery, strlen(shortquery), "key1", buf, sizeof(buf), 0);
361 	ck_assert_int_eq(ret, 1);
362 	ck_assert_str_eq("1", buf);
363 
364 	memset(buf, 77, sizeof(buf));
365 	ret = mg_get_var2(
366 	    shortquery, strlen(shortquery), "key2", buf, sizeof(buf), 0);
367 	ck_assert_int_eq(ret, 1);
368 	ck_assert_str_eq("2", buf);
369 
370 	memset(buf, 77, sizeof(buf));
371 	ret = mg_get_var2(
372 	    shortquery, strlen(shortquery), "key3", buf, sizeof(buf), 0);
373 	ck_assert_int_eq(ret, 1);
374 	ck_assert_str_eq("3", buf);
375 
376 	/* mg_get_var call mg_get_var2 with last argument 0 */
377 	memset(buf, 77, sizeof(buf));
378 	ret = mg_get_var(shortquery, strlen(shortquery), "key1", buf, sizeof(buf));
379 	ck_assert_int_eq(ret, 1);
380 	ck_assert_str_eq("1", buf);
381 
382 	/* longer value in the middle of a longer string */
383 	memset(buf, 77, sizeof(buf));
384 	ret =
385 	    mg_get_var2(longquery, strlen(longquery), "key7", buf, sizeof(buf), 0);
386 	ck_assert_int_eq(ret, 10);
387 	ck_assert_str_eq("this is it", buf);
388 
389 	/* longer value in the middle of a longer string - seccond occurrence of key
390 	 */
391 	memset(buf, 77, sizeof(buf));
392 	ret =
393 	    mg_get_var2(longquery, strlen(longquery), "key7", buf, sizeof(buf), 1);
394 	ck_assert_int_eq(ret, 10);
395 	ck_assert_str_eq("that is it", buf);
396 
397 	/* key with = but without value in the middle of a longer string */
398 	memset(buf, 77, sizeof(buf));
399 	ret =
400 	    mg_get_var2(longquery, strlen(longquery), "key5", buf, sizeof(buf), 0);
401 	ck_assert_int_eq(ret, 0);
402 	ck_assert_str_eq(buf, "");
403 
404 	/* key without = and without value in the middle of a longer string */
405 	memset(buf, 77, sizeof(buf));
406 	ret =
407 	    mg_get_var2(longquery, strlen(longquery), "key6", buf, sizeof(buf), 0);
408 	ck_assert_int_eq(ret, -1);
409 	ck_assert_str_eq(buf, "");
410 	/* TODO: this is the same situation as with mg_get_value */
411 }
412 END_TEST
413 
414 
START_TEST(test_mg_md5)415 START_TEST(test_mg_md5)
416 {
417 	char buf[33];
418 	char *ret;
419 	const char *long_str =
420 	    "_123456789A123456789B123456789C123456789D123456789E123456789F123456789"
421 	    "G123456789H123456789I123456789J123456789K123456789L123456789M123456789"
422 	    "N123456789O123456789P123456789Q123456789R123456789S123456789T123456789"
423 	    "U123456789V123456789W123456789X123456789Y123456789Z";
424 
425 	memset(buf, 77, sizeof(buf));
426 	ret = mg_md5(buf, NULL);
427 	ck_assert_str_eq(buf, "d41d8cd98f00b204e9800998ecf8427e");
428 	ck_assert_str_eq(ret, "d41d8cd98f00b204e9800998ecf8427e");
429 	ck_assert_ptr_eq(ret, buf);
430 
431 	memset(buf, 77, sizeof(buf));
432 	ret = mg_md5(buf, "The quick brown fox jumps over the lazy dog.", NULL);
433 	ck_assert_str_eq(buf, "e4d909c290d0fb1ca068ffaddf22cbd0");
434 	ck_assert_str_eq(ret, "e4d909c290d0fb1ca068ffaddf22cbd0");
435 	ck_assert_ptr_eq(ret, buf);
436 
437 	memset(buf, 77, sizeof(buf));
438 	ret = mg_md5(buf,
439 	             "",
440 	             "The qu",
441 	             "ick bro",
442 	             "",
443 	             "wn fox ju",
444 	             "m",
445 	             "ps over the la",
446 	             "",
447 	             "",
448 	             "zy dog.",
449 	             "",
450 	             NULL);
451 	ck_assert_str_eq(buf, "e4d909c290d0fb1ca068ffaddf22cbd0");
452 	ck_assert_str_eq(ret, "e4d909c290d0fb1ca068ffaddf22cbd0");
453 	ck_assert_ptr_eq(ret, buf);
454 
455 	memset(buf, 77, sizeof(buf));
456 	ret = mg_md5(buf, long_str, NULL);
457 	ck_assert_str_eq(buf, "1cb13cf9f16427807f081b2138241f08");
458 	ck_assert_str_eq(ret, "1cb13cf9f16427807f081b2138241f08");
459 	ck_assert_ptr_eq(ret, buf);
460 
461 	memset(buf, 77, sizeof(buf));
462 	ret = mg_md5(buf, long_str + 1, NULL);
463 	ck_assert_str_eq(buf, "cf62d3264334154f5779d3694cc5093f");
464 	ck_assert_str_eq(ret, "cf62d3264334154f5779d3694cc5093f");
465 	ck_assert_ptr_eq(ret, buf);
466 }
467 END_TEST
468 
469 
START_TEST(test_mg_url_encode)470 START_TEST(test_mg_url_encode)
471 {
472 	char buf[20];
473 	int ret;
474 
475 	memset(buf, 77, sizeof(buf));
476 	ret = mg_url_encode("abc", buf, sizeof(buf));
477 	ck_assert_int_eq(3, ret);
478 	ck_assert_str_eq("abc", buf);
479 
480 	memset(buf, 77, sizeof(buf));
481 	ret = mg_url_encode("a%b/c&d.e", buf, sizeof(buf));
482 	ck_assert_int_eq(15, ret);
483 	ck_assert_str_eq("a%25b%2fc%26d.e", buf);
484 
485 	memset(buf, 77, sizeof(buf));
486 	ret = mg_url_encode("%%%", buf, 4);
487 	ck_assert_int_eq(-1, ret);
488 	ck_assert_str_eq("%25", buf);
489 }
490 END_TEST
491 
492 
START_TEST(test_mg_url_decode)493 START_TEST(test_mg_url_decode)
494 {
495 	char buf[20];
496 	int ret;
497 
498 	/* decode entire string */
499 	ret = mg_url_decode("abc", 3, buf, sizeof(buf), 0);
500 	ck_assert_int_eq(ret, 3);
501 	ck_assert_str_eq(buf, "abc");
502 
503 	/* decode only a part of the string */
504 	ret = mg_url_decode("abcdef", 3, buf, sizeof(buf), 0);
505 	ck_assert_int_eq(ret, 3);
506 	ck_assert_str_eq(buf, "abc");
507 
508 	/* a + remains a + in standard decoding */
509 	ret = mg_url_decode("x+y", 3, buf, sizeof(buf), 0);
510 	ck_assert_int_eq(ret, 3);
511 	ck_assert_str_eq(buf, "x+y");
512 
513 	/* a + becomes a space in form decoding */
514 	ret = mg_url_decode("x+y", 3, buf, sizeof(buf), 1);
515 	ck_assert_int_eq(ret, 3);
516 	ck_assert_str_eq(buf, "x y");
517 
518 	/* a %25 is a % character */
519 	ret = mg_url_decode("%25", 3, buf, sizeof(buf), 1);
520 	ck_assert_int_eq(ret, 1);
521 	ck_assert_str_eq(buf, "%");
522 
523 	/* a %20 is space, %21 is ! */
524 	ret = mg_url_decode("%20%21", 6, buf, sizeof(buf), 0);
525 	ck_assert_int_eq(ret, 2);
526 	ck_assert_str_eq(buf, " !");
527 }
528 END_TEST
529 
530 
START_TEST(test_mg_get_response_code_text)531 START_TEST(test_mg_get_response_code_text)
532 {
533 	int i;
534 	size_t j, len;
535 	const char *resp;
536 
537 	for (i = 100; i < 600; i++) {
538 		resp = mg_get_response_code_text(NULL, i);
539 		ck_assert_ptr_ne(resp, NULL);
540 		len = strlen(resp);
541 		ck_assert_uint_gt(len, 1);
542 		ck_assert_uint_lt(len, 32);
543 		for (j = 0; j < len; j++) {
544 			if (resp[j] == ' ') {
545 				/* space is valid */
546 			} else if (resp[j] == '-') {
547 				/* hyphen is valid */
548 			} else if (resp[j] >= 'A' && resp[j] <= 'Z') {
549 				/* A-Z is valid */
550 			} else if (resp[j] >= 'a' && resp[j] <= 'z') {
551 				/* a-z is valid */
552 			} else {
553 				ck_abort_msg("Found letter %c (%02xh) in %s",
554 				             resp[j],
555 				             resp[j],
556 				             resp);
557 			}
558 		}
559 	}
560 }
561 END_TEST
562 
563 
564 #if !defined(REPLACE_CHECK_FOR_LOCAL_DEBUGGING)
565 Suite *
make_public_func_suite(void)566 make_public_func_suite(void)
567 {
568 	Suite *const suite = suite_create("PublicFunc");
569 
570 	TCase *const tcase_version = tcase_create("Version");
571 	TCase *const tcase_get_valid_options = tcase_create("Options");
572 	TCase *const tcase_get_builtin_mime_type = tcase_create("MIME types");
573 	TCase *const tcase_strncasecmp = tcase_create("strcasecmp");
574 	TCase *const tcase_urlencodingdecoding =
575 	    tcase_create("URL encoding decoding");
576 	TCase *const tcase_cookies = tcase_create("Cookies and variables");
577 	TCase *const tcase_md5 = tcase_create("MD5");
578 	TCase *const tcase_aux = tcase_create("Aux functions");
579 
580 	tcase_add_test(tcase_version, test_mg_version);
581 	tcase_set_timeout(tcase_version, civetweb_min_test_timeout);
582 	suite_add_tcase(suite, tcase_version);
583 
584 	tcase_add_test(tcase_get_valid_options, test_mg_get_valid_options);
585 	tcase_set_timeout(tcase_get_valid_options, civetweb_min_test_timeout);
586 	suite_add_tcase(suite, tcase_get_valid_options);
587 
588 	tcase_add_test(tcase_get_builtin_mime_type, test_mg_get_builtin_mime_type);
589 	tcase_set_timeout(tcase_get_builtin_mime_type, civetweb_min_test_timeout);
590 	suite_add_tcase(suite, tcase_get_builtin_mime_type);
591 
592 	tcase_add_test(tcase_strncasecmp, test_mg_strncasecmp);
593 	tcase_set_timeout(tcase_strncasecmp, civetweb_min_test_timeout);
594 	suite_add_tcase(suite, tcase_strncasecmp);
595 
596 	tcase_add_test(tcase_urlencodingdecoding, test_mg_url_encode);
597 	tcase_add_test(tcase_urlencodingdecoding, test_mg_url_decode);
598 	tcase_set_timeout(tcase_urlencodingdecoding, civetweb_min_test_timeout);
599 	suite_add_tcase(suite, tcase_urlencodingdecoding);
600 
601 	tcase_add_test(tcase_cookies, test_mg_get_cookie);
602 	tcase_add_test(tcase_cookies, test_mg_get_var);
603 	tcase_set_timeout(tcase_cookies, civetweb_min_test_timeout);
604 	suite_add_tcase(suite, tcase_cookies);
605 
606 	tcase_add_test(tcase_md5, test_mg_md5);
607 	tcase_set_timeout(tcase_md5, civetweb_min_test_timeout);
608 	suite_add_tcase(suite, tcase_md5);
609 
610 	tcase_add_test(tcase_aux, test_mg_get_response_code_text);
611 	tcase_set_timeout(tcase_aux, civetweb_min_test_timeout);
612 	suite_add_tcase(suite, tcase_aux);
613 
614 	return suite;
615 }
616 #endif
617