~ubuntu-branches/debian/stretch/libxr/stretch

« back to all changes in this revision

Viewing changes to lib/xr-call-xml-rpc.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Boucher
  • Date: 2009-10-14 00:52:51 UTC
  • Revision ID: james.westby@ubuntu.com-20091014005251-epx05xv5ef9188q0
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "xml-priv.h"
 
2
 
 
3
static void _xr_value_serialize_xmlrpc(xmlNode* node, xr_value* val)
 
4
{
 
5
  xmlNode* value;
 
6
  char buf[50];
 
7
  GSList* i;
 
8
 
 
9
  if (xr_value_get_type(val) != XRV_MEMBER)
 
10
    node = xmlNewChild(node, NULL, BAD_CAST "value", NULL);
 
11
 
 
12
  switch (xr_value_get_type(val))
 
13
  {
 
14
    case XRV_ARRAY:
 
15
    {
 
16
      value = xmlNewChild(node, NULL, BAD_CAST "array", NULL);
 
17
      value = xmlNewChild(value, NULL, BAD_CAST "data", NULL);
 
18
      for (i = xr_value_get_items(val); i; i = i->next)
 
19
        _xr_value_serialize_xmlrpc(value, i->data);
 
20
      break;
 
21
    }
 
22
    case XRV_STRUCT:
 
23
    {
 
24
      value = xmlNewChild(node, NULL, BAD_CAST "struct", NULL);
 
25
      for (i = xr_value_get_members(val); i; i = i->next)
 
26
        _xr_value_serialize_xmlrpc(value, i->data);
 
27
      break;
 
28
    }
 
29
    case XRV_MEMBER:
 
30
    {
 
31
      value = xmlNewChild(node, NULL, BAD_CAST "member", NULL);
 
32
      xmlNewChild(value, NULL, BAD_CAST "name", BAD_CAST xr_value_get_member_name(val));
 
33
      _xr_value_serialize_xmlrpc(value, xr_value_get_member_value(val));
 
34
      break;
 
35
    }
 
36
    case XRV_INT:
 
37
    {
 
38
      int int_val = -1;
 
39
      xr_value_to_int(val, &int_val);
 
40
      snprintf(buf, sizeof(buf), "%d", int_val);
 
41
      xmlNewChild(node, NULL, BAD_CAST "int", BAD_CAST buf);
 
42
      break;
 
43
    }
 
44
    case XRV_STRING:
 
45
    {
 
46
      char* str_val = NULL;
 
47
      xr_value_to_string(val, &str_val);
 
48
      xmlAddChild(node, xmlNewText(BAD_CAST str_val));
 
49
      g_free(str_val);
 
50
      break;
 
51
    }
 
52
    case XRV_BOOLEAN:
 
53
    {
 
54
      int bool_val = -1;
 
55
      xr_value_to_bool(val, &bool_val);
 
56
      xmlNewChild(node, NULL, BAD_CAST "boolean", BAD_CAST (bool_val ? "1" : "0"));
 
57
      break;
 
58
    }
 
59
    case XRV_DOUBLE:
 
60
    {
 
61
      double dbl_val = -1;
 
62
      xr_value_to_double(val, &dbl_val);
 
63
      snprintf(buf, sizeof(buf), "%g", dbl_val);
 
64
      xmlNewChild(node, NULL, BAD_CAST "double", BAD_CAST buf);
 
65
      break;
 
66
    }
 
67
    case XRV_TIME:
 
68
    {
 
69
      char* str_val = NULL;
 
70
      xr_value_to_time(val, &str_val);
 
71
      xmlNewChild(node, NULL, BAD_CAST "dateTime.iso8601", BAD_CAST str_val);
 
72
      g_free(str_val);
 
73
      break;
 
74
    }
 
75
    case XRV_BLOB:
 
76
    {
 
77
      char* data = NULL;
 
78
      xr_blob* b = NULL;
 
79
      xr_value_to_blob(val, &b);
 
80
      data = g_base64_encode(b->buf, b->len);
 
81
      xr_blob_unref(b);
 
82
      xmlNewChild(node, NULL, BAD_CAST "base64", BAD_CAST data);
 
83
      g_free(data);
 
84
      break;
 
85
    }
 
86
  }
 
87
}
 
88
 
 
89
static xr_value* _xr_value_unserialize_xmlrpc(xmlNode* node)
 
90
{
 
91
  gboolean is_string_without_element = TRUE;
 
92
  for_each_node(node, tn)
 
93
    /* check if node contains only text and entity reference nodes */
 
94
    if (tn->type != XML_TEXT_NODE && tn->type != XML_ENTITY_REF_NODE)
 
95
      is_string_without_element = FALSE;
 
96
 
 
97
    if (match_node(tn, "int") || match_node(tn, "i4"))
 
98
      return xr_value_int_new(xml_get_cont_int(tn));
 
99
    else if (match_node(tn, "string"))
 
100
    {
 
101
      char* str = xml_get_cont_str(tn);
 
102
      xr_value* val = xr_value_string_new(str);
 
103
      g_free(str);
 
104
      return val;
 
105
    }
 
106
    else if (match_node(tn, "boolean"))
 
107
      return xr_value_bool_new(xml_get_cont_bool(tn));
 
108
    else if (match_node(tn, "double"))
 
109
      return xr_value_double_new(xml_get_cont_double(tn));
 
110
    else if (match_node(tn, "dateTime.iso8601"))
 
111
    {
 
112
      char* str = xml_get_cont_str(tn);
 
113
      xr_value* val = xr_value_time_new(str);
 
114
      g_free(str);
 
115
      return val;
 
116
    }
 
117
    else if (match_node(tn, "base64"))
 
118
    {
 
119
      xr_blob* b;
 
120
      xr_value* bv;
 
121
      char* base64 = xml_get_cont_str(tn);
 
122
      gsize len = 0;
 
123
      char* buf = g_base64_decode(base64, &len);
 
124
      g_free(base64);
 
125
      b = xr_blob_new(buf, len);
 
126
      bv = xr_value_blob_new(b);
 
127
      xr_blob_unref(b);
 
128
      return bv;
 
129
    }
 
130
    else if (match_node(tn, "array"))
 
131
    {
 
132
      xr_value* arr = xr_value_array_new();
 
133
      for_each_node(tn, d)
 
134
        if (match_node(d, "data"))
 
135
        {
 
136
          for_each_node(d, v)
 
137
            if (match_node(v, "value"))
 
138
            {
 
139
              xr_value* elem = _xr_value_unserialize_xmlrpc(v);
 
140
              if (elem == NULL)
 
141
              {
 
142
                xr_value_unref(arr);
 
143
                return NULL;
 
144
              }
 
145
              xr_value_array_append(arr, elem);
 
146
            }
 
147
          for_each_node_end()
 
148
          return arr;
 
149
        }
 
150
      for_each_node_end()
 
151
      return arr;
 
152
    }
 
153
    else if (match_node(tn, "struct"))
 
154
    {
 
155
      xr_value* str = xr_value_struct_new();
 
156
      for_each_node(tn, m)
 
157
        if (match_node(m, "member"))
 
158
        {
 
159
          char* name = NULL;
 
160
          xr_value* val = NULL;
 
161
          int names = 0, values = 0;
 
162
 
 
163
          for_each_node(m, me)
 
164
            if (match_node(me, "name"))
 
165
            {
 
166
              if (names++ == 0)
 
167
                name = xml_get_cont_str(me);
 
168
            }
 
169
            else if (match_node(me, "value"))
 
170
            {
 
171
              if (values++ == 0)
 
172
                val = _xr_value_unserialize_xmlrpc(me);
 
173
            }
 
174
          for_each_node_end()
 
175
 
 
176
          if (values != 1 || names != 1)
 
177
          {
 
178
            g_free(name);
 
179
            xr_value_unref(val);
 
180
            xr_value_unref(str);
 
181
            return NULL;
 
182
          }
 
183
          xr_value_struct_set_member(str, name, val);
 
184
          g_free(name);
 
185
        }
 
186
      for_each_node_end()
 
187
      return str;
 
188
    }
 
189
  for_each_node_end()
 
190
 
 
191
  if (is_string_without_element)
 
192
  {
 
193
    xmlChar* str = xmlNodeGetContent(node);
 
194
    xr_value* val = xr_value_string_new(str);
 
195
    xmlFree(str);
 
196
    return val;
 
197
  }
 
198
 
 
199
  return NULL;
 
200
}
 
201
 
 
202
static void xr_call_serialize_request_xmlrpc(xr_call* call, char** buf, int* len)
 
203
{
 
204
  xmlDoc* doc = xmlNewDoc(BAD_CAST "1.0");
 
205
  xmlNode* root = xmlNewNode(NULL, BAD_CAST "methodCall");
 
206
  xmlDocSetRootElement(doc, root);
 
207
  xmlNewChild(root, NULL, BAD_CAST "methodName", call->method);
 
208
  xmlNode* params = xmlNewChild(root, NULL, BAD_CAST "params", NULL);
 
209
 
 
210
  GSList* i;
 
211
  for (i = call->params; i; i = i->next)
 
212
  {
 
213
    xmlNode* param = xmlNewChild(params, NULL, BAD_CAST "param", NULL);
 
214
    _xr_value_serialize_xmlrpc(param, i->data);
 
215
  }
 
216
 
 
217
  if (xr_debug_enabled & XR_DEBUG_HTTP)
 
218
    xmlDocDumpFormatMemoryEnc(doc, (xmlChar**)buf, len, "UTF-8", 1);
 
219
  else
 
220
    xmlDocDumpMemoryEnc(doc, (xmlChar**)buf, len, "UTF-8");
 
221
 
 
222
  xmlFreeDoc(doc);
 
223
}
 
224
 
 
225
static void xr_call_serialize_response_xmlrpc(xr_call* call, char** buf, int* len)
 
226
{
 
227
  xmlDoc* doc = xmlNewDoc(BAD_CAST "1.0");
 
228
  xmlNode* root = xmlNewNode(NULL, BAD_CAST "methodResponse");
 
229
  xmlDocSetRootElement(doc, root);
 
230
 
 
231
  if (call->error_set)
 
232
  {
 
233
    xmlNode* fault = xmlNewChild(root, NULL, BAD_CAST "fault", NULL);
 
234
    xr_value* v = xr_value_struct_new();
 
235
    xr_value_struct_set_member(v, "faultCode", xr_value_int_new(call->errcode));
 
236
    xr_value_struct_set_member(v, "faultString", xr_value_string_new(call->errmsg));
 
237
    _xr_value_serialize_xmlrpc(fault, v);
 
238
    xr_value_unref(v);
 
239
  }
 
240
  else if (call->retval)
 
241
  {
 
242
    xmlNode* params = xmlNewChild(root, NULL, BAD_CAST "params", NULL);
 
243
    xmlNode* param = xmlNewChild(params, NULL, BAD_CAST "param", NULL);
 
244
    _xr_value_serialize_xmlrpc(param, call->retval);
 
245
  }
 
246
 
 
247
  if (xr_debug_enabled & XR_DEBUG_HTTP)
 
248
    xmlDocDumpFormatMemoryEnc(doc, (xmlChar**)buf, len, "UTF-8", 1);
 
249
  else
 
250
    xmlDocDumpMemoryEnc(doc, (xmlChar**)buf, len, "UTF-8");
 
251
 
 
252
  xmlFreeDoc(doc);
 
253
}
 
254
 
 
255
static gboolean xr_call_unserialize_request_xmlrpc(xr_call* call, const char* buf, int len)
 
256
{
 
257
  xmlDoc* doc = xmlReadMemory(buf, len, 0, 0, XML_PARSE_NOWARNING|XML_PARSE_NOERROR|XML_PARSE_NONET);
 
258
  if (doc == NULL)
 
259
  {
 
260
    xr_call_set_error(call, -1, "Can't parse XML-RPC XML request. Invalid XML document.");
 
261
    goto err_0;
 
262
  }
 
263
 
 
264
  xmlNode* root = xmlDocGetRootElement(doc);
 
265
  if (root == NULL)
 
266
  {
 
267
    xr_call_set_error(call, -1, "Can't parse XML-RPC XML request. Root element is missing.");
 
268
    goto err_1;
 
269
  }
 
270
 
 
271
  xmlXPathContext* ctx = xmlXPathNewContext(doc);
 
272
 
 
273
  call->method = xp_eval_cont_str(ctx, "/methodCall/methodName");
 
274
  if (call->method == NULL)
 
275
  {
 
276
    xr_call_set_error(call, -1, "Can't parse XML-RPC XML request. Missing methodName.");
 
277
    goto err_2;
 
278
  }
 
279
 
 
280
  int i;
 
281
  struct nodeset* ns = xp_eval_nodes(ctx, "/methodCall/params/param/value");
 
282
  for (i = 0; i < ns->count; i++)
 
283
  {
 
284
    xr_value* v = _xr_value_unserialize_xmlrpc(ns->nodes[i]);
 
285
    if (v == NULL)
 
286
    {
 
287
      xr_call_set_error(call, -1, "Can't parse XML-RPC XML request. Failed to unserialize parameter %d.", i);
 
288
      goto err_3;
 
289
    }
 
290
    xr_call_add_param(call, v);
 
291
  }
 
292
  xp_free_nodes(ns);
 
293
 
 
294
  xmlXPathFreeContext(ctx);
 
295
  xmlFreeDoc(doc);
 
296
  return TRUE;
 
297
 
 
298
 err_3:
 
299
  xp_free_nodes(ns);
 
300
 err_2:
 
301
  xmlXPathFreeContext(ctx);
 
302
 err_1:
 
303
  xmlFreeDoc(doc);
 
304
 err_0:
 
305
  return FALSE;
 
306
}
 
307
 
 
308
static gboolean xr_call_unserialize_response_xmlrpc(xr_call* call, const char* buf, int len)
 
309
{
 
310
  xmlDoc* doc = xmlReadMemory(buf, len, 0, 0, XML_PARSE_NOWARNING|XML_PARSE_NOERROR|XML_PARSE_NONET);
 
311
  if (doc == NULL)
 
312
  {
 
313
    xr_call_set_error(call, -1, "Can't parse XML-RPC XML response. Invalid XML document.");
 
314
    goto err_0;
 
315
  }
 
316
 
 
317
  xmlNode* root = xmlDocGetRootElement(doc);
 
318
  if (root == NULL)
 
319
  {
 
320
    xr_call_set_error(call, -1, "Can't parse XML-RPC XML response. Root element is missing.");
 
321
    goto err_1;
 
322
  }
 
323
 
 
324
  xmlXPathContext* ctx = xmlXPathNewContext(doc);
 
325
 
 
326
  struct nodeset* ns = xp_eval_nodes(ctx, "/methodResponse/params/param/value");
 
327
  if (ns->count == 1)
 
328
  {
 
329
    call->retval = _xr_value_unserialize_xmlrpc(ns->nodes[0]);
 
330
    if (call->retval == NULL)
 
331
    {
 
332
      xr_call_set_error(call, -1, "Can't parse XML-RPC XML response. Failed to unserialize retval.");
 
333
      goto err_2;
 
334
    }
 
335
    goto done;
 
336
  }
 
337
  else if (ns->count > 1) // more than one param is bad
 
338
  {
 
339
    xr_call_set_error(call, -1, "Can't parse XML-RPC XML response. Too many return values.");
 
340
    goto err_2;
 
341
  }
 
342
  xp_free_nodes(ns);
 
343
 
 
344
  // ok no params/param, check for fault
 
345
  ns = xp_eval_nodes(ctx, "/methodResponse/fault/value");
 
346
  if (ns->count == 1)
 
347
  {
 
348
    call->retval = _xr_value_unserialize_xmlrpc(ns->nodes[0]);
 
349
    if (call->retval == NULL)
 
350
    {
 
351
      xr_call_set_error(call, -1, "Can't parse XML-RPC XML response. Failed to unserialize fault response.");
 
352
      goto err_2;
 
353
    }
 
354
    // check if client returned standard XML-RPC error message, we want to process
 
355
    // it differently than normal retval
 
356
    int errcode = 0;
 
357
    char* errmsg = NULL;
 
358
    if (xr_value_is_error_retval(call->retval, &errcode, &errmsg))
 
359
    {
 
360
      xr_call_set_error(call, errcode, "%s", errmsg);
 
361
      g_free(errmsg);
 
362
      goto err_3;
 
363
    }
 
364
    else
 
365
    {
 
366
      xr_call_set_error(call, -1, "Can't parse XML-RPC XML response. Invalid fault response.");
 
367
      goto err_3;
 
368
    }
 
369
  }
 
370
  else // no fault either
 
371
  {
 
372
    xr_call_set_error(call, -1, "Can't parse XML-RPC XML response. Failed to unserialize retval.");
 
373
    goto err_2;
 
374
  }
 
375
 
 
376
done:
 
377
  xp_free_nodes(ns);
 
378
  xmlXPathFreeContext(ctx);
 
379
  xmlFreeDoc(doc);
 
380
  return TRUE;
 
381
 
 
382
 err_3:
 
383
  xr_value_unref(call->retval);
 
384
  call->retval = NULL;
 
385
 err_2:
 
386
  xp_free_nodes(ns);
 
387
  xmlXPathFreeContext(ctx);
 
388
 err_1:
 
389
  xmlFreeDoc(doc);
 
390
 err_0:
 
391
  return FALSE;
 
392
}
 
393
 
 
394
static void xr_call_free_buffer_xmlrpc(xr_call* call, char* buf)
 
395
{
 
396
  xmlFree(buf);
 
397
}