| |
|
|
| #ifdef _WIN32 |
| # include <direct.h> |
| #else |
| # include <unistd.h> |
| #endif |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <limits.h> |
|
|
| #include "casprintf.h" |
|
|
| #include "xmlrpc_config.h" |
|
|
| #include "xmlrpc-c/base.h" |
| #include "xmlrpc-c/server.h" |
| #include "xmlrpc-c/string_int.h" |
|
|
| #include "bool.h" |
| #include "testtool.h" |
| #include "value.h" |
| #include "serialize.h" |
| #include "parse_xml.h" |
| #include "cgi.h" |
| #include "xml_data.h" |
| #include "client.h" |
| #include "abyss.h" |
| #include "server_abyss.h" |
| #include "method_registry.h" |
| #include "memblock.h" |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| int total_tests = 0; |
| int total_failures = 0; |
|
|
| bool const runningUnderWindows = |
| #ifdef _WIN32 |
| true; |
| #else |
| false; |
| #endif |
|
|
|
|
| |
| |
| |
| |
| |
| |
|
|
| static char* test_string_1 = "foo"; |
| static char* test_string_2 = "bar"; |
|
|
| |
| |
| |
| |
|
|
| static void |
| testVersion(void) { |
|
|
| unsigned int major, minor, point; |
|
|
| xmlrpc_version(&major, &minor, &point); |
|
|
| #ifndef _WIN32 |
| |
|
|
| TEST(major == xmlrpc_version_major); |
| TEST(minor == xmlrpc_version_minor); |
| TEST(point == xmlrpc_version_point); |
| #endif |
| } |
|
|
|
|
|
|
| static void |
| testEnv(void) { |
| xmlrpc_env env, env2; |
|
|
| |
| xmlrpc_env_init(&env); |
| TEST(!env.fault_occurred); |
| TEST(env.fault_code == 0); |
| TEST(env.fault_string == NULL); |
|
|
| |
| xmlrpc_env_set_fault(&env, 1, test_string_1); |
| TEST(env.fault_occurred); |
| TEST(env.fault_code == 1); |
| TEST(env.fault_string != test_string_1); |
| TEST(xmlrpc_streq(env.fault_string, test_string_1)); |
|
|
| |
| xmlrpc_env_set_fault(&env, 2, test_string_2); |
| TEST(env.fault_occurred); |
| TEST(env.fault_code == 2); |
| TEST(xmlrpc_streq(env.fault_string, test_string_2)); |
|
|
| |
| xmlrpc_env_set_fault_formatted(&env, 3, "a%s%d", "bar", 9); |
| TEST(env.fault_occurred); |
| TEST(env.fault_code == 3); |
| TEST(xmlrpc_streq(env.fault_string, "abar9")); |
|
|
| |
| xmlrpc_env_clean(&env); |
|
|
| |
| xmlrpc_env_init(&env2); |
| xmlrpc_env_clean(&env2); |
| } |
|
|
|
|
|
|
| static char *(base64_triplets[]) = { |
| "", "", "\r\n", |
| "a", "YQ==", "YQ==\r\n", |
| "aa", "YWE=", "YWE=\r\n", |
| "aaa", "YWFh", "YWFh\r\n", |
| "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", |
| "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY" |
| "2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", |
| "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY" |
| "2Rl\r\n" |
| "ZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=\r\n", |
| NULL}; |
|
|
|
|
|
|
| static void |
| testBase64Conversion(void) { |
|
|
| xmlrpc_env env; |
| char ** triplet; |
|
|
| xmlrpc_env_init(&env); |
|
|
| for (triplet = base64_triplets; *triplet != NULL; triplet += 3) { |
| char * bin_data; |
| char * nocrlf_ascii_data; |
| char * ascii_data; |
| xmlrpc_mem_block * output; |
|
|
| bin_data = *triplet; |
| nocrlf_ascii_data = *(triplet + 1); |
| ascii_data = *(triplet + 2); |
|
|
| |
| output = xmlrpc_base64_encode(&env, |
| (unsigned char*) bin_data, |
| strlen(bin_data)); |
| TEST_NO_FAULT(&env); |
| TEST(output != NULL); |
| TEST(xmlrpc_mem_block_size(output) == strlen(ascii_data)); |
| TEST(memcmp(xmlrpc_mem_block_contents(output), ascii_data, |
| strlen(ascii_data)) == 0); |
| xmlrpc_mem_block_free(output); |
|
|
| |
| output = |
| xmlrpc_base64_encode_without_newlines(&env, |
| (unsigned char*) bin_data, |
| strlen(bin_data)); |
| TEST_NO_FAULT(&env); |
| TEST(output != NULL); |
| TEST(xmlrpc_mem_block_size(output) == strlen(nocrlf_ascii_data)); |
| TEST(memcmp(xmlrpc_mem_block_contents(output), nocrlf_ascii_data, |
| strlen(nocrlf_ascii_data)) == 0); |
| xmlrpc_mem_block_free(output); |
|
|
| |
| output = xmlrpc_base64_decode(&env, ascii_data, strlen(ascii_data)); |
| TEST_NO_FAULT(&env); |
| TEST(output != NULL); |
| TEST(xmlrpc_mem_block_size(output) == strlen(bin_data)); |
| TEST(memcmp(xmlrpc_mem_block_contents(output), bin_data, |
| strlen(bin_data)) == 0); |
| xmlrpc_mem_block_free(output); |
| } |
|
|
| |
| { |
| xmlrpc_env env2; |
| xmlrpc_mem_block * output; |
|
|
| xmlrpc_env_init(&env2); |
| output = xmlrpc_base64_decode(&env2, "====", 4); |
| TEST(output == NULL); |
| TEST_FAULT(&env2, XMLRPC_PARSE_ERROR); |
| xmlrpc_env_clean(&env2); |
| } |
| |
| { |
| xmlrpc_env env2; |
| xmlrpc_mem_block * output; |
| xmlrpc_env_init(&env2); |
| output = xmlrpc_base64_decode(&env2, "a==", 4); |
| TEST(output == NULL); |
| TEST_FAULT(&env2, XMLRPC_PARSE_ERROR); |
| xmlrpc_env_clean(&env2); |
| } |
| xmlrpc_env_clean(&env); |
| } |
|
|
|
|
|
|
| static void |
| testBoundsChecks(void) { |
|
|
| xmlrpc_env env; |
| xmlrpc_value *array; |
| int i1, i2, i3, i4; |
|
|
| |
| xmlrpc_env_init(&env); |
| array = xmlrpc_build_value(&env, "(iii)", 100, 200, 300); |
| TEST_NO_FAULT(&env); |
| xmlrpc_env_clean(&env); |
| |
| |
| xmlrpc_env_init(&env); |
| xmlrpc_decompose_value(&env, array, "(iiii)", &i1, &i2, &i3, &i4); |
| TEST_FAULT(&env, XMLRPC_INDEX_ERROR); |
| xmlrpc_env_clean(&env); |
|
|
| |
| xmlrpc_env_init(&env); |
| xmlrpc_decompose_value(&env, array, "(ii)", &i1, &i2, &i3, &i4); |
| TEST_FAULT(&env, XMLRPC_INDEX_ERROR); |
| xmlrpc_env_clean(&env); |
|
|
| |
| xmlrpc_DECREF(array); |
| } |
|
|
|
|
|
|
| static void |
| testNestingLimit(void) { |
|
|
| xmlrpc_env env; |
| xmlrpc_value *val; |
|
|
| xmlrpc_env_init(&env); |
| |
| |
| |
| |
| |
| xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 3); |
| val = xmlrpc_parse_response(&env, |
| good_response_xml, strlen(good_response_xml)); |
| TEST_NO_FAULT(&env); |
| TEST(val != NULL); |
| xmlrpc_DECREF(val); |
|
|
| |
| xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 2); |
| val = xmlrpc_parse_response(&env, |
| good_response_xml, strlen(good_response_xml)); |
| TEST_FAULT(&env, XMLRPC_PARSE_ERROR); |
| TEST(val == NULL); |
|
|
| |
| xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, XMLRPC_NESTING_LIMIT_DEFAULT); |
| TEST(xmlrpc_limit_get(XMLRPC_NESTING_LIMIT_ID) |
| == XMLRPC_NESTING_LIMIT_DEFAULT); |
|
|
| xmlrpc_env_clean(&env); |
| } |
|
|
|
|
|
|
| static void |
| testXmlSizeLimit(void) { |
|
|
| xmlrpc_env env; |
| const char * methodName; |
| xmlrpc_value * paramsP; |
| |
| |
| |
| |
| |
|
|
| |
| xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, 6); |
| |
| |
| xmlrpc_env_init(&env); |
| xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call), |
| &methodName, ¶msP); |
| TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR); |
| xmlrpc_env_clean(&env); |
|
|
| { |
| xmlrpc_value * resultP; |
| int faultCode; |
| const char * faultString; |
|
|
| |
| xmlrpc_env_init(&env); |
| xmlrpc_parse_response2(&env, |
| good_response_xml, strlen(good_response_xml), |
| &resultP, &faultCode, &faultString); |
| TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR); |
| xmlrpc_env_clean(&env); |
| } |
| |
| xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, XMLRPC_XML_SIZE_LIMIT_DEFAULT); |
| } |
|
|
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| #define TESTDATA_DIR "data" |
|
|
| static const char * goodRequests[] = { |
| TESTDATA_DIR DIRECTORY_SEPARATOR "req_out_of_order.xml", |
| TESTDATA_DIR DIRECTORY_SEPARATOR "req_no_params.xml", |
| TESTDATA_DIR DIRECTORY_SEPARATOR "req_value_name.xml", |
| NULL |
| }; |
|
|
| #define MAX_SAMPLE_FILE_LEN (16 * 1024) |
|
|
|
|
|
|
| static void |
| reportFileOpenError(const char * const path, |
| int const openErrno) { |
|
|
| if (runningUnderWindows) { |
| char cwdname[1024]; |
| char * succeeded; |
|
|
| succeeded = getcwd(cwdname, sizeof(cwdname)); |
| if (succeeded) |
| fprintf(stderr, "Running in current work directory '%s'\n", |
| cwdname); |
| } |
| fprintf(stderr, "Could not open file '%s'. errno=%d (%s)\n", |
| path, openErrno, strerror(openErrno)); |
| } |
|
|
|
|
|
|
| static void |
| readFile(const char * const path, |
| const char ** const outDataP, |
| size_t * const outSizeP) { |
|
|
| static char fileBuff[MAX_SAMPLE_FILE_LEN]; |
|
|
| FILE * fileP; |
| size_t bytesRead; |
|
|
| fileP = fopen(path, "r"); |
|
|
| if (fileP == NULL) { |
| |
| |
| |
| reportFileOpenError(path, errno); |
| exit(1); |
| } |
| |
| |
| |
| |
| |
| bytesRead = fread(fileBuff, sizeof(char), MAX_SAMPLE_FILE_LEN, fileP); |
| TEST(0 < bytesRead && bytesRead < MAX_SAMPLE_FILE_LEN); |
| |
| fclose(fileP); |
|
|
| *outDataP = fileBuff; |
| *outSizeP = bytesRead; |
| } |
|
|
|
|
|
|
| static void |
| testSampleFiles(void) { |
|
|
| xmlrpc_env env; |
| const char ** pathP; |
|
|
| xmlrpc_env_init(&env); |
|
|
| |
|
|
| for (pathP = goodRequests; *pathP != NULL; ++pathP) { |
| const char * const path = *pathP; |
|
|
| const char * data; |
| size_t dataLen; |
| const char * methodName; |
| xmlrpc_value * params; |
|
|
| readFile(path, &data, &dataLen); |
|
|
| xmlrpc_parse_call(&env, data, dataLen, &methodName, ¶ms); |
|
|
| TEST_NO_FAULT(&env); |
|
|
| strfree(methodName); |
| xmlrpc_DECREF(params); |
| } |
|
|
| xmlrpc_env_clean(&env); |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #if HAVE_UNICODE_WCHAR |
|
|
| typedef struct { |
| char *utf8; |
| wchar_t wcs[16]; |
| } utf8_and_wcs; |
|
|
| static utf8_and_wcs good_utf8[] = { |
|
|
| |
| {"\316\272\341\275\271\317\203\316\274\316\265", |
| {0x03BA, 0x1F79, 0x03C3, 0x03BC, 0x03B5, 0}}, |
|
|
| |
| |
| {"\302\200", {0x0080, 0}}, |
| {"\340\240\200", {0x0800, 0}}, |
|
|
| |
| {"\177", {0x007F, 0}}, |
| {"\337\277", {0x07FF, 0}}, |
| |
|
|
| |
| {"\001", {0x0001, 0}}, |
| {"\355\237\277", {0xD7FF, 0}}, |
| {"\356\200\200", {0xE000, 0}}, |
| {"\357\277\275", {0xFFFD, 0}}, |
|
|
| |
| {"", {0}}, |
| {"abc", {0x0061, 0x0062, 0x0063, 0}}, |
| {"[\302\251]", {0x005B, 0x00A9, 0x005D, 0}}, |
| |
| {NULL, {0}} |
| }; |
|
|
| static char *(bad_utf8[]) = { |
|
|
| |
| "\200", "\277", |
|
|
| |
| "\300", "\300x", "\300xx", |
| "\340", "\340x", "\340xx", "\340xxx", |
|
|
| |
| "\340\200", "\340\200x", "\340\200xx", |
| "\357\277", "\357\277x", "\357\277xx", |
|
|
| |
| "\376", "\377", |
|
|
| |
| "\300\257", "\340\200\257", |
|
|
| |
| "\300\200", "\340\200\200", |
|
|
| |
| "\301\277", "\340\237\277", |
|
|
| |
| "\357\277\276", |
| "\357\277\277", |
|
|
| |
| "\355\240\200", |
| "\355\277\277", |
| "\355\240\200\355\260\200", |
| "\355\257\277\355\277\277", |
|
|
| |
| |
| |
| "\360\220\200\200", |
| "\370\210\200\200\200", |
| "\374\204\200\200\200\200", |
|
|
| NULL |
| }; |
| #endif |
|
|
| |
| |
| #if 0 |
| #ifndef HAVE_WCSNCMP |
| int wcsncmp(wchar_t *wcs1, wchar_t* wcs2, size_t len) |
| { |
| size_t i; |
| |
| unsigned long c1, c2; |
| for (i=0; i < len; i++) { |
| c1 = wcs1[i]; |
| c2 = wcs2[i]; |
| |
| if (c1 == 0 || c1 != c2) |
| return c1 - c2; |
| } |
| return 0; |
| } |
| #endif |
| #endif |
|
|
| static void |
| test_utf8_coding(void) { |
|
|
| #if HAVE_UNICODE_WCHAR |
| xmlrpc_env env, env2; |
| utf8_and_wcs *good_data; |
| char **bad_data; |
| char *utf8; |
| wchar_t *wcs; |
| xmlrpc_mem_block *output; |
|
|
| xmlrpc_env_init(&env); |
|
|
| |
| for (good_data = good_utf8; good_data->utf8 != NULL; good_data++) { |
| utf8 = good_data->utf8; |
| wcs = good_data->wcs; |
|
|
| |
| xmlrpc_validate_utf8(&env, utf8, strlen(utf8)); |
| TEST_NO_FAULT(&env); |
|
|
| |
| output = xmlrpc_utf8_to_wcs(&env, utf8, strlen(utf8)); |
| TEST_NO_FAULT(&env); |
| TEST(output != NULL); |
| TEST(wcslen(wcs) == XMLRPC_TYPED_MEM_BLOCK_SIZE(wchar_t, output)); |
| TEST(0 == |
| wcsncmp(wcs, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(wchar_t, output), |
| wcslen(wcs))); |
| xmlrpc_mem_block_free(output); |
|
|
| |
| output = xmlrpc_wcs_to_utf8(&env, wcs, wcslen(wcs)); |
| TEST_NO_FAULT(&env); |
| TEST(output != NULL); |
| TEST(strlen(utf8) == XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output)); |
| TEST(xmlrpc_strneq(utf8, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output), |
| strlen(utf8))); |
| xmlrpc_mem_block_free(output); |
| } |
|
|
| |
| for (bad_data = bad_utf8; *bad_data != NULL; bad_data++) { |
| utf8 = *bad_data; |
| |
| |
| xmlrpc_env_init(&env2); |
| xmlrpc_validate_utf8(&env2, utf8, strlen(utf8)); |
| TEST_FAULT(&env2, XMLRPC_INVALID_UTF8_ERROR); |
| |
| xmlrpc_env_clean(&env2); |
|
|
| |
| xmlrpc_env_init(&env2); |
| output = xmlrpc_utf8_to_wcs(&env2, utf8, strlen(utf8)); |
| TEST_FAULT(&env2, XMLRPC_INVALID_UTF8_ERROR); |
| TEST(output == NULL); |
| xmlrpc_env_clean(&env2); |
| } |
| xmlrpc_env_clean(&env); |
| #endif |
| } |
|
|
|
|
|
|
| static void |
| test_server_cgi_maybe(void) { |
|
|
| #ifndef _WIN32 |
|
|
| test_server_cgi(); |
|
|
| #endif |
| } |
|
|
|
|
|
|
| static void |
| test_client_maybe(void) { |
|
|
| #ifndef _WIN32 |
|
|
| test_client(); |
|
|
| #endif |
| } |
|
|
|
|
|
|
| int |
| main(int argc, |
| char ** argv ATTR_UNUSED) { |
|
|
| int retval; |
|
|
| if (argc-1 > 0) { |
| fprintf(stderr, "There are no arguments.\n"); |
| retval = 1; |
| } else { |
| xmlrpc_env env; |
| xmlrpc_env_init(&env); |
| xmlrpc_init(&env); |
| testVersion(); |
| testEnv(); |
| printf("\n"); |
| test_memBlock(); |
| testBase64Conversion(); |
| printf("\n"); |
| test_value(); |
| testBoundsChecks(); |
| printf("\n"); |
| test_serialize(); |
| test_parse_xml(); |
| test_method_registry(); |
| testNestingLimit(); |
| testXmlSizeLimit(); |
| testSampleFiles(); |
| printf("\n"); |
| test_server_cgi_maybe(); |
| test_abyss(); |
| test_server_abyss(); |
|
|
| test_utf8_coding(); |
|
|
| printf("\n"); |
|
|
| test_client_maybe(); |
|
|
| printf("\n"); |
|
|
| xmlrpc_term(); |
|
|
| |
| printf("Ran %d tests, %d failed, %.1f%% passed\n", |
| total_tests, total_failures, |
| 100.0 - (100.0 * total_failures) / total_tests); |
|
|
| |
| if (total_failures == 0) { |
| printf("OK\n"); |
| retval = 0; |
| } else { |
| retval = 1; |
| printf("FAILED\n"); |
| } |
| xmlrpc_env_clean(&env); |
| } |
| return retval; |
| } |
|
|
|
|
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|