Return to http_servlet_xmlrpc.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / libpdel / http / servlet |
1.1 ! misho 1: ! 2: /* ! 3: * Copyright (c) 2001-2002 Packet Design, LLC. ! 4: * All rights reserved. ! 5: * ! 6: * Subject to the following obligations and disclaimer of warranty, ! 7: * use and redistribution of this software, in source or object code ! 8: * forms, with or without modifications are expressly permitted by ! 9: * Packet Design; provided, however, that: ! 10: * ! 11: * (i) Any and all reproductions of the source or object code ! 12: * must include the copyright notice above and the following ! 13: * disclaimer of warranties; and ! 14: * (ii) No rights are granted, in any manner or form, to use ! 15: * Packet Design trademarks, including the mark "PACKET DESIGN" ! 16: * on advertising, endorsements, or otherwise except as such ! 17: * appears in the above copyright notice or in the software. ! 18: * ! 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND ! 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO ! 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING ! 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED ! 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, ! 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, ! 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS ! 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, ! 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE ! 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE ! 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, ! 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL ! 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF ! 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF ! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF ! 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF ! 36: * THE POSSIBILITY OF SUCH DAMAGE. ! 37: * ! 38: * Author: Archie Cobbs <archie@freebsd.org> ! 39: */ ! 40: ! 41: #include <sys/types.h> ! 42: #include <sys/param.h> ! 43: #include <sys/stat.h> ! 44: ! 45: #include <netinet/in_systm.h> ! 46: #include <netinet/in.h> ! 47: ! 48: #include <stdlib.h> ! 49: #include <stdio.h> ! 50: #include <string.h> ! 51: #include <stdarg.h> ! 52: #include <syslog.h> ! 53: #include <errno.h> ! 54: #include <assert.h> ! 55: ! 56: #include <openssl/ssl.h> ! 57: ! 58: #include "structs/structs.h" ! 59: #include "structs/type/array.h" ! 60: #include "structs/type/struct.h" ! 61: #include "structs/type/union.h" ! 62: #include "structs/xml.h" ! 63: #include "structs/xmlrpc.h" ! 64: ! 65: #include "http/http_defs.h" ! 66: #include "http/http_server.h" ! 67: #include "http/http_servlet.h" ! 68: #include "http/servlet/xml.h" ! 69: #include "http/servlet/xmlrpc.h" ! 70: #include "util/typed_mem.h" ! 71: ! 72: #define MEM_TYPE "http_servlet_xmlrpc" ! 73: ! 74: #define BOGUS_RTYPE ((const struct structs_type *)0x1832f0ad) ! 75: ! 76: struct xmlrpc_state { ! 77: struct http_servlet *servlet; /* servlet */ ! 78: struct http_servlet_xmlrpc_method *methods; /* methods */ ! 79: void *arg; ! 80: void (*destroy)(void *); ! 81: http_logger_t *logger; ! 82: }; ! 83: ! 84: /* Internal functions */ ! 85: static http_servlet_run_t http_servlet_xmlrpc_run; ! 86: static http_servlet_destroy_t http_servlet_xmlrpc_destroy; ! 87: ! 88: static struct http_servlet_xmlrpc_method *http_servlet_xmlrpc_copy_methods( ! 89: const struct http_servlet_xmlrpc_method *methods); ! 90: static void http_servlet_xmlrpc_free_methods( ! 91: struct http_servlet_xmlrpc_method *methods); ! 92: ! 93: static http_servlet_xml_handler_t http_servlet_xmlrpc_handler; ! 94: ! 95: /* ! 96: * Create a new http_servlet_xmlrpc servlet. ! 97: */ ! 98: struct http_servlet * ! 99: http_servlet_xmlrpc_create(const struct http_servlet_xmlrpc_info *info, ! 100: void *arg, void (*destroy)(void *)) ! 101: { ! 102: struct http_servlet_xml_info xinfo; ! 103: struct http_servlet *servlet; ! 104: struct xmlrpc_state *state; ! 105: ! 106: /* Create servlet */ ! 107: if ((servlet = MALLOC(MEM_TYPE, sizeof(*servlet))) == NULL) ! 108: return (NULL); ! 109: memset(servlet, 0, sizeof(*servlet)); ! 110: servlet->run = http_servlet_xmlrpc_run; ! 111: servlet->destroy = http_servlet_xmlrpc_destroy; ! 112: ! 113: /* Create servlet state structure */ ! 114: if ((state = MALLOC(MEM_TYPE, sizeof(*state))) == NULL) ! 115: goto fail; ! 116: memset(state, 0, sizeof(*state)); ! 117: state->arg = arg; ! 118: state->destroy = destroy; ! 119: state->logger = info->logger; ! 120: ! 121: /* Copy method list */ ! 122: if ((state->methods ! 123: = http_servlet_xmlrpc_copy_methods(info->methods)) == NULL) ! 124: goto fail; ! 125: ! 126: /* Set up info for the more general http_servlet_xml servlet */ ! 127: memset(&xinfo, 0, sizeof(xinfo)); ! 128: xinfo.handler = http_servlet_xmlrpc_handler; ! 129: xinfo.ptag = XML_RPC_REQUEST_TAG; ! 130: xinfo.ptype = &structs_type_xmlrpc_request; ! 131: xinfo.rtag = XML_RPC_REPLY_TAG; ! 132: xinfo.rtype = &structs_type_xmlrpc_response; ! 133: xinfo.allow_post = 1; ! 134: xinfo.allow_get = 0; ! 135: xinfo.logger = info->logger; ! 136: xinfo.flags = STRUCTS_XML_FULL; ! 137: ! 138: /* Create "inner" XML servlet using 'xinfo' */ ! 139: if ((state->servlet = http_servlet_xml_create(&xinfo, ! 140: state, NULL)) == NULL) ! 141: goto fail; ! 142: ! 143: /* Done */ ! 144: servlet->arg = state; ! 145: return (servlet); ! 146: ! 147: fail: ! 148: /* Clean up after failure */ ! 149: if (state != NULL) { ! 150: if (state->methods != NULL) ! 151: http_servlet_xmlrpc_free_methods(state->methods); ! 152: FREE(MEM_TYPE, state); ! 153: } ! 154: FREE(MEM_TYPE, servlet); ! 155: return (NULL); ! 156: } ! 157: ! 158: static int ! 159: http_servlet_xmlrpc_run(struct http_servlet *servlet, ! 160: struct http_request *req, struct http_response *resp) ! 161: { ! 162: struct xmlrpc_state *const state = servlet->arg; ! 163: ! 164: return ((*state->servlet->run)(state->servlet, req, resp)); ! 165: } ! 166: ! 167: static void ! 168: http_servlet_xmlrpc_destroy(struct http_servlet *servlet) ! 169: { ! 170: struct xmlrpc_state *const state = servlet->arg; ! 171: ! 172: /* Destroy 'inner' servlet */ ! 173: http_server_destroy_servlet(&state->servlet); ! 174: ! 175: /* Destroy 'outer' servlet */ ! 176: if (state->destroy != NULL) ! 177: (*state->destroy)(state->arg); ! 178: http_servlet_xmlrpc_free_methods(state->methods); ! 179: FREE(MEM_TYPE, state); ! 180: FREE(MEM_TYPE, servlet); ! 181: } ! 182: ! 183: /* ! 184: * Our "wrapper" handler that converts an XML-RPC request/reply ! 185: * into a more normal request/reply. ! 186: */ ! 187: static void * ! 188: http_servlet_xmlrpc_handler(void *arg, struct http_request *req, ! 189: const void *payload, const char *pattrs, char **rattrsp, ! 190: const char *mtype) ! 191: { ! 192: const struct xmlrpc_state *const state = arg; ! 193: const struct structs_type *const xrept = &structs_type_xmlrpc_response; ! 194: const struct http_servlet_xmlrpc_method *method; ! 195: const struct xmlrpc_request *const xreq = payload; /* XML-RPC request */ ! 196: void **params = NULL; /* parameter list for handler */ ! 197: void *reply = NULL; /* reply returned by handler */ ! 198: struct xmlrpc_response_union *xreply = NULL; /* XML-RPC reply */ ! 199: const struct structs_type *rtype = NULL;/* handlers' reply type */ ! 200: void *ret = NULL; /* this func's return value */ ! 201: int faulted = 0; /* handler returned fault */ ! 202: char *errbuf = NULL; /* error message, if any */ ! 203: int exploded_params = 0; /* exploded parameters */ ! 204: int exploded_response = 0; /* exploded response */ ! 205: int errno_save; /* saved errno value */ ! 206: u_int i; ! 207: ! 208: /* Find method */ ! 209: for (method = state->methods; method->name != NULL ! 210: && *method->name != '\0' ! 211: && strcmp(method->name, xreq->methodName) != 0; method++); ! 212: if (method->name == NULL) { ! 213: ASPRINTF(TYPED_MEM_TEMP, &errbuf, ! 214: "method name \"%s\" not recognized", xreq->methodName); ! 215: if (errbuf == NULL) ! 216: goto fail; ! 217: (*state->logger)(LOG_ERR, "XML-RPC: %s", errbuf); ! 218: errno = ENOSYS; ! 219: goto null_reply; ! 220: } ! 221: exploded_params = (method->ptypes == NULL); ! 222: ! 223: /* Check number of arguments */ ! 224: if (xreq->params.length < method->min_params ! 225: || xreq->params.length > method->max_params) { ! 226: ASPRINTF(TYPED_MEM_TEMP, &errbuf, ! 227: "%d parameter(s) present for method \"%s\" which takes" ! 228: " between %u and %u parameter(s)", xreq->params.length, ! 229: xreq->methodName, method->min_params, method->max_params); ! 230: if (errbuf == NULL) ! 231: goto fail; ! 232: (*state->logger)(LOG_ERR, "XML-RPC: %s", errbuf); ! 233: errno = EINVAL; ! 234: goto null_reply; ! 235: } ! 236: ! 237: /* Get parameters from the XML-RPC request */ ! 238: if ((params = MALLOC(TYPED_MEM_TEMP, ! 239: xreq->params.length * sizeof(*params))) == NULL) ! 240: goto null_reply; ! 241: memset(params, 0, xreq->params.length * sizeof(*params)); ! 242: for (i = 0; i < xreq->params.length; i++) { ! 243: char ebuf[256]; ! 244: ! 245: /* Optionally leave parameter list "exploded" */ ! 246: if (exploded_params) { ! 247: params[i] = &xreq->params.elems[i].value; ! 248: continue; ! 249: } ! 250: ! 251: /* "Compact" this parameter using structs_xmlrpc2struct() */ ! 252: if ((params[i] = MALLOC(TYPED_MEM_TEMP, ! 253: method->ptypes[i]->size)) == NULL) ! 254: break; ! 255: if (structs_init(method->ptypes[i], NULL, params[i]) == -1) { ! 256: FREE(TYPED_MEM_TEMP, params[i]); ! 257: params[i] = NULL; ! 258: break; ! 259: } ! 260: if (structs_xmlrpc2struct(&structs_type_xmlrpc_value, ! 261: &xreq->params.elems[i].value, NULL, method->ptypes[i], ! 262: params[i], NULL, ebuf, sizeof(ebuf)) == -1) { ! 263: errno_save = errno; ! 264: ASPRINTF(TYPED_MEM_TEMP, &errbuf, "parameter #%d of" ! 265: " method \"%s\" has an invalid type or value: %s", ! 266: i + 1, xreq->methodName, ebuf); ! 267: if (errbuf == NULL) ! 268: goto fail; ! 269: (*state->logger)(LOG_ERR, "XML-RPC: %s", errbuf); ! 270: errno = errno_save; ! 271: break; ! 272: } ! 273: } ! 274: if (i < xreq->params.length) ! 275: goto null_reply; ! 276: ! 277: /* Invoke our simplified handler */ ! 278: rtype = BOGUS_RTYPE; ! 279: reply = (*method->handler)(state->arg, xreq->methodName, req, ! 280: xreq->params.length, (const void **)params, TYPED_MEM_TEMP, ! 281: &rtype, &faulted); ! 282: if (reply == NULL) { ! 283: errno_save = errno; ! 284: (*state->logger)(LOG_ERR, ! 285: "XML-RPC: handler for \"%s\" failed: %s", ! 286: xreq->methodName, strerror(errno)); ! 287: errno = errno_save; ! 288: goto null_reply; ! 289: } ! 290: ! 291: /* Sanity check returned reply type */ ! 292: if (rtype == BOGUS_RTYPE) { ! 293: ASPRINTF(TYPED_MEM_TEMP, &errbuf, "handler didn't set 'rtype'"); ! 294: if (errbuf == NULL) ! 295: goto fail; ! 296: (*state->logger)(LOG_ERR, "XML-RPC: handler for" ! 297: " \"%s\" failed: %s", xreq->methodName, errbuf); ! 298: errno = ECONNABORTED; ! 299: goto null_reply; ! 300: } ! 301: if (faulted && rtype != &structs_type_xmlrpc_compact_fault) { ! 302: ASPRINTF(TYPED_MEM_TEMP, &errbuf, "handler returned a fault" ! 303: " but didn't set 'rtype' to" ! 304: " &structs_type_xmlrpc_compact_fault"); ! 305: if (errbuf == NULL) ! 306: goto fail; ! 307: (*state->logger)(LOG_ERR, "XML-RPC: handler for" ! 308: " \"%s\" failed: %s", xreq->methodName, errbuf); ! 309: errno = ECONNABORTED; ! 310: goto null_reply; ! 311: } ! 312: ! 313: /* Check for "exploded" return value */ ! 314: if (rtype == NULL) { ! 315: rtype = &structs_type_xmlrpc_value; ! 316: exploded_response = 1; ! 317: } ! 318: ! 319: null_reply: ! 320: /* Save errno (used to create the fault when/if reply == NULL) */ ! 321: errno_save = errno; ! 322: ! 323: /* Create the XML-RPC reply */ ! 324: if ((xreply = MALLOC(mtype, sizeof(*xreply))) == NULL) ! 325: goto fail; ! 326: if (structs_init(xrept, NULL, xreply) == -1) { ! 327: FREE(mtype, xreply); ! 328: xreply = NULL; ! 329: goto fail; ! 330: } ! 331: ! 332: /* If handler returned NULL, create a fault structure using errno */ ! 333: if (reply == NULL) { ! 334: struct xmlrpc_compact_fault *fault; ! 335: ! 336: /* Create an initialize fault structure from error string */ ! 337: if ((fault = MALLOC(TYPED_MEM_TEMP, sizeof(*fault))) == NULL) ! 338: goto fail; ! 339: if (structs_init(&structs_type_xmlrpc_compact_fault, ! 340: NULL, fault) == -1) { ! 341: FREE(TYPED_MEM_TEMP, fault); ! 342: goto fail; ! 343: } ! 344: fault->faultCode = errno; ! 345: if (structs_set_string(&structs_type_xmlrpc_compact_fault, ! 346: "faultString", errbuf != NULL ? errbuf : ! 347: strerror(errno_save), fault, NULL, 0) == -1) ! 348: ; /* too bad, just ignore error */ ! 349: ! 350: /* Now pretend like handler() itself returned the fault */ ! 351: reply = fault; ! 352: rtype = &structs_type_xmlrpc_compact_fault; ! 353: faulted = 1; ! 354: } ! 355: ! 356: /* Set fault if error, otherwise set reply as XML-RPC reply parameter */ ! 357: if (faulted) { ! 358: if (structs_struct2xmlrpc(rtype, reply, ! 359: NULL, xrept, xreply, "fault.value") == -1) ! 360: goto fail; ! 361: } else { ! 362: if (structs_array_insert(xrept, "params", 0, xreply) == -1) ! 363: goto fail; ! 364: if (exploded_response) { ! 365: if (structs_set(xrept, reply, ! 366: "params.0.value", xreply) == -1) ! 367: goto fail; ! 368: } else if (structs_struct2xmlrpc(rtype, reply, NULL, ! 369: xrept, xreply, "params.0.value") == -1) ! 370: goto fail; ! 371: } ! 372: ! 373: /* Done, so return reply */ ! 374: ret = xreply; ! 375: xreply = NULL; ! 376: ! 377: fail: ! 378: /* Cleanup and exit */ ! 379: errno_save = errno; ! 380: if (params != NULL) { ! 381: if (!exploded_params) { ! 382: for (i = 0; i < xreq->params.length; i++) { ! 383: if (params[i] != NULL) { ! 384: structs_free(method->ptypes[i], ! 385: NULL, params[i]); ! 386: FREE(TYPED_MEM_TEMP, params[i]); ! 387: } ! 388: } ! 389: } ! 390: FREE(TYPED_MEM_TEMP, params); ! 391: } ! 392: if (reply != NULL) { ! 393: structs_free(rtype, NULL, reply); ! 394: FREE(TYPED_MEM_TEMP, reply); ! 395: } ! 396: if (xreply != NULL) { ! 397: structs_free(xrept, NULL, xreply); ! 398: FREE(mtype, xreply); ! 399: } ! 400: if (errbuf != NULL) ! 401: FREE(TYPED_MEM_TEMP, errbuf); ! 402: errno = errno_save; ! 403: return (ret); ! 404: } ! 405: ! 406: /* ! 407: * Copy an XML-RPC method list ! 408: */ ! 409: static struct http_servlet_xmlrpc_method * ! 410: http_servlet_xmlrpc_copy_methods( ! 411: const struct http_servlet_xmlrpc_method *const methods) ! 412: { ! 413: const struct http_servlet_xmlrpc_method *method; ! 414: struct http_servlet_xmlrpc_method *mcopy; ! 415: int num; ! 416: int i; ! 417: ! 418: /* Count the number of methods */ ! 419: for (num = 0, method = methods; method->name != NULL; num++, method++); ! 420: ! 421: /* Allocate an array */ ! 422: if ((mcopy = MALLOC(MEM_TYPE, (num + 1) * sizeof(*mcopy))) == NULL) ! 423: return (NULL); ! 424: memset(mcopy, 0, (num + 1) * sizeof(*mcopy)); ! 425: ! 426: /* Make a 'deep' copy (except for structs types XXX) */ ! 427: for (i = 0; i < num; i++) { ! 428: const struct http_servlet_xmlrpc_method *const orig ! 429: = &methods[i]; ! 430: struct http_servlet_xmlrpc_method *const copy = &mcopy[i]; ! 431: ! 432: /* Copy all except the malloc'd stuff */ ! 433: *copy = *orig; ! 434: copy->name = NULL; ! 435: copy->ptypes = NULL; ! 436: ! 437: /* Copy types array */ ! 438: if (orig->ptypes != NULL) { ! 439: if ((copy->ptypes = MALLOC(MEM_TYPE, copy->max_params ! 440: * sizeof(*copy->ptypes))) == NULL) { ! 441: http_servlet_xmlrpc_free_methods(mcopy); ! 442: return (NULL); ! 443: } ! 444: memcpy(copy->ptypes, orig->ptypes, ! 445: copy->max_params * sizeof(*copy->ptypes)); ! 446: } ! 447: ! 448: /* Copy name */ ! 449: if ((copy->name = STRDUP(MEM_TYPE, orig->name)) == NULL) { ! 450: FREE(MEM_TYPE, copy->ptypes); ! 451: http_servlet_xmlrpc_free_methods(mcopy); ! 452: return (NULL); ! 453: } ! 454: } ! 455: ! 456: /* Done */ ! 457: return (mcopy); ! 458: } ! 459: ! 460: static void ! 461: http_servlet_xmlrpc_free_methods(struct http_servlet_xmlrpc_method *methods) ! 462: { ! 463: const struct http_servlet_xmlrpc_method *method; ! 464: int i; ! 465: ! 466: for (i = 0, method = methods; method->name != NULL; i++, method++) { ! 467: FREE(MEM_TYPE, (char *)method->name); ! 468: FREE(MEM_TYPE, method->ptypes); ! 469: } ! 470: FREE(MEM_TYPE, methods); ! 471: } ! 472: