1 /* Copyright information is at the end of the file. */
11 #include "xmlrpc_config.h"
13 #include "xmlrpc-c/base.h"
14 #include "xmlrpc-c/server.h"
18 #include "serialize.h"
19 #include "parse_xml.h"
23 #include "server_abyss.h"
24 #include "method_registry.h"
26 /*=========================================================================
28 **=========================================================================
29 ** This is a super light-weight test harness. It's vaguely inspired by
30 ** Kent Beck's book on eXtreme Programming (XP)--the output is succinct,
31 ** new tests can be coded quickly, and the whole thing runs in a few
34 ** To run the tests, type './rpctest'.
35 ** To check for memory leaks, install RedHat's 'memprof' utility, and
36 ** type 'memprof rpctest'.
38 ** If you add new tests to this file, please deallocate any data
39 ** structures you use in the appropriate fashion. This allows us to test
40 ** various destructor code for memory leaks.
44 int total_failures = 0;
47 /*=========================================================================
49 **=========================================================================
50 ** Some common test data which need to be allocated at a fixed address,
51 ** or which are inconvenient to allocate inline.
54 static char* test_string_1 = "foo";
55 static char* test_string_2 = "bar";
56 static int test_int_array_1[5] = {1, 2, 3, 4, 5};
57 static int test_int_array_2[3] = {6, 7, 8};
58 static int test_int_array_3[8] = {1, 2, 3, 4, 5, 6, 7, 8};
60 /*=========================================================================
62 **=========================================================================
65 static void test_env(void)
70 /* Test xmlrpc_env_init. */
71 xmlrpc_env_init(&env);
72 TEST(!env.fault_occurred);
73 TEST(env.fault_code == 0);
74 TEST(env.fault_string == NULL);
76 /* Test xmlrpc_set_fault. */
77 xmlrpc_env_set_fault(&env, 1, test_string_1);
78 TEST(env.fault_occurred);
79 TEST(env.fault_code == 1);
80 TEST(env.fault_string != test_string_1);
81 TEST(strcmp(env.fault_string, test_string_1) == 0);
83 /* Change an existing fault. */
84 xmlrpc_env_set_fault(&env, 2, test_string_2);
85 TEST(env.fault_occurred);
86 TEST(env.fault_code == 2);
87 TEST(strcmp(env.fault_string, test_string_2) == 0);
89 /* Set a fault with a format string. */
90 xmlrpc_env_set_fault_formatted(&env, 3, "a%s%d", "bar", 9);
91 TEST(env.fault_occurred);
92 TEST(env.fault_code == 3);
93 TEST(strcmp(env.fault_string, "abar9") == 0);
95 /* Set a fault with an oversized string. */
96 s = "12345678901234567890123456789012345678901234567890";
97 xmlrpc_env_set_fault_formatted(&env, 4, "%s%s%s%s%s%s", s, s, s, s, s, s);
98 TEST(env.fault_occurred);
99 TEST(env.fault_code == 4);
100 TEST(strlen(env.fault_string) == 255);
102 /* Test cleanup code (with help from memprof). */
103 xmlrpc_env_clean(&env);
105 /* Test cleanup code on in absence of xmlrpc_env_set_fault. */
106 xmlrpc_env_init(&env2);
107 xmlrpc_env_clean(&env2);
110 static void test_mem_block (void)
113 xmlrpc_mem_block* block;
115 xmlrpc_mem_block* typed_heap_block;
116 xmlrpc_mem_block typed_auto_block;
117 void** typed_contents;
119 xmlrpc_env_init(&env);
121 /* Allocate a zero-size block. */
122 block = xmlrpc_mem_block_new(&env, 0);
125 TEST(xmlrpc_mem_block_size(block) == 0);
127 /* Grow the block a little bit. */
128 xmlrpc_mem_block_resize(&env, block, strlen(test_string_1) + 1);
130 TEST(xmlrpc_mem_block_size(block) == strlen(test_string_1) + 1);
132 /* Insert a string into the block, and resize it by large amount.
133 ** We want to cause a reallocation and copy of the block contents. */
134 strcpy(xmlrpc_mem_block_contents(block), test_string_1);
135 xmlrpc_mem_block_resize(&env, block, 10000);
137 TEST(xmlrpc_mem_block_size(block) == 10000);
138 TEST(strcmp(xmlrpc_mem_block_contents(block), test_string_1) == 0);
140 /* Test cleanup code (with help from memprof). */
141 xmlrpc_mem_block_free(block);
143 /* Allocate a bigger block. */
144 block = xmlrpc_mem_block_new(&env, 128);
147 TEST(xmlrpc_mem_block_size(block) == 128);
149 /* Test cleanup code (with help from memprof). */
150 xmlrpc_mem_block_free(block);
152 /* Allocate a "typed" memory block. */
153 typed_heap_block = XMLRPC_TYPED_MEM_BLOCK_NEW(void*, &env, 20);
155 TEST(typed_heap_block != NULL);
156 TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 20);
157 typed_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(void*, typed_heap_block);
158 TEST(typed_contents != NULL);
160 /* Resize a typed memory block. */
161 XMLRPC_TYPED_MEM_BLOCK_RESIZE(void*, &env, typed_heap_block, 100);
163 TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 100);
165 /* Test cleanup code (with help from memprof). */
166 XMLRPC_TYPED_MEM_BLOCK_FREE(void*, typed_heap_block);
168 /* Test _INIT and _CLEAN for stack-based memory blocks. */
169 XMLRPC_TYPED_MEM_BLOCK_INIT(void*, &env, &typed_auto_block, 30);
170 TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, &typed_auto_block) == 30);
171 XMLRPC_TYPED_MEM_BLOCK_CLEAN(void*, &typed_auto_block);
173 /* Test xmlrpc_mem_block_append. */
174 block = XMLRPC_TYPED_MEM_BLOCK_NEW(int, &env, 5);
176 memcpy(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block),
177 test_int_array_1, sizeof(test_int_array_1));
178 XMLRPC_TYPED_MEM_BLOCK_APPEND(int, &env, block, test_int_array_2, 3);
179 TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(int, block) == 8);
180 TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block),
181 test_int_array_3, sizeof(test_int_array_3)) == 0);
182 XMLRPC_TYPED_MEM_BLOCK_FREE(int, block);
184 xmlrpc_env_clean(&env);
187 static char *(base64_triplets[]) = {
189 "a", "YQ==", "YQ==\r\n",
190 "aa", "YWE=", "YWE=\r\n",
191 "aaa", "YWFh", "YWFh\r\n",
192 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
193 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
194 "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY"
195 "2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=",
196 "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY"
198 "ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=\r\n",
202 test_base64_conversion(void) {
206 xmlrpc_env_init(&env);
208 for (triplet = base64_triplets; *triplet != NULL; triplet += 3) {
210 char * nocrlf_ascii_data;
212 xmlrpc_mem_block * output;
215 nocrlf_ascii_data = *(triplet + 1);
216 ascii_data = *(triplet + 2);
218 /* Test our encoding routine. */
219 output = xmlrpc_base64_encode(&env,
220 (unsigned char*) bin_data,
223 TEST(output != NULL);
224 TEST(xmlrpc_mem_block_size(output) == strlen(ascii_data));
225 TEST(memcmp(xmlrpc_mem_block_contents(output), ascii_data,
226 strlen(ascii_data)) == 0);
227 xmlrpc_mem_block_free(output);
229 /* Test our newline-free encoding routine. */
231 xmlrpc_base64_encode_without_newlines(&env,
232 (unsigned char*) bin_data,
235 TEST(output != NULL);
236 TEST(xmlrpc_mem_block_size(output) == strlen(nocrlf_ascii_data));
237 TEST(memcmp(xmlrpc_mem_block_contents(output), nocrlf_ascii_data,
238 strlen(nocrlf_ascii_data)) == 0);
239 xmlrpc_mem_block_free(output);
241 /* Test our decoding routine. */
242 output = xmlrpc_base64_decode(&env, ascii_data, strlen(ascii_data));
244 TEST(output != NULL);
245 TEST(xmlrpc_mem_block_size(output) == strlen(bin_data));
246 TEST(memcmp(xmlrpc_mem_block_contents(output), bin_data,
247 strlen(bin_data)) == 0);
248 xmlrpc_mem_block_free(output);
251 /* Now for something broken... */
254 xmlrpc_mem_block * output;
256 xmlrpc_env_init(&env2);
257 output = xmlrpc_base64_decode(&env2, "====", 4);
258 TEST(output == NULL);
259 TEST_FAULT(&env2, XMLRPC_PARSE_ERROR);
260 xmlrpc_env_clean(&env2);
262 /* Now for something broken in a really sneaky way... */
265 xmlrpc_mem_block * output;
266 xmlrpc_env_init(&env2);
267 output = xmlrpc_base64_decode(&env2, "a==", 4);
268 TEST(output == NULL);
269 TEST_FAULT(&env2, XMLRPC_PARSE_ERROR);
270 xmlrpc_env_clean(&env2);
272 xmlrpc_env_clean(&env);
277 static void test_bounds_checks (void)
283 /* Get an array to work with. */
284 xmlrpc_env_init(&env);
285 array = xmlrpc_build_value(&env, "(iii)", 100, 200, 300);
287 xmlrpc_env_clean(&env);
289 /* Test xmlrpc_decompose_value with too few values. */
290 xmlrpc_env_init(&env);
291 xmlrpc_decompose_value(&env, array, "(iiii)", &i1, &i2, &i3, &i4);
292 TEST_FAULT(&env, XMLRPC_INDEX_ERROR);
293 xmlrpc_env_clean(&env);
295 /* Test xmlrpc_decompose_value with too many values. */
296 xmlrpc_env_init(&env);
297 xmlrpc_decompose_value(&env, array, "(ii)", &i1, &i2, &i3, &i4);
298 TEST_FAULT(&env, XMLRPC_INDEX_ERROR);
299 xmlrpc_env_clean(&env);
301 /* Dispose of our array. */
302 xmlrpc_DECREF(array);
307 static void test_nesting_limit (void)
312 xmlrpc_env_init(&env);
314 /* Test with an adequate limit for a result value which is an
315 array which contains an element which is a struct, whose values
318 xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 3);
319 val = xmlrpc_parse_response(&env,
320 good_response_xml, strlen(good_response_xml));
325 /* Test with an inadequate limit. */
326 xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 2);
327 val = xmlrpc_parse_response(&env,
328 good_response_xml, strlen(good_response_xml));
329 TEST_FAULT(&env, XMLRPC_PARSE_ERROR); /* BREAKME - Will change. */
332 /* Reset the default limit. */
333 xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, XMLRPC_NESTING_LIMIT_DEFAULT);
334 TEST(xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID)
335 == XMLRPC_NESTING_LIMIT_DEFAULT);
337 xmlrpc_env_clean(&env);
343 test_xml_size_limit(void) {
346 const char * methodName;
347 xmlrpc_value * paramsP;
349 /* NOTE - This test suite only verifies the last-ditch size-checking
350 code. There should also be matching code in all server (and
351 preferably all client) modules as well.
354 /* Set our XML size limit to something ridiculous. */
355 xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, 6);
357 /* Attempt to parse a call. */
358 xmlrpc_env_init(&env);
359 xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call),
360 &methodName, ¶msP);
361 TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR);
362 xmlrpc_env_clean(&env);
365 xmlrpc_value * resultP;
367 const char * faultString;
369 /* Attempt to parse a response. */
370 xmlrpc_env_init(&env);
371 xmlrpc_parse_response2(&env,
372 good_response_xml, strlen(good_response_xml),
373 &resultP, &faultCode, &faultString);
374 TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR);
375 xmlrpc_env_clean(&env);
377 /* Reset the default limit. */
378 xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, XMLRPC_XML_SIZE_LIMIT_DEFAULT);
383 /*=========================================================================
385 **=========================================================================
386 ** Read in a bunch of sample test files and make sure we get plausible
389 ** We use these files to test strange-but-legal encodings, illegal-but-
390 ** supported encodings, etc.
393 #define TESTDATA_DIR "data"
395 static char *good_requests[] = {
396 TESTDATA_DIR DIRECTORY_SEPARATOR "req_out_of_order.xml",
397 TESTDATA_DIR DIRECTORY_SEPARATOR "req_no_params.xml",
398 TESTDATA_DIR DIRECTORY_SEPARATOR "req_value_name.xml",
402 #define MAX_SAMPLE_FILE_LEN (16 * 1024)
404 static char file_buff [MAX_SAMPLE_FILE_LEN];
407 read_file (char *path, char **out_data, size_t *out_size)
413 f = fopen(path, "r");
415 /* Since this error is fairly likely to happen, give an
416 ** informative error message... */
418 fprintf(stderr, "Could not open file '%s'. errno=%d (%s)\n",
419 path, errno, strerror(errno));
423 /* Read in one buffer full of data, and make sure that everything
424 ** fit. (We perform a lazy error/no-eof/zero-length-file test using
426 bytes_read = fread(file_buff, sizeof(char), MAX_SAMPLE_FILE_LEN, f);
427 TEST(0 < bytes_read && bytes_read < MAX_SAMPLE_FILE_LEN);
429 /* Close the file and return our data. */
431 *out_data = file_buff;
432 *out_size = bytes_read;
435 static void test_sample_files (void)
441 const char *method_name;
442 xmlrpc_value *params;
444 xmlrpc_env_init(&env);
446 /* Test our good requests. */
447 for (paths = good_requests; *paths != NULL; paths++) {
449 read_file(path, &data, &data_len);
450 xmlrpc_parse_call(&env, data, data_len, &method_name, ¶ms);
452 strfree(method_name);
453 xmlrpc_DECREF(params);
456 xmlrpc_env_clean(&env);
460 /*=========================================================================
462 **=========================================================================
463 ** We need to test our UTF-8 decoder thoroughly. Most of these test
464 ** cases are taken from the UTF-8-test.txt file by Markus Kuhn
466 ** http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
469 #if HAVE_UNICODE_WCHAR
476 static utf8_and_wcs good_utf8[] = {
479 {"\316\272\341\275\271\317\203\316\274\316\265",
480 {0x03BA, 0x1F79, 0x03C3, 0x03BC, 0x03B5, 0}},
482 /* First sequences of a given length. */
483 /* '\000' is not a legal C string. */
484 {"\302\200", {0x0080, 0}},
485 {"\340\240\200", {0x0800, 0}},
487 /* Last sequences of a given length. */
488 {"\177", {0x007F, 0}},
489 {"\337\277", {0x07FF, 0}},
490 /* 0xFFFF is not a legal Unicode character. */
492 /* Other boundry conditions. */
493 {"\001", {0x0001, 0}},
494 {"\355\237\277", {0xD7FF, 0}},
495 {"\356\200\200", {0xE000, 0}},
496 {"\357\277\275", {0xFFFD, 0}},
498 /* Other random test cases. */
500 {"abc", {0x0061, 0x0062, 0x0063, 0}},
501 {"[\302\251]", {0x005B, 0x00A9, 0x005D, 0}},
506 static char *(bad_utf8[]) = {
508 /* Continuation bytes. */
511 /* Lonely start characters. */
512 "\300", "\300x", "\300xx",
513 "\340", "\340x", "\340xx", "\340xxx",
515 /* Last byte missing. */
516 "\340\200", "\340\200x", "\340\200xx",
517 "\357\277", "\357\277x", "\357\277xx",
523 "\300\257", "\340\200\257",
525 /* Overlong ASCII NUL. */
526 "\300\200", "\340\200\200",
528 /* Maximum overlong sequences. */
529 "\301\277", "\340\237\277",
531 /* Illegal code positions. */
532 "\357\277\276", /* U+FFFE */
533 "\357\277\277", /* U+FFFF */
535 /* UTF-16 surrogates (unpaired and paired). */
538 "\355\240\200\355\260\200",
539 "\355\257\277\355\277\277",
541 /* Valid UCS-4 characters (we don't handle these yet).
542 ** On systems with UCS-4 or UTF-16 wchar_t values, we
543 ** may eventually handle these in some fashion. */
545 "\370\210\200\200\200",
546 "\374\204\200\200\200\200",
550 #endif /* HAVE_UNICODE_WCHAR */
552 /* This routine is missing on certain platforms. This implementation
553 ** *appears* to be correct. */
556 int wcsncmp(wchar_t *wcs1, wchar_t* wcs2, size_t len)
559 /* XXX - 'unsigned long' should be 'uwchar_t'. */
560 unsigned long c1, c2;
561 for (i=0; i < len; i++) {
564 /* This clever comparison borrowed from the GNU C Library. */
565 if (c1 == 0 || c1 != c2)
570 #endif /* HAVE_WCSNCMP */
574 test_utf8_coding(void) {
576 #if HAVE_UNICODE_WCHAR
577 xmlrpc_env env, env2;
578 utf8_and_wcs *good_data;
582 xmlrpc_mem_block *output;
584 xmlrpc_env_init(&env);
586 /* Test each of our valid UTF-8 sequences. */
587 for (good_data = good_utf8; good_data->utf8 != NULL; good_data++) {
588 utf8 = good_data->utf8;
589 wcs = good_data->wcs;
591 /* Attempt to validate the UTF-8 string. */
592 xmlrpc_validate_utf8(&env, utf8, strlen(utf8));
595 /* Attempt to decode the UTF-8 string. */
596 output = xmlrpc_utf8_to_wcs(&env, utf8, strlen(utf8));
598 TEST(output != NULL);
599 TEST(wcslen(wcs) == XMLRPC_TYPED_MEM_BLOCK_SIZE(wchar_t, output));
601 wcsncmp(wcs, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, output),
603 xmlrpc_mem_block_free(output);
605 /* Test the UTF-8 encoder, too. */
606 output = xmlrpc_wcs_to_utf8(&env, wcs, wcslen(wcs));
608 TEST(output != NULL);
609 TEST(strlen(utf8) == XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output));
611 strncmp(utf8, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output),
613 xmlrpc_mem_block_free(output);
616 /* Test each of our illegal UTF-8 sequences. */
617 for (bad_data = bad_utf8; *bad_data != NULL; bad_data++) {
620 /* Attempt to validate the UTF-8 string. */
621 xmlrpc_env_init(&env2);
622 xmlrpc_validate_utf8(&env2, utf8, strlen(utf8));
623 TEST_FAULT(&env2, XMLRPC_INVALID_UTF8_ERROR);
624 /* printf("Fault: %s\n", env2.fault_string); --Hand-checked */
625 xmlrpc_env_clean(&env2);
627 /* Attempt to decode the UTF-8 string. */
628 xmlrpc_env_init(&env2);
629 output = xmlrpc_utf8_to_wcs(&env2, utf8, strlen(utf8));
630 TEST_FAULT(&env2, XMLRPC_INVALID_UTF8_ERROR);
631 TEST(output == NULL);
632 xmlrpc_env_clean(&env2);
634 xmlrpc_env_clean(&env);
635 #endif /* HAVE_UNICODE_WCHAR */
641 test_server_cgi_maybe(void) {
653 test_client_maybe(void) {
655 #ifndef WIN32 /* Must get Windows Curl transport working for this to work */
666 char ** argv ATTR_UNUSED) {
671 fprintf(stderr, "There are no arguments.");
674 /* Add your test suites here. */
677 test_base64_conversion();
680 test_bounds_checks();
684 test_method_registry();
685 test_nesting_limit();
686 test_xml_size_limit();
689 test_server_cgi_maybe();
698 /* Summarize our test run. */
699 printf("\nRan %d tests, %d failed, %.1f%% passed\n",
700 total_tests, total_failures,
701 100.0 - (100.0 * total_failures) / total_tests);
703 /* Print the final result. */
704 if (total_failures == 0) {
718 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
720 ** Redistribution and use in source and binary forms, with or without
721 ** modification, are permitted provided that the following conditions
723 ** 1. Redistributions of source code must retain the above copyright
724 ** notice, this list of conditions and the following disclaimer.
725 ** 2. Redistributions in binary form must reproduce the above copyright
726 ** notice, this list of conditions and the following disclaimer in the
727 ** documentation and/or other materials provided with the distribution.
728 ** 3. The name of the author may not be used to endorse or promote products
729 ** derived from this software without specific prior written permission.
731 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
732 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
733 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
734 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
735 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
736 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
737 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
738 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
739 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
740 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF