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.
14 #include <libxml/tree.h>
16 #include "soup-xmlrpc.h"
21 * @short_description: XML-RPC support
25 static xmlNode *find_real_node (xmlNode *node);
27 static gboolean insert_value (xmlNode *parent, GValue *value);
30 insert_value (xmlNode *parent, GValue *value)
32 GType type = G_VALUE_TYPE (value);
36 xvalue = xmlNewChild (parent, NULL, (const xmlChar *)"value", NULL);
38 if (type == G_TYPE_INT) {
39 snprintf (buf, sizeof (buf), "%d", g_value_get_int (value));
40 xmlNewChild (xvalue, NULL,
41 (const xmlChar *)"int",
42 (const xmlChar *)buf);
43 } else if (type == G_TYPE_BOOLEAN) {
44 snprintf (buf, sizeof (buf), "%d", g_value_get_boolean (value));
45 xmlNewChild (xvalue, NULL,
46 (const xmlChar *)"boolean",
47 (const xmlChar *)buf);
48 } else if (type == G_TYPE_STRING) {
49 xmlNewTextChild (xvalue, NULL,
50 (const xmlChar *)"string",
51 (const xmlChar *)g_value_get_string (value));
52 } else if (type == G_TYPE_DOUBLE) {
53 g_ascii_dtostr (buf, sizeof (buf), g_value_get_double (value));
54 xmlNewChild (xvalue, NULL,
55 (const xmlChar *)"double",
56 (const xmlChar *)buf);
57 } else if (type == SOUP_TYPE_DATE) {
58 SoupDate *date = g_value_get_boxed (value);
59 char *timestamp = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC);
60 xmlNewChild (xvalue, NULL,
61 (const xmlChar *)"dateTime.iso8601",
62 (const xmlChar *)timestamp);
64 } else if (type == SOUP_TYPE_BYTE_ARRAY) {
65 GByteArray *ba = g_value_get_boxed (value);
68 encoded = g_base64_encode (ba->data, ba->len);
69 xmlNewChild (xvalue, NULL,
70 (const xmlChar *)"base64",
71 (const xmlChar *)encoded);
73 } else if (type == G_TYPE_HASH_TABLE) {
74 GHashTable *hash = g_value_get_boxed (value);
76 gpointer mname, mvalue;
77 xmlNode *struct_node, *member;
79 struct_node = xmlNewChild (xvalue, NULL,
80 (const xmlChar *)"struct", NULL);
82 g_hash_table_iter_init (&iter, hash);
84 while (g_hash_table_iter_next (&iter, &mname, &mvalue)) {
85 member = xmlNewChild (struct_node, NULL,
86 (const xmlChar *)"member", NULL);
87 xmlNewTextChild (member, NULL,
88 (const xmlChar *)"name",
89 (const xmlChar *)mname);
90 if (!insert_value (member, mvalue)) {
91 xmlFreeNode (struct_node);
99 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
100 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
102 } else if (type == G_TYPE_VALUE_ARRAY) {
103 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
104 G_GNUC_END_IGNORE_DEPRECATIONS
106 GValueArray *va = g_value_get_boxed (value);
110 node = xmlNewChild (xvalue, NULL,
111 (const xmlChar *)"array", NULL);
112 node = xmlNewChild (node, NULL,
113 (const xmlChar *)"data", NULL);
114 for (i = 0; i < va->n_values; i++) {
115 if (!insert_value (node, &va->values[i]))
125 * soup_xmlrpc_build_method_call:
126 * @method_name: the name of the XML-RPC method
127 * @params: (array length=n_params): arguments to @method
128 * @n_params: length of @params
130 * This creates an XML-RPC methodCall and returns it as a string.
131 * This is the low-level method that soup_xmlrpc_request_new() is
134 * @params is an array of #GValue representing the parameters to
135 * @method. (It is *not* a #GValueArray, although if you have a
136 * #GValueArray, you can just pass its <literal>values</literal>f and
137 * <literal>n_values</literal> fields.)
139 * The correspondence between glib types and XML-RPC types is:
141 * int: #int (%G_TYPE_INT)
142 * boolean: #gboolean (%G_TYPE_BOOLEAN)
143 * string: #char* (%G_TYPE_STRING)
144 * double: #double (%G_TYPE_DOUBLE)
145 * datetime.iso8601: #SoupDate (%SOUP_TYPE_DATE)
146 * base64: #GByteArray (%SOUP_TYPE_BYTE_ARRAY)
147 * struct: #GHashTable (%G_TYPE_HASH_TABLE)
148 * array: #GValueArray (%G_TYPE_VALUE_ARRAY)
150 * For structs, use a #GHashTable that maps strings to #GValue;
151 * soup_value_hash_new() and related methods can help with this.
153 * Return value: the text of the methodCall, or %NULL on error
156 soup_xmlrpc_build_method_call (const char *method_name,
157 GValue *params, int n_params)
160 xmlNode *node, *param;
165 doc = xmlNewDoc ((const xmlChar *)"1.0");
166 doc->standalone = FALSE;
167 doc->encoding = xmlCharStrdup ("UTF-8");
169 node = xmlNewDocNode (doc, NULL, (const xmlChar *)"methodCall", NULL);
170 xmlDocSetRootElement (doc, node);
171 xmlNewChild (node, NULL, (const xmlChar *)"methodName",
172 (const xmlChar *)method_name);
174 node = xmlNewChild (node, NULL, (const xmlChar *)"params", NULL);
175 for (i = 0; i < n_params; i++) {
176 param = xmlNewChild (node, NULL,
177 (const xmlChar *)"param", NULL);
178 if (!insert_value (param, ¶ms[i])) {
184 xmlDocDumpMemory (doc, &xmlbody, &len);
185 body = g_strndup ((char *)xmlbody, len);
192 soup_xmlrpc_request_newv (const char *uri, const char *method_name, va_list args)
198 params = soup_value_array_from_args (args);
202 body = soup_xmlrpc_build_method_call (method_name, params->values,
204 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
205 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
207 g_value_array_free (params);
208 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
209 G_GNUC_END_IGNORE_DEPRECATIONS
214 msg = soup_message_new ("POST", uri);
215 soup_message_set_request (msg, "text/xml", SOUP_MEMORY_TAKE,
216 body, strlen (body));
221 * soup_xmlrpc_request_new:
222 * @uri: URI of the XML-RPC service
223 * @method_name: the name of the XML-RPC method to invoke at @uri
224 * @...: parameters for @method
226 * Creates an XML-RPC methodCall and returns a #SoupMessage, ready
227 * to send, for that method call.
229 * The parameters are passed as type/value pairs; ie, first a #GType,
230 * and then a value of the appropriate type, finally terminated by
233 * Return value: (transfer full): a #SoupMessage encoding the
234 * indicated XML-RPC request.
237 soup_xmlrpc_request_new (const char *uri, const char *method_name, ...)
242 va_start (args, method_name);
243 msg = soup_xmlrpc_request_newv (uri, method_name, args);
249 * soup_xmlrpc_build_method_response:
250 * @value: the return value
252 * This creates a (successful) XML-RPC methodResponse and returns it
253 * as a string. To create a fault response, use
254 * soup_xmlrpc_build_fault().
256 * The glib type to XML-RPC type mapping is as with
257 * soup_xmlrpc_build_method_call(), qv.
259 * Return value: the text of the methodResponse, or %NULL on error
262 soup_xmlrpc_build_method_response (GValue *value)
270 doc = xmlNewDoc ((const xmlChar *)"1.0");
271 doc->standalone = FALSE;
272 doc->encoding = xmlCharStrdup ("UTF-8");
274 node = xmlNewDocNode (doc, NULL,
275 (const xmlChar *)"methodResponse", NULL);
276 xmlDocSetRootElement (doc, node);
278 node = xmlNewChild (node, NULL, (const xmlChar *)"params", NULL);
279 node = xmlNewChild (node, NULL, (const xmlChar *)"param", NULL);
280 if (!insert_value (node, value)) {
285 xmlDocDumpMemory (doc, &xmlbody, &len);
286 body = g_strndup ((char *)xmlbody, len);
293 soup_xmlrpc_build_faultv (int fault_code, const char *fault_format, va_list args)
296 xmlNode *node, *member;
299 char *fault_string, *body;
302 fault_string = g_strdup_vprintf (fault_format, args);
304 doc = xmlNewDoc ((const xmlChar *)"1.0");
305 doc->standalone = FALSE;
306 doc->encoding = xmlCharStrdup ("UTF-8");
308 node = xmlNewDocNode (doc, NULL,
309 (const xmlChar *)"methodResponse", NULL);
310 xmlDocSetRootElement (doc, node);
311 node = xmlNewChild (node, NULL, (const xmlChar *)"fault", NULL);
312 node = xmlNewChild (node, NULL, (const xmlChar *)"value", NULL);
313 node = xmlNewChild (node, NULL, (const xmlChar *)"struct", NULL);
315 memset (&value, 0, sizeof (value));
317 member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL);
318 xmlNewChild (member, NULL,
319 (const xmlChar *)"name", (const xmlChar *)"faultCode");
320 g_value_init (&value, G_TYPE_INT);
321 g_value_set_int (&value, fault_code);
322 insert_value (member, &value);
323 g_value_unset (&value);
325 member = xmlNewChild (node, NULL, (const xmlChar *)"member", NULL);
326 xmlNewChild (member, NULL,
327 (const xmlChar *)"name", (const xmlChar *)"faultString");
328 g_value_init (&value, G_TYPE_STRING);
329 g_value_take_string (&value, fault_string);
330 insert_value (member, &value);
331 g_value_unset (&value);
333 xmlDocDumpMemory (doc, &xmlbody, &len);
334 body = g_strndup ((char *)xmlbody, len);
342 * soup_xmlrpc_build_fault:
343 * @fault_code: the fault code
344 * @fault_format: a printf()-style format string
345 * @...: the parameters to @fault_format
347 * This creates an XML-RPC fault response and returns it as a string.
348 * (To create a successful response, use
349 * soup_xmlrpc_build_method_response().)
351 * Return value: the text of the fault
354 soup_xmlrpc_build_fault (int fault_code, const char *fault_format, ...)
359 va_start (args, fault_format);
360 body = soup_xmlrpc_build_faultv (fault_code, fault_format, args);
366 * soup_xmlrpc_set_response:
367 * @msg: an XML-RPC request
368 * @type: the type of the response value
369 * @...: the response value
371 * Sets the status code and response body of @msg to indicate a
372 * successful XML-RPC call, with a return value given by @type and the
373 * following varargs argument, of the type indicated by @type.
376 soup_xmlrpc_set_response (SoupMessage *msg, GType type, ...)
382 va_start (args, type);
383 SOUP_VALUE_SETV (&value, type, args);
386 body = soup_xmlrpc_build_method_response (&value);
387 g_value_unset (&value);
388 soup_message_set_status (msg, SOUP_STATUS_OK);
389 soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
390 body, strlen (body));
394 * soup_xmlrpc_set_fault:
395 * @msg: an XML-RPC request
396 * @fault_code: the fault code
397 * @fault_format: a printf()-style format string
398 * @...: the parameters to @fault_format
400 * Sets the status code and response body of @msg to indicate an
401 * unsuccessful XML-RPC call, with the error described by @fault_code
405 soup_xmlrpc_set_fault (SoupMessage *msg, int fault_code,
406 const char *fault_format, ...)
411 va_start (args, fault_format);
412 body = soup_xmlrpc_build_faultv (fault_code, fault_format, args);
415 soup_message_set_status (msg, SOUP_STATUS_OK);
416 soup_message_set_response (msg, "text/xml", SOUP_MEMORY_TAKE,
417 body, strlen (body));
423 parse_value (xmlNode *xmlvalue, GValue *value)
426 const char *typename;
429 memset (value, 0, sizeof (GValue));
431 typenode = find_real_node (xmlvalue->children);
433 /* If no type node, it's a string */
434 content = xmlNodeGetContent (typenode);
435 g_value_init (value, G_TYPE_STRING);
436 g_value_set_string (value, (char *)content);
441 typename = (const char *)typenode->name;
443 if (!strcmp (typename, "i4") || !strcmp (typename, "int")) {
444 content = xmlNodeGetContent (typenode);
445 g_value_init (value, G_TYPE_INT);
446 g_value_set_int (value, atoi ((char *)content));
448 } else if (!strcmp (typename, "boolean")) {
449 content = xmlNodeGetContent (typenode);
450 g_value_init (value, G_TYPE_BOOLEAN);
451 g_value_set_boolean (value, atoi ((char *)content));
453 } else if (!strcmp (typename, "string")) {
454 content = xmlNodeGetContent (typenode);
455 g_value_init (value, G_TYPE_STRING);
456 g_value_set_string (value, (char *)content);
458 } else if (!strcmp (typename, "double")) {
459 content = xmlNodeGetContent (typenode);
460 g_value_init (value, G_TYPE_DOUBLE);
461 g_value_set_double (value, g_ascii_strtod ((char *)content, NULL));
463 } else if (!strcmp (typename, "dateTime.iso8601")) {
464 content = xmlNodeGetContent (typenode);
465 g_value_init (value, SOUP_TYPE_DATE);
466 g_value_take_boxed (value, soup_date_new_from_string ((char *)content));
468 } else if (!strcmp (typename, "base64")) {
473 content = xmlNodeGetContent (typenode);
474 decoded = g_base64_decode ((char *)content, &len);
475 ba = g_byte_array_sized_new (len);
476 g_byte_array_append (ba, decoded, len);
479 g_value_init (value, SOUP_TYPE_BYTE_ARRAY);
480 g_value_take_boxed (value, ba);
481 } else if (!strcmp (typename, "struct")) {
482 xmlNode *member, *child, *mname, *mxval;
486 hash = soup_value_hash_new ();
487 for (member = find_real_node (typenode->children);
489 member = find_real_node (member->next)) {
490 if (strcmp ((const char *)member->name, "member") != 0) {
491 g_hash_table_destroy (hash);
494 mname = mxval = NULL;
495 memset (&mgval, 0, sizeof (mgval));
497 for (child = find_real_node (member->children);
499 child = find_real_node (child->next)) {
500 if (!strcmp ((const char *)child->name, "name"))
502 else if (!strcmp ((const char *)child->name, "value"))
508 if (!mname || !mxval || !parse_value (mxval, &mgval)) {
509 g_hash_table_destroy (hash);
513 content = xmlNodeGetContent (mname);
514 soup_value_hash_insert_value (hash, (char *)content, &mgval);
516 g_value_unset (&mgval);
518 g_value_init (value, G_TYPE_HASH_TABLE);
519 g_value_take_boxed (value, hash);
520 } else if (!strcmp (typename, "array")) {
521 xmlNode *data, *xval;
525 data = find_real_node (typenode->children);
526 if (!data || strcmp ((const char *)data->name, "data") != 0)
529 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
530 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
532 array = g_value_array_new (1);
533 for (xval = find_real_node (data->children);
535 xval = find_real_node (xval->next)) {
536 memset (&gval, 0, sizeof (gval));
537 if (strcmp ((const char *)xval->name, "value") != 0 ||
538 !parse_value (xval, &gval)) {
539 g_value_array_free (array);
543 g_value_array_append (array, &gval);
544 g_value_unset (&gval);
546 g_value_init (value, G_TYPE_VALUE_ARRAY);
547 g_value_take_boxed (value, array);
548 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
549 G_GNUC_END_IGNORE_DEPRECATIONS
558 * soup_xmlrpc_parse_method_call:
559 * @method_call: the XML-RPC methodCall string
560 * @length: the length of @method_call, or -1 if it is NUL-terminated
561 * @method_name: (out): on return, the methodName from @method_call
562 * @params: (out): on return, the parameters from @method_call
564 * Parses @method_call to get the name and parameters, and returns the
565 * parameter values in a #GValueArray; see also
566 * soup_xmlrpc_extract_method_call(), which is more convenient if you
567 * know in advance what the types of the parameters will be.
569 * Return value: success or failure.
572 soup_xmlrpc_parse_method_call (const char *method_call, int length,
573 char **method_name, GValueArray **params)
576 xmlNode *node, *param, *xval;
577 xmlChar *xmlMethodName = NULL;
578 gboolean success = FALSE;
581 doc = xmlParseMemory (method_call,
582 length == -1 ? strlen (method_call) : length);
586 node = xmlDocGetRootElement (doc);
587 if (!node || strcmp ((const char *)node->name, "methodCall") != 0)
590 node = find_real_node (node->children);
591 if (!node || strcmp ((const char *)node->name, "methodName") != 0)
593 xmlMethodName = xmlNodeGetContent (node);
595 node = find_real_node (node->next);
597 if (strcmp ((const char *)node->name, "params") != 0)
600 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
601 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
603 *params = soup_value_array_new ();
604 param = find_real_node (node->children);
605 while (param && !strcmp ((const char *)param->name, "param")) {
606 xval = find_real_node (param->children);
607 if (!xval || strcmp ((const char *)xval->name, "value") != 0 ||
608 !parse_value (xval, &value)) {
609 g_value_array_free (*params);
612 g_value_array_append (*params, &value);
613 g_value_unset (&value);
615 param = find_real_node (param->next);
617 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
618 G_GNUC_END_IGNORE_DEPRECATIONS
621 *params = soup_value_array_new ();
624 *method_name = g_strdup ((char *)xmlMethodName);
629 xmlFree (xmlMethodName);
634 * soup_xmlrpc_extract_method_call:
635 * @method_call: the XML-RPC methodCall string
636 * @length: the length of @method_call, or -1 if it is NUL-terminated
637 * @method_name: (out): on return, the methodName from @method_call
638 * @...: return types and locations for parameters
640 * Parses @method_call to get the name and parameters, and puts
641 * the parameters into variables of the appropriate types.
643 * The parameters are handled similarly to
644 * @soup_xmlrpc_build_method_call, with pairs of types and values,
645 * terminated by %G_TYPE_INVALID, except that values are pointers to
646 * variables of the indicated type, rather than values of the type.
648 * See also soup_xmlrpc_parse_method_call(), which can be used if
649 * you don't know the types of the parameters.
651 * Return value: success or failure.
654 soup_xmlrpc_extract_method_call (const char *method_call, int length,
655 char **method_name, ...)
661 if (!soup_xmlrpc_parse_method_call (method_call, length,
662 method_name, ¶ms))
665 va_start (args, method_name);
666 success = soup_value_array_to_args (params, args);
669 #ifdef G_GNUC_BEGIN_IGNORE_DEPRECATIONS
670 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
672 g_value_array_free (params);
673 #ifdef G_GNUC_END_IGNORE_DEPRECATIONS
674 G_GNUC_END_IGNORE_DEPRECATIONS
680 * soup_xmlrpc_parse_method_response:
681 * @method_response: the XML-RPC methodResponse string
682 * @length: the length of @method_response, or -1 if it is NUL-terminated
683 * @value: (out): on return, the return value from @method_call
684 * @error: error return value
686 * Parses @method_response and returns the return value in @value. If
687 * @method_response is a fault, @value will be unchanged, and @error
688 * will be set to an error of type %SOUP_XMLRPC_FAULT, with the error
689 * #code containing the fault code, and the error #message containing
690 * the fault string. (If @method_response cannot be parsed at all,
691 * soup_xmlrpc_parse_method_response() will return %FALSE, but @error
694 * Return value: %TRUE if a return value was parsed, %FALSE if the
695 * response could not be parsed, or contained a fault.
698 soup_xmlrpc_parse_method_response (const char *method_response, int length,
699 GValue *value, GError **error)
703 gboolean success = FALSE;
705 doc = xmlParseMemory (method_response,
706 length == -1 ? strlen (method_response) : length);
710 node = xmlDocGetRootElement (doc);
711 if (!node || strcmp ((const char *)node->name, "methodResponse") != 0)
714 node = find_real_node (node->children);
718 if (!strcmp ((const char *)node->name, "fault") && error) {
722 GHashTable *fault_hash;
724 node = find_real_node (node->children);
725 if (!node || strcmp ((const char *)node->name, "value") != 0)
727 if (!parse_value (node, &fault_val))
729 if (!G_VALUE_HOLDS (&fault_val, G_TYPE_HASH_TABLE)) {
730 g_value_unset (&fault_val);
733 fault_hash = g_value_get_boxed (&fault_val);
734 if (!soup_value_hash_lookup (fault_hash, "faultCode",
735 G_TYPE_INT, &fault_code) ||
736 !soup_value_hash_lookup (fault_hash, "faultString",
737 G_TYPE_STRING, &fault_string)) {
738 g_value_unset (&fault_val);
742 g_set_error (error, SOUP_XMLRPC_FAULT,
743 fault_code, "%s", fault_string);
744 g_value_unset (&fault_val);
745 } else if (!strcmp ((const char *)node->name, "params")) {
746 node = find_real_node (node->children);
747 if (!node || strcmp ((const char *)node->name, "param") != 0)
749 node = find_real_node (node->children);
750 if (!node || strcmp ((const char *)node->name, "value") != 0)
752 if (!parse_value (node, value))
763 * soup_xmlrpc_extract_method_response:
764 * @method_response: the XML-RPC methodResponse string
765 * @length: the length of @method_response, or -1 if it is NUL-terminated
766 * @error: error return value
767 * @type: the expected type of the return value
768 * @...: location for return value
770 * Parses @method_response and extracts the return value into
771 * a variable of the correct type.
773 * If @method_response is a fault, the return value will be unset,
774 * and @error will be set to an error of type %SOUP_XMLRPC_FAULT, with
775 * the error #code containing the fault code, and the error #message
776 * containing the fault string. (If @method_response cannot be parsed
777 * at all, soup_xmlrpc_extract_method_response() will return %FALSE,
778 * but @error will be unset.)
780 * Return value: %TRUE if a return value was parsed, %FALSE if the
781 * response was of the wrong type, or contained a fault.
784 soup_xmlrpc_extract_method_response (const char *method_response, int length,
785 GError **error, GType type, ...)
790 if (!soup_xmlrpc_parse_method_response (method_response, length,
793 if (!G_VALUE_HOLDS (&value, type))
796 va_start (args, type);
797 SOUP_VALUE_GETV (&value, type, args);
805 soup_xmlrpc_error_quark (void)
809 error = g_quark_from_static_string ("soup_xmlrpc_error_quark");
816 * A #GError domain representing an XML-RPC fault code. Used with
817 * #SoupXMLRPCFault (although servers may also return fault codes not
818 * in that enumeration).
823 * @SOUP_XMLRPC_FAULT_PARSE_ERROR_NOT_WELL_FORMED: request was not
825 * @SOUP_XMLRPC_FAULT_PARSE_ERROR_UNSUPPORTED_ENCODING: request was in
826 * an unsupported encoding
827 * @SOUP_XMLRPC_FAULT_PARSE_ERROR_INVALID_CHARACTER_FOR_ENCODING:
828 * request contained an invalid character
829 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_XML_RPC: request was not
831 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_REQUESTED_METHOD_NOT_FOUND: method
833 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS: invalid
835 * @SOUP_XMLRPC_FAULT_SERVER_ERROR_INTERNAL_XML_RPC_ERROR: internal
837 * @SOUP_XMLRPC_FAULT_APPLICATION_ERROR: start of reserved range for
838 * application error codes
839 * @SOUP_XMLRPC_FAULT_SYSTEM_ERROR: start of reserved range for
841 * @SOUP_XMLRPC_FAULT_TRANSPORT_ERROR: start of reserved range for
842 * transport error codes
844 * Pre-defined XML-RPC fault codes from <ulink
845 * url="http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php">http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php</ulink>.
846 * These are an extension, not part of the XML-RPC spec; you can't
847 * assume servers will use them.
851 soup_xmlrpc_fault_quark (void)
855 error = g_quark_from_static_string ("soup_xmlrpc_fault_quark");
860 find_real_node (xmlNode *node)
862 while (node && (node->type == XML_COMMENT_NODE ||
863 xmlIsBlankNode (node)))