1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-xmlrpc.c: XML-RPC parser/generator
5 * Copyright (C) 2007 Red Hat, Inc.
15 #include <libxml/tree.h>
17 #include "soup-xmlrpc.h"
18 #include "soup-value-utils.h"
19 #include "soup-date.h"
20 #include "soup-message.h"
21 #include "soup-misc.h"
22 #include "soup-session.h"
26 * @short_description: XML-RPC support
30 static xmlNode *find_real_node (xmlNode *node);
32 static gboolean insert_value (xmlNode *parent, GValue *value);
35 insert_member (gpointer name, gpointer value, gpointer data)
37 xmlNode *member, **struct_node = data;
42 member = xmlNewChild (*struct_node, NULL,
43 (const xmlChar *)"member", NULL);
44 xmlNewTextChild (member, NULL,
45 (const xmlChar *)"name", (const xmlChar *)name);
46 if (!insert_value (member, value)) {
47 xmlFreeNode (*struct_node);
53 insert_value (xmlNode *parent, GValue *value)
55 GType type = G_VALUE_TYPE (value);
59 xvalue = xmlNewChild (parent, NULL, (const xmlChar *)"value", NULL);
61 if (type == G_TYPE_INT) {
62 snprintf (buf, sizeof (buf), "%d", g_value_get_int (value));
63 xmlNewChild (xvalue, NULL,
64 (const xmlChar *)"int",
65 (const xmlChar *)buf);
66 } else if (type == G_TYPE_BOOLEAN) {
67 snprintf (buf, sizeof (buf), "%d", g_value_get_boolean (value));
68 xmlNewChild (xvalue, NULL,
69 (const xmlChar *)"boolean",
70 (const xmlChar *)buf);
71 } else if (type == G_TYPE_STRING) {
72 xmlNewTextChild (xvalue, NULL,
73 (const xmlChar *)"string",
74 (const xmlChar *)g_value_get_string (value));
75 } else if (type == G_TYPE_DOUBLE) {
76 g_ascii_dtostr (buf, sizeof (buf), g_value_get_double (value));
77 xmlNewChild (xvalue, NULL,
78 (const xmlChar *)"double",
79 (const xmlChar *)buf);
80 } else if (type == SOUP_TYPE_DATE) {
81 SoupDate *date = g_value_get_boxed (value);
82 char *timestamp = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC);
83 xmlNewChild (xvalue, NULL,
84 (const xmlChar *)"dateTime.iso8601",
85 (const xmlChar *)timestamp);
87 } else if (type == SOUP_TYPE_BYTE_ARRAY) {
88 GByteArray *ba = g_value_get_boxed (value);
91 encoded = g_base64_encode (ba->data, ba->len);
92 xmlNewChild (xvalue, NULL,
93 (const xmlChar *)"base64",
94 (const xmlChar *)encoded);
96 } else if (type == G_TYPE_HASH_TABLE) {
97 GHashTable *hash = g_value_get_boxed (value);
100 struct_node = xmlNewChild (xvalue, NULL,
101 (const xmlChar *)"struct", NULL);
102 g_hash_table_foreach (hash, insert_member, &struct_node);
105 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
106 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
108 } else if (type == G_TYPE_VALUE_ARRAY) {
109 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
110 G_GNUC_END_IGNORE_DEPRECATIONS
112 GValueArray *va = g_value_get_boxed (value);
116 node = xmlNewChild (xvalue, NULL,
117 (const xmlChar *)"array", NULL);
118 node = xmlNewChild (node, NULL,
119 (const xmlChar *)"data", NULL);
120 for (i = 0; i < va->n_values; i++) {
121 if (!insert_value (node, &va->values[i]))
131 * soup_xmlrpc_build_method_call:
132 * @method_name: the name of the XML-RPC method
133 * @params: (array length=n_params): arguments to @method
134 * @n_params: length of @params
136 * This creates an XML-RPC methodCall and returns it as a string.
137 * This is the low-level method that soup_xmlrpc_request_new() is
140 * @params is an array of #GValue representing the parameters to
141 * @method. (It is *not* a #GValueArray, although if you have a
142 * #GValueArray, you can just pass its <literal>values</literal>f and
143 * <literal>n_values</literal> fields.)
145 * The correspondence between glib types and XML-RPC types is:
147 * int: #int (%G_TYPE_INT)
148 * boolean: #gboolean (%G_TYPE_BOOLEAN)
149 * string: #char* (%G_TYPE_STRING)
150 * double: #double (%G_TYPE_DOUBLE)
151 * datetime.iso8601: #SoupDate (%SOUP_TYPE_DATE)
152 * base64: #GByteArray (%SOUP_TYPE_BYTE_ARRAY)
153 * struct: #GHashTable (%G_TYPE_HASH_TABLE)
154 * array: #GValueArray (%G_TYPE_VALUE_ARRAY)
156 * For structs, use a #GHashTable that maps strings to #GValue;
157 * soup_value_hash_new() and related methods can help with this.
159 * Return value: the text of the methodCall, or %NULL on error
162 soup_xmlrpc_build_method_call (const char *method_name,
163 GValue *params, int n_params)
166 xmlNode *node, *param;
171 doc = xmlNewDoc ((const xmlChar *)"1.0");
172 doc->standalone = FALSE;
173 doc->encoding = xmlCharStrdup ("UTF-8");
175 node = xmlNewDocNode (doc, NULL, (const xmlChar *)"methodCall", NULL);
176 xmlDocSetRootElement (doc, node);
177 xmlNewChild (node, NULL, (const xmlChar *)"methodName",
178 (const xmlChar *)method_name);
180 node = xmlNewChild (node, NULL, (const xmlChar *)"params", NULL);
181 for (i = 0; i < n_params; i++) {
182 param = xmlNewChild (node, NULL,
183 (const xmlChar *)"param", NULL);
184 if (!insert_value (param, ¶ms[i])) {
190 xmlDocDumpMemory (doc, &xmlbody, &len);
191 body = g_strndup ((char *)xmlbody, len);
198 soup_xmlrpc_request_newv (const char *uri, const char *method_name, va_list args)
204 params = soup_value_array_from_args (args);
208 body = soup_xmlrpc_build_method_call (method_name, params->values,
210 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
211 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
213 g_value_array_free (params);
214 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
215 G_GNUC_END_IGNORE_DEPRECATIONS
220 msg = soup_message_new ("POST", uri);
221 soup_message_set_request (msg, "text/xml", SOUP_MEMORY_TAKE,
222 body, strlen (body));
227 * soup_xmlrpc_request_new:
228 * @uri: URI of the XML-RPC service
229 * @method_name: the name of the XML-RPC method to invoke at @uri
230 * @...: parameters for @method
232 * Creates an XML-RPC methodCall and returns a #SoupMessage, ready
233 * to send, for that method call.
235 * The parameters are passed as type/value pairs; ie, first a #GType,
236 * and then a value of the appropriate type, finally terminated by
239 * Return value: (transfer full): a #SoupMessage encoding the
240 * indicated XML-RPC request.
243 soup_xmlrpc_request_new (const char *uri, const char *method_name, ...)
248 va_start (args, method_name);
249 msg = soup_xmlrpc_request_newv (uri, method_name, args);
255 * soup_xmlrpc_build_method_response:
256 * @value: the return value
258 * This creates a (successful) XML-RPC methodResponse and returns it
259 * as a string. To create a fault response, use
260 * soup_xmlrpc_build_fault().
262 * The glib type to XML-RPC type mapping is as with
263 * soup_xmlrpc_build_method_call(), qv.
265 * Return value: the text of the methodResponse, or %NULL on error
268 soup_xmlrpc_build_method_response (GValue *value)
276 doc = xmlNewDoc ((const xmlChar *)"1.0");
277 doc->standalone = FALSE;
278 doc->encoding = xmlCharStrdup ("UTF-8");
280 node = xmlNewDocNode (doc, NULL,
281 (const xmlChar *)"methodResponse", NULL);
282 xmlDocSetRootElement (doc, node);
284 node = xmlNewChild (node, NULL, (const xmlChar *)"params", NULL);
285 node = xmlNewChild (node, NULL, (const xmlChar *)"param", NULL);
286 if (!insert_value (node, value)) {
291 xmlDocDumpMemory (doc, &xmlbody, &len);
292 body = g_strndup ((char *)xmlbody, len);
299 soup_xmlrpc_build_faultv (int fault_code, const char *fault_format, va_list args)
302 xmlNode *node, *member;
305 char *fault_string, *body;
308 fault_string = g_strdup_vprintf (fault_format, args);
310 doc = xmlNewDoc ((const xmlChar *)"1.0");
311 doc->standalone = FALSE;
312 doc->encoding = xmlCharStrdup ("UTF-8");
314 node = xmlNewDocNode (doc, NULL,
315 (const xmlChar *)"methodResponse", NULL);
316 xmlDocSetRootElement (doc, node);
317 node = xmlNewChild (node, NULL, (const xmlChar *)"fault", NULL);
318 node = xmlNewChild (node, NULL, (const xmlChar *)"value", NULL);
319 node = xmlNewChild (node, NULL, (const xmlChar *)"struct", NULL);
321 memset (&value, 0, sizeof (value));
323 member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL);
324 xmlNewChild (member, NULL,
325 (const xmlChar *)"name", (const xmlChar *)"faultCode");
326 g_value_init (&value, G_TYPE_INT);
327 g_value_set_int (&value, fault_code);
328 insert_value (member, &value);
329 g_value_unset (&value);
331 member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL);
332 xmlNewChild (member, NULL,
333 (const xmlChar *)"name", (const xmlChar *)"faultString");
334 g_value_init (&value, G_TYPE_STRING);
335 g_value_take_string (&value, fault_string);
336 insert_value (member, &value);
337 g_value_unset (&value);
339 xmlDocDumpMemory (doc, &xmlbody, &len);
340 body = g_strndup ((char *)xmlbody, len);
348 * soup_xmlrpc_build_fault:
349 * @fault_code: the fault code
350 * @fault_format: a printf()-style format string
351 * @...: the parameters to @fault_format
353 * This creates an XML-RPC fault response and returns it as a string.
354 * (To create a successful response, use
355 * soup_xmlrpc_build_method_response().)
357 * Return value: the text of the fault
360 soup_xmlrpc_build_fault (int fault_code, const char *fault_format, ...)
365 va_start (args, fault_format);
366 body = soup_xmlrpc_build_faultv (fault_code, fault_format, args);
372 * soup_xmlrpc_set_response:
373 * @msg: an XML-RPC request
374 * @type: the type of the response value
375 * @...: the response value
377 * Sets the status code and response body of @msg to indicate a
378 * successful XML-RPC call, with a return value given by @type and the
379 * following varargs argument, of the type indicated by @type.
382 soup_xmlrpc_set_response (SoupMessage *msg, GType type, ...)
388 va_start (args, type);
389 SOUP_VALUE_SETV (&value, type, args);
392 body = soup_xmlrpc_build_method_response (&value);
393 g_value_unset (&value);
394 soup_message_set_status (msg, SOUP_STATUS_OK);
395 soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
396 body, strlen (body));
400 * soup_xmlrpc_set_fault:
401 * @msg: an XML-RPC request
402 * @fault_code: the fault code
403 * @fault_format: a printf()-style format string
404 * @...: the parameters to @fault_format
406 * Sets the status code and response body of @msg to indicate an
407 * unsuccessful XML-RPC call, with the error described by @fault_code
411 soup_xmlrpc_set_fault (SoupMessage *msg, int fault_code,
412 const char *fault_format, ...)
417 va_start (args, fault_format);
418 body = soup_xmlrpc_build_faultv (fault_code, fault_format, args);
421 soup_message_set_status (msg, SOUP_STATUS_OK);
422 soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
423 body, strlen (body));
429 parse_value (xmlNode *xmlvalue, GValue *value)
432 const char *typename;
435 memset (value, 0, sizeof (GValue));
437 typenode = find_real_node (xmlvalue->children);
439 /* If no type node, it's a string */
440 content = xmlNodeGetContent (typenode);
441 g_value_init (value, G_TYPE_STRING);
442 g_value_set_string (value, (char *)content);
447 typename = (const char *)typenode->name;
449 if (!strcmp (typename, "i4") || !strcmp (typename, "int")) {
450 content = xmlNodeGetContent (typenode);
451 g_value_init (value, G_TYPE_INT);
452 g_value_set_int (value, atoi ((char *)content));
454 } else if (!strcmp (typename, "boolean")) {
455 content = xmlNodeGetContent (typenode);
456 g_value_init (value, G_TYPE_BOOLEAN);
457 g_value_set_boolean (value, atoi ((char *)content));
459 } else if (!strcmp (typename, "string")) {
460 content = xmlNodeGetContent (typenode);
461 g_value_init (value, G_TYPE_STRING);
462 g_value_set_string (value, (char *)content);
464 } else if (!strcmp (typename, "double")) {
465 content = xmlNodeGetContent (typenode);
466 g_value_init (value, G_TYPE_DOUBLE);
467 g_value_set_double (value, g_ascii_strtod ((char *)content, NULL));
469 } else if (!strcmp (typename, "dateTime.iso8601")) {
470 content = xmlNodeGetContent (typenode);
471 g_value_init (value, SOUP_TYPE_DATE);
472 g_value_take_boxed (value, soup_date_new_from_string ((char *)content));
474 } else if (!strcmp (typename, "base64")) {
479 content = xmlNodeGetContent (typenode);
480 decoded = g_base64_decode ((char *)content, &len);
481 ba = g_byte_array_sized_new (len);
482 g_byte_array_append (ba, decoded, len);
485 g_value_init (value, SOUP_TYPE_BYTE_ARRAY);
486 g_value_take_boxed (value, ba);
487 } else if (!strcmp (typename, "struct")) {
488 xmlNode *member, *child, *mname, *mxval;
492 hash = soup_value_hash_new ();
493 for (member = find_real_node (typenode->children);
495 member = find_real_node (member->next)) {
496 if (strcmp ((const char *)member->name, "member") != 0) {
497 g_hash_table_destroy (hash);
500 mname = mxval = NULL;
501 memset (&mgval, 0, sizeof (mgval));
503 for (child = find_real_node (member->children);
505 child = find_real_node (child->next)) {
506 if (!strcmp ((const char *)child->name, "name"))
508 else if (!strcmp ((const char *)child->name, "value"))
514 if (!mname || !mxval || !parse_value (mxval, &mgval)) {
515 g_hash_table_destroy (hash);
519 content = xmlNodeGetContent (mname);
520 soup_value_hash_insert_value (hash, (char *)content, &mgval);
522 g_value_unset (&mgval);
524 g_value_init (value, G_TYPE_HASH_TABLE);
525 g_value_take_boxed (value, hash);
526 } else if (!strcmp (typename, "array")) {
527 xmlNode *data, *xval;
531 data = find_real_node (typenode->children);
532 if (!data || strcmp ((const char *)data->name, "data") != 0)
535 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
536 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
538 array = g_value_array_new (1);
539 for (xval = find_real_node (data->children);
541 xval = find_real_node (xval->next)) {
542 memset (&gval, 0, sizeof (gval));
543 if (strcmp ((const char *)xval->name, "value") != 0 ||
544 !parse_value (xval, &gval)) {
545 g_value_array_free (array);
549 g_value_array_append (array, &gval);
550 g_value_unset (&gval);
552 g_value_init (value, G_TYPE_VALUE_ARRAY);
553 g_value_take_boxed (value, array);
554 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
555 G_GNUC_END_IGNORE_DEPRECATIONS
564 * soup_xmlrpc_parse_method_call:
565 * @method_call: the XML-RPC methodCall string
566 * @length: the length of @method_call, or -1 if it is NUL-terminated
567 * @method_name: (out): on return, the methodName from @method_call
568 * @params: (out): on return, the parameters from @method_call
570 * Parses @method_call to get the name and parameters, and returns the
571 * parameter values in a #GValueArray; see also
572 * soup_xmlrpc_extract_method_call(), which is more convenient if you
573 * know in advance what the types of the parameters will be.
575 * Return value: success or failure.
578 soup_xmlrpc_parse_method_call (const char *method_call, int length,
579 char **method_name, GValueArray **params)
582 xmlNode *node, *param, *xval;
583 xmlChar *xmlMethodName = NULL;
584 gboolean success = FALSE;
587 doc = xmlParseMemory (method_call,
588 length == -1 ? strlen (method_call) : length);
592 node = xmlDocGetRootElement (doc);
593 if (!node || strcmp ((const char *)node->name, "methodCall") != 0)
596 node = find_real_node (node->children);
597 if (!node || strcmp ((const char *)node->name, "methodName") != 0)
599 xmlMethodName = xmlNodeGetContent (node);
601 node = find_real_node (node->next);
602 if (!node || strcmp ((const char *)node->name, "params") != 0)
605 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
606 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
608 *params = g_value_array_new (1);
609 param = find_real_node (node->children);
610 while (param && !strcmp ((const char *)param->name, "param")) {
611 xval = find_real_node (param->children);
612 if (!xval || strcmp ((const char *)xval->name, "value") != 0 ||
613 !parse_value (xval, &value)) {
614 g_value_array_free (*params);
617 g_value_array_append (*params, &value);
618 g_value_unset (&value);
620 param = find_real_node (param->next);
622 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
623 G_GNUC_END_IGNORE_DEPRECATIONS
627 *method_name = g_strdup ((char *)xmlMethodName);
632 xmlFree (xmlMethodName);
637 * soup_xmlrpc_extract_method_call:
638 * @method_call: the XML-RPC methodCall string
639 * @length: the length of @method_call, or -1 if it is NUL-terminated
640 * @method_name: (out): on return, the methodName from @method_call
641 * @...: return types and locations for parameters
643 * Parses @method_call to get the name and parameters, and puts
644 * the parameters into variables of the appropriate types.
646 * The parameters are handled similarly to
647 * @soup_xmlrpc_build_method_call, with pairs of types and values,
648 * terminated by %G_TYPE_INVALID, except that values are pointers to
649 * variables of the indicated type, rather than values of the type.
651 * See also soup_xmlrpc_parse_method_call(), which can be used if
652 * you don't know the types of the parameters.
654 * Return value: success or failure.
657 soup_xmlrpc_extract_method_call (const char *method_call, int length,
658 char **method_name, ...)
664 if (!soup_xmlrpc_parse_method_call (method_call, length,
665 method_name, ¶ms))
668 va_start (args, method_name);
669 success = soup_value_array_to_args (params, args);
672 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
673 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
675 g_value_array_free (params);
676 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
677 G_GNUC_END_IGNORE_DEPRECATIONS
683 * soup_xmlrpc_parse_method_response:
684 * @method_response: the XML-RPC methodResponse string
685 * @length: the length of @method_response, or -1 if it is NUL-terminated
686 * @value: (out): on return, the return value from @method_call
687 * @error: error return value
689 * Parses @method_response and returns the return value in @value. If
690 * @method_response is a fault, @value will be unchanged, and @error
691 * will be set to an error of type %SOUP_XMLRPC_FAULT, with the error
692 * #code containing the fault code, and the error #message containing
693 * the fault string. (If @method_response cannot be parsed at all,
694 * soup_xmlrpc_parse_method_response() will return %FALSE, but @error
697 * Return value: %TRUE if a return value was parsed, %FALSE if the
698 * response could not be parsed, or contained a fault.
701 soup_xmlrpc_parse_method_response (const char *method_response, int length,
702 GValue *value, GError **error)
706 gboolean success = FALSE;
708 doc = xmlParseMemory (method_response,
709 length == -1 ? strlen (method_response) : length);
713 node = xmlDocGetRootElement (doc);
714 if (!node || strcmp ((const char *)node->name, "methodResponse") != 0)
717 node = find_real_node (node->children);
721 if (!strcmp ((const char *)node->name, "fault") && error) {
725 GHashTable *fault_hash;
727 node = find_real_node (node->children);
728 if (!node || strcmp ((const char *)node->name, "value") != 0)
730 if (!parse_value (node, &fault_val))
732 if (!G_VALUE_HOLDS (&fault_val, G_TYPE_HASH_TABLE)) {
733 g_value_unset (&fault_val);
736 fault_hash = g_value_get_boxed (&fault_val);
737 if (!soup_value_hash_lookup (fault_hash, "faultCode",
738 G_TYPE_INT, &fault_code) ||
739 !soup_value_hash_lookup (fault_hash, "faultString",
740 G_TYPE_STRING, &fault_string)) {
741 g_value_unset (&fault_val);
745 g_set_error (error, SOUP_XMLRPC_FAULT,
746 fault_code, "%s", fault_string);
747 g_value_unset (&fault_val);
748 } else if (!strcmp ((const char *)node->name, "params")) {
749 node = find_real_node (node->children);
750 if (!node || strcmp ((const char *)node->name, "param") != 0)
752 node = find_real_node (node->children);
753 if (!node || strcmp ((const char *)node->name, "value") != 0)
755 if (!parse_value (node, value))
766 * soup_xmlrpc_extract_method_response:
767 * @method_response: the XML-RPC methodResponse string
768 * @length: the length of @method_response, or -1 if it is NUL-terminated
769 * @error: error return value
770 * @type: the expected type of the return value
771 * @...: location for return value
773 * Parses @method_response and extracts the return value into
774 * a variable of the correct type.
776 * If @method_response is a fault, the return value will be unset,
777 * and @error will be set to an error of type %SOUP_XMLRPC_FAULT, with
778 * the error #code containing the fault code, and the error #message
779 * containing the fault string. (If @method_response cannot be parsed
780 * at all, soup_xmlrpc_extract_method_response() will return %FALSE,
781 * but @error will be unset.)
783 * Return value: %TRUE if a return value was parsed, %FALSE if the
784 * response was of the wrong type, or contained a fault.
787 soup_xmlrpc_extract_method_response (const char *method_response, int length,
788 GError **error, GType type, ...)
793 if (!soup_xmlrpc_parse_method_response (method_response, length,
796 if (!G_VALUE_HOLDS (&value, type))
799 va_start (args, type);
800 SOUP_VALUE_GETV (&value, type, args);
808 soup_xmlrpc_error_quark (void)
812 error = g_quark_from_static_string ("soup_xmlrpc_error_quark");
819 * A #GError domain representing an XML-RPC fault code. Used with
820 * #SoupXMLRPCFault (although servers may also return fault codes not
821 * in that enumeration).
826 * @SOUP_XMLRPC_FAULT_PARSE_ERROR_NOT_WELL_FORMED: request was not
828 * @SOUP_XMLRPC_FAULT_PARSE_ERROR_UNSUPPORTED_ENCODING: request was in
829 * an unsupported encoding
830 * @SOUP_XMLRPC_FAULT_PARSE_ERROR_INVALID_CHARACTER_FOR_ENCODING:
831 * request contained an invalid character
832 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_XML_RPC: request was not
834 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_REQUESTED_METHOD_NOT_FOUND: method
836 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS: invalid
838 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_INTERNAL_XML_RPC_ERROR: internal
840 * @SOUP_XMLRPC_FAULT_APPLICATION_ERROR: start of reserved range for
841 * application error codes
842 * @SOUP_XMLRPC_FAULT_SYSTEM_ERROR: start of reserved range for
844 * @SOUP_XMLRPC_FAULT_TRANSPORT_ERROR: start of reserved range for
845 * transport error codes
847 * Pre-defined XML-RPC fault codes from <ulink
848 * url="http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php">http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php</ulink>.
849 * These are an extension, not part of the XML-RPC spec; you can't
850 * assume servers will use them.
854 soup_xmlrpc_fault_quark (void)
858 error = g_quark_from_static_string ("soup_xmlrpc_fault_quark");
863 find_real_node (xmlNode *node)
865 while (node && (node->type == XML_COMMENT_NODE ||
866 xmlIsBlankNode (node)))