1 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
6 ** 1. Redistributions of source code must retain the above copyright
7 ** notice, this list of conditions and the following disclaimer.
8 ** 2. Redistributions in binary form must reproduce the above copyright
9 ** notice, this list of conditions and the following disclaimer in the
10 ** documentation and/or other materials provided with the distribution.
11 ** 3. The name of the author may not be used to endorse or promote products
12 ** derived from this software without specific prior written permission.
14 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 #include "xmlrpc_config.h"
34 #include "xmlrpc_int.h"
36 #define CRLF "\015\012"
37 #define SMALL_BUFFER_SZ (128)
38 #define XML_PROLOGUE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"CRLF
41 /*=========================================================================
43 **=========================================================================
44 ** A lightweight print routine for use with various serialization
45 ** functions. Only use this routine for printing small objects--it uses
46 ** a fixed-size internal buffer and returns an error on overflow.
47 ** In particular, do NOT use this routine to print XML-RPC string values!
51 format_out(xmlrpc_env
*env
,
52 xmlrpc_mem_block
*output
,
57 char buffer
[SMALL_BUFFER_SZ
];
60 XMLRPC_ASSERT_ENV_OK(env
);
62 va_start(args
, format_string
);
64 /* We assume that this function is present and works correctly. Right. */
65 count
= vsnprintf(buffer
, SMALL_BUFFER_SZ
, format_string
, args
);
67 /* Old C libraries return -1 if vsnprintf overflows its buffer.
68 ** New C libraries return the number of characters which *would* have
69 ** been printed if the error did not occur. This is impressively vile.
70 ** Thank the C99 committee for this bright idea. But wait! We also
71 ** need to keep track of the trailing NULL. */
72 if (count
< 0 || count
>= (SMALL_BUFFER_SZ
- 1))
73 XMLRPC_FAIL(env
, XMLRPC_INTERNAL_ERROR
,
74 "format_out overflowed internal buffer");
76 /* Append our new data to our output. */
77 XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env
, output
, buffer
, count
);
78 XMLRPC_FAIL_IF_FAULT(env
);
85 /*=========================================================================
86 ** Warnings About Invalid UTF-8
87 **=========================================================================
88 ** We claim to send UTF-8 data to the network. But we rely on application
89 ** programs to pass us correctly-formed UTF-8 data, which is very naive
92 ** In debudding mode, we call this routine to issue dire-sounding
93 ** warnings. For the sake of safety, this routine never exits the
94 ** program or does anything else drastic.
96 ** This routine almost certainly slows down our output.
99 #if !defined NDEBUG && defined HAVE_UNICODE_WCHAR
102 sanity_check_utf8(const char * const str
,
107 xmlrpc_env_init(&env
);
108 xmlrpc_validate_utf8(&env
, str
, len
);
109 if (env
.fault_occurred
)
110 fprintf(stderr
, "*** xmlrpc-c WARNING ***: %s (%s)\n",
111 "Application sending corrupted UTF-8 data to network",
113 xmlrpc_env_clean(&env
);
119 /*=========================================================================
121 **=========================================================================
124 static xmlrpc_mem_block
*
125 escape_string(xmlrpc_env
* const env
,
126 const char * const str
,
129 xmlrpc_mem_block
*retval
;
133 XMLRPC_ASSERT_ENV_OK(env
);
134 XMLRPC_ASSERT(str
!= NULL
);
136 /* Sanity-check this string before we print it. */
137 #if !defined NDEBUG && defined HAVE_UNICODE_WCHAR
138 sanity_check_utf8(str
, len
);
141 /* Calculate the amount of space we'll need. */
143 for (i
= 0; i
< len
; i
++) {
145 needed
+= 4; /* < */
146 else if (str
[i
] == '>')
147 needed
+= 4; /* > */
148 else if (str
[i
] == '&')
149 needed
+= 5; /* & */
154 /* Allocate our memory block. */
155 retval
= XMLRPC_TYPED_MEM_BLOCK_NEW(char, env
, needed
);
156 XMLRPC_FAIL_IF_FAULT(env
);
158 /* Copy over the newly-allocated data. */
159 out
= XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, retval
);
160 for (i
= 0; i
< len
; i
++) {
166 } else if (str
[i
] == '>') {
171 } else if (str
[i
] == '&') {
183 if (env
->fault_occurred
) {
185 XMLRPC_TYPED_MEM_BLOCK_FREE(char, retval
);
193 static xmlrpc_mem_block
*
194 escape_block (xmlrpc_env
*env
,
195 xmlrpc_mem_block
*block
) {
197 XMLRPC_ASSERT_ENV_OK(env
);
198 XMLRPC_ASSERT(block
!= NULL
);
200 return escape_string(env
,
201 XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, block
),
202 XMLRPC_TYPED_MEM_BLOCK_SIZE(char, block
));
207 /*=========================================================================
208 ** xmlrpc_serialize_string_data
209 **=========================================================================
210 ** Escape and print the contents of a string.
214 xmlrpc_serialize_string_data(xmlrpc_env
*env
,
215 xmlrpc_mem_block
*output
,
216 xmlrpc_value
*string
) {
218 xmlrpc_mem_block
*escaped
;
222 /* Since this routine can only be called internally, we only need
223 ** an assertion here, not a runtime type check.
224 ** XXX - Temporarily disabled because we're using this code to
225 ** print <dateTime.iso8601> values as well. */
226 /* XMLRPC_ASSERT(string->_type == XMLRPC_TYPE_STRING); */
228 /* Escape any '&' and '<' characters in the string. */
229 escaped
= escape_block(env
, &string
->_block
);
230 XMLRPC_FAIL_IF_FAULT(env
);
231 contents
= XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, escaped
);
232 size
= XMLRPC_TYPED_MEM_BLOCK_SIZE(char, escaped
) - 1;
234 /* Print the string. */
235 XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env
, output
, contents
, size
);
236 XMLRPC_FAIL_IF_FAULT(env
);
240 XMLRPC_TYPED_MEM_BLOCK_FREE(char, escaped
);
245 /*=========================================================================
246 ** xmlrpc_serialize_base64_data
247 **=========================================================================
248 ** Print the contents of a memory block as well-formed Base64 data.
252 xmlrpc_serialize_base64_data (xmlrpc_env
*env
,
253 xmlrpc_mem_block
*output
,
254 unsigned char* data
, size_t len
) {
256 xmlrpc_mem_block
*encoded
;
257 unsigned char *contents
;
260 /* Encode the data. */
261 encoded
= xmlrpc_base64_encode_without_newlines(env
, data
, len
);
262 XMLRPC_FAIL_IF_FAULT(env
);
263 contents
= XMLRPC_TYPED_MEM_BLOCK_CONTENTS(unsigned char, encoded
);
264 size
= XMLRPC_TYPED_MEM_BLOCK_SIZE(unsigned char, encoded
);
266 /* Print the data. */
267 XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env
, output
, contents
, size
);
268 XMLRPC_FAIL_IF_FAULT(env
);
272 XMLRPC_TYPED_MEM_BLOCK_FREE(char, encoded
);
277 /*=========================================================================
278 ** xmlrpc_serialize_struct
279 **=========================================================================
280 ** Dump the contents of a struct.
284 xmlrpc_serialize_struct(xmlrpc_env
*env
,
285 xmlrpc_mem_block
*output
,
286 xmlrpc_value
*strct
) {
290 xmlrpc_value
*key
, *value
;
292 format_out(env
, output
, "<struct>"CRLF
);
293 XMLRPC_FAIL_IF_FAULT(env
);
295 size
= xmlrpc_struct_size(env
, strct
);
296 XMLRPC_FAIL_IF_FAULT(env
);
297 for (i
= 0; i
< size
; i
++) {
298 xmlrpc_struct_get_key_and_value(env
, strct
, (int)i
, &key
, &value
);
299 XMLRPC_FAIL_IF_FAULT(env
);
300 format_out(env
, output
, "<member><name>");
301 XMLRPC_FAIL_IF_FAULT(env
);
302 xmlrpc_serialize_string_data(env
, output
, key
);
303 XMLRPC_FAIL_IF_FAULT(env
);
304 format_out(env
, output
, "</name>"CRLF
);
305 XMLRPC_FAIL_IF_FAULT(env
);
306 xmlrpc_serialize_value(env
, output
, value
);
307 XMLRPC_FAIL_IF_FAULT(env
);
308 format_out(env
, output
, "</member>"CRLF
);
309 XMLRPC_FAIL_IF_FAULT(env
);
312 format_out(env
, output
, "</struct>");
313 XMLRPC_FAIL_IF_FAULT(env
);
321 /*=========================================================================
322 ** xmlrpc_serialize_value
323 **=========================================================================
324 ** Dump a value in the appropriate fashion.
328 xmlrpc_serialize_value(xmlrpc_env
*env
,
329 xmlrpc_mem_block
*output
,
330 xmlrpc_value
*value
) {
334 unsigned char* contents
;
337 XMLRPC_ASSERT_ENV_OK(env
);
338 XMLRPC_ASSERT(output
!= NULL
);
339 XMLRPC_ASSERT_VALUE_OK(value
);
341 /* Print our ubiquitous header. */
342 format_out(env
, output
, "<value>");
343 XMLRPC_FAIL_IF_FAULT(env
);
345 switch (value
->_type
) {
347 case XMLRPC_TYPE_INT
:
348 /* XXX - We assume that '%i' is the appropriate format specifier
349 ** for an xmlrpc_int32 value. We should add some test cases to
350 ** make sure this works. */
351 format_out(env
, output
, "<i4>%i</i4>", value
->_value
.i
);
354 case XMLRPC_TYPE_BOOL
:
355 /* XXX - We assume that '%i' is the appropriate format specifier
356 ** for an xmlrpc_bool value. */
357 format_out(env
, output
, "<boolean>%i</boolean>",
358 (value
->_value
.b
) ? 1 : 0);
361 case XMLRPC_TYPE_DOUBLE
:
362 /* We must output a number of the form [+-]?\d*.\d*. */
363 format_out(env
, output
, "<double>%.17g</double>", value
->_value
.d
);
366 case XMLRPC_TYPE_STRING
:
367 format_out(env
, output
, "<string>");
368 XMLRPC_FAIL_IF_FAULT(env
);
369 xmlrpc_serialize_string_data(env
, output
, value
);
370 XMLRPC_FAIL_IF_FAULT(env
);
371 format_out(env
, output
, "</string>");
374 case XMLRPC_TYPE_ARRAY
:
375 format_out(env
, output
, "<array><data>"CRLF
);
376 XMLRPC_FAIL_IF_FAULT(env
);
378 /* Serialize each item. */
379 size
= xmlrpc_array_size(env
, value
);
380 XMLRPC_FAIL_IF_FAULT(env
);
381 for (i
= 0; i
< size
; i
++) {
382 item
= xmlrpc_array_get_item(env
, value
, (int)i
);
383 XMLRPC_FAIL_IF_FAULT(env
);
384 xmlrpc_serialize_value(env
, output
, item
);
385 XMLRPC_FAIL_IF_FAULT(env
);
386 format_out(env
, output
, CRLF
);
387 XMLRPC_FAIL_IF_FAULT(env
);
390 format_out(env
, output
, "</data></array>");
393 case XMLRPC_TYPE_STRUCT
:
394 xmlrpc_serialize_struct(env
, output
, value
);
397 case XMLRPC_TYPE_BASE64
:
398 format_out(env
, output
, "<base64>"CRLF
);
399 XMLRPC_FAIL_IF_FAULT(env
);
400 contents
= XMLRPC_TYPED_MEM_BLOCK_CONTENTS(unsigned char,
402 size
= XMLRPC_TYPED_MEM_BLOCK_SIZE(unsigned char, &value
->_block
);
403 xmlrpc_serialize_base64_data(env
, output
, contents
, size
);
404 XMLRPC_FAIL_IF_FAULT(env
);
405 format_out(env
, output
, "</base64>");
408 case XMLRPC_TYPE_DATETIME
:
409 format_out(env
, output
, "<dateTime.iso8601>");
410 XMLRPC_FAIL_IF_FAULT(env
);
411 xmlrpc_serialize_string_data(env
, output
, value
);
412 XMLRPC_FAIL_IF_FAULT(env
);
413 format_out(env
, output
, "</dateTime.iso8601>");
416 case XMLRPC_TYPE_C_PTR
:
417 xmlrpc_env_set_fault_formatted(
418 env
, XMLRPC_INTERNAL_ERROR
,
419 "Tried to serialize a C pointer value.");
422 case XMLRPC_TYPE_DEAD
:
423 xmlrpc_env_set_fault_formatted(
424 env
, XMLRPC_INTERNAL_ERROR
,
425 "Tried to serialize a deaad value.");
429 xmlrpc_env_set_fault_formatted(
430 env
, XMLRPC_INTERNAL_ERROR
,
431 "Invalid xmlrpc_value type: %d", value
->_type
);
433 XMLRPC_FAIL_IF_FAULT(env
);
435 /* Print our ubiquitous footer. */
436 format_out(env
, output
, "</value>");
437 XMLRPC_FAIL_IF_FAULT(env
);
445 /*=========================================================================
446 ** xmlrpc_serialize_params
447 **=========================================================================
448 ** Serialize a list as a set of parameters.
452 xmlrpc_serialize_params(xmlrpc_env
*env
,
453 xmlrpc_mem_block
*output
,
454 xmlrpc_value
*param_array
) {
459 XMLRPC_ASSERT_ENV_OK(env
);
460 XMLRPC_ASSERT(output
!= NULL
);
461 XMLRPC_ASSERT_VALUE_OK(param_array
);
463 format_out(env
, output
, "<params>"CRLF
);
464 XMLRPC_FAIL_IF_FAULT(env
);
466 /* Dump each parameter. */
467 size
= xmlrpc_array_size(env
, param_array
);
468 XMLRPC_FAIL_IF_FAULT(env
);
469 for (i
= 0; i
< size
; i
++) {
470 format_out(env
, output
, "<param>");
471 XMLRPC_FAIL_IF_FAULT(env
);
472 item
= xmlrpc_array_get_item(env
, param_array
, (int)i
);
473 XMLRPC_FAIL_IF_FAULT(env
);
474 xmlrpc_serialize_value(env
, output
, item
);
475 XMLRPC_FAIL_IF_FAULT(env
);
476 format_out(env
, output
, "</param>"CRLF
);
477 XMLRPC_FAIL_IF_FAULT(env
);
480 format_out(env
, output
, "</params>"CRLF
);
481 XMLRPC_FAIL_IF_FAULT(env
);
489 /*=========================================================================
490 ** xmlrpc_serialize_call
491 **=========================================================================
492 ** Serialize an XML-RPC call.
496 xmlrpc_serialize_call(xmlrpc_env
* const env
,
497 xmlrpc_mem_block
* const output
,
498 const char * const method_name
,
499 xmlrpc_value
* const param_array
) {
501 xmlrpc_mem_block
*escaped
;
505 XMLRPC_ASSERT_ENV_OK(env
);
506 XMLRPC_ASSERT(output
!= NULL
);
507 XMLRPC_ASSERT(method_name
!= NULL
);
508 XMLRPC_ASSERT_VALUE_OK(param_array
);
510 /* Set up our error-handling preconditions. */
513 /* Dump our header. */
514 format_out(env
, output
, XML_PROLOGUE
);
515 XMLRPC_FAIL_IF_FAULT(env
);
516 format_out(env
, output
, "<methodCall>"CRLF
"<methodName>");
517 XMLRPC_FAIL_IF_FAULT(env
);
519 /* Dump the method name. */
520 escaped
= escape_string(env
, method_name
, strlen(method_name
));
521 XMLRPC_FAIL_IF_FAULT(env
);
522 contents
= XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, escaped
);
523 size
= XMLRPC_TYPED_MEM_BLOCK_SIZE(char, escaped
);
524 XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env
, output
, contents
, size
);
525 XMLRPC_FAIL_IF_FAULT(env
);
527 /* Dump our parameters and footer. */
528 format_out(env
, output
, "</methodName>"CRLF
);
529 XMLRPC_FAIL_IF_FAULT(env
);
530 xmlrpc_serialize_params(env
, output
, param_array
);
531 XMLRPC_FAIL_IF_FAULT(env
);
532 format_out(env
, output
, "</methodCall>"CRLF
);
533 XMLRPC_FAIL_IF_FAULT(env
);
537 xmlrpc_mem_block_free(escaped
);
542 /*=========================================================================
543 ** xmlrpc_serialize_response
544 **=========================================================================
545 ** Serialize the (non-fault) response to an XML-RPC call.
549 xmlrpc_serialize_response (xmlrpc_env
*env
,
550 xmlrpc_mem_block
*output
,
551 xmlrpc_value
*value
) {
553 XMLRPC_ASSERT_ENV_OK(env
);
554 XMLRPC_ASSERT(output
!= NULL
);
555 XMLRPC_ASSERT_VALUE_OK(value
);
557 format_out(env
, output
, XML_PROLOGUE
);
558 XMLRPC_FAIL_IF_FAULT(env
);
559 format_out(env
, output
, "<methodResponse>"CRLF
"<params>"CRLF
"<param>");
560 XMLRPC_FAIL_IF_FAULT(env
);
562 xmlrpc_serialize_value(env
, output
, value
);
563 XMLRPC_FAIL_IF_FAULT(env
);
565 format_out(env
, output
,
566 "</param>"CRLF
"</params>"CRLF
"</methodResponse>"CRLF
);
567 XMLRPC_FAIL_IF_FAULT(env
);
575 /*=========================================================================
576 ** xmlrpc_serialize_fault
577 **=========================================================================
578 ** Serialize an XML-RPC fault.
580 ** If this function fails, it will set up the first env argument. You'll
581 ** need to take some other drastic action to produce a serialized fault
582 ** of your own. (This function should only fail in an out-of-memory
583 ** situation, AFAIK.)
587 xmlrpc_serialize_fault(xmlrpc_env
*env
,
588 xmlrpc_mem_block
*output
,
593 XMLRPC_ASSERT_ENV_OK(env
);
594 XMLRPC_ASSERT(output
!= NULL
);
595 XMLRPC_ASSERT(fault
!= NULL
&& fault
->fault_occurred
);
597 /* Build a fault structure. */
598 strct
= xmlrpc_build_value(env
, "{s:i,s:s}",
599 "faultCode", (xmlrpc_int32
) fault
->fault_code
,
600 "faultString", fault
->fault_string
);
601 XMLRPC_FAIL_IF_FAULT(env
);
603 /* Output our header. */
604 format_out(env
, output
, XML_PROLOGUE
);
605 XMLRPC_FAIL_IF_FAULT(env
);
606 format_out(env
, output
, "<methodResponse>"CRLF
"<fault>"CRLF
);
607 XMLRPC_FAIL_IF_FAULT(env
);
609 /* Serialize our fault structure. */
610 xmlrpc_serialize_value(env
, output
, strct
);
611 XMLRPC_FAIL_IF_FAULT(env
);
613 /* Output our footer. */
614 format_out(env
, output
, CRLF
"</fault>"CRLF
"</methodResponse>"CRLF
);
615 XMLRPC_FAIL_IF_FAULT(env
);
619 xmlrpc_DECREF(strct
);