1 /* Copyright information is at end of file */
3 #include "xmlrpc_config.h"
11 #include "xmlrpc-c/base.h"
12 #include "xmlrpc-c/base_int.h"
14 #define CRLF "\015\012"
15 #define SMALL_BUFFER_SZ (128)
16 #define XML_PROLOGUE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"CRLF
19 /*=========================================================================
21 **=========================================================================
22 ** A lightweight print routine for use with various serialization
23 ** functions. Only use this routine for printing small objects--it uses
24 ** a fixed-size internal buffer and returns an error on overflow.
25 ** In particular, do NOT use this routine to print XML-RPC string values!
29 format_out(xmlrpc_env *env,
30 xmlrpc_mem_block *output,
35 char buffer[SMALL_BUFFER_SZ];
38 XMLRPC_ASSERT_ENV_OK(env);
40 va_start(args, format_string);
42 /* We assume that this function is present and works correctly. Right. */
43 count = vsnprintf(buffer, SMALL_BUFFER_SZ, format_string, args);
45 /* Old C libraries return -1 if vsnprintf overflows its buffer.
46 ** New C libraries return the number of characters which *would* have
47 ** been printed if the error did not occur. This is impressively vile.
48 ** Thank the C99 committee for this bright idea. But wait! We also
49 ** need to keep track of the trailing NULL. */
50 if (count < 0 || count >= (SMALL_BUFFER_SZ - 1))
51 XMLRPC_FAIL(env, XMLRPC_INTERNAL_ERROR,
52 "format_out overflowed internal buffer");
54 /* Append our new data to our output. */
55 XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, output, buffer, count);
56 XMLRPC_FAIL_IF_FAULT(env);
65 assertValidUtf8(const char * const str ATTR_UNUSED,
66 size_t const len ATTR_UNUSED) {
67 /*----------------------------------------------------------------------------
68 Assert that the string 'str' of length 'len' is valid UTF-8.
69 -----------------------------------------------------------------------------*/
71 /* Check the assertion; if it's false, issue a message to
72 Standard Error, but otherwise ignore it.
76 xmlrpc_env_init(&env);
77 xmlrpc_validate_utf8(&env, str, len);
78 if (env.fault_occurred)
79 fprintf(stderr, "*** xmlrpc-c WARNING ***: %s (%s)\n",
80 "Xmlrpc-c sending corrupted UTF-8 data to network",
82 xmlrpc_env_clean(&env);
89 escapedSize(const char * const chars,
96 for (i = 0; i < len; ++i) {
99 else if (chars[i] == '>')
100 size += 4; /* > */
101 else if (chars[i] == '&')
102 size += 5; /* & */
112 escapeForXml(xmlrpc_env * const envP,
113 const char * const chars,
115 xmlrpc_mem_block ** const outputPP) {
116 /*----------------------------------------------------------------------------
117 Escape & and < in a UTF-8 string so as to make it suitable for the
118 content of an XML element. I.e. turn them into entity references
119 & and <. Also change > to >, even though not required
120 for XML, for symmetry.
121 -----------------------------------------------------------------------------*/
122 xmlrpc_mem_block * outputP;
125 XMLRPC_ASSERT_ENV_OK(envP);
126 XMLRPC_ASSERT(chars != NULL);
128 assertValidUtf8(chars, len);
130 /* Note that in UTF-8, any byte that has high bit of zero is a
131 character all by itself (every byte of a multi-byte UTF-8 character
132 has the high bit set). Also, the Unicode code points < 128 are
133 identical to the ASCII ones.
136 outputSize = escapedSize(chars, len);
138 outputP = XMLRPC_MEMBLOCK_NEW(char, envP, outputSize);
139 if (!envP->fault_occurred) {
142 p = XMLRPC_MEMBLOCK_CONTENTS(char, outputP); /* Start at beginning */
144 for (i = 0; i < len; i++) {
145 if (chars[i] == '<') {
146 memcpy(p, "<", 4);
148 } else if (chars[i] == '>') {
149 memcpy(p, ">", 4);
151 } else if (chars[i] == '&') {
152 memcpy(p, "&", 5);
160 assert(p == XMLRPC_MEMBLOCK_CONTENTS(char, outputP) + outputSize);
162 if (envP->fault_occurred)
163 XMLRPC_MEMBLOCK_FREE(char, outputP);
170 serializeUtf8MemBlock(xmlrpc_env * const envP,
171 xmlrpc_mem_block * const outputP,
172 xmlrpc_mem_block * const inputP) {
173 /*----------------------------------------------------------------------------
174 Append the characters in *inputP to the XML stream in *outputP.
176 *inputP contains Unicode characters in UTF-8.
178 We assume *inputP ends with a NUL character that marks end of
179 string, and we ignore that. (There might also be NUL characters
180 inside the string, though).
181 -----------------------------------------------------------------------------*/
182 xmlrpc_mem_block * escapedP;
184 XMLRPC_ASSERT_ENV_OK(envP);
185 XMLRPC_ASSERT(outputP != NULL);
186 XMLRPC_ASSERT(inputP != NULL);
189 XMLRPC_MEMBLOCK_CONTENTS(const char, inputP),
190 XMLRPC_MEMBLOCK_SIZE(const char, inputP) - 1,
191 /* -1 is for the terminating NUL */
193 if (!envP->fault_occurred) {
194 const char * const contents =
195 XMLRPC_MEMBLOCK_CONTENTS(const char, escapedP);
196 size_t const size = XMLRPC_MEMBLOCK_SIZE(char, escapedP);
198 XMLRPC_MEMBLOCK_APPEND(char, envP, outputP, contents, size);
200 XMLRPC_MEMBLOCK_FREE(const char, escapedP);
207 xmlrpc_serialize_base64_data(xmlrpc_env * const envP,
208 xmlrpc_mem_block * const output,
209 unsigned char * const data,
211 /*----------------------------------------------------------------------------
212 Encode the 'len' bytes at 'data' in base64 ASCII and append the result to
214 -----------------------------------------------------------------------------*/
215 xmlrpc_mem_block * encoded;
217 encoded = xmlrpc_base64_encode(envP, data, len);
218 if (!envP->fault_occurred) {
219 unsigned char * const contents =
220 XMLRPC_MEMBLOCK_CONTENTS(unsigned char, encoded);
222 XMLRPC_MEMBLOCK_SIZE(unsigned char, encoded);
224 XMLRPC_MEMBLOCK_APPEND(char, envP, output, contents, size);
226 XMLRPC_MEMBLOCK_FREE(char, encoded);
232 /*=========================================================================
233 ** xmlrpc_serialize_struct
234 **=========================================================================
235 ** Dump the contents of a struct.
239 xmlrpc_serialize_struct(xmlrpc_env *env,
240 xmlrpc_mem_block *output,
241 xmlrpc_value *strct) {
245 xmlrpc_value *key, *value;
247 format_out(env, output, "<struct>"CRLF);
248 XMLRPC_FAIL_IF_FAULT(env);
250 size = xmlrpc_struct_size(env, strct);
251 XMLRPC_FAIL_IF_FAULT(env);
252 for (i = 0; i < size; i++) {
253 xmlrpc_struct_get_key_and_value(env, strct, i, &key, &value);
254 XMLRPC_FAIL_IF_FAULT(env);
255 format_out(env, output, "<member><name>");
256 XMLRPC_FAIL_IF_FAULT(env);
257 serializeUtf8MemBlock(env, output, &key->_block);
258 XMLRPC_FAIL_IF_FAULT(env);
259 format_out(env, output, "</name>"CRLF);
260 XMLRPC_FAIL_IF_FAULT(env);
261 xmlrpc_serialize_value(env, output, value);
262 XMLRPC_FAIL_IF_FAULT(env);
263 format_out(env, output, "</member>"CRLF);
264 XMLRPC_FAIL_IF_FAULT(env);
267 format_out(env, output, "</struct>");
268 XMLRPC_FAIL_IF_FAULT(env);
276 /*=========================================================================
277 ** xmlrpc_serialize_value
278 **=========================================================================
279 ** Dump a value in the appropriate fashion.
283 xmlrpc_serialize_value(xmlrpc_env *env,
284 xmlrpc_mem_block *output,
285 xmlrpc_value *value) {
289 unsigned char* contents;
292 XMLRPC_ASSERT_ENV_OK(env);
293 XMLRPC_ASSERT(output != NULL);
294 XMLRPC_ASSERT_VALUE_OK(value);
296 /* Print our ubiquitous header. */
297 format_out(env, output, "<value>");
298 XMLRPC_FAIL_IF_FAULT(env);
300 switch (value->_type) {
302 case XMLRPC_TYPE_INT:
303 /* XXX - We assume that '%i' is the appropriate format specifier
304 ** for an xmlrpc_int32 value. We should add some test cases to
305 ** make sure this works. */
306 format_out(env, output, "<i4>%i</i4>", value->_value.i);
309 case XMLRPC_TYPE_BOOL:
310 /* XXX - We assume that '%i' is the appropriate format specifier
311 ** for an xmlrpc_bool value. */
312 format_out(env, output, "<boolean>%i</boolean>",
313 (value->_value.b) ? 1 : 0);
316 case XMLRPC_TYPE_DOUBLE:
317 /* We must output a number of the form [+-]?\d*.\d*. */
318 format_out(env, output, "<double>%f</double>", value->_value.d);
321 case XMLRPC_TYPE_STRING:
322 format_out(env, output, "<string>");
323 XMLRPC_FAIL_IF_FAULT(env);
324 serializeUtf8MemBlock(env, output, &value->_block);
325 XMLRPC_FAIL_IF_FAULT(env);
326 format_out(env, output, "</string>");
329 case XMLRPC_TYPE_ARRAY:
330 format_out(env, output, "<array><data>"CRLF);
331 XMLRPC_FAIL_IF_FAULT(env);
333 /* Serialize each item. */
334 size = xmlrpc_array_size(env, value);
335 XMLRPC_FAIL_IF_FAULT(env);
336 for (i = 0; i < size; i++) {
337 item = xmlrpc_array_get_item(env, value, i);
338 XMLRPC_FAIL_IF_FAULT(env);
339 xmlrpc_serialize_value(env, output, item);
340 XMLRPC_FAIL_IF_FAULT(env);
341 format_out(env, output, CRLF);
342 XMLRPC_FAIL_IF_FAULT(env);
345 format_out(env, output, "</data></array>");
348 case XMLRPC_TYPE_STRUCT:
349 xmlrpc_serialize_struct(env, output, value);
352 case XMLRPC_TYPE_BASE64:
353 format_out(env, output, "<base64>"CRLF);
354 XMLRPC_FAIL_IF_FAULT(env);
355 contents = XMLRPC_TYPED_MEM_BLOCK_CONTENTS(unsigned char,
357 size = XMLRPC_TYPED_MEM_BLOCK_SIZE(unsigned char, &value->_block);
358 xmlrpc_serialize_base64_data(env, output, contents, size);
359 XMLRPC_FAIL_IF_FAULT(env);
360 format_out(env, output, "</base64>");
363 case XMLRPC_TYPE_DATETIME:
364 format_out(env, output, "<dateTime.iso8601>");
365 XMLRPC_FAIL_IF_FAULT(env);
366 serializeUtf8MemBlock(env, output, &value->_block);
367 XMLRPC_FAIL_IF_FAULT(env);
368 format_out(env, output, "</dateTime.iso8601>");
371 case XMLRPC_TYPE_C_PTR:
372 xmlrpc_env_set_fault_formatted(
373 env, XMLRPC_INTERNAL_ERROR,
374 "Tried to serialize a C pointer value.");
377 case XMLRPC_TYPE_NIL:
378 format_out(env, output, "<nil/>");
379 XMLRPC_FAIL_IF_FAULT(env);
382 case XMLRPC_TYPE_DEAD:
383 xmlrpc_env_set_fault_formatted(
384 env, XMLRPC_INTERNAL_ERROR,
385 "Tried to serialize a deaad value.");
389 xmlrpc_env_set_fault_formatted(
390 env, XMLRPC_INTERNAL_ERROR,
391 "Invalid xmlrpc_value type: %d", value->_type);
393 XMLRPC_FAIL_IF_FAULT(env);
395 /* Print our ubiquitous footer. */
396 format_out(env, output, "</value>");
397 XMLRPC_FAIL_IF_FAULT(env);
405 /*=========================================================================
406 ** xmlrpc_serialize_params
407 **=========================================================================
408 ** Serialize a list as a set of parameters.
412 xmlrpc_serialize_params(xmlrpc_env *env,
413 xmlrpc_mem_block *output,
414 xmlrpc_value *param_array) {
419 XMLRPC_ASSERT_ENV_OK(env);
420 XMLRPC_ASSERT(output != NULL);
421 XMLRPC_ASSERT_VALUE_OK(param_array);
423 format_out(env, output, "<params>"CRLF);
424 XMLRPC_FAIL_IF_FAULT(env);
426 /* Dump each parameter. */
427 size = xmlrpc_array_size(env, param_array);
428 XMLRPC_FAIL_IF_FAULT(env);
429 for (i = 0; i < size; i++) {
430 format_out(env, output, "<param>");
431 XMLRPC_FAIL_IF_FAULT(env);
432 item = xmlrpc_array_get_item(env, param_array, i);
433 XMLRPC_FAIL_IF_FAULT(env);
434 xmlrpc_serialize_value(env, output, item);
435 XMLRPC_FAIL_IF_FAULT(env);
436 format_out(env, output, "</param>"CRLF);
437 XMLRPC_FAIL_IF_FAULT(env);
440 format_out(env, output, "</params>"CRLF);
441 XMLRPC_FAIL_IF_FAULT(env);
449 /*=========================================================================
450 ** xmlrpc_serialize_call
451 **=========================================================================
452 ** Serialize an XML-RPC call.
456 xmlrpc_serialize_call(xmlrpc_env * const env,
457 xmlrpc_mem_block * const output,
458 const char * const method_name,
459 xmlrpc_value * const param_array) {
461 xmlrpc_mem_block * encodedP;
465 XMLRPC_ASSERT_ENV_OK(env);
466 XMLRPC_ASSERT(output != NULL);
467 XMLRPC_ASSERT(method_name != NULL);
468 XMLRPC_ASSERT_VALUE_OK(param_array);
470 /* Set up our error-handling preconditions. */
473 /* Dump our header. */
474 format_out(env, output, XML_PROLOGUE);
475 XMLRPC_FAIL_IF_FAULT(env);
476 format_out(env, output, "<methodCall>"CRLF"<methodName>");
477 XMLRPC_FAIL_IF_FAULT(env);
479 /* Dump the method name. */
480 escapeForXml(env, method_name, strlen(method_name), &encodedP);
481 XMLRPC_FAIL_IF_FAULT(env);
482 contents = XMLRPC_MEMBLOCK_CONTENTS(char, encodedP);
483 size = XMLRPC_MEMBLOCK_SIZE(char, encodedP);
484 XMLRPC_MEMBLOCK_APPEND(char, env, output, contents, size);
485 XMLRPC_FAIL_IF_FAULT(env);
487 /* Dump our parameters and footer. */
488 format_out(env, output, "</methodName>"CRLF);
489 XMLRPC_FAIL_IF_FAULT(env);
490 xmlrpc_serialize_params(env, output, param_array);
491 XMLRPC_FAIL_IF_FAULT(env);
492 format_out(env, output, "</methodCall>"CRLF);
493 XMLRPC_FAIL_IF_FAULT(env);
497 XMLRPC_MEMBLOCK_FREE(char, encodedP);
502 /*=========================================================================
503 ** xmlrpc_serialize_response
504 **=========================================================================
505 ** Serialize the (non-fault) response to an XML-RPC call.
509 xmlrpc_serialize_response (xmlrpc_env *env,
510 xmlrpc_mem_block *output,
511 xmlrpc_value *value) {
513 XMLRPC_ASSERT_ENV_OK(env);
514 XMLRPC_ASSERT(output != NULL);
515 XMLRPC_ASSERT_VALUE_OK(value);
517 format_out(env, output, XML_PROLOGUE);
518 XMLRPC_FAIL_IF_FAULT(env);
519 format_out(env, output, "<methodResponse>"CRLF"<params>"CRLF"<param>");
520 XMLRPC_FAIL_IF_FAULT(env);
522 xmlrpc_serialize_value(env, output, value);
523 XMLRPC_FAIL_IF_FAULT(env);
525 format_out(env, output,
526 "</param>"CRLF"</params>"CRLF"</methodResponse>"CRLF);
527 XMLRPC_FAIL_IF_FAULT(env);
535 /*=========================================================================
536 ** xmlrpc_serialize_fault
537 **=========================================================================
538 ** Serialize an XML-RPC fault.
540 ** If this function fails, it will set up the first env argument. You'll
541 ** need to take some other drastic action to produce a serialized fault
542 ** of your own. (This function should only fail in an out-of-memory
543 ** situation, AFAIK.)
547 xmlrpc_serialize_fault(xmlrpc_env *env,
548 xmlrpc_mem_block *output,
553 XMLRPC_ASSERT_ENV_OK(env);
554 XMLRPC_ASSERT(output != NULL);
555 XMLRPC_ASSERT(fault != NULL && fault->fault_occurred);
557 /* Set up our error-handling preconditions. */
560 /* Build a fault structure. */
561 strct = xmlrpc_build_value(env, "{s:i,s:s}",
562 "faultCode", (xmlrpc_int32) fault->fault_code,
563 "faultString", fault->fault_string);
564 XMLRPC_FAIL_IF_FAULT(env);
566 /* Output our header. */
567 format_out(env, output, XML_PROLOGUE);
568 XMLRPC_FAIL_IF_FAULT(env);
569 format_out(env, output, "<methodResponse>"CRLF"<fault>"CRLF);
570 XMLRPC_FAIL_IF_FAULT(env);
572 /* Serialize our fault structure. */
573 xmlrpc_serialize_value(env, output, strct);
574 XMLRPC_FAIL_IF_FAULT(env);
576 /* Output our footer. */
577 format_out(env, output, CRLF"</fault>"CRLF"</methodResponse>"CRLF);
578 XMLRPC_FAIL_IF_FAULT(env);
582 xmlrpc_DECREF(strct);
588 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
590 ** Redistribution and use in source and binary forms, with or without
591 ** modification, are permitted provided that the following conditions
593 ** 1. Redistributions of source code must retain the above copyright
594 ** notice, this list of conditions and the following disclaimer.
595 ** 2. Redistributions in binary form must reproduce the above copyright
596 ** notice, this list of conditions and the following disclaimer in the
597 ** documentation and/or other materials provided with the distribution.
598 ** 3. The name of the author may not be used to endorse or promote products
599 ** derived from this software without specific prior written permission.
601 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
602 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
603 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
604 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
605 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
606 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
607 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
608 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
609 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
610 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF