summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2006-06-19 16:57:47 +0000
committerDan Winship <danw@src.gnome.org>2006-06-19 16:57:47 +0000
commit4b67cc60b82756a86225a2a2268f538f552bf9b2 (patch)
treec32a556157278ab74521dcf0be47f740b58bbaba
parent3075ce163a6acedcb255690cd7732e3222f06a02 (diff)
downloadlibsoup-4b67cc60b82756a86225a2a2268f538f552bf9b2.tar.gz
add tests for apache mod_php5 and xmlrpc-epi-php
* configure.in: add tests for apache mod_php5 and xmlrpc-epi-php * tests/xmlrpc-test.c: XML-RPC regression test * tests/xmlrpc-server.php: PHP server for xmlrpc-test * tests/httpd.conf.in: add php stuff * tests/apache-wrapper.c (apache_cleanup): Use "graceful-stop" rather than "stop", so that it stops listening on the socket before exiting, so that we can immediately start another apache (eg, in "make check"). * libsoup/soup-date.c (soup_mktime_utc): Fix a bug in leap-year counting. * libsoup/soup-xmlrpc-message.c (soup_xmlrpc_message_write_datetime): rename from "..._write_time", to make it consistent with the XML-RPC type name and the corresponding SoupXmlrpcResponse method. Also, fix it to use the same ISO 8601 format as the spec, and use the right value for the seconds field. (soup_xmlrpc_message_write_base64): Change the buf arg to a gconstpointer rather than a const char *. * libsoup/soup-xmlrpc-response.c (soup_xmlrpc_value_get_base64): Return a GByteArray containing the decoded data, rather than the base64-encoded string. (soup_xmlrpc_value_dump_internal): Update for that (and don't leak it). (soup_xmlrpc_value_array_get_iterator, soup_xmlrpc_value_array_iterator_get_value): Make these actually work.
-rw-r--r--ChangeLog36
-rw-r--r--configure.in26
-rw-r--r--libsoup/soup-date.c2
-rw-r--r--libsoup/soup-xmlrpc-message.c6
-rw-r--r--libsoup/soup-xmlrpc-message.h66
-rw-r--r--libsoup/soup-xmlrpc-response.c47
-rw-r--r--libsoup/soup-xmlrpc-response.h2
-rw-r--r--tests/.cvsignore1
-rw-r--r--tests/Makefile.am12
-rw-r--r--tests/apache-wrapper.c2
-rw-r--r--tests/httpd.conf.in6
-rw-r--r--tests/xmlrpc-server.php75
-rw-r--r--tests/xmlrpc-test.c457
13 files changed, 676 insertions, 62 deletions
diff --git a/ChangeLog b/ChangeLog
index 1423e26a..c93debc2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2006-06-14 Dan Winship <danw@novell.com>
+
+ * configure.in: add tests for apache mod_php5 and xmlrpc-epi-php
+
+ * tests/xmlrpc-test.c: XML-RPC regression test
+
+ * tests/xmlrpc-server.php: PHP server for xmlrpc-test
+
+ * tests/httpd.conf.in: add php stuff
+
+ * tests/apache-wrapper.c (apache_cleanup): Use "graceful-stop"
+ rather than "stop", so that it stops listening on the socket
+ before exiting, so that we can immediately start another apache
+ (eg, in "make check").
+
+ * libsoup/soup-date.c (soup_mktime_utc): Fix a bug in leap-year
+ counting.
+
+ * libsoup/soup-xmlrpc-message.c
+ (soup_xmlrpc_message_write_datetime): rename from
+ "..._write_time", to make it consistent with the XML-RPC type name
+ and the corresponding SoupXmlrpcResponse method. Also, fix it to
+ use the same ISO 8601 format as the spec, and use the right value
+ for the seconds field.
+ (soup_xmlrpc_message_write_base64): Change the buf arg to a
+ gconstpointer rather than a const char *.
+
+ * libsoup/soup-xmlrpc-response.c (soup_xmlrpc_value_get_base64):
+ Return a GByteArray containing the decoded data, rather than
+ the base64-encoded string.
+ (soup_xmlrpc_value_dump_internal): Update for that (and don't
+ leak it).
+ (soup_xmlrpc_value_array_get_iterator,
+ soup_xmlrpc_value_array_iterator_get_value): Make these actually
+ work.
+
2006-06-12 Dan Winship <danw@novell.com>
* configure.in: 2.2.94
diff --git a/configure.in b/configure.in
index 9ae01f06..4bf8f4a2 100644
--- a/configure.in
+++ b/configure.in
@@ -256,6 +256,32 @@ else
fi
AM_CONDITIONAL(HAVE_APACHE, test $have_apache = 1)
+if test "$have_apache" = 1; then
+ AC_MSG_CHECKING([for mod_php5])
+ if test -f $APACHE_MODULE_DIR/mod_php5.so; then
+ have_php=yes
+ IF_HAVE_PHP=""
+ else
+ have_php=no
+ IF_HAVE_PHP="#"
+ fi
+ AC_MSG_RESULT($have_php)
+
+ if test "$have_php" = yes; then
+ AC_MSG_CHECKING([for xmlrpc-epi-php])
+ if php5 --rf xmlrpc_server_create | grep -q "does not exist"; then
+ have_xmlrpc_epi_php=no
+ else
+ have_xmlrpc_epi_php=yes
+ fi
+ AC_MSG_RESULT($have_xmlrpc_epi_php)
+ fi
+fi
+
+AC_SUBST(IF_HAVE_PHP)
+AM_CONDITIONAL(HAVE_XMLRPC_EPI_PHP, test $have_xmlrpc_epi_php = yes)
+
+
dnl *************************
dnl *** Output Everything ***
dnl *************************
diff --git a/libsoup/soup-date.c b/libsoup/soup-date.c
index 3085ae62..90c37d8e 100644
--- a/libsoup/soup-date.c
+++ b/libsoup/soup-date.c
@@ -68,7 +68,7 @@ soup_mktime_utc (struct tm *tm)
tt = (tm->tm_year - 70) * 365;
tt += (tm->tm_year - 68) / 4;
tt += days_before[tm->tm_mon] + tm->tm_mday - 1;
- if (tm->tm_year % 4 == 2 && tm->tm_mon < 2)
+ if (tm->tm_year % 4 == 0 && tm->tm_mon < 2)
tt--;
tt = ((((tt * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec;
return tt;
diff --git a/libsoup/soup-xmlrpc-message.c b/libsoup/soup-xmlrpc-message.c
index 4f37999e..d061282e 100644
--- a/libsoup/soup-xmlrpc-message.c
+++ b/libsoup/soup-xmlrpc-message.c
@@ -202,7 +202,7 @@ soup_xmlrpc_message_write_double (SoupXmlrpcMessage *msg, double d)
}
void
-soup_xmlrpc_message_write_time (SoupXmlrpcMessage *msg, const time_t timeval)
+soup_xmlrpc_message_write_datetime (SoupXmlrpcMessage *msg, const time_t timeval)
{
SoupXmlrpcMessagePrivate *priv;
struct tm time;
@@ -212,7 +212,7 @@ soup_xmlrpc_message_write_time (SoupXmlrpcMessage *msg, const time_t timeval)
priv = SOUP_XMLRPC_MESSAGE_GET_PRIVATE (msg);
soup_gmtime (&timeval, &time);
- strftime (str, 128, "%Y%m%dT%H%M%s", &time);
+ strftime (str, 128, "%Y%m%dT%H:%M:%S", &time);
priv->last_node = xmlNewChild (priv->last_node, NULL, (xmlChar *)"value", NULL);
xmlNewTextChild (priv->last_node, NULL, (xmlChar *)"dateTime.iso8601", (xmlChar *)str);
@@ -220,7 +220,7 @@ soup_xmlrpc_message_write_time (SoupXmlrpcMessage *msg, const time_t timeval)
}
void
-soup_xmlrpc_message_write_base64 (SoupXmlrpcMessage *msg, const char *buf, int len)
+soup_xmlrpc_message_write_base64 (SoupXmlrpcMessage *msg, gconstpointer buf, int len)
{
SoupXmlrpcMessagePrivate *priv;
char *str;
diff --git a/libsoup/soup-xmlrpc-message.h b/libsoup/soup-xmlrpc-message.h
index a86b2a6b..f74c405c 100644
--- a/libsoup/soup-xmlrpc-message.h
+++ b/libsoup/soup-xmlrpc-message.h
@@ -36,39 +36,39 @@ GType soup_xmlrpc_message_get_type (void);
SoupXmlrpcMessage *soup_xmlrpc_message_new (const char *uri_string);
SoupXmlrpcMessage *soup_xmlrpc_message_new_from_uri (const SoupUri *uri);
-void soup_xmlrpc_message_start_call (SoupXmlrpcMessage *msg,
- const char *method_name);
-void soup_xmlrpc_message_end_call (SoupXmlrpcMessage *msg);
-
-void soup_xmlrpc_message_start_param (SoupXmlrpcMessage *msg);
-void soup_xmlrpc_message_end_param (SoupXmlrpcMessage *msg);
-
-void soup_xmlrpc_message_write_int (SoupXmlrpcMessage *msg,
- long i);
-void soup_xmlrpc_message_write_boolean (SoupXmlrpcMessage *msg,
- gboolean b);
-void soup_xmlrpc_message_write_string (SoupXmlrpcMessage *msg,
- const char *str);
-void soup_xmlrpc_message_write_double (SoupXmlrpcMessage *msg,
- double d);
-void soup_xmlrpc_message_write_time (SoupXmlrpcMessage *msg,
- const time_t timeval);
-void soup_xmlrpc_message_write_base64 (SoupXmlrpcMessage *msg,
- const char *buf,
- int len);
-
-void soup_xmlrpc_message_start_struct (SoupXmlrpcMessage *msg);
-void soup_xmlrpc_message_end_struct (SoupXmlrpcMessage *msg);
-
-void soup_xmlrpc_message_start_member (SoupXmlrpcMessage *msg,
- const char *name);
-void soup_xmlrpc_message_end_member (SoupXmlrpcMessage *msg);
-
-void soup_xmlrpc_message_start_array (SoupXmlrpcMessage *msg);
-void soup_xmlrpc_message_end_array (SoupXmlrpcMessage *msg);
-
-xmlChar *soup_xmlrpc_message_to_string (SoupXmlrpcMessage *msg);
-void soup_xmlrpc_message_persist (SoupXmlrpcMessage *msg);
+void soup_xmlrpc_message_start_call (SoupXmlrpcMessage *msg,
+ const char *method_name);
+void soup_xmlrpc_message_end_call (SoupXmlrpcMessage *msg);
+
+void soup_xmlrpc_message_start_param (SoupXmlrpcMessage *msg);
+void soup_xmlrpc_message_end_param (SoupXmlrpcMessage *msg);
+
+void soup_xmlrpc_message_write_int (SoupXmlrpcMessage *msg,
+ long i);
+void soup_xmlrpc_message_write_boolean (SoupXmlrpcMessage *msg,
+ gboolean b);
+void soup_xmlrpc_message_write_string (SoupXmlrpcMessage *msg,
+ const char *str);
+void soup_xmlrpc_message_write_double (SoupXmlrpcMessage *msg,
+ double d);
+void soup_xmlrpc_message_write_datetime (SoupXmlrpcMessage *msg,
+ const time_t timeval);
+void soup_xmlrpc_message_write_base64 (SoupXmlrpcMessage *msg,
+ gconstpointer buf,
+ int len);
+
+void soup_xmlrpc_message_start_struct (SoupXmlrpcMessage *msg);
+void soup_xmlrpc_message_end_struct (SoupXmlrpcMessage *msg);
+
+void soup_xmlrpc_message_start_member (SoupXmlrpcMessage *msg,
+ const char *name);
+void soup_xmlrpc_message_end_member (SoupXmlrpcMessage *msg);
+
+void soup_xmlrpc_message_start_array (SoupXmlrpcMessage *msg);
+void soup_xmlrpc_message_end_array (SoupXmlrpcMessage *msg);
+
+xmlChar *soup_xmlrpc_message_to_string (SoupXmlrpcMessage *msg);
+void soup_xmlrpc_message_persist (SoupXmlrpcMessage *msg);
SoupXmlrpcResponse *soup_xmlrpc_message_parse_response (SoupXmlrpcMessage *msg);
diff --git a/libsoup/soup-xmlrpc-response.c b/libsoup/soup-xmlrpc-response.c
index 8153b42d..ab7abeb1 100644
--- a/libsoup/soup-xmlrpc-response.c
+++ b/libsoup/soup-xmlrpc-response.c
@@ -356,12 +356,13 @@ soup_xmlrpc_value_get_datetime (SoupXmlrpcValue *value, time_t *timeval)
return TRUE;
}
-/* FIXME: this is broken; it returns the encoded value, not decoded */
gboolean
-soup_xmlrpc_value_get_base64 (SoupXmlrpcValue *value, char **buf)
+soup_xmlrpc_value_get_base64 (SoupXmlrpcValue *value, GByteArray **data)
{
xmlNode *xml;
xmlChar *content;
+ char *decoded;
+ int len;
xml = (xmlNode *) value;
if (strcmp ((char *)xml->name, "value"))
@@ -371,9 +372,13 @@ soup_xmlrpc_value_get_base64 (SoupXmlrpcValue *value, char **buf)
return FALSE;
content = xmlNodeGetContent (xml);
- *buf = content ? g_strdup ((char *)content) : g_strdup ("");
+ decoded = soup_base64_decode ((const char *)content, &len);
xmlFree (content);
+ *data = g_byte_array_new ();
+ g_byte_array_append (*data, (guchar *)decoded, len);
+ g_free (decoded);
+
return TRUE;
}
@@ -443,11 +448,13 @@ soup_xmlrpc_value_array_get_iterator (SoupXmlrpcValue *value, SoupXmlrpcValueArr
xml = (xmlNode *) value;
- if (!xml->children || strcmp((char *)xml->children->name, "data") == 0 || xml->children->next)
+ if (!xml->children || strcmp((char *)xml->children->name, "array") != 0 ||
+ xml->children->next || !xml->children->children ||
+ strcmp((char *)xml->children->children->name, "data") != 0 ||
+ xml->children->children->next)
return FALSE;
- *iter = (SoupXmlrpcValueArrayIterator *) xml->children;
-
+ *iter = (SoupXmlrpcValueArrayIterator *) xml->children->children->children;
return TRUE;
}
@@ -476,17 +483,7 @@ gboolean
soup_xmlrpc_value_array_iterator_get_value (SoupXmlrpcValueArrayIterator *iter,
SoupXmlrpcValue **value)
{
- xmlNode *xml;
-
- xml = (xmlNode *) iter;
-
- if (!xml || strcmp((char *)xml->name, "data"))
- return FALSE;
- xml = exactly_one_child (xml);
- if (!xml)
- return FALSE;
-
- *value = (SoupXmlrpcValue *) xml;
+ *value = (SoupXmlrpcValue *) iter;
return TRUE;
}
@@ -525,6 +522,7 @@ soup_xmlrpc_value_dump_internal (SoupXmlrpcValue *value, int d)
char *str;
double f;
time_t timeval;
+ GByteArray *base64;
GHashTable *hash;
SoupXmlrpcValueArrayIterator *iter;
@@ -580,10 +578,19 @@ soup_xmlrpc_value_dump_internal (SoupXmlrpcValue *value, int d)
case SOUP_XMLRPC_VALUE_TYPE_BASE64:
indent (d);
- if (!soup_xmlrpc_value_get_base64 (value, &str))
+ if (!soup_xmlrpc_value_get_base64 (value, &base64))
g_printerr ("BAD BASE64\n");
- else
- g_printerr ("BASE64: %s\n", str);
+ else {
+ GString *hex = g_string_new (NULL);
+ int i;
+
+ for (i = 0; i < base64->len; i++)
+ g_string_append_printf (hex, "%02x", base64->data[i]);
+
+ g_printerr ("BASE64: %s\n", hex->str);
+ g_string_free (hex, TRUE);
+ g_byte_array_free (base64, TRUE);
+ }
break;
diff --git a/libsoup/soup-xmlrpc-response.h b/libsoup/soup-xmlrpc-response.h
index 10c2dd72..f2207c79 100644
--- a/libsoup/soup-xmlrpc-response.h
+++ b/libsoup/soup-xmlrpc-response.h
@@ -65,7 +65,7 @@ gboolean soup_xmlrpc_value_get_string (SoupXmlrpcValue *value,
gboolean soup_xmlrpc_value_get_datetime (SoupXmlrpcValue *value,
time_t *timeval);
gboolean soup_xmlrpc_value_get_base64 (SoupXmlrpcValue *value,
- char **buf);
+ GByteArray **data);
gboolean soup_xmlrpc_value_get_struct (SoupXmlrpcValue *value,
GHashTable **table);
diff --git a/tests/.cvsignore b/tests/.cvsignore
index 35b83c68..e1166adf 100644
--- a/tests/.cvsignore
+++ b/tests/.cvsignore
@@ -12,3 +12,4 @@ revserver
simple-httpd
simple-proxy
uri-parsing
+xmlrpc-test
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8d05c13a..41313bf1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -15,7 +15,8 @@ noinst_PROGRAMS = \
revserver \
simple-httpd \
simple-proxy \
- uri-parsing
+ uri-parsing \
+ xmlrpc-test
auth_test_SOURCES = auth-test.c apache-wrapper.c apache-wrapper.h
date_SOURCES = date.c
@@ -27,12 +28,16 @@ revserver_SOURCES = revserver.c
simple_httpd_SOURCES = simple-httpd.c
simple_proxy_SOURCES = simple-proxy.c
uri_parsing_SOURCES = uri-parsing.c
+xmlrpc_test_SOURCES = xmlrpc-test.c apache-wrapper.c apache-wrapper.h
if HAVE_APACHE
APACHE_TESTS = auth-test
endif
+if HAVE_XMLRPC_EPI_PHP
+XMLRPC_TESTS = xmlrpc-test
+endif
-TESTS = date uri-parsing $(APACHE_TESTS)
+TESTS = date uri-parsing $(APACHE_TESTS) $(XMLRPC_TESTS)
EXTRA_DIST = \
libsoup.supp \
@@ -40,4 +45,5 @@ EXTRA_DIST = \
test-key.pem \
htdigest \
htpasswd \
- httpd.conf.in
+ httpd.conf.in \
+ xmlrpc-server.php
diff --git a/tests/apache-wrapper.c b/tests/apache-wrapper.c
index 2f5cd8c9..5c507351 100644
--- a/tests/apache-wrapper.c
+++ b/tests/apache-wrapper.c
@@ -46,7 +46,7 @@ apache_init (void)
void
apache_cleanup (void)
{
- apache_cmd ("stop");
+ apache_cmd ("graceful-stop");
}
#endif /* HAVE_APACHE */
diff --git a/tests/httpd.conf.in b/tests/httpd.conf.in
index eee3a52d..80899ac2 100644
--- a/tests/httpd.conf.in
+++ b/tests/httpd.conf.in
@@ -4,6 +4,9 @@ ServerName 127.0.0.1
Listen 127.0.0.1:47524
PidFile @builddir@/httpd.pid
+DocumentRoot @srcdir@
+
+# Change this to "./error.log" if it's failing and you don't know why
ErrorLog /dev/null
LoadModule alias_module @APACHE_MODULE_DIR@/mod_alias.so
@@ -12,8 +15,11 @@ LoadModule auth_digest_module @APACHE_MODULE_DIR@/mod_auth_digest.so
LoadModule authn_file_module @APACHE_MODULE_DIR@/mod_authn_file.so
LoadModule authz_user_module @APACHE_MODULE_DIR@/mod_authz_user.so
LoadModule dir_module @APACHE_MODULE_DIR@/mod_dir.so
+LoadModule mime_module @APACHE_MODULE_DIR@/mod_mime.so
+@IF_HAVE_PHP@LoadModule php5_module @APACHE_MODULE_DIR@/mod_php5.so
DirectoryIndex httpd.pid
+AddType application/x-httpd-php .php
Alias /Basic/realm1/realm2/realm1 @builddir@
Alias /Basic/realm1/realm2 @builddir@
diff --git a/tests/xmlrpc-server.php b/tests/xmlrpc-server.php
new file mode 100644
index 00000000..cf209489
--- /dev/null
+++ b/tests/xmlrpc-server.php
@@ -0,0 +1,75 @@
+<?php
+
+function sum ($method_name, $params, $app_data)
+{
+ $sum = 0;
+ foreach ($params[0] as $val) {
+ $sum = $sum + $val;
+ }
+ return $sum;
+}
+
+function countBools ($method_name, $params, $app_data)
+{
+ $counts["true"] = $counts["false"] = 0;
+ foreach ($params[0] as $val) {
+ if (xmlrpc_get_type ($val) != "boolean")
+ return "bad value: $val";
+
+ if ($val)
+ $counts["true"] = $counts["true"] + 1;
+ else
+ $counts["false"] = $counts["false"] + 1;
+ }
+ return $counts;
+}
+
+function md5sum ($method_name, $params, $app_data)
+{
+ $val = md5 ($params[0]->scalar, true);
+ xmlrpc_set_type ($val, "base64");
+ return $val;
+}
+
+function dateChange ($method_name, $params, $app_data)
+{
+ $date_str = $params[0]["date"]->scalar;
+ $date = strptime ($date_str, "%Y%m%dT%H:%M:%S");
+
+ foreach ($params[0] as $name => $val) {
+ if ($name == "date")
+ continue;
+ $date[$name] = $val;
+ }
+
+ $ret = sprintf ("%04d%02d%02dT%02d:%02d:%02d",
+ $date["tm_year"] + 1900, $date["tm_mon"] + 1,
+ $date["tm_mday"], $date["tm_hour"],
+ $date["tm_min"], $date["tm_sec"]);
+ xmlrpc_set_type ($ret, "datetime");
+ return $ret;
+}
+
+function echo_ ($method_name, $params, $app_data)
+{
+ return $params[0];
+}
+
+# Work around xmlrpc-epi-php lossage; otherwise the datetime values
+# we return will sometimes get a DST adjustment we don't want.
+putenv ("TZ=");
+
+$xmlrpc_server = xmlrpc_server_create ();
+xmlrpc_server_register_method($xmlrpc_server, "sum", "sum");
+xmlrpc_server_register_method($xmlrpc_server, "countBools", "countBools");
+xmlrpc_server_register_method($xmlrpc_server, "md5sum", "md5sum");
+xmlrpc_server_register_method($xmlrpc_server, "dateChange", "dateChange");
+xmlrpc_server_register_method($xmlrpc_server, "echo", "echo_");
+
+$response = xmlrpc_server_call_method ($xmlrpc_server, $HTTP_RAW_POST_DATA,
+ 0, array ("output_type" => "xml"));
+echo ($response);
+
+xmlrpc_server_destroy ($xmlrpc_server);
+
+?>
diff --git a/tests/xmlrpc-test.c b/tests/xmlrpc-test.c
new file mode 100644
index 00000000..2a80f064
--- /dev/null
+++ b/tests/xmlrpc-test.c
@@ -0,0 +1,457 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2003, Ximian, Inc.
+ */
+
+#include <string.h>
+#include <unistd.h>
+
+#include <libsoup/soup.h>
+#include <libsoup/soup-date.h>
+#include <libsoup/soup-md5-utils.h>
+#include <libsoup/soup-xmlrpc-message.h>
+#include <libsoup/soup-xmlrpc-response.h>
+
+#include "apache-wrapper.h"
+
+SoupSession *session;
+static const char *uri = "http://localhost:47524/xmlrpc-server.php";
+int debug;
+
+static const char *const value_type[] = {
+ "BAD",
+ "int",
+ "boolean",
+ "string",
+ "double",
+ "datetime",
+ "base64",
+ "struct",
+ "array"
+};
+
+static SoupXmlrpcValue *
+do_xmlrpc (SoupXmlrpcMessage *xmsg, SoupXmlrpcValueType type)
+{
+ SoupMessage *msg = SOUP_MESSAGE (xmsg);
+ SoupXmlrpcResponse *response;
+ SoupXmlrpcValue *value;
+ int status;
+
+ soup_xmlrpc_message_persist (xmsg);
+ status = soup_session_send_message (session, msg);
+
+ if (debug > 1) {
+ printf ("\n%.*s\n%d %s\n%.*s\n",
+ msg->request.length, msg->request.body,
+ msg->status_code, msg->reason_phrase,
+ msg->response.length, msg->response.body);
+ }
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+ printf ("ERROR: %d %s\n", status, msg->reason_phrase);
+ return FALSE;
+ }
+
+ response = soup_xmlrpc_message_parse_response (xmsg);
+ if (!response || soup_xmlrpc_response_is_fault (response)) {
+ if (!response)
+ printf ("ERROR: no response\n");
+ else
+ printf ("ERROR: fault\n");
+ return FALSE;
+ }
+
+ value = soup_xmlrpc_response_get_value (response);
+ if (!value) {
+ printf ("ERROR: no value?\n");
+ return NULL;
+ } else if (soup_xmlrpc_value_get_type (value) != type) {
+ printf ("ERROR: wrong value type; expected %s, got %s\n",
+ value_type[type], value_type[soup_xmlrpc_value_get_type (value)]);
+ return NULL;
+ }
+
+ return value;
+}
+
+static gboolean
+test_sum (void)
+{
+ SoupXmlrpcMessage *msg;
+ SoupXmlrpcValue *value;
+ int i, val, sum;
+ long result;
+
+ printf ("sum (array of int -> int): ");
+
+ msg = soup_xmlrpc_message_new (uri);
+ soup_xmlrpc_message_start_call (msg, "sum");
+ soup_xmlrpc_message_start_param (msg);
+ soup_xmlrpc_message_start_array (msg);
+ for (i = sum = 0; i < 10; i++) {
+ val = rand () % 100;
+ if (debug)
+ printf ("%s%d", i == 0 ? "[" : ", ", val);
+ soup_xmlrpc_message_write_int (msg, val);
+ sum += val;
+ }
+ if (debug)
+ printf ("] -> ");
+ soup_xmlrpc_message_end_array (msg);
+ soup_xmlrpc_message_end_param (msg);
+ soup_xmlrpc_message_end_call (msg);
+
+ value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_INT);
+ if (!value)
+ return FALSE;
+
+ if (!soup_xmlrpc_value_get_int (value, &result)) {
+ printf ("wrong type?\n");
+ return FALSE;
+ }
+
+ if (debug)
+ printf ("%ld: ", result);
+ printf ("%s\n", result == sum ? "OK!" : "WRONG!");
+ return result == sum;
+}
+
+static gboolean
+test_countBools (void)
+{
+ SoupXmlrpcMessage *msg;
+ SoupXmlrpcValue *value;
+ int i, trues, falses;
+ long ret_trues, ret_falses;
+ gboolean val, ok;
+ GHashTable *result;
+
+ printf ("countBools (array of boolean -> struct of ints): ");
+
+ msg = soup_xmlrpc_message_new (uri);
+ soup_xmlrpc_message_start_call (msg, "countBools");
+ soup_xmlrpc_message_start_param (msg);
+ soup_xmlrpc_message_start_array (msg);
+ for (i = trues = falses = 0; i < 10; i++) {
+ val = rand () > (RAND_MAX / 2);
+ if (debug)
+ printf ("%s%c", i == 0 ? "[" : ", ", val ? 'T' : 'F');
+ soup_xmlrpc_message_write_boolean (msg, val);
+ if (val)
+ trues++;
+ else
+ falses++;
+ }
+ if (debug)
+ printf ("] -> ");
+ soup_xmlrpc_message_end_array (msg);
+ soup_xmlrpc_message_end_param (msg);
+ soup_xmlrpc_message_end_call (msg);
+
+ value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_STRUCT);
+ if (!value)
+ return FALSE;
+
+ if (!soup_xmlrpc_value_get_struct (value, &result)) {
+ printf ("wrong type?\n");
+ return FALSE;
+ }
+
+ if (!soup_xmlrpc_value_get_int (g_hash_table_lookup (result, "true"), &ret_trues)) {
+ printf ("NO 'true' value in response\n");
+ return FALSE;
+ }
+ if (!soup_xmlrpc_value_get_int (g_hash_table_lookup (result, "false"), &ret_falses)) {
+ printf ("NO 'false' value in response\n");
+ return FALSE;
+ }
+
+ if (debug)
+ printf ("{ true: %ld, false: %ld } ", ret_trues, ret_falses);
+ ok = (trues == ret_trues) && (falses == ret_falses);
+ printf ("%s\n", ok ? "OK!" : "WRONG!");
+ return ok;
+}
+
+static gboolean
+test_md5sum (void)
+{
+ SoupXmlrpcMessage *msg;
+ SoupXmlrpcValue *value;
+ GByteArray *result;
+ char data[512];
+ int i;
+ SoupMD5Context md5;
+ guchar digest[16];
+ gboolean ok;
+
+ printf ("md5sum (base64 -> base64): ");
+
+ msg = soup_xmlrpc_message_new (uri);
+ soup_xmlrpc_message_start_call (msg, "md5sum");
+ soup_xmlrpc_message_start_param (msg);
+ for (i = 0; i < sizeof (data); i++)
+ data[i] = (char)(rand () & 0xFF);
+ soup_xmlrpc_message_write_base64 (msg, data, sizeof (data));
+ soup_xmlrpc_message_end_param (msg);
+ soup_xmlrpc_message_end_call (msg);
+
+ value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_BASE64);
+ if (!value)
+ return FALSE;
+
+ if (!soup_xmlrpc_value_get_base64 (value, &result)) {
+ printf ("wrong type?\n");
+ return FALSE;
+ }
+
+ if (result->len != 16) {
+ printf ("result has WRONG length (%d)\n", result->len);
+ g_byte_array_free (result, TRUE);
+ return FALSE;
+ }
+
+ soup_md5_init (&md5);
+ soup_md5_update (&md5, data, sizeof (data));
+ soup_md5_final (&md5, digest);
+
+ ok = (memcmp (digest, result->data, 16) == 0);
+ printf ("%s\n", ok ? "OK!" : "WRONG!");
+ g_byte_array_free (result, TRUE);
+ return ok;
+}
+
+static gboolean
+test_dateChange (void)
+{
+ SoupXmlrpcMessage *msg;
+ SoupXmlrpcValue *value;
+ struct tm tm;
+ time_t when, result;
+ char timestamp[128];
+
+ printf ("dateChange (struct of time and ints -> time): ");
+
+ msg = soup_xmlrpc_message_new (uri);
+ soup_xmlrpc_message_start_call (msg, "dateChange");
+ soup_xmlrpc_message_start_param (msg);
+ soup_xmlrpc_message_start_struct (msg);
+
+ soup_xmlrpc_message_start_member (msg, "date");
+ memset (&tm, 0, sizeof (tm));
+ tm.tm_year = 70 + (rand () % 50);
+ tm.tm_mon = rand () % 12;
+ tm.tm_mday = 1 + (rand () % 28);
+ tm.tm_hour = rand () % 24;
+ tm.tm_min = rand () % 60;
+ tm.tm_sec = rand () % 60;
+ when = soup_mktime_utc (&tm);
+ soup_xmlrpc_message_write_datetime (msg, when);
+ soup_xmlrpc_message_end_member (msg);
+
+ if (debug) {
+ strftime (timestamp, sizeof (timestamp),
+ "%Y-%m-%dT%H:%M:%S", &tm);
+ printf ("{ date: %s", timestamp);
+ }
+
+ if (rand () % 3) {
+ tm.tm_year = 70 + (rand () % 50);
+ if (debug)
+ printf (", tm_year: %d", tm.tm_year);
+ soup_xmlrpc_message_start_member (msg, "tm_year");
+ soup_xmlrpc_message_write_int (msg, tm.tm_year);
+ soup_xmlrpc_message_end_member (msg);
+ }
+ if (rand () % 3) {
+ tm.tm_mon = rand () % 12;
+ if (debug)
+ printf (", tm_mon: %d", tm.tm_mon);
+ soup_xmlrpc_message_start_member (msg, "tm_mon");
+ soup_xmlrpc_message_write_int (msg, tm.tm_mon);
+ soup_xmlrpc_message_end_member (msg);
+ }
+ if (rand () % 3) {
+ tm.tm_mday = 1 + (rand () % 28);
+ if (debug)
+ printf (", tm_mday: %d", tm.tm_mday);
+ soup_xmlrpc_message_start_member (msg, "tm_mday");
+ soup_xmlrpc_message_write_int (msg, tm.tm_mday);
+ soup_xmlrpc_message_end_member (msg);
+ }
+ if (rand () % 3) {
+ tm.tm_hour = rand () % 24;
+ if (debug)
+ printf (", tm_hour: %d", tm.tm_hour);
+ soup_xmlrpc_message_start_member (msg, "tm_hour");
+ soup_xmlrpc_message_write_int (msg, tm.tm_hour);
+ soup_xmlrpc_message_end_member (msg);
+ }
+ if (rand () % 3) {
+ tm.tm_min = rand () % 60;
+ if (debug)
+ printf (", tm_min: %d", tm.tm_min);
+ soup_xmlrpc_message_start_member (msg, "tm_min");
+ soup_xmlrpc_message_write_int (msg, tm.tm_min);
+ soup_xmlrpc_message_end_member (msg);
+ }
+ if (rand () % 3) {
+ tm.tm_sec = rand () % 60;
+ if (debug)
+ printf (", tm_sec: %d", tm.tm_sec);
+ soup_xmlrpc_message_start_member (msg, "tm_sec");
+ soup_xmlrpc_message_write_int (msg, tm.tm_sec);
+ soup_xmlrpc_message_end_member (msg);
+ }
+ when = soup_mktime_utc (&tm);
+
+ if (debug)
+ printf (" } -> ");
+
+ soup_xmlrpc_message_end_struct (msg);
+ soup_xmlrpc_message_end_param (msg);
+ soup_xmlrpc_message_end_call (msg);
+
+ value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_DATETIME);
+ if (!value)
+ return FALSE;
+
+ if (!soup_xmlrpc_value_get_datetime (value, &result)) {
+ printf ("wrong type?\n");
+ return FALSE;
+ }
+
+ if (debug) {
+ memset (&tm, 0, sizeof (tm));
+ soup_gmtime (&result, &tm);
+ strftime (timestamp, sizeof (timestamp),
+ "%Y-%m-%dT%H:%M:%S", &tm);
+ printf ("%s: ", timestamp);
+ }
+
+ printf ("%s\n", (when == result) ? "OK!" : "WRONG!");
+ return (when == result);
+}
+
+static const char *const echo_strings[] = {
+ "This is a test",
+ "& so is this",
+ "and so is <this>",
+ "&amp; so is &lt;this&gt;"
+};
+#define N_ECHO_STRINGS G_N_ELEMENTS (echo_strings)
+
+static gboolean
+test_echo (void)
+{
+ SoupXmlrpcMessage *msg;
+ SoupXmlrpcValue *value, *elt;
+ SoupXmlrpcValueArrayIterator *iter;
+ char *echo;
+ int i;
+
+ printf ("echo (array of string -> array of string): ");
+
+ msg = soup_xmlrpc_message_new (uri);
+ soup_xmlrpc_message_start_call (msg, "echo");
+ soup_xmlrpc_message_start_param (msg);
+ soup_xmlrpc_message_start_array (msg);
+ for (i = 0; i < N_ECHO_STRINGS; i++) {
+ if (debug)
+ printf ("%s\"%s\"", i == 0 ? "[" : ", ", echo_strings[i]);
+ soup_xmlrpc_message_write_string (msg, echo_strings[i]);
+ }
+ if (debug)
+ printf ("] -> ");
+ soup_xmlrpc_message_end_array (msg);
+ soup_xmlrpc_message_end_param (msg);
+ soup_xmlrpc_message_end_call (msg);
+
+ value = do_xmlrpc (msg, SOUP_XMLRPC_VALUE_TYPE_ARRAY);
+ if (!value)
+ return FALSE;
+
+ if (!soup_xmlrpc_value_array_get_iterator (value, &iter)) {
+ printf ("wrong type?\n");
+ return FALSE;
+ }
+ i = 0;
+ while (iter) {
+ if (!soup_xmlrpc_value_array_iterator_get_value (iter, &elt)) {
+ printf (" WRONG! Can't get result element %d\n", i + 1);
+ return FALSE;
+ }
+ if (!soup_xmlrpc_value_get_string (elt, &echo)) {
+ printf (" WRONG! Result element %d is not a string", i + 1);
+ return FALSE;
+ }
+ if (debug)
+ printf ("%s\"%s\"", i == 0 ? "[" : ", ", echo);
+ if (strcmp (echo_strings[i], echo) != 0) {
+ printf (" WRONG! Mismatch at %d\n", i + 1);
+ return FALSE;
+ }
+
+ iter = soup_xmlrpc_value_array_iterator_next (iter);
+ i++;
+ }
+ if (debug)
+ printf ("] ");
+
+ printf ("%s\n", i == N_ECHO_STRINGS ? "OK!" : "WRONG! Too few results");
+ return i == N_ECHO_STRINGS;
+}
+
+static void
+usage (void)
+{
+ fprintf (stderr, "Usage: xmlrpc-test [-d] [-d]\n");
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ int opt, errors = 0;
+
+ g_type_init ();
+ g_thread_init (NULL);
+
+ while ((opt = getopt (argc, argv, "d")) != -1) {
+ switch (opt) {
+ case 'd':
+ debug++;
+ break;
+
+ case '?':
+ usage ();
+ break;
+ }
+ }
+
+ srand (time (NULL));
+
+ if (!apache_init ()) {
+ fprintf (stderr, "Could not start apache\n");
+ return 1;
+ }
+
+ session = soup_session_sync_new ();
+
+ if (!test_sum ())
+ errors++;
+ if (!test_countBools ())
+ errors++;
+ if (!test_md5sum ())
+ errors++;
+ if (!test_dateChange ())
+ errors++;
+ if (!test_echo ())
+ errors++;
+
+ apache_cleanup ();
+
+ printf ("\n%d errors\n", errors);
+ return errors > 0;
+}