Author: danw Date: Sun Jan 27 19:21:30 2008 New Revision: 1056 URL: http://svn.gnome.org/viewvc/libsoup?rev=1056&view=rev
Log: * libsoup/soup-dns.c (resolver_thread): fix mutex use to avoid a race condition * libsoup/soup-xmlrpc.c (soup_xmlrpc_build_faultv): (soup_xmlrpc_set_response, soup_xmlrpc_set_fault): (soup_xmlrpc_parse_method_call): Fix misc server-side stuff (soup_xmlrpc_parse_method_response): Fix fault parsing * libsoup/soup-xmlrpc.h (SoupXMLRPCFault): add semi-standard fault codes from http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php * tests/xmlrpc-server.php (sum): return a <fault> if the arguments are wrong (so that xmlrpc-test can test that case). (dateChange): change to take two parameters, a date and a struct, instead of putting the date in the struct, since we weren't previously testing multiple parameter handling. * tests/xmlrpc-test.c (main): Add a -u flag to specify an alternate URL. (do_xmlrpc): Remove level 3 debug output, which is now redundant with the SoupLogger stuff. (test_dateChange): update for dateChange prototype change (test_fault_malformed, test_fault_method, test_fault_args): test handling of faults * tests/xmlrpc-server-test.c: Test the server-side XML-RPC API (by implementing the same methods as xmlrpc-server.php and then using xmlrpc-test) Added: trunk/tests/xmlrpc-server-test.c Modified: trunk/ChangeLog trunk/libsoup/soup-dns.c trunk/libsoup/soup-xmlrpc.c trunk/libsoup/soup-xmlrpc.h trunk/tests/ (props changed) trunk/tests/Makefile.am trunk/tests/libsoup.supp trunk/tests/xmlrpc-server.php trunk/tests/xmlrpc-test.c Modified: trunk/libsoup/soup-dns.c ============================================================================== --- trunk/libsoup/soup-dns.c (original) +++ trunk/libsoup/soup-dns.c Sun Jan 27 19:21:30 2008 @@ -517,9 +517,9 @@ else if (entry->sockaddr == NULL) resolve_address (entry); + g_mutex_lock (soup_dns_lock); entry->resolver_thread = NULL; - g_mutex_lock (soup_dns_lock); async_lookups = entry->async_lookups; entry->async_lookups = NULL; g_mutex_unlock (soup_dns_lock); Modified: trunk/libsoup/soup-xmlrpc.c ============================================================================== --- trunk/libsoup/soup-xmlrpc.c (original) +++ trunk/libsoup/soup-xmlrpc.c Sun Jan 27 19:21:30 2008 @@ -301,23 +301,23 @@ node = xmlNewDocNode (doc, NULL, (const xmlChar *)"methodResponse", NULL); xmlDocSetRootElement (doc, node); - node = xmlNewDocNode (doc, NULL, (const xmlChar *)"fault", NULL); - node = xmlNewDocNode (doc, NULL, (const xmlChar *)"value", NULL); - node = xmlNewDocNode (doc, NULL, (const xmlChar *)"struct", NULL); + node = xmlNewChild (node, NULL, (const xmlChar *)"fault", NULL); + node = xmlNewChild (node, NULL, (const xmlChar *)"value", NULL); + node = xmlNewChild (node, NULL, (const xmlChar *)"struct", NULL); memset (&value, 0, sizeof (value)); - member = xmlNewDocNode (doc, NULL, (const xmlChar *)"member", NULL); - xmlNewDocNode (doc, NULL, - (const xmlChar *)"name", (const xmlChar *)"faultCode"); + member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL); + xmlNewChild (member, NULL, + (const xmlChar *)"name", (const xmlChar *)"faultCode"); g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, fault_code); insert_value (member, &value); g_value_unset (&value); - member = xmlNewDocNode (doc, NULL, (const xmlChar *)"member", NULL); - xmlNewDocNode (doc, NULL, - (const xmlChar *)"name", (const xmlChar *)"faultString"); + member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL); + xmlNewChild (member, NULL, + (const xmlChar *)"name", (const xmlChar *)"faultString"); g_value_init (&value, G_TYPE_STRING); g_value_take_string (&value, fault_string); insert_value (member, &value); @@ -373,14 +373,14 @@ char *body; va_start (args, type); - SOUP_VALUE_GETV (&value, type, args); + SOUP_VALUE_SETV (&value, type, args); va_end (args); body = soup_xmlrpc_build_method_response (&value); g_value_unset (&value); soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_request (msg, "text/xml", SOUP_MEMORY_TAKE, - body, strlen (body)); + soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE, + body, strlen (body)); } /** @@ -406,8 +406,8 @@ va_end (args); soup_message_set_status (msg, SOUP_STATUS_OK); - soup_message_set_request (msg, "text/xml", SOUP_MEMORY_TAKE, - body, strlen (body)); + soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE, + body, strlen (body)); } @@ -586,13 +586,15 @@ param = find_real_node (node->children); while (param && !strcmp ((const char *)param->name, "param")) { xval = find_real_node (param->children); - if (!xval || !strcmp ((const char *)xval->name, "value") || + if (!xval || strcmp ((const char *)xval->name, "value") != 0 || !parse_value (xval, &value)) { g_value_array_free (*params); goto fail; } g_value_array_append (*params, &value); g_value_unset (&value); + + param = find_real_node (param->next); } success = TRUE; @@ -685,30 +687,32 @@ goto fail; if (!strcmp ((const char *)node->name, "fault") && error) { - int fault_code = -1; - xmlChar *fault_string = NULL; + int fault_code; + char *fault_string; + GValue fault_val; + GHashTable *fault_hash; - for (node = find_real_node (node->children); - node; - node = find_real_node (node->next)) { - if (!strcmp ((const char *)node->name, "faultCode")) { - xmlChar *content = xmlNodeGetContent (node); - fault_code = atoi ((char *)content); - xmlFree (content); - } else if (!strcmp ((const char *)node->name, "faultString")) { - fault_string = xmlNodeGetContent (node); - } else { - if (fault_string) - xmlFree (fault_string); - goto fail; - } + node = find_real_node (node->children); + if (!node || strcmp ((const char *)node->name, "value") != 0) + goto fail; + if (!parse_value (node, &fault_val)) + goto fail; + if (!G_VALUE_HOLDS (&fault_val, G_TYPE_HASH_TABLE)) { + g_value_unset (&fault_val); + goto fail; } - if (fault_code != -1 && fault_string != NULL) { - g_set_error (error, SOUP_XMLRPC_FAULT, - fault_code, "%s", fault_string); + fault_hash = g_value_get_boxed (&fault_val); + if (!soup_value_hash_lookup (fault_hash, "faultCode", + G_TYPE_INT, &fault_code) || + !soup_value_hash_lookup (fault_hash, "faultString", + G_TYPE_STRING, &fault_string)) { + g_value_unset (&fault_val); + goto fail; } - if (fault_string) - xmlFree (fault_string); + + g_set_error (error, SOUP_XMLRPC_FAULT, + fault_code, "%s", fault_string); + g_value_unset (&fault_val); } else if (!strcmp ((const char *)node->name, "params")) { node = find_real_node (node->children); if (!node || strcmp ((const char *)node->name, "param") != 0) Modified: trunk/libsoup/soup-xmlrpc.h ============================================================================== --- trunk/libsoup/soup-xmlrpc.h (original) +++ trunk/libsoup/soup-xmlrpc.h Sun Jan 27 19:21:30 2008 @@ -61,6 +61,22 @@ #define SOUP_XMLRPC_FAULT soup_xmlrpc_fault_quark() GQuark soup_xmlrpc_fault_quark (void); +/* From http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php. + * These are an extension, not part of the XML-RPC spec; you can't + * assume servers will use them. + */ +typedef enum { + SOUP_XMLRPC_FAULT_PARSE_ERROR_NOT_WELL_FORMED = -32700, + SOUP_XMLRPC_FAULT_PARSE_ERROR_UNSUPPORTED_ENCODING = -32701, + SOUP_XMLRPC_FAULT_PARSE_ERROR_INVALID_CHARACTER_FOR_ENCODING = -32702, + SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_XML_RPC = -32600, + SOUP_XMLRPC_FAULT_SERVER_ERROR_REQUESTED_METHOD_NOT_FOUND = -32601, + SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS = -32602, + SOUP_XMLRPC_FAULT_SERVER_ERROR_INTERNAL_XML_RPC_ERROR = -32603, + SOUP_XMLRPC_FAULT_APPLICATION_ERROR = -32500, + SOUP_XMLRPC_FAULT_SYSTEM_ERROR = -32400, + SOUP_XMLRPC_FAULT_TRANSPORT_ERROR = -32300, +} SoupXMLRPCFault; G_END_DECLS Modified: trunk/tests/Makefile.am ============================================================================== --- trunk/tests/Makefile.am (original) +++ trunk/tests/Makefile.am Sun Jan 27 19:21:30 2008 @@ -44,6 +44,7 @@ ssl_test_SOURCES = ssl-test.c $(TEST_SRCS) uri_parsing_SOURCES = uri-parsing.c $(TEST_SRCS) xmlrpc_test_SOURCES = xmlrpc-test.c $(TEST_SRCS) +xmlrpc_server_test_SOURCES = xmlrpc-server-test.c $(TEST_SRCS) if HAVE_APACHE APACHE_TESTS = auth-test proxy-test pull-api @@ -55,7 +56,7 @@ SSL_TESTS = ssl-test endif if HAVE_XMLRPC_EPI_PHP -XMLRPC_TESTS = xmlrpc-test +XMLRPC_TESTS = xmlrpc-test xmlrpc-server-test endif TESTS = \ Modified: trunk/tests/libsoup.supp ============================================================================== --- trunk/tests/libsoup.supp (original) +++ trunk/tests/libsoup.supp Sun Jan 27 19:21:30 2008 @@ -817,6 +817,17 @@ fun:g_child_watch_source_init_multi_threaded fun:g_child_watch_source_init } +{ + glib/childwatch2b + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_2.2.5 + fun:g_thread_create_posix_impl + fun:g_thread_create_full + fun:g_child_watch_source_init_multi_threaded + fun:g_child_watch_source_init +} { Added: trunk/tests/xmlrpc-server-test.c ============================================================================== --- (empty file) +++ trunk/tests/xmlrpc-server-test.c Sun Jan 27 19:21:30 2008 @@ -0,0 +1,337 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2008 Red Hat, Inc. + */ + +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <sys/wait.h> + +#include <libsoup/soup.h> + +#include "test-utils.h" + +GMainLoop *loop; + +static void +type_error (SoupMessage *msg, GType expected, GValueArray *params, int bad_value) +{ + soup_xmlrpc_set_fault (msg, + SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS, + "Bad parameter #%d: expected %s, got %s", + bad_value + 1, g_type_name (expected), + g_type_name (G_VALUE_TYPE (¶ms->values[bad_value]))); +} + +static void +args_error (SoupMessage *msg, GValueArray *params, int expected) +{ + soup_xmlrpc_set_fault (msg, + SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS, + "Wrong number of parameters: expected %d, got %d", + expected, params->n_values); +} + +static void +do_sum (SoupMessage *msg, GValueArray *params) +{ + int sum = 0, i, val; + GValueArray *nums; + + if (params->n_values != 1) { + args_error (msg, params, 1); + return; + } + if (!soup_value_array_get_nth (params, 0, G_TYPE_VALUE_ARRAY, &nums)) { + type_error (msg, G_TYPE_VALUE_ARRAY, params, 0); + return; + } + + for (i = 0; i < nums->n_values; i++) { + if (!soup_value_array_get_nth (nums, i, G_TYPE_INT, &val)) { + type_error (msg, G_TYPE_INT, nums, i); + return; + } + sum += val; + } + + soup_xmlrpc_set_response (msg, G_TYPE_INT, sum); + +} + +static void +do_countBools (SoupMessage *msg, GValueArray *params) +{ + int i, trues = 0, falses = 0; + GValueArray *bools; + GHashTable *ret = soup_value_hash_new (); + gboolean val; + + if (params->n_values != 1) { + args_error (msg, params, 1); + return; + } + if (!soup_value_array_get_nth (params, 0, G_TYPE_VALUE_ARRAY, &bools)) { + type_error (msg, G_TYPE_VALUE_ARRAY, params, 0); + return; + } + + for (i = 0; i < bools->n_values; i++) { + if (!soup_value_array_get_nth (bools, i, G_TYPE_BOOLEAN, &val)) { + type_error (msg, G_TYPE_BOOLEAN, params, i); + return; + } + if (val) + trues++; + else + falses++; + } + + soup_value_hash_insert (ret, "true", G_TYPE_INT, trues); + soup_value_hash_insert (ret, "false", G_TYPE_INT, falses); + soup_xmlrpc_set_response (msg, G_TYPE_HASH_TABLE, ret); + g_hash_table_destroy (ret); + +} + +static void +do_md5sum (SoupMessage *msg, GValueArray *params) +{ + GChecksum *checksum; + GByteArray *data, *digest; + gsize digest_len = 16; + + if (params->n_values != 1) { + args_error (msg, params, 1); + return; + } + + if (!soup_value_array_get_nth (params, 0, SOUP_TYPE_BYTE_ARRAY, &data)) { + type_error (msg, SOUP_TYPE_BYTE_ARRAY, params, 0); + return; + } + checksum = g_checksum_new (G_CHECKSUM_MD5); + g_checksum_update (checksum, data->data, data->len); + digest = g_byte_array_new (); + g_byte_array_set_size (digest, digest_len); + g_checksum_get_digest (checksum, digest->data, &digest_len); + g_checksum_free (checksum); + + soup_xmlrpc_set_response (msg, SOUP_TYPE_BYTE_ARRAY, digest); + g_byte_array_free (digest, TRUE); +} + + +static void +do_dateChange (SoupMessage *msg, GValueArray *params) +{ + GHashTable *arg; + SoupDate *date; + int val; + + if (params->n_values != 2) { + args_error (msg, params, 2); + return; + } + + if (!soup_value_array_get_nth (params, 0, SOUP_TYPE_DATE, &date)) { + type_error (msg, SOUP_TYPE_DATE, params, 0); + return; + } + if (!soup_value_array_get_nth (params, 1, G_TYPE_HASH_TABLE, &arg)) { + type_error (msg, G_TYPE_HASH_TABLE, params, 1); + return; + } + + if (soup_value_hash_lookup (arg, "tm_year", G_TYPE_INT, &val)) + date->year = val + 1900; + if (soup_value_hash_lookup (arg, "tm_mon", G_TYPE_INT, &val)) + date->month = val + 1; + if (soup_value_hash_lookup (arg, "tm_mday", G_TYPE_INT, &val)) + date->day = val; + if (soup_value_hash_lookup (arg, "tm_hour", G_TYPE_INT, &val)) + date->hour = val; + if (soup_value_hash_lookup (arg, "tm_min", G_TYPE_INT, &val)) + date->minute = val; + if (soup_value_hash_lookup (arg, "tm_sec", G_TYPE_INT, &val)) + date->second = val; + + soup_xmlrpc_set_response (msg, SOUP_TYPE_DATE, date); +} + +static void +do_echo (SoupMessage *msg, GValueArray *params) +{ + int i; + const char *val; + GValueArray *in, *out; + + if (!soup_value_array_get_nth (params, 0, G_TYPE_VALUE_ARRAY, &in)) { + type_error (msg, G_TYPE_VALUE_ARRAY, params, 0); + return; + } + + out = g_value_array_new (in->n_values); + for (i = 0; i < in->n_values; i++) { + if (!soup_value_array_get_nth (in, i, G_TYPE_STRING, &val)) { + type_error (msg, G_TYPE_STRING, in, i); + return; + } + soup_value_array_append (out, G_TYPE_STRING, val); + } + + soup_xmlrpc_set_response (msg, G_TYPE_VALUE_ARRAY, out); + g_value_array_free (out); + +} + +static void +server_callback (SoupServer *server, SoupMessage *msg, + const char *path, GHashTable *query, + SoupClientContext *context, gpointer data) +{ + char *method_name; + GValueArray *params; + + if (msg->method != SOUP_METHOD_POST) { + soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + return; + } + + soup_message_set_status (msg, SOUP_STATUS_OK); + + if (!soup_xmlrpc_parse_method_call (msg->request_body->data, + msg->request_body->length, + &method_name, ¶ms)) { + soup_xmlrpc_set_fault (msg, SOUP_XMLRPC_FAULT_PARSE_ERROR_NOT_WELL_FORMED, + "Could not parse method call"); + return; + } + + if (!strcmp (method_name, "sum")) + do_sum (msg, params); + else if (!strcmp (method_name, "countBools")) + do_countBools (msg, params); + else if (!strcmp (method_name, "md5sum")) + do_md5sum (msg, params); + else if (!strcmp (method_name, "dateChange")) + do_dateChange (msg, params); + else if (!strcmp (method_name, "echo")) + do_echo (msg, params); + else { + soup_xmlrpc_set_fault (msg, SOUP_XMLRPC_FAULT_SERVER_ERROR_REQUESTED_METHOD_NOT_FOUND, + "Unknown method %s", method_name); + } + + g_free (method_name); + g_value_array_free (params); +} + +static void +xmlrpc_test_exited (GPid pid, int status, gpointer data) +{ + errors = WIFEXITED (status) ? WEXITSTATUS (status) : 1; + g_main_loop_quit (loop); +} + +static gboolean +xmlrpc_test_print (GIOChannel *io, GIOCondition cond, gpointer data) +{ + char *line; + gsize len; + GIOStatus status; + + if (!(cond & G_IO_IN)) + return FALSE; + + status = g_io_channel_read_line (io, &line, &len, NULL, NULL); + if (status == G_IO_STATUS_NORMAL) { + /* Don't print the exit status, just the debug stuff */ + if (strncmp (line, "xmlrpc-test:", strlen ("xmlrpc-test:")) != 0) + printf ("%s", line); + g_free (line); + return TRUE; + } else if (status == G_IO_STATUS_AGAIN) + return TRUE; + else + return FALSE; +} + +static void +do_xmlrpc_tests (SoupURI *uri) +{ + char *argv[7]; + int arg, out; + gboolean ok; + GPid pid; + GError *error = NULL; + GIOChannel *child_out; + + argv[0] = "./xmlrpc-test"; + argv[1] = "-u"; + argv[2] = soup_uri_to_string (uri, FALSE); + + for (arg = 0; arg < debug_level && arg < 3; arg++) + argv[arg + 3] = "-d"; + argv[arg + 3] = NULL; + + ok = g_spawn_async_with_pipes (NULL, argv, NULL, + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, &pid, + NULL, &out, NULL, + &error); + g_free (argv[2]); + + if (!ok) { + printf ("Could not run xmlrpc-test: %s\n", error->message); + errors++; + return; + } + + g_child_watch_add (pid, xmlrpc_test_exited, NULL); + child_out = g_io_channel_unix_new (out); + g_io_add_watch (child_out, G_IO_IN | G_IO_ERR | G_IO_HUP, + xmlrpc_test_print, NULL); + g_io_channel_unref (child_out); +} + +gboolean run_tests = TRUE; + +static GOptionEntry no_test_entry[] = { + { "no-tests", 'n', G_OPTION_FLAG_NO_ARG | G_OPTION_FLAG_REVERSE, + G_OPTION_ARG_NONE, &run_tests, + "Don't run tests, just run the test server", NULL }, + { NULL } +}; + +int +main (int argc, char **argv) +{ + SoupServer *server; + SoupURI *uri; + + test_init (argc, argv, no_test_entry); + + server = soup_test_server_new (FALSE); + soup_server_add_handler (server, "/xmlrpc-server.php", + server_callback, NULL, NULL); + + loop = g_main_loop_new (NULL, TRUE); + + if (run_tests) { + uri = soup_uri_new ("http://localhost/xmlrpc-server.php"); + soup_uri_set_port (uri, soup_server_get_port (server)); + do_xmlrpc_tests (uri); + soup_uri_free (uri); + } else + printf ("Listening on port %d\n", soup_server_get_port (server)); + + g_main_loop_run (loop); + g_main_loop_unref (loop); + + if (run_tests) + test_cleanup (); + return errors != 0; +} Modified: trunk/tests/xmlrpc-server.php ============================================================================== Binary files. No diff available. Modified: trunk/tests/xmlrpc-test.c ============================================================================== --- trunk/tests/xmlrpc-test.c (original) +++ trunk/tests/xmlrpc-test.c Sun Jan 27 19:21:30 2008 @@ -13,7 +13,8 @@ #include "test-utils.h" SoupSession *session; -static const char *uri = "http://localhost:47524/xmlrpc-server.php"; +static const char *default_uri = "http://localhost:47524/xmlrpc-server.php"; +const char *uri = NULL; static const char *const value_type[] = { "BAD", @@ -51,13 +52,6 @@ body, strlen (body)); soup_session_send_message (session, msg); - if (debug_level >= 3) { - debug_printf (3, "\n%s\n%d %s\n%s\n", - msg->request_body->data, - msg->status_code, msg->reason_phrase, - msg->response_body->data); - } - if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { debug_printf (1, "ERROR: %d %s\n", msg->status_code, msg->reason_phrase); @@ -231,9 +225,7 @@ GValue retval; gboolean ok; - debug_printf (1, "dateChange (struct of time and ints -> time): "); - - structval = soup_value_hash_new (); + debug_printf (1, "dateChange (date, struct of ints -> time): "); date = soup_date_new (1970 + (rand () % 50), 1 + rand () % 12, @@ -241,54 +233,55 @@ rand () % 24, rand () % 60, rand () % 60); - soup_value_hash_insert (structval, "date", SOUP_TYPE_DATE, date); - if (debug_level >= 2) { timestamp = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC); - debug_printf (2, "{ date: %s", timestamp); + debug_printf (2, "date: %s, {", timestamp); g_free (timestamp); } + structval = soup_value_hash_new (); + if (rand () % 3) { date->year = 1970 + (rand () % 50); - debug_printf (2, ", tm_year: %d", date->year - 1900); + debug_printf (2, "tm_year: %d, ", date->year - 1900); soup_value_hash_insert (structval, "tm_year", G_TYPE_INT, date->year - 1900); } if (rand () % 3) { date->month = 1 + rand () % 12; - debug_printf (2, ", tm_mon: %d", date->month - 1); + debug_printf (2, "tm_mon: %d, ", date->month - 1); soup_value_hash_insert (structval, "tm_mon", G_TYPE_INT, date->month - 1); } if (rand () % 3) { date->day = 1 + rand () % 28; - debug_printf (2, ", tm_mday: %d", date->day); + debug_printf (2, "tm_mday: %d, ", date->day); soup_value_hash_insert (structval, "tm_mday", G_TYPE_INT, date->day); } if (rand () % 3) { date->hour = rand () % 24; - debug_printf (2, ", tm_hour: %d", date->hour); + debug_printf (2, "tm_hour: %d, ", date->hour); soup_value_hash_insert (structval, "tm_hour", G_TYPE_INT, date->hour); } if (rand () % 3) { date->minute = rand () % 60; - debug_printf (2, ", tm_min: %d", date->minute); + debug_printf (2, "tm_min: %d, ", date->minute); soup_value_hash_insert (structval, "tm_min", G_TYPE_INT, date->minute); } if (rand () % 3) { date->second = rand () % 60; - debug_printf (2, ", tm_sec: %d", date->second); + debug_printf (2, "tm_sec: %d, ", date->second); soup_value_hash_insert (structval, "tm_sec", G_TYPE_INT, date->second); } - debug_printf (2, " } -> "); + debug_printf (2, "} -> "); ok = (do_xmlrpc ("dateChange", &retval, + SOUP_TYPE_DATE, date, G_TYPE_HASH_TABLE, structval, G_TYPE_INVALID) && check_xmlrpc (&retval, SOUP_TYPE_DATE, &result)); @@ -377,11 +370,82 @@ return TRUE; } +static gboolean +do_bad_xmlrpc (const char *body) +{ + SoupMessage *msg; + GError *err = NULL; + GValue retval; + + msg = soup_message_new ("POST", uri); + soup_message_set_request (msg, "text/xml", SOUP_MEMORY_COPY, + body, strlen (body)); + soup_session_send_message (session, msg); + + if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) { + debug_printf (1, "ERROR: %d %s\n", msg->status_code, + msg->reason_phrase); + g_object_unref (msg); + return FALSE; + } + + if (!soup_xmlrpc_parse_method_response (msg->response_body->data, + msg->response_body->length, + &retval, &err)) { + if (err) { + debug_printf (1, "FAULT: %d %s (OK!)\n", + err->code, err->message); + g_error_free (err); + g_object_unref (msg); + return TRUE; + } else + debug_printf (1, "ERROR: could not parse response\n"); + } else + debug_printf (1, "Unexpectedly got successful response!\n"); + + g_object_unref (msg); + return FALSE; +} + +static gboolean +test_fault_malformed (void) +{ + debug_printf (1, "malformed request: "); + + return do_bad_xmlrpc ("<methodCall/>"); +} + +static gboolean +test_fault_method (void) +{ + debug_printf (1, "request to non-existent method: "); + + return do_bad_xmlrpc ("<methodCall><methodName>no_such_method</methodName><params><param><value><int>1</int></value></param></params></methodCall>"); +} + +static gboolean +test_fault_args (void) +{ + debug_printf (1, "request with invalid args: "); + + return do_bad_xmlrpc ("<methodCall><methodName>sum</methodName><params><param><value><int>1</int></value></param></params></methodCall>"); +} + +static GOptionEntry uri_entry[] = { + { "uri", 'u', 0, G_OPTION_ARG_STRING, &uri, + "Alternate URI for server", NULL }, + { NULL } +}; + int main (int argc, char **argv) { - test_init (argc, argv, NULL); - apache_init (); + test_init (argc, argv, uri_entry); + + if (!uri) { + apache_init (); + uri = default_uri; + } srand (time (NULL)); @@ -397,10 +461,16 @@ errors++; if (!test_echo ()) errors++; + if (!test_fault_malformed ()) + errors++; + if (!test_fault_method ()) + errors++; + if (!test_fault_args ()) + errors++; soup_session_abort (session); g_object_unref (session); test_cleanup (); - return errors = 0; + return errors != 0; } _______________________________________________ SVN-commits-list mailing list (read only) http://mail.gnome.org/mailman/listinfo/svn-commits-list Want to limit the commits to a few modules? Go to above URL, log in to edit your options and select the modules ('topics') you want. Module maintainer? It is possible to set the reply-to to your development mailing list. Email [EMAIL PROTECTED] if interested.