mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-29 14:44:17 +00:00
add xmlrpc-c 1.03.14 to in tree libs
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3772 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
1 parent
6d9679b164
commit
3abb7730b2
338 files changed
+98032
-2
No files matched your search
@@ -0,0 +1,3 @@
|
||||
Makefile
|
||||
test
|
||||
cgitest1
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include "test.h"
|
||||
#include "cgi.h"
|
||||
|
||||
static const char cgiResponse1[] =
|
||||
"....Status: 200 OK\n"
|
||||
"Content-type: text/xml; charset=\"utf-8\"\n"
|
||||
"Content-length: 141\n"
|
||||
"\n"
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
|
||||
"<methodResponse>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><i4>12</i4></value></param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodResponse>\r\n";
|
||||
|
||||
|
||||
|
||||
void
|
||||
test_server_cgi(void) {
|
||||
/*----------------------------------------------------------------------------
|
||||
Here, we pretend to be a web server when someone has requested a POST
|
||||
to the CGI script "cgitest1".
|
||||
-----------------------------------------------------------------------------*/
|
||||
FILE * cgiOutputP;
|
||||
|
||||
printf("Running CGI tests...\n");
|
||||
|
||||
cgiOutputP = popen("REQUEST_METHOD=POST "
|
||||
"CONTENT_TYPE=text/xml "
|
||||
"CONTENT_LENGTH=211 "
|
||||
"./cgitest1 "
|
||||
"<sample_add_call.xml",
|
||||
"r");
|
||||
|
||||
if (cgiOutputP == NULL)
|
||||
TEST_ERROR("Unable to run 'cgitest' program.");
|
||||
else {
|
||||
unsigned char cgiResponse[4096];
|
||||
size_t bytesRead;
|
||||
|
||||
bytesRead = fread(cgiResponse, 1, sizeof(cgiResponse), cgiOutputP);
|
||||
|
||||
TEST(bytesRead == strlen(cgiResponse1));
|
||||
|
||||
TEST(memcmp(cgiResponse, cgiResponse1, bytesRead) == 0);
|
||||
}
|
||||
printf("\n");
|
||||
printf("CGI tests done.\n");
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
void
|
||||
test_server_cgi(void);
|
||||
@@ -0,0 +1,79 @@
|
||||
/*============================================================================
|
||||
Act like a CGI script -- read POST data from Standard Input, interpret
|
||||
it as an XML-RPC call, and write an XML-RPC response to Standard Output.
|
||||
|
||||
This is for use by a test program.
|
||||
============================================================================*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include "xmlrpc-c/base.h"
|
||||
#include "xmlrpc-c/server.h"
|
||||
#include "xmlrpc-c/server_cgi.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
|
||||
int total_tests;
|
||||
int total_failures;
|
||||
|
||||
|
||||
|
||||
static xmlrpc_value *
|
||||
sample_add(xmlrpc_env * const env,
|
||||
xmlrpc_value * const param_array,
|
||||
void * const user_data ATTR_UNUSED) {
|
||||
|
||||
xmlrpc_int32 x, y, z;
|
||||
|
||||
/* Parse our argument array. */
|
||||
xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y);
|
||||
if (env->fault_occurred)
|
||||
return NULL;
|
||||
|
||||
/* Add our two numbers. */
|
||||
z = x + y;
|
||||
|
||||
/* Return our result. */
|
||||
return xmlrpc_build_value(env, "i", z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc ATTR_UNUSED,
|
||||
char ** argv ATTR_UNUSED) {
|
||||
|
||||
xmlrpc_env env;
|
||||
xmlrpc_registry * registryP;
|
||||
xmlrpc_value * argArrayP;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
registryP = xmlrpc_registry_new(&env);
|
||||
TEST(registryP != NULL);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
xmlrpc_registry_add_method(&env, registryP, NULL, "sample.add",
|
||||
sample_add, NULL);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
argArrayP = xmlrpc_build_value(&env, "(ii)",
|
||||
(xmlrpc_int32) 25, (xmlrpc_int32) 17);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* The following reads from Standard Input and writes to Standard
|
||||
Output
|
||||
*/
|
||||
xmlrpc_server_cgi_process_call(registryP);
|
||||
|
||||
xmlrpc_DECREF(argArrayP);
|
||||
xmlrpc_registry_free(registryP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include "xmlrpc-c/base.h"
|
||||
#include "xmlrpc-c/client.h"
|
||||
|
||||
#include "test.h"
|
||||
#include "client.h"
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_init_cleanup(void) {
|
||||
|
||||
xmlrpc_env env;
|
||||
struct xmlrpc_clientparms clientParms1;
|
||||
struct xmlrpc_curl_xportparms curlTransportParms1;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
xmlrpc_client_init2(&env, 0, "testprog", "1.0", NULL, 0);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_client_cleanup();
|
||||
|
||||
xmlrpc_client_init2(&env, 0, "testprog", "1.0", &clientParms1, 0);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_client_cleanup();
|
||||
|
||||
clientParms1.transport = "curl";
|
||||
xmlrpc_client_init2(&env, 0, "testprog", "1.0",
|
||||
&clientParms1, XMLRPC_CPSIZE(transport));
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_client_cleanup();
|
||||
|
||||
clientParms1.transportparmsP = NULL;
|
||||
xmlrpc_client_init2(&env, 0, "testprog", "1.0",
|
||||
&clientParms1, XMLRPC_CPSIZE(transportparmsP));
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_client_cleanup();
|
||||
|
||||
clientParms1.transportparmsP = (struct xmlrpc_xportparms *)
|
||||
&curlTransportParms1;
|
||||
{
|
||||
xmlrpc_env env2;
|
||||
xmlrpc_env_init(&env2);
|
||||
xmlrpc_client_init2(&env2, 0, "testprog", "1.0",
|
||||
&clientParms1, XMLRPC_CPSIZE(transportparmsP));
|
||||
TEST_FAULT(&env2, XMLRPC_INTERNAL_ERROR);
|
||||
}
|
||||
clientParms1.transportparm_size = 0;
|
||||
xmlrpc_client_init2(&env, 0, "testprog", "1.0",
|
||||
&clientParms1, XMLRPC_CPSIZE(transportparm_size));
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_client_cleanup();
|
||||
|
||||
curlTransportParms1.network_interface = "eth0";
|
||||
clientParms1.transportparm_size = XMLRPC_CXPSIZE(network_interface);
|
||||
xmlrpc_client_init2(&env, 0, "testprog", "1.0",
|
||||
&clientParms1, XMLRPC_CPSIZE(transportparm_size));
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_client_cleanup();
|
||||
|
||||
curlTransportParms1.no_ssl_verifypeer = 1;
|
||||
curlTransportParms1.no_ssl_verifyhost = 1;
|
||||
clientParms1.transportparm_size = XMLRPC_CXPSIZE(no_ssl_verifyhost);
|
||||
xmlrpc_client_init2(&env, 0, "testprog", "1.0",
|
||||
&clientParms1, XMLRPC_CPSIZE(transportparm_size));
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_client_cleanup();
|
||||
|
||||
curlTransportParms1.user_agent = "testprog/1.0";
|
||||
clientParms1.transportparm_size = XMLRPC_CXPSIZE(user_agent);
|
||||
xmlrpc_client_init2(&env, 0, "testprog", "1.0",
|
||||
&clientParms1, XMLRPC_CPSIZE(transportparm_size));
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_client_cleanup();
|
||||
|
||||
xmlrpc_client_init(0, "testprog", "1.0");
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_client_cleanup();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
test_client(void) {
|
||||
|
||||
printf("Running client tests.");
|
||||
|
||||
test_init_cleanup();
|
||||
|
||||
printf("\n");
|
||||
printf("Client tests done.\n");
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
void
|
||||
test_client(void);
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "*** Testing for heap block overruns..."
|
||||
efrpctest
|
||||
if ! test $?; then exit 1; fi
|
||||
|
||||
echo "*** Testing for heap block underruns..."
|
||||
EF_PROTECT_BELOW=1 efrpctest
|
||||
if ! test $?; then exit 1; fi
|
||||
|
||||
echo "*** Testing for access to freed heap blocks..."
|
||||
EF_PROTECT_FREE=1 efrpctest
|
||||
if ! test $?; then exit 1; fi
|
||||
|
||||
echo "*** Testing for single-byte overruns..."
|
||||
EF_ALIGNMENT=0 efrpctest
|
||||
if ! test $?; then exit 1; fi
|
||||
@@ -0,0 +1,11 @@
|
||||
POST /cgi-bin/sample-cgi.cgi 1.0
|
||||
Host: localhost
|
||||
Content-Type: text/xml
|
||||
Content-Length: 141
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>system.listMethods</methodName>
|
||||
<params>
|
||||
</params>
|
||||
</methodCall>
|
||||
@@ -0,0 +1,297 @@
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include "xmlrpc-c/base.h"
|
||||
#include "xmlrpc-c/xmlparser.h"
|
||||
|
||||
#include "test.h"
|
||||
#include "xml_data.h"
|
||||
#include "parse_xml.h"
|
||||
|
||||
|
||||
|
||||
static void test_expat (void)
|
||||
{
|
||||
xmlrpc_env env;
|
||||
xml_element *elem, *array, *data, *value1, *i4;
|
||||
char *cdata;
|
||||
size_t size;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
/* Parse a moderately complex XML document. */
|
||||
elem = xml_parse(&env, expat_data, strlen(expat_data));
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(elem != NULL);
|
||||
|
||||
/* Verify our results. */
|
||||
TEST(strcmp(xml_element_name(elem), "value") == 0);
|
||||
TEST(xml_element_children_size(elem) == 1);
|
||||
array = xml_element_children(elem)[0];
|
||||
TEST(strcmp(xml_element_name(array), "array") == 0);
|
||||
TEST(xml_element_children_size(array) == 1);
|
||||
data = xml_element_children(array)[0];
|
||||
TEST(strcmp(xml_element_name(data), "data") == 0);
|
||||
TEST(xml_element_children_size(data) > 1);
|
||||
value1 = xml_element_children(data)[0];
|
||||
TEST(strcmp(xml_element_name(value1), "value") == 0);
|
||||
TEST(xml_element_children_size(value1) == 1);
|
||||
i4 = xml_element_children(value1)[0];
|
||||
TEST(strcmp(xml_element_name(i4), "i4") == 0);
|
||||
TEST(xml_element_children_size(i4) == 0);
|
||||
cdata = xml_element_cdata(i4);
|
||||
size = xml_element_cdata_size(i4);
|
||||
TEST(size == strlen("2147483647"));
|
||||
TEST(memcmp(cdata, "2147483647", strlen("2147483647")) == 0);
|
||||
|
||||
/* Test cleanup code (w/memprof). */
|
||||
xml_element_free(elem);
|
||||
|
||||
/* Try to parse broken XML. We want to know that a proper error occurs,
|
||||
** AND that we don't leak any memory (w/memprof). */
|
||||
elem = xml_parse(&env, expat_error_data, strlen(expat_error_data));
|
||||
TEST(env.fault_occurred);
|
||||
TEST(elem == NULL);
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_parse_xml_value(void) {
|
||||
|
||||
xmlrpc_env env, env2;
|
||||
xmlrpc_value *s, *sval;
|
||||
xmlrpc_int32 int_max, int_min, int_one;
|
||||
xmlrpc_bool bool_false, bool_true;
|
||||
char *str_hello, *str_untagged, *datetime;
|
||||
unsigned char *b64_data;
|
||||
size_t b64_len;
|
||||
double negone, zero, one;
|
||||
int size, sval_int;
|
||||
const char **bad_value;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
{
|
||||
xmlrpc_value * valueP;
|
||||
|
||||
/* Parse a correctly-formed response. */
|
||||
valueP = xmlrpc_parse_response(&env, correct_value,
|
||||
strlen(correct_value));
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(valueP != NULL);
|
||||
|
||||
/* Analyze it and make sure it contains the correct values. */
|
||||
xmlrpc_decompose_value(
|
||||
&env, valueP, "((iibbs68())idddSs)",
|
||||
&int_max, &int_min,
|
||||
&bool_false, &bool_true, &str_hello,
|
||||
&b64_data, &b64_len, &datetime,
|
||||
&int_one, &negone, &zero, &one, &s, &str_untagged);
|
||||
|
||||
xmlrpc_DECREF(valueP);
|
||||
}
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(int_max == INT_MAX);
|
||||
TEST(int_min == INT_MIN);
|
||||
TEST(!bool_false);
|
||||
TEST(bool_true);
|
||||
TEST(strlen(str_hello) == strlen("Hello, world! <&>"));
|
||||
TEST(strcmp(str_hello, "Hello, world! <&>") == 0);
|
||||
TEST(b64_len == 11);
|
||||
TEST(memcmp(b64_data, "base64 data", b64_len) == 0);
|
||||
TEST(strcmp(datetime, "19980717T14:08:55") == 0);
|
||||
TEST(int_one == 1);
|
||||
TEST(negone == -1.0);
|
||||
TEST(zero == 0.0);
|
||||
TEST(one == 1.0);
|
||||
TEST(strcmp(str_untagged, "Untagged string") == 0);
|
||||
free(str_hello);
|
||||
free(b64_data);
|
||||
free(datetime);
|
||||
free(str_untagged);
|
||||
|
||||
/* Analyze the contents of our struct. */
|
||||
TEST(s != NULL);
|
||||
size = xmlrpc_struct_size(&env, s);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(size == 2);
|
||||
sval = xmlrpc_struct_get_value(&env, s, "ten <&>");
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_decompose_value(&env, sval, "i", &sval_int);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(sval_int == 10);
|
||||
sval = xmlrpc_struct_get_value(&env, s, "twenty");
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_decompose_value(&env, sval, "i", &sval_int);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(sval_int == 20);
|
||||
xmlrpc_DECREF(s);
|
||||
|
||||
/* Test our error-checking code. This is exposed to potentially-malicious
|
||||
** network data, so we need to handle evil data gracefully, without
|
||||
** barfing or leaking memory. (w/memprof) */
|
||||
|
||||
{
|
||||
xmlrpc_value * valueP;
|
||||
|
||||
/* First, test some poorly-formed XML data. */
|
||||
xmlrpc_env_init(&env2);
|
||||
valueP = xmlrpc_parse_response(&env2, unparseable_value,
|
||||
strlen(unparseable_value));
|
||||
TEST_FAULT(&env2, XMLRPC_PARSE_ERROR);
|
||||
TEST(valueP == NULL);
|
||||
xmlrpc_env_clean(&env2);
|
||||
}
|
||||
/* Next, check for bogus values. These are all well-formed XML, but
|
||||
** they aren't legal XML-RPC. */
|
||||
for (bad_value = bad_values; *bad_value != NULL; bad_value++) {
|
||||
xmlrpc_value * valueP;
|
||||
xml_element *elem;
|
||||
|
||||
/* First, check to make sure that our test case is well-formed XML.
|
||||
** (It's easy to make mistakes when writing the test cases!) */
|
||||
elem = xml_parse(&env, *bad_value, strlen(*bad_value));
|
||||
TEST_NO_FAULT(&env);
|
||||
xml_element_free(elem);
|
||||
|
||||
/* Now, make sure the higher-level routine barfs appropriately. */
|
||||
xmlrpc_env_init(&env2);
|
||||
valueP = xmlrpc_parse_response(&env2, *bad_value, strlen(*bad_value));
|
||||
TEST_FAULT(&env2, XMLRPC_PARSE_ERROR);
|
||||
TEST(valueP == NULL);
|
||||
xmlrpc_env_clean(&env2);
|
||||
}
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
static void test_parse_xml_response (void)
|
||||
{
|
||||
xmlrpc_env env, env2;
|
||||
int i1;
|
||||
const char **bad_resp;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
{
|
||||
xmlrpc_value * v;
|
||||
/* Parse a valid response. */
|
||||
v = xmlrpc_parse_response(&env, serialized_response,
|
||||
strlen(serialized_response));
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(v != NULL);
|
||||
xmlrpc_decompose_value(&env, v, "i", &i1);
|
||||
xmlrpc_DECREF(v);
|
||||
}
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(i1 == 30);
|
||||
|
||||
{
|
||||
xmlrpc_value * v;
|
||||
xmlrpc_env fault;
|
||||
|
||||
/* Parse a valid fault. */
|
||||
xmlrpc_env_init(&fault);
|
||||
v = xmlrpc_parse_response(&fault, serialized_fault,
|
||||
strlen(serialized_fault));
|
||||
|
||||
TEST(fault.fault_occurred);
|
||||
TEST(fault.fault_code == 6);
|
||||
TEST(strcmp(fault.fault_string, "A fault occurred") == 0);
|
||||
xmlrpc_env_clean(&fault);
|
||||
}
|
||||
/* We don't need to test our handling of poorly formatted XML here,
|
||||
** because we already did that in test_parse_xml_value. */
|
||||
|
||||
/* Next, check for bogus responses. These are all well-formed XML, but
|
||||
** they aren't legal XML-RPC. */
|
||||
for (bad_resp = bad_responses; *bad_resp != NULL; bad_resp++) {
|
||||
xmlrpc_value * v;
|
||||
xml_element *elem;
|
||||
|
||||
/* First, check to make sure that our test case is well-formed XML.
|
||||
** (It's easy to make mistakes when writing the test cases!) */
|
||||
elem = xml_parse(&env, *bad_resp, strlen(*bad_resp));
|
||||
TEST_NO_FAULT(&env);
|
||||
xml_element_free(elem);
|
||||
|
||||
/* Now, make sure the higher-level routine barfs appropriately. */
|
||||
xmlrpc_env_init(&env2);
|
||||
v = xmlrpc_parse_response(&env2, *bad_resp, strlen(*bad_resp));
|
||||
TEST(env2.fault_occurred);
|
||||
TEST(env2.fault_code != 0); /* We use 0 as a code in our bad faults. */
|
||||
TEST(v == NULL);
|
||||
xmlrpc_env_clean(&env2);
|
||||
}
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
static void test_parse_xml_call (void)
|
||||
{
|
||||
xmlrpc_env env, env2;
|
||||
const char *method_name;
|
||||
xmlrpc_value *params;
|
||||
int i1, i2;
|
||||
const char **bad_call;
|
||||
xml_element *elem;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
/* Parse a valid call. */
|
||||
xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call),
|
||||
&method_name, ¶ms);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(params != NULL);
|
||||
xmlrpc_decompose_value(&env, params, "(ii)", &i1, &i2);
|
||||
xmlrpc_DECREF(params);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(strcmp(method_name, "gloom&doom") == 0);
|
||||
TEST(i1 == 10 && i2 == 20);
|
||||
strfree(method_name);
|
||||
|
||||
/* Test some poorly-formed XML data. */
|
||||
xmlrpc_env_init(&env2);
|
||||
xmlrpc_parse_call(&env2, unparseable_value, strlen(unparseable_value),
|
||||
&method_name, ¶ms);
|
||||
TEST_FAULT(&env2, XMLRPC_PARSE_ERROR);
|
||||
TEST(method_name == NULL && params == NULL);
|
||||
xmlrpc_env_clean(&env2);
|
||||
|
||||
/* Next, check for bogus values. These are all well-formed XML, but
|
||||
** they aren't legal XML-RPC. */
|
||||
for (bad_call = bad_calls; *bad_call != NULL; bad_call++) {
|
||||
|
||||
/* First, check to make sure that our test case is well-formed XML.
|
||||
** (It's easy to make mistakes when writing the test cases!) */
|
||||
elem = xml_parse(&env, *bad_call, strlen(*bad_call));
|
||||
TEST_NO_FAULT(&env);
|
||||
xml_element_free(elem);
|
||||
|
||||
/* Now, make sure the higher-level routine barfs appropriately. */
|
||||
xmlrpc_env_init(&env2);
|
||||
xmlrpc_parse_call(&env2, *bad_call, strlen(*bad_call),
|
||||
&method_name, ¶ms);
|
||||
TEST_FAULT(&env2, XMLRPC_PARSE_ERROR);
|
||||
TEST(method_name == NULL && params == NULL);
|
||||
xmlrpc_env_clean(&env2);
|
||||
}
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
test_parse_xml(void) {
|
||||
|
||||
test_expat();
|
||||
test_parse_xml_value();
|
||||
test_parse_xml_response();
|
||||
test_parse_xml_call();
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
void
|
||||
test_parse_xml(void);
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- This may or may not be legal XML-RPC, but some old clients (including
|
||||
Ruby and xmlrpc-epi) send it. This should be interpreted as a call with no
|
||||
parameters. -->
|
||||
|
||||
<methodCall>
|
||||
<methodName>foo</methodName>
|
||||
</methodCall>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<params>
|
||||
<param>
|
||||
<value><int>2</int></value>
|
||||
</param>
|
||||
<param>
|
||||
<value><int>2</int></value>
|
||||
</param>
|
||||
</params>
|
||||
<methodName>add</methodName>
|
||||
</methodCall>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>foo</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value><struct>
|
||||
<member>
|
||||
<value><i4>0</i4></value>
|
||||
<name>child elements reversed!</name>
|
||||
</member>
|
||||
</struct></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<methodCall>
|
||||
<methodName>sample.add</methodName>
|
||||
<params>
|
||||
<param><value><i4>5</i4></value></param>
|
||||
<param><value><i4>7</i4></value></param>
|
||||
</params>
|
||||
</methodCall>
|
||||
@@ -0,0 +1,275 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include "xmlrpc-c/base.h"
|
||||
|
||||
#include "test.h"
|
||||
#include "xml_data.h"
|
||||
#include "serialize.h"
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_serialize_basic(void) {
|
||||
|
||||
xmlrpc_env env;
|
||||
xmlrpc_value * v;
|
||||
xmlrpc_mem_block *output;
|
||||
size_t size;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
/* Build a nice, messy value to serialize. We should attempt to use
|
||||
** use every data type except double (which doesn't serialize in a
|
||||
** portable manner. */
|
||||
v = xmlrpc_build_value(&env, "(iibbs68())",
|
||||
(xmlrpc_int32) INT_MAX, (xmlrpc_int32) INT_MIN,
|
||||
(xmlrpc_bool) 0, (xmlrpc_bool) 1,
|
||||
"Hello, world! <&>",
|
||||
"base64 data", (size_t) 11,
|
||||
"19980717T14:08:55");
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Serialize the value. */
|
||||
output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_serialize_value(&env, output, v);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Make sure we serialized the correct value. */
|
||||
size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output);
|
||||
TEST(size == strlen(serialized_data));
|
||||
TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output),
|
||||
serialized_data, size) == 0);
|
||||
|
||||
/* (Debugging code to display the value.) */
|
||||
/* XMLRPC_TYPED_MEM_BLOCK_APPEND(char, &env, output, "\0", 1);
|
||||
** TEST_NO_FAULT(&env);
|
||||
** printf("%s\n", XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output)); */
|
||||
|
||||
/* Clean up our value. */
|
||||
XMLRPC_TYPED_MEM_BLOCK_FREE(char, output);
|
||||
xmlrpc_DECREF(v);
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_serialize_double(void) {
|
||||
|
||||
/* Test serialize of a double. */
|
||||
|
||||
xmlrpc_env env;
|
||||
xmlrpc_value * v;
|
||||
xmlrpc_mem_block *output;
|
||||
char * result;
|
||||
/* serialized result, as asciiz string */
|
||||
size_t resultLength;
|
||||
/* Length in characters of the serialized result */
|
||||
float serializedValue;
|
||||
char nextChar;
|
||||
int itemsMatched;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
/* Build a double to serialize */
|
||||
v = xmlrpc_build_value(&env, "d", 3.14159);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Serialize the value. */
|
||||
output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_serialize_value(&env, output, v);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Make sure we serialized the correct value. Note that because
|
||||
doubles aren't precise, this might serialize as 3.1415899999
|
||||
or something like that. So we check it arithmetically.
|
||||
*/
|
||||
resultLength = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output);
|
||||
result = malloc(resultLength + 1);
|
||||
|
||||
memcpy(result, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output),
|
||||
resultLength);
|
||||
result[resultLength] = '\0';
|
||||
|
||||
itemsMatched = sscanf(result,
|
||||
"<value><double>%f</double></value>\r\n%c",
|
||||
&serializedValue, &nextChar);
|
||||
|
||||
TEST(itemsMatched == 1);
|
||||
TEST(serializedValue - 3.14159 < .000001);
|
||||
/* We'd like to test more precision, but sscanf doesn't do doubles */
|
||||
|
||||
free(result);
|
||||
|
||||
/* Clean up our value. */
|
||||
XMLRPC_TYPED_MEM_BLOCK_FREE(char, output);
|
||||
xmlrpc_DECREF(v);
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_serialize_struct(void) {
|
||||
|
||||
/* Serialize a simple struct. */
|
||||
|
||||
char const serialized_struct[] =
|
||||
"<value><struct>\r\n" \
|
||||
"<member><name><&></name>\r\n" \
|
||||
"<value><i4>10</i4></value></member>\r\n" \
|
||||
"</struct></value>";
|
||||
|
||||
xmlrpc_env env;
|
||||
xmlrpc_value * v;
|
||||
xmlrpc_mem_block *output;
|
||||
size_t size;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
v = xmlrpc_build_value(&env, "{s:i}", "<&>", (xmlrpc_int32) 10);
|
||||
TEST_NO_FAULT(&env);
|
||||
output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_serialize_value(&env, output, v);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Make sure we serialized the correct value. */
|
||||
size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output);
|
||||
TEST(size == strlen(serialized_struct));
|
||||
TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output),
|
||||
serialized_struct, size) == 0);
|
||||
|
||||
/* Clean up our struct. */
|
||||
XMLRPC_TYPED_MEM_BLOCK_FREE(char, output);
|
||||
xmlrpc_DECREF(v);
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_serialize_methodResponse(void) {
|
||||
|
||||
/* Serialize a methodResponse. */
|
||||
|
||||
xmlrpc_env env;
|
||||
xmlrpc_value * v;
|
||||
xmlrpc_mem_block *output;
|
||||
size_t size;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0);
|
||||
TEST_NO_FAULT(&env);
|
||||
v = xmlrpc_build_value(&env, "i", (xmlrpc_int32) 30);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_serialize_response(&env, output, v);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Make sure we serialized the correct value. */
|
||||
size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output);
|
||||
TEST(size == strlen(serialized_response));
|
||||
TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output),
|
||||
serialized_response, size) == 0);
|
||||
|
||||
/* Clean up our methodResponse. */
|
||||
xmlrpc_DECREF(v);
|
||||
XMLRPC_TYPED_MEM_BLOCK_FREE(char, output);
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_serialize_methodCall(void) {
|
||||
|
||||
/* Serialize a methodCall. */
|
||||
|
||||
xmlrpc_env env;
|
||||
xmlrpc_value * v;
|
||||
xmlrpc_mem_block *output;
|
||||
size_t size;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0);
|
||||
TEST_NO_FAULT(&env);
|
||||
v = xmlrpc_build_value(&env, "(ii)", (xmlrpc_int32) 10, (xmlrpc_int32) 20);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_serialize_call(&env, output, "gloom&doom", v);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Make sure we serialized the correct value. */
|
||||
size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output);
|
||||
TEST(size == strlen(serialized_call));
|
||||
TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output),
|
||||
serialized_call, size) == 0);
|
||||
|
||||
/* Clean up our methodCall. */
|
||||
xmlrpc_DECREF(v);
|
||||
XMLRPC_TYPED_MEM_BLOCK_FREE(char, output);
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_serialize_fault(void) {
|
||||
/* Serialize a fault. */
|
||||
|
||||
xmlrpc_env env;
|
||||
xmlrpc_env fault;
|
||||
xmlrpc_mem_block *output;
|
||||
size_t size;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
output = XMLRPC_TYPED_MEM_BLOCK_NEW(char, &env, 0);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_env_init(&fault);
|
||||
xmlrpc_env_set_fault(&fault, 6, "A fault occurred");
|
||||
xmlrpc_serialize_fault(&env, output, &fault);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Make sure we serialized the correct value. */
|
||||
size = XMLRPC_TYPED_MEM_BLOCK_SIZE(char, output);
|
||||
TEST(size == strlen(serialized_fault));
|
||||
TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output),
|
||||
serialized_fault, size) == 0);
|
||||
|
||||
/* Clean up our fault. */
|
||||
xmlrpc_env_clean(&fault);
|
||||
XMLRPC_TYPED_MEM_BLOCK_FREE(char, output);
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
test_serialize(void) {
|
||||
|
||||
printf("Running serialize tests.");
|
||||
|
||||
test_serialize_basic();
|
||||
test_serialize_double();
|
||||
test_serialize_struct();
|
||||
test_serialize_methodResponse();
|
||||
test_serialize_methodCall();
|
||||
test_serialize_fault();
|
||||
|
||||
printf("\n");
|
||||
printf("Serialize tests done.\n");
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
void
|
||||
test_serialize(void);
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include "xmlrpc-c/base.h"
|
||||
#include "xmlrpc-c/server.h"
|
||||
#include "xmlrpc-c/abyss.h"
|
||||
#include "xmlrpc-c/server_abyss.h"
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include "server_abyss.h"
|
||||
|
||||
|
||||
void
|
||||
test_server_abyss(void) {
|
||||
|
||||
|
||||
xmlrpc_env env;
|
||||
xmlrpc_registry * registryP;
|
||||
TServer abyssServer;
|
||||
|
||||
printf("Running Abyss server tests...\n");
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
registryP = xmlrpc_registry_new(&env);
|
||||
|
||||
TEST(registryP != NULL);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
ServerCreate(&abyssServer, "testserver", 8080, NULL, NULL);
|
||||
|
||||
xmlrpc_server_abyss_set_handlers(&abyssServer, registryP);
|
||||
|
||||
xmlrpc_server_abyss_set_handler(&env, &abyssServer, "/RPC3", registryP);
|
||||
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
ServerFree(&abyssServer);
|
||||
|
||||
printf("\n");
|
||||
printf("Abyss server tests done.\n");
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
void
|
||||
test_server_abyss(void);
|
||||
@@ -0,0 +1,938 @@
|
||||
/* Copyright information is at the end of the file. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "xmlrpc_config.h"
|
||||
|
||||
#include "xmlrpc-c/base.h"
|
||||
#include "xmlrpc-c/server.h"
|
||||
|
||||
#include "test.h"
|
||||
#include "value.h"
|
||||
#include "serialize.h"
|
||||
#include "parse_xml.h"
|
||||
#include "cgi.h"
|
||||
#include "xml_data.h"
|
||||
#include "client.h"
|
||||
#include "server_abyss.h"
|
||||
|
||||
/*=========================================================================
|
||||
** Test Harness
|
||||
**=========================================================================
|
||||
** This is a super light-weight test harness. It's vaguely inspired by
|
||||
** Kent Beck's book on eXtreme Programming (XP)--the output is succinct,
|
||||
** new tests can be coded quickly, and the whole thing runs in a few
|
||||
** second's time.
|
||||
**
|
||||
** To run the tests, type './rpctest'.
|
||||
** To check for memory leaks, install RedHat's 'memprof' utility, and
|
||||
** type 'memprof rpctest'.
|
||||
**
|
||||
** If you add new tests to this file, please deallocate any data
|
||||
** structures you use in the appropriate fashion. This allows us to test
|
||||
** various destructor code for memory leaks.
|
||||
*/
|
||||
|
||||
int total_tests = 0;
|
||||
int total_failures = 0;
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
** Test Data
|
||||
**=========================================================================
|
||||
** Some common test data which need to be allocated at a fixed address,
|
||||
** or which are inconvenient to allocate inline.
|
||||
*/
|
||||
|
||||
static char* test_string_1 = "foo";
|
||||
static char* test_string_2 = "bar";
|
||||
static int test_int_array_1[5] = {1, 2, 3, 4, 5};
|
||||
static int test_int_array_2[3] = {6, 7, 8};
|
||||
static int test_int_array_3[8] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
|
||||
/*=========================================================================
|
||||
** Test Suites
|
||||
**=========================================================================
|
||||
*/
|
||||
|
||||
static void test_env(void)
|
||||
{
|
||||
xmlrpc_env env, env2;
|
||||
char *s;
|
||||
|
||||
/* Test xmlrpc_env_init. */
|
||||
xmlrpc_env_init(&env);
|
||||
TEST(!env.fault_occurred);
|
||||
TEST(env.fault_code == 0);
|
||||
TEST(env.fault_string == NULL);
|
||||
|
||||
/* Test xmlrpc_set_fault. */
|
||||
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(strcmp(env.fault_string, test_string_1) == 0);
|
||||
|
||||
/* Change an existing fault. */
|
||||
xmlrpc_env_set_fault(&env, 2, test_string_2);
|
||||
TEST(env.fault_occurred);
|
||||
TEST(env.fault_code == 2);
|
||||
TEST(strcmp(env.fault_string, test_string_2) == 0);
|
||||
|
||||
/* Set a fault with a format string. */
|
||||
xmlrpc_env_set_fault_formatted(&env, 3, "a%s%d", "bar", 9);
|
||||
TEST(env.fault_occurred);
|
||||
TEST(env.fault_code == 3);
|
||||
TEST(strcmp(env.fault_string, "abar9") == 0);
|
||||
|
||||
/* Set a fault with an oversized string. */
|
||||
s = "12345678901234567890123456789012345678901234567890";
|
||||
xmlrpc_env_set_fault_formatted(&env, 4, "%s%s%s%s%s%s", s, s, s, s, s, s);
|
||||
TEST(env.fault_occurred);
|
||||
TEST(env.fault_code == 4);
|
||||
TEST(strlen(env.fault_string) == 255);
|
||||
|
||||
/* Test cleanup code (with help from memprof). */
|
||||
xmlrpc_env_clean(&env);
|
||||
|
||||
/* Test cleanup code on in absence of xmlrpc_env_set_fault. */
|
||||
xmlrpc_env_init(&env2);
|
||||
xmlrpc_env_clean(&env2);
|
||||
}
|
||||
|
||||
static void test_mem_block (void)
|
||||
{
|
||||
xmlrpc_env env;
|
||||
xmlrpc_mem_block* block;
|
||||
|
||||
xmlrpc_mem_block* typed_heap_block;
|
||||
xmlrpc_mem_block typed_auto_block;
|
||||
void** typed_contents;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
/* Allocate a zero-size block. */
|
||||
block = xmlrpc_mem_block_new(&env, 0);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(block != NULL);
|
||||
TEST(xmlrpc_mem_block_size(block) == 0);
|
||||
|
||||
/* Grow the block a little bit. */
|
||||
xmlrpc_mem_block_resize(&env, block, strlen(test_string_1) + 1);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(xmlrpc_mem_block_size(block) == strlen(test_string_1) + 1);
|
||||
|
||||
/* Insert a string into the block, and resize it by large amount.
|
||||
** We want to cause a reallocation and copy of the block contents. */
|
||||
strcpy(xmlrpc_mem_block_contents(block), test_string_1);
|
||||
xmlrpc_mem_block_resize(&env, block, 10000);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(xmlrpc_mem_block_size(block) == 10000);
|
||||
TEST(strcmp(xmlrpc_mem_block_contents(block), test_string_1) == 0);
|
||||
|
||||
/* Test cleanup code (with help from memprof). */
|
||||
xmlrpc_mem_block_free(block);
|
||||
|
||||
/* Allocate a bigger block. */
|
||||
block = xmlrpc_mem_block_new(&env, 128);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(block != NULL);
|
||||
TEST(xmlrpc_mem_block_size(block) == 128);
|
||||
|
||||
/* Test cleanup code (with help from memprof). */
|
||||
xmlrpc_mem_block_free(block);
|
||||
|
||||
/* Allocate a "typed" memory block. */
|
||||
typed_heap_block = XMLRPC_TYPED_MEM_BLOCK_NEW(void*, &env, 20);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(typed_heap_block != NULL);
|
||||
TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 20);
|
||||
typed_contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(void*, typed_heap_block);
|
||||
TEST(typed_contents != NULL);
|
||||
|
||||
/* Resize a typed memory block. */
|
||||
XMLRPC_TYPED_MEM_BLOCK_RESIZE(void*, &env, typed_heap_block, 100);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, typed_heap_block) == 100);
|
||||
|
||||
/* Test cleanup code (with help from memprof). */
|
||||
XMLRPC_TYPED_MEM_BLOCK_FREE(void*, typed_heap_block);
|
||||
|
||||
/* Test _INIT and _CLEAN for stack-based memory blocks. */
|
||||
XMLRPC_TYPED_MEM_BLOCK_INIT(void*, &env, &typed_auto_block, 30);
|
||||
TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(void*, &typed_auto_block) == 30);
|
||||
XMLRPC_TYPED_MEM_BLOCK_CLEAN(void*, &typed_auto_block);
|
||||
|
||||
/* Test xmlrpc_mem_block_append. */
|
||||
block = XMLRPC_TYPED_MEM_BLOCK_NEW(int, &env, 5);
|
||||
TEST_NO_FAULT(&env);
|
||||
memcpy(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block),
|
||||
test_int_array_1, sizeof(test_int_array_1));
|
||||
XMLRPC_TYPED_MEM_BLOCK_APPEND(int, &env, block, test_int_array_2, 3);
|
||||
TEST(XMLRPC_TYPED_MEM_BLOCK_SIZE(int, block) == 8);
|
||||
TEST(memcmp(XMLRPC_TYPED_MEM_BLOCK_CONTENTS(int, block),
|
||||
test_int_array_3, sizeof(test_int_array_3)) == 0);
|
||||
XMLRPC_TYPED_MEM_BLOCK_FREE(int, block);
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
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 test_base64_conversion (void)
|
||||
{
|
||||
xmlrpc_env env, env2;
|
||||
char **triplet, *bin_data, *nocrlf_ascii_data, *ascii_data;
|
||||
xmlrpc_mem_block *output;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
for (triplet = base64_triplets; *triplet != NULL; triplet += 3) {
|
||||
bin_data = *triplet;
|
||||
nocrlf_ascii_data = *(triplet + 1);
|
||||
ascii_data = *(triplet + 2);
|
||||
|
||||
/* Test our encoding routine. */
|
||||
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);
|
||||
|
||||
/* Test our newline-free encoding routine. */
|
||||
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);
|
||||
|
||||
/* Test our decoding routine. */
|
||||
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);
|
||||
}
|
||||
|
||||
/* Now for something broken... */
|
||||
xmlrpc_env_init(&env2);
|
||||
output = xmlrpc_base64_decode(&env2, "====", 4);
|
||||
TEST(output == NULL);
|
||||
TEST_FAULT(&env2, XMLRPC_PARSE_ERROR);
|
||||
xmlrpc_env_clean(&env2);
|
||||
|
||||
/* Now for something broken in a really sneaky way... */
|
||||
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 test_bounds_checks (void)
|
||||
{
|
||||
xmlrpc_env env;
|
||||
xmlrpc_value *array;
|
||||
int i1, i2, i3, i4;
|
||||
|
||||
/* Get an array to work with. */
|
||||
xmlrpc_env_init(&env);
|
||||
array = xmlrpc_build_value(&env, "(iii)", 100, 200, 300);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_env_clean(&env);
|
||||
|
||||
/* Test xmlrpc_decompose_value with too few values. */
|
||||
xmlrpc_env_init(&env);
|
||||
xmlrpc_decompose_value(&env, array, "(iiii)", &i1, &i2, &i3, &i4);
|
||||
TEST_FAULT(&env, XMLRPC_INDEX_ERROR);
|
||||
xmlrpc_env_clean(&env);
|
||||
|
||||
/* Test xmlrpc_decompose_value with too many values. */
|
||||
xmlrpc_env_init(&env);
|
||||
xmlrpc_decompose_value(&env, array, "(ii)", &i1, &i2, &i3, &i4);
|
||||
TEST_FAULT(&env, XMLRPC_INDEX_ERROR);
|
||||
xmlrpc_env_clean(&env);
|
||||
|
||||
/* Dispose of our array. */
|
||||
xmlrpc_DECREF(array);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
** test_method_registry
|
||||
**=========================================================================
|
||||
** We need to define some static callbacks to test this code.
|
||||
*/
|
||||
|
||||
#define FOO_USER_DATA ((void*) 0xF00)
|
||||
#define BAR_USER_DATA ((void*) 0xBAF)
|
||||
|
||||
static xmlrpc_value *test_foo (xmlrpc_env *env,
|
||||
xmlrpc_value *param_array,
|
||||
void *user_data)
|
||||
{
|
||||
xmlrpc_int32 x, y;
|
||||
|
||||
TEST_NO_FAULT(env);
|
||||
TEST(param_array != NULL);
|
||||
TEST(user_data == FOO_USER_DATA);
|
||||
|
||||
xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y);
|
||||
TEST_NO_FAULT(env);
|
||||
TEST(x == 25);
|
||||
TEST(y == 17);
|
||||
|
||||
return xmlrpc_build_value(env, "i", (xmlrpc_int32) x + y);
|
||||
}
|
||||
|
||||
static xmlrpc_value *test_bar (xmlrpc_env *env,
|
||||
xmlrpc_value *param_array,
|
||||
void *user_data)
|
||||
{
|
||||
xmlrpc_int32 x, y;
|
||||
|
||||
TEST_NO_FAULT(env);
|
||||
TEST(param_array != NULL);
|
||||
TEST(user_data == BAR_USER_DATA);
|
||||
|
||||
xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y);
|
||||
TEST_NO_FAULT(env);
|
||||
TEST(x == 25);
|
||||
TEST(y == 17);
|
||||
|
||||
xmlrpc_env_set_fault(env, 123, "Test fault");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static xmlrpc_value *
|
||||
test_default(xmlrpc_env * const env,
|
||||
const char * const host ATTR_UNUSED,
|
||||
const char * const method_name ATTR_UNUSED,
|
||||
xmlrpc_value * const param_array,
|
||||
void * const user_data) {
|
||||
|
||||
xmlrpc_int32 x, y;
|
||||
|
||||
TEST_NO_FAULT(env);
|
||||
TEST(param_array != NULL);
|
||||
TEST(user_data == FOO_USER_DATA);
|
||||
|
||||
xmlrpc_decompose_value(env, param_array, "(ii)", &x, &y);
|
||||
TEST_NO_FAULT(env);
|
||||
TEST(x == 25);
|
||||
TEST(y == 17);
|
||||
|
||||
return xmlrpc_build_value(env, "i", 2 * (x + y));
|
||||
}
|
||||
|
||||
static xmlrpc_value *
|
||||
process_call_helper (xmlrpc_env *env,
|
||||
xmlrpc_registry *registry,
|
||||
const char *method_name,
|
||||
xmlrpc_value *arg_array)
|
||||
{
|
||||
xmlrpc_mem_block *call, *response;
|
||||
xmlrpc_value *value;
|
||||
|
||||
/* Build a call, and tell the registry to handle it. */
|
||||
call = xmlrpc_mem_block_new(env, 0);
|
||||
TEST_NO_FAULT(env);
|
||||
xmlrpc_serialize_call(env, call, method_name, arg_array);
|
||||
TEST_NO_FAULT(env);
|
||||
response = xmlrpc_registry_process_call(env, registry, NULL,
|
||||
xmlrpc_mem_block_contents(call),
|
||||
xmlrpc_mem_block_size(call));
|
||||
TEST_NO_FAULT(env);
|
||||
TEST(response != NULL);
|
||||
|
||||
/* Parse the response. */
|
||||
value = xmlrpc_parse_response(env, xmlrpc_mem_block_contents(response),
|
||||
xmlrpc_mem_block_size(response));
|
||||
|
||||
xmlrpc_mem_block_free(call);
|
||||
xmlrpc_mem_block_free(response);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_method_registry(void) {
|
||||
|
||||
xmlrpc_env env, env2;
|
||||
xmlrpc_value *arg_array, *value;
|
||||
xmlrpc_registry *registry;
|
||||
xmlrpc_mem_block *response;
|
||||
xmlrpc_int32 i;
|
||||
|
||||
xmlrpc_value *multi;
|
||||
xmlrpc_int32 foo1_result, foo2_result;
|
||||
xmlrpc_int32 bar_code, nosuch_code, multi_code, bogus1_code, bogus2_code;
|
||||
char *bar_string, *nosuch_string, *multi_string;
|
||||
char *bogus1_string, *bogus2_string;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
/* Create a new registry. */
|
||||
registry = xmlrpc_registry_new(&env);
|
||||
TEST(registry != NULL);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Add some test methods. */
|
||||
xmlrpc_registry_add_method(&env, registry, NULL, "test.foo",
|
||||
test_foo, FOO_USER_DATA);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_registry_add_method(&env, registry, NULL, "test.bar",
|
||||
test_bar, BAR_USER_DATA);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Build an argument array for our calls. */
|
||||
arg_array = xmlrpc_build_value(&env, "(ii)",
|
||||
(xmlrpc_int32) 25, (xmlrpc_int32) 17);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Call test.foo and check the result. */
|
||||
value = process_call_helper(&env, registry, "test.foo", arg_array);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(value != NULL);
|
||||
xmlrpc_decompose_value(&env, value, "i", &i);
|
||||
xmlrpc_DECREF(value);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(i == 42);
|
||||
|
||||
/* Call test.bar and check the result. */
|
||||
xmlrpc_env_init(&env2);
|
||||
value = process_call_helper(&env2, registry, "test.bar", arg_array);
|
||||
TEST_FAULT(&env2, 123);
|
||||
TEST(env2.fault_string && strcmp(env2.fault_string, "Test fault") == 0);
|
||||
xmlrpc_env_clean(&env2);
|
||||
|
||||
/* Call a non-existant method and check the result. */
|
||||
xmlrpc_env_init(&env2);
|
||||
value = process_call_helper(&env2, registry, "test.nosuch", arg_array);
|
||||
TEST(value == NULL);
|
||||
TEST_FAULT(&env2, XMLRPC_NO_SUCH_METHOD_ERROR);
|
||||
xmlrpc_env_clean(&env2);
|
||||
|
||||
/* Test system.multicall. */
|
||||
multi = xmlrpc_build_value(&env,
|
||||
"(({s:s,s:V}{s:s,s:V}{s:s,s:V}"
|
||||
"{s:s,s:()}s{}{s:s,s:V}))",
|
||||
"methodName", "test.foo",
|
||||
"params", arg_array,
|
||||
"methodName", "test.bar",
|
||||
"params", arg_array,
|
||||
"methodName", "test.nosuch",
|
||||
"params", arg_array,
|
||||
"methodName", "system.multicall",
|
||||
"params",
|
||||
"bogus_entry",
|
||||
"methodName", "test.foo",
|
||||
"params", arg_array);
|
||||
TEST_NO_FAULT(&env);
|
||||
value = process_call_helper(&env, registry, "system.multicall", multi);
|
||||
TEST_NO_FAULT(&env);
|
||||
xmlrpc_decompose_value(&env, value,
|
||||
"((i){s:i,s:s,*}{s:i,s:s,*}"
|
||||
"{s:i,s:s,*}{s:i,s:s,*}{s:i,s:s,*}(i))",
|
||||
&foo1_result,
|
||||
"faultCode", &bar_code,
|
||||
"faultString", &bar_string,
|
||||
"faultCode", &nosuch_code,
|
||||
"faultString", &nosuch_string,
|
||||
"faultCode", &multi_code,
|
||||
"faultString", &multi_string,
|
||||
"faultCode", &bogus1_code,
|
||||
"faultString", &bogus1_string,
|
||||
"faultCode", &bogus2_code,
|
||||
"faultString", &bogus2_string,
|
||||
&foo2_result);
|
||||
xmlrpc_DECREF(value);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(foo1_result == 42);
|
||||
TEST(bar_code == 123);
|
||||
TEST(strcmp(bar_string, "Test fault") == 0);
|
||||
TEST(nosuch_code == XMLRPC_NO_SUCH_METHOD_ERROR);
|
||||
TEST(multi_code == XMLRPC_REQUEST_REFUSED_ERROR);
|
||||
TEST(foo2_result == 42);
|
||||
xmlrpc_DECREF(multi);
|
||||
free(bar_string);
|
||||
free(nosuch_string);
|
||||
free(multi_string);
|
||||
free(bogus1_string);
|
||||
free(bogus2_string);
|
||||
|
||||
/* PASS bogus XML data and make sure our parser pukes gracefully.
|
||||
** (Because of the way the code is laid out, and the presence of other
|
||||
** test suites, this lets us skip tests for invalid XML-RPC data.) */
|
||||
xmlrpc_env_init(&env2);
|
||||
response = xmlrpc_registry_process_call(&env, registry, NULL,
|
||||
expat_error_data,
|
||||
strlen(expat_error_data));
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(response != NULL);
|
||||
value = xmlrpc_parse_response(&env2, xmlrpc_mem_block_contents(response),
|
||||
xmlrpc_mem_block_size(response));
|
||||
TEST(value == NULL);
|
||||
TEST_FAULT(&env2, XMLRPC_PARSE_ERROR);
|
||||
xmlrpc_mem_block_free(response);
|
||||
xmlrpc_env_clean(&env2);
|
||||
|
||||
xmlrpc_registry_set_default_method(&env, registry, &test_default,
|
||||
FOO_USER_DATA);
|
||||
TEST_NO_FAULT(&env);
|
||||
value = process_call_helper(&env, registry, "test.nosuch", arg_array);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(value != NULL);
|
||||
xmlrpc_decompose_value(&env, value, "i", &i);
|
||||
xmlrpc_DECREF(value);
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(i == 84);
|
||||
|
||||
/* Change the default method. */
|
||||
xmlrpc_registry_set_default_method(&env, registry, &test_default,
|
||||
BAR_USER_DATA);
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Test cleanup code (w/memprof). */
|
||||
xmlrpc_registry_free(registry);
|
||||
xmlrpc_DECREF(arg_array);
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
static void test_nesting_limit (void)
|
||||
{
|
||||
xmlrpc_env env;
|
||||
xmlrpc_value *val;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
/* Test with an adequate limit for (...(...()...)...). */
|
||||
xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 2);
|
||||
val = xmlrpc_parse_response(&env, correct_value, strlen(correct_value));
|
||||
TEST_NO_FAULT(&env);
|
||||
TEST(val != NULL);
|
||||
xmlrpc_DECREF(val);
|
||||
|
||||
/* Test with an inadequate limit. */
|
||||
xmlrpc_limit_set(XMLRPC_NESTING_LIMIT_ID, 1);
|
||||
val = xmlrpc_parse_response(&env, correct_value, strlen(correct_value));
|
||||
TEST_FAULT(&env, XMLRPC_PARSE_ERROR); /* BREAKME - Will change. */
|
||||
TEST(val == NULL);
|
||||
|
||||
/* Reset the default limit. */
|
||||
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 test_xml_size_limit (void)
|
||||
{
|
||||
xmlrpc_env env;
|
||||
const char *method_name;
|
||||
xmlrpc_value *params, *val;
|
||||
|
||||
|
||||
/* NOTE - This test suite only verifies the last-ditch size-checking
|
||||
** code. There should also be matching code in all server (and
|
||||
** preferably all client) modules as well. */
|
||||
|
||||
/* Set our XML size limit to something ridiculous. */
|
||||
xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, 6);
|
||||
|
||||
/* Attempt to parse a call. */
|
||||
xmlrpc_env_init(&env);
|
||||
xmlrpc_parse_call(&env, serialized_call, strlen(serialized_call),
|
||||
&method_name, ¶ms);
|
||||
TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR);
|
||||
TEST(method_name == NULL);
|
||||
TEST(params == NULL);
|
||||
xmlrpc_env_clean(&env);
|
||||
|
||||
/* Attempt to parse a response. */
|
||||
xmlrpc_env_init(&env);
|
||||
val = xmlrpc_parse_response(&env, correct_value, strlen(correct_value));
|
||||
TEST_FAULT(&env, XMLRPC_LIMIT_EXCEEDED_ERROR);
|
||||
TEST(val == NULL);
|
||||
xmlrpc_env_clean(&env);
|
||||
|
||||
/* Reset the default limit. */
|
||||
xmlrpc_limit_set(XMLRPC_XML_SIZE_LIMIT_ID, XMLRPC_XML_SIZE_LIMIT_DEFAULT);
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
** test_sample_files
|
||||
**=========================================================================
|
||||
** Read in a bunch of sample test files and make sure we get plausible
|
||||
** results.
|
||||
**
|
||||
** We use these files to test strange-but-legal encodings, illegal-but-
|
||||
** supported encodings, etc.
|
||||
*/
|
||||
|
||||
static char *good_requests[] = {
|
||||
"req_out_of_order.xml",
|
||||
"req_no_params.xml",
|
||||
"req_value_name.xml",
|
||||
NULL
|
||||
};
|
||||
|
||||
#define MAX_SAMPLE_FILE_LEN (16 * 1024)
|
||||
|
||||
static char file_buff [MAX_SAMPLE_FILE_LEN];
|
||||
|
||||
static void
|
||||
read_file (char *path, char **out_data, size_t *out_size)
|
||||
{
|
||||
FILE *f;
|
||||
size_t bytes_read;
|
||||
|
||||
/* Open the file. */
|
||||
f = fopen(path, "r");
|
||||
if (f == NULL) {
|
||||
/* Since this error is fairly likely to happen, give an
|
||||
** informative error message... */
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "Could not open file '%s'. errno=%d (%s)\n",
|
||||
path, errno, strerror(errno));
|
||||
abort();
|
||||
}
|
||||
|
||||
/* Read in one buffer full of data, and make sure that everything
|
||||
** fit. (We perform a lazy error/no-eof/zero-length-file test using
|
||||
** bytes_read.) */
|
||||
bytes_read = fread(file_buff, sizeof(char), MAX_SAMPLE_FILE_LEN, f);
|
||||
TEST(0 < bytes_read && bytes_read < MAX_SAMPLE_FILE_LEN);
|
||||
|
||||
/* Close the file and return our data. */
|
||||
fclose(f);
|
||||
*out_data = file_buff;
|
||||
*out_size = bytes_read;
|
||||
}
|
||||
|
||||
static void test_sample_files (void)
|
||||
{
|
||||
xmlrpc_env env;
|
||||
char **paths, *path;
|
||||
char *data;
|
||||
size_t data_len;
|
||||
const char *method_name;
|
||||
xmlrpc_value *params;
|
||||
|
||||
xmlrpc_env_init(&env);
|
||||
|
||||
/* Test our good requests. */
|
||||
for (paths = good_requests; *paths != NULL; paths++) {
|
||||
path = *paths;
|
||||
read_file(path, &data, &data_len);
|
||||
xmlrpc_parse_call(&env, data, data_len, &method_name, ¶ms);
|
||||
TEST_NO_FAULT(&env);
|
||||
strfree(method_name);
|
||||
xmlrpc_DECREF(params);
|
||||
}
|
||||
|
||||
xmlrpc_env_clean(&env);
|
||||
}
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
** test_utf8_coding
|
||||
**=========================================================================
|
||||
** We need to test our UTF-8 decoder thoroughly. Most of these test
|
||||
** cases are taken from the UTF-8-test.txt file by Markus Kuhn
|
||||
** <mkuhn@acm.org>:
|
||||
** http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
|
||||
*/
|
||||
|
||||
#ifdef HAVE_UNICODE_WCHAR
|
||||
|
||||
typedef struct {
|
||||
char *utf8;
|
||||
wchar_t wcs[16];
|
||||
} utf8_and_wcs;
|
||||
|
||||
static utf8_and_wcs good_utf8[] = {
|
||||
|
||||
/* Greek 'kosme'. */
|
||||
{"\316\272\341\275\271\317\203\316\274\316\265",
|
||||
{0x03BA, 0x1F79, 0x03C3, 0x03BC, 0x03B5, 0}},
|
||||
|
||||
/* First sequences of a given length. */
|
||||
/* '\000' is not a legal C string. */
|
||||
{"\302\200", {0x0080, 0}},
|
||||
{"\340\240\200", {0x0800, 0}},
|
||||
|
||||
/* Last sequences of a given length. */
|
||||
{"\177", {0x007F, 0}},
|
||||
{"\337\277", {0x07FF, 0}},
|
||||
/* 0xFFFF is not a legal Unicode character. */
|
||||
|
||||
/* Other boundry conditions. */
|
||||
{"\001", {0x0001, 0}},
|
||||
{"\355\237\277", {0xD7FF, 0}},
|
||||
{"\356\200\200", {0xE000, 0}},
|
||||
{"\357\277\275", {0xFFFD, 0}},
|
||||
|
||||
/* Other random test cases. */
|
||||
{"", {0}},
|
||||
{"abc", {0x0061, 0x0062, 0x0063, 0}},
|
||||
{"[\302\251]", {0x005B, 0x00A9, 0x005D, 0}},
|
||||
|
||||
{NULL, {0}}
|
||||
};
|
||||
|
||||
static char *(bad_utf8[]) = {
|
||||
|
||||
/* Continuation bytes. */
|
||||
"\200", "\277",
|
||||
|
||||
/* Lonely start characters. */
|
||||
"\300", "\300x", "\300xx",
|
||||
"\340", "\340x", "\340xx", "\340xxx",
|
||||
|
||||
/* Last byte missing. */
|
||||
"\340\200", "\340\200x", "\340\200xx",
|
||||
"\357\277", "\357\277x", "\357\277xx",
|
||||
|
||||
/* Illegal bytes. */
|
||||
"\376", "\377",
|
||||
|
||||
/* Overlong '/'. */
|
||||
"\300\257", "\340\200\257",
|
||||
|
||||
/* Overlong ASCII NUL. */
|
||||
"\300\200", "\340\200\200",
|
||||
|
||||
/* Maximum overlong sequences. */
|
||||
"\301\277", "\340\237\277",
|
||||
|
||||
/* Illegal code positions. */
|
||||
"\357\277\276", /* U+FFFE */
|
||||
"\357\277\277", /* U+FFFF */
|
||||
|
||||
/* UTF-16 surrogates (unpaired and paired). */
|
||||
"\355\240\200",
|
||||
"\355\277\277",
|
||||
"\355\240\200\355\260\200",
|
||||
"\355\257\277\355\277\277",
|
||||
|
||||
/* Valid UCS-4 characters (we don't handle these yet).
|
||||
** On systems with UCS-4 or UTF-16 wchar_t values, we
|
||||
** may eventually handle these in some fashion. */
|
||||
"\360\220\200\200",
|
||||
"\370\210\200\200\200",
|
||||
"\374\204\200\200\200\200",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
/* This routine is missing on certain platforms. This implementation
|
||||
** *appears* to be correct. */
|
||||
#if 0
|
||||
#ifndef HAVE_WCSNCMP
|
||||
int wcsncmp(wchar_t *wcs1, wchar_t* wcs2, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
/* XXX - 'unsigned long' should be 'uwchar_t'. */
|
||||
unsigned long c1, c2;
|
||||
for (i=0; i < len; i++) {
|
||||
c1 = wcs1[i];
|
||||
c2 = wcs2[i];
|
||||
/* This clever comparison borrowed from the GNU C Library. */
|
||||
if (c1 == 0 || c1 != c2)
|
||||
return c1 - c2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* HAVE_WCSNCMP */
|
||||
#endif
|
||||
|
||||
static void test_utf8_coding (void)
|
||||
{
|
||||
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);
|
||||
|
||||
/* Test each of our valid UTF-8 sequences. */
|
||||
for (good_data = good_utf8; good_data->utf8 != NULL; good_data++) {
|
||||
utf8 = good_data->utf8;
|
||||
wcs = good_data->wcs;
|
||||
|
||||
/* Attempt to validate the UTF-8 string. */
|
||||
xmlrpc_validate_utf8(&env, utf8, strlen(utf8));
|
||||
TEST_NO_FAULT(&env);
|
||||
|
||||
/* Attempt to decode the UTF-8 string. */
|
||||
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);
|
||||
|
||||
/* Test the UTF-8 encoder, too. */
|
||||
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(0 ==
|
||||
strncmp(utf8, XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, output),
|
||||
strlen(utf8)));
|
||||
xmlrpc_mem_block_free(output);
|
||||
}
|
||||
|
||||
/* Test each of our illegal UTF-8 sequences. */
|
||||
for (bad_data = bad_utf8; *bad_data != NULL; bad_data++) {
|
||||
utf8 = *bad_data;
|
||||
|
||||
/* Attempt to validate the UTF-8 string. */
|
||||
xmlrpc_env_init(&env2);
|
||||
xmlrpc_validate_utf8(&env2, utf8, strlen(utf8));
|
||||
TEST_FAULT(&env2, XMLRPC_INVALID_UTF8_ERROR);
|
||||
/* printf("Fault: %s\n", env2.fault_string); --Hand-checked */
|
||||
xmlrpc_env_clean(&env2);
|
||||
|
||||
/* Attempt to decode the UTF-8 string. */
|
||||
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 /* HAVE_UNICODE_WCHAR */
|
||||
|
||||
|
||||
/*=========================================================================
|
||||
** Test Driver
|
||||
**=========================================================================
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc,
|
||||
char ** argv ATTR_UNUSED) {
|
||||
|
||||
if (argc-1 > 0) {
|
||||
fprintf(stderr, "There are no arguments.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Add your test suites here. */
|
||||
test_env();
|
||||
test_mem_block();
|
||||
test_base64_conversion();
|
||||
printf("\n");
|
||||
test_value();
|
||||
test_bounds_checks();
|
||||
printf("\n");
|
||||
test_serialize();
|
||||
test_parse_xml();
|
||||
|
||||
test_method_registry();
|
||||
test_nesting_limit();
|
||||
test_xml_size_limit();
|
||||
test_sample_files();
|
||||
printf("\n");
|
||||
|
||||
#ifndef WIN32 /* CGI unsupported in Windows */
|
||||
test_server_cgi();
|
||||
#endif
|
||||
test_server_abyss();
|
||||
|
||||
#ifdef HAVE_UNICODE_WCHAR
|
||||
test_utf8_coding();
|
||||
#endif /* HAVE_UNICODE_WCHAR */
|
||||
|
||||
printf("\n");
|
||||
|
||||
#ifndef WIN32 /* TODO: Client test uses curl... */
|
||||
test_client();
|
||||
#endif
|
||||
|
||||
/* Summarize our test run. */
|
||||
printf("\nRan %d tests, %d failed, %.1f%% passed\n",
|
||||
total_tests, total_failures,
|
||||
100.0 - (100.0 * total_failures) / total_tests);
|
||||
|
||||
/* Print the final result. */
|
||||
if (total_failures == 0) {
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
** SUCH DAMAGE. */
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern int total_tests;
|
||||
extern int total_failures;
|
||||
|
||||
|
||||
static __inline void
|
||||
strfree(const char * const string) {
|
||||
free((char*)string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This is a good place to set a breakpoint. */
|
||||
static __inline void
|
||||
test_failure(const char * const file,
|
||||
unsigned int const line,
|
||||
const char * const label,
|
||||
const char * const statement) {
|
||||
|
||||
++total_failures;
|
||||
printf("\n%s:%u: test failure: %s (%s)\n", file, line, label, statement);
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define TEST(statement) \
|
||||
do { \
|
||||
++total_tests; \
|
||||
if ((statement)) { \
|
||||
printf("."); \
|
||||
} else { \
|
||||
test_failure(__FILE__, __LINE__, "expected", #statement); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TEST_NO_FAULT(env) \
|
||||
do { \
|
||||
++total_tests; \
|
||||
if (!(env)->fault_occurred) { \
|
||||
printf("."); \
|
||||
} else { \
|
||||
test_failure(__FILE__, __LINE__, "fault occurred", \
|
||||
(env)->fault_string); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TEST_FAULT(env, code) \
|
||||
do { \
|
||||
++total_tests; \
|
||||
if ((env)->fault_occurred && (env)->fault_code == (code)) { \
|
||||
printf("."); \
|
||||
} else { \
|
||||
test_failure(__FILE__, __LINE__, "wrong/no fault occurred", \
|
||||
(env)->fault_string); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
#define TEST_ERROR(reason) \
|
||||
do { \
|
||||
printf("Unable to test at %s/%u. %s", __FILE__, __LINE__, reason); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,2 @@
|
||||
void
|
||||
test_value(void);
|
||||
@@ -0,0 +1,202 @@
|
||||
#include <stddef.h>
|
||||
|
||||
#define XML_PROLOGUE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
|
||||
|
||||
#define RAW_STRING_DATA \
|
||||
"<value><array><data>\r\n" \
|
||||
"<value><i4>2147483647</i4></value>\r\n" \
|
||||
"<value><i4>-2147483648</i4></value>\r\n" \
|
||||
"<value><boolean>0</boolean></value>\r\n" \
|
||||
"<value><boolean>1</boolean></value>\r\n" \
|
||||
"<value><string>Hello, world! <&></string></value>\r\n" \
|
||||
"<value><base64>\r\n" \
|
||||
"YmFzZTY0IGRhdGE=\r\n" \
|
||||
"</base64></value>\r\n" \
|
||||
"<value>" \
|
||||
"<dateTime.iso8601>19980717T14:08:55</dateTime.iso8601>" \
|
||||
"</value>\r\n" \
|
||||
"<value><array><data>\r\n" \
|
||||
"</data></array></value>\r\n" \
|
||||
"</data></array></value>"
|
||||
|
||||
char const serialized_data[] = RAW_STRING_DATA;
|
||||
|
||||
char const serialized_call[] =
|
||||
XML_PROLOGUE
|
||||
"<methodCall>\r\n"
|
||||
"<methodName>gloom&doom</methodName>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><i4>10</i4></value></param>\r\n"
|
||||
"<param><value><i4>20</i4></value></param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodCall>\r\n";
|
||||
|
||||
char const serialized_response[] =
|
||||
XML_PROLOGUE
|
||||
"<methodResponse>\r\n"
|
||||
"<params>\r\n"
|
||||
"<param><value><i4>30</i4></value></param>\r\n"
|
||||
"</params>\r\n"
|
||||
"</methodResponse>\r\n";
|
||||
|
||||
char const serialized_fault[] =
|
||||
XML_PROLOGUE
|
||||
"<methodResponse>\r\n"
|
||||
"<fault>\r\n"
|
||||
"<value><struct>\r\n"
|
||||
"<member><name>faultCode</name>\r\n"
|
||||
"<value><i4>6</i4></value></member>\r\n"
|
||||
"<member><name>faultString</name>\r\n"
|
||||
"<value><string>A fault occurred</string></value></member>\r\n"
|
||||
"</struct></value>\r\n"
|
||||
"</fault>\r\n"
|
||||
"</methodResponse>\r\n";
|
||||
|
||||
char const expat_data[] = XML_PROLOGUE RAW_STRING_DATA "\r\n";
|
||||
char const expat_error_data[] =
|
||||
XML_PROLOGUE \
|
||||
"<foo><bar>abc</bar><baz></baz>\r\n";
|
||||
|
||||
char const correct_value[] =
|
||||
XML_PROLOGUE
|
||||
"<methodResponse><params><param>\r\n"
|
||||
"<value><array><data>\r\n"
|
||||
RAW_STRING_DATA "\r\n"
|
||||
"<value><int>1</int></value>\r\n"
|
||||
"<value><double>-1.0</double></value>\r\n"
|
||||
"<value><double>0.0</double></value>\r\n"
|
||||
"<value><double>1.0</double></value>\r\n"
|
||||
"<value><struct>\r\n"
|
||||
"<member><name>ten <&></name>\r\n"
|
||||
"<value><i4>10</i4></value></member>\r\n"
|
||||
"<member><name>twenty</name>\r\n"
|
||||
"<value><i4>20</i4></value></member>\r\n"
|
||||
"</struct></value>\r\n"
|
||||
"<value>Untagged string</value>\r\n"
|
||||
"</data></array></value>\r\n"
|
||||
"</param></params></methodResponse>\r\n";
|
||||
|
||||
#define VALUE_HEADER \
|
||||
XML_PROLOGUE"<methodResponse><params><param><value>\r\n"
|
||||
#define VALUE_FOOTER \
|
||||
"</value></param></params></methodResponse>\r\n"
|
||||
|
||||
#define MEMBER_HEADER \
|
||||
VALUE_HEADER"<struct><member>"
|
||||
#define MEMBER_FOOTER \
|
||||
"</member></struct>"VALUE_FOOTER
|
||||
#define ARBITRARY_VALUE \
|
||||
"<value><i4>0</i4></value>"
|
||||
|
||||
char const unparseable_value[] = VALUE_HEADER"<i4>"VALUE_FOOTER;
|
||||
|
||||
const char * bad_values[] = {
|
||||
VALUE_HEADER"<i4>0</i4><i4>0</i4>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<foo></foo>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<i4><i4>4</i4></i4>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<i4>2147483648</i4>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<i4>-2147483649</i4>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<i4> 0</i4>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<i4>0 </i4>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<boolean>2</boolean>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<boolean>-1</boolean>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<double> 0.0</double>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<double>0.0 </double>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<array></array>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<array><data></data><data></data></array>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<array><data></data><data></data></array>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<array><data><foo></foo></data></array>"VALUE_FOOTER,
|
||||
VALUE_HEADER"<struct><foo></foo></struct>"VALUE_FOOTER,
|
||||
MEMBER_HEADER MEMBER_FOOTER,
|
||||
MEMBER_HEADER"<name>a</name>"MEMBER_FOOTER,
|
||||
MEMBER_HEADER"<name>a</name>"ARBITRARY_VALUE"<f></f>"MEMBER_FOOTER,
|
||||
MEMBER_HEADER"<foo></foo>"ARBITRARY_VALUE MEMBER_FOOTER,
|
||||
MEMBER_HEADER"<name>a</name><foo></foo>"MEMBER_FOOTER,
|
||||
MEMBER_HEADER"<name><foo></foo></name>"ARBITRARY_VALUE MEMBER_FOOTER,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define RESPONSE_HEADER \
|
||||
XML_PROLOGUE"<methodResponse>\r\n"
|
||||
#define RESPONSE_FOOTER \
|
||||
"</methodResponse>\r\n"
|
||||
|
||||
#define PARAMS_RESP_HEADER \
|
||||
RESPONSE_HEADER"<params>"
|
||||
#define PARAMS_RESP_FOOTER \
|
||||
"</params>"RESPONSE_FOOTER
|
||||
|
||||
#define FAULT_HEADER \
|
||||
RESPONSE_HEADER"<fault>"
|
||||
#define FAULT_FOOTER \
|
||||
"</fault>"RESPONSE_FOOTER
|
||||
|
||||
#define FAULT_STRUCT_HEADER \
|
||||
FAULT_HEADER"<value><struct>"
|
||||
#define FAULT_STRUCT_FOOTER \
|
||||
"</struct></value>"FAULT_FOOTER
|
||||
|
||||
const char * bad_responses[] = {
|
||||
XML_PROLOGUE"<foo></foo>\r\n",
|
||||
RESPONSE_HEADER RESPONSE_FOOTER,
|
||||
RESPONSE_HEADER"<params></params><params></params>"RESPONSE_FOOTER,
|
||||
RESPONSE_HEADER"<foo></foo>"RESPONSE_FOOTER,
|
||||
|
||||
/* Make sure we insist on only one parameter in a response. */
|
||||
PARAMS_RESP_HEADER PARAMS_RESP_FOOTER,
|
||||
PARAMS_RESP_HEADER
|
||||
"<param><i4>0</i4></param>"
|
||||
"<param><i4>0</i4></param>"
|
||||
PARAMS_RESP_FOOTER,
|
||||
|
||||
/* Test other sorts of bad parameters. */
|
||||
PARAMS_RESP_HEADER"<foo></foo>"PARAMS_RESP_FOOTER,
|
||||
PARAMS_RESP_HEADER"<param></param>"PARAMS_RESP_FOOTER,
|
||||
PARAMS_RESP_HEADER"<param><foo></foo></param>"PARAMS_RESP_FOOTER,
|
||||
PARAMS_RESP_HEADER
|
||||
"<param>"ARBITRARY_VALUE ARBITRARY_VALUE"</param>"
|
||||
PARAMS_RESP_FOOTER,
|
||||
|
||||
/* Basic fault tests. */
|
||||
FAULT_HEADER FAULT_FOOTER,
|
||||
FAULT_HEADER"<foo></foo>"FAULT_FOOTER,
|
||||
FAULT_HEADER"<value></value><value></value>"FAULT_FOOTER,
|
||||
FAULT_HEADER"<value><i4>1</i4></value>"FAULT_FOOTER,
|
||||
|
||||
/* Make sure we insist on the proper members within the fault struct. */
|
||||
FAULT_STRUCT_HEADER
|
||||
"<member><name>faultString</name>"
|
||||
"<value><string>foo</string></value></member>"
|
||||
FAULT_STRUCT_FOOTER,
|
||||
FAULT_STRUCT_HEADER
|
||||
"<member><name>faultCode</name>"
|
||||
"<value><i4>0</i4></value></member>"
|
||||
FAULT_STRUCT_FOOTER,
|
||||
FAULT_STRUCT_HEADER
|
||||
"<member><name>faultCode</name>"
|
||||
"<value><i4>0</i4></value></member>"
|
||||
"<member><name>faultString</name>"
|
||||
"<value><i4>0</i4></value></member>"
|
||||
FAULT_STRUCT_FOOTER,
|
||||
FAULT_STRUCT_HEADER
|
||||
"<member><name>faultCode</name>"
|
||||
"<value><string>0</string></value></member>"
|
||||
"<member><name>faultString</name>"
|
||||
"<value><string>foo</string></value></member>"
|
||||
FAULT_STRUCT_FOOTER,
|
||||
NULL};
|
||||
|
||||
#define CALL_HEADER \
|
||||
XML_PROLOGUE"<methodCall>\r\n"
|
||||
#define CALL_FOOTER \
|
||||
"</methodCall>\r\n"
|
||||
|
||||
const char * bad_calls[] = {
|
||||
XML_PROLOGUE"<foo></foo>\r\n",
|
||||
CALL_HEADER CALL_FOOTER,
|
||||
CALL_HEADER"<methodName>m</methodName><foo></foo>"CALL_FOOTER,
|
||||
CALL_HEADER"<foo></foo><params></params>"CALL_FOOTER,
|
||||
CALL_HEADER"<methodName><f></f></methodName><params></params>"CALL_FOOTER,
|
||||
NULL};
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
extern char const serialized_data[];
|
||||
|
||||
extern char const serialized_call[];
|
||||
|
||||
extern char const serialized_response[];
|
||||
|
||||
extern char const serialized_fault[];
|
||||
|
||||
extern char const expat_data[];
|
||||
extern char const expat_error_data[];
|
||||
|
||||
extern char const correct_value[];
|
||||
|
||||
extern char const unparseable_value[];
|
||||
|
||||
extern const char *(bad_values[]);
|
||||
|
||||
extern const char *(bad_responses[]);
|
||||
|
||||
extern const char *(bad_calls[]);
|
||||
Reference in new issue
Block a user