Annotation of embedaddon/libpdel/http/http_xml.c, revision 1.1

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: 
        !            43: #include <netinet/in.h>
        !            44: #include <arpa/inet.h>
        !            45: 
        !            46: #include <stdio.h>
        !            47: #include <stdlib.h>
        !            48: #include <stdarg.h>
        !            49: #include <string.h>
        !            50: #include <syslog.h>
        !            51: #include <errno.h>
        !            52: #include <pthread.h>
        !            53: 
        !            54: #include <openssl/ssl.h>
        !            55: 
        !            56: #include "structs/structs.h"
        !            57: #include "structs/type/array.h"
        !            58: #include "structs/type/union.h"
        !            59: #include "structs/xml.h"
        !            60: #include "structs/xmlrpc.h"
        !            61: 
        !            62: #include "io/boundary_fp.h"
        !            63: #include "io/string_fp.h"
        !            64: #include "sys/alog.h"
        !            65: #include "util/typed_mem.h"
        !            66: 
        !            67: #include "http/http_defs.h"
        !            68: #include "http/http_server.h"
        !            69: #include "http/xml.h"
        !            70: 
        !            71: #define MEM_TYPE               "http_xml_send_xmlrpc"
        !            72: 
        !            73: /* Context for http_xml_send_xmlrpc() */
        !            74: struct http_xml_send_xmlrpc_ctx {
        !            75:        struct xmlrpc_request           *xreq;
        !            76:        struct xmlrpc_response_union    *xrep;
        !            77: };
        !            78: 
        !            79: /*
        !            80:  * Internal functions
        !            81:  */
        !            82: static void    http_xml_send_xmlrpc_cleanup(void *arg);
        !            83: static void    http_xml_send_cleanup(void *arg);
        !            84: 
        !            85: /*
        !            86:  * Send an XML-RPC message
        !            87:  *
        !            88:  * Returns:
        !            89:  *      0      Success
        !            90:  *     -1      System error, errno is set
        !            91:  *     -2      XML-RPC fault received
        !            92:  *
        !            93:  * The reply 'rep' may be NULL to ignore any reply value, otherwise
        !            94:  * it should already be initialized.
        !            95:  *
        !            96:  * If an XML-RPC fault is received, and "faultp" is not NULL, then
        !            97:  * it will be initialized with the fault received.
        !            98:  *
        !            99:  * This properly handles the calling thread's being canceled.
        !           100:  */
        !           101: int
        !           102: http_xml_send_xmlrpc(struct http_client *client,
        !           103:        struct in_addr ip, u_int16_t port, int https,
        !           104:        const char *username, const char *password,
        !           105:        const char *methodName, u_int nparams,
        !           106:        const struct structs_type **ptypes, const void **pdatas,
        !           107:        const struct structs_type *rep_type, void *rep,
        !           108:        struct xmlrpc_compact_fault *faultp, structs_xmllog_t *rlogger)
        !           109: {
        !           110:        const struct structs_type *const xreq_type
        !           111:            = &structs_type_xmlrpc_request;
        !           112:        const struct structs_type *const xrep_type
        !           113:            = &structs_type_xmlrpc_response;
        !           114:        const struct structs_type *const ftype
        !           115:            = &structs_type_xmlrpc_compact_fault;
        !           116:        struct http_xml_send_xmlrpc_ctx *ctx;
        !           117:        struct xmlrpc_compact_fault fault;
        !           118:        char ebuf[128];
        !           119:        int ret = -1;
        !           120:        int r;
        !           121: 
        !           122:        /* Get context */
        !           123:        if ((ctx = MALLOC(MEM_TYPE, sizeof(*ctx))) == NULL) {
        !           124:                alogf(LOG_ERR, "%s: %m", "malloc");
        !           125:                return (-1);
        !           126:        }
        !           127:        memset(ctx, 0, sizeof(*ctx));
        !           128:        pthread_cleanup_push(http_xml_send_xmlrpc_cleanup, ctx);
        !           129: 
        !           130:        /* Build XML-RPC request and reply */
        !           131:        if ((ctx->xreq = structs_xmlrpc_build_request(MEM_TYPE,
        !           132:            methodName, nparams, ptypes, pdatas)) == NULL) {
        !           133:                alogf(LOG_ERR, "%s: %m", "structs_xmlrpc_build_request");
        !           134:                goto fail;
        !           135:        }
        !           136:        if ((ctx->xrep = MALLOC(MEM_TYPE, xrep_type->size)) == NULL) {
        !           137:                alogf(LOG_ERR, "%s: %m", "malloc");
        !           138:                goto fail;
        !           139:        }
        !           140:        if (structs_init(xrep_type, NULL, ctx->xrep) == -1) {
        !           141:                alogf(LOG_ERR, "%s: %m", "structs_init");
        !           142:                FREE(MEM_TYPE, ctx->xrep);
        !           143:                ctx->xrep = NULL;
        !           144:                goto fail;
        !           145:        }
        !           146: 
        !           147: #ifdef XML_RPC_DEBUG
        !           148:        printf("%s: sending this XML-RPC request:\n", __FUNCTION__);
        !           149:        (void)structs_xml_output(xreq_type, XML_RPC_REQUEST_TAG,
        !           150:            NULL, ctx->xreq, stdout, NULL, 0);
        !           151: #endif
        !           152: 
        !           153:        /* Send request and get reply; note: we could get canceled here. */
        !           154:        r = http_xml_send(client, ip, port, https, XML_RPC_URL,
        !           155:            username, password, XML_RPC_REQUEST_TAG, NULL, xreq_type,
        !           156:            ctx->xreq, STRUCTS_XML_FULL, XML_RPC_REPLY_TAG, NULL, NULL,
        !           157:            xrep_type, ctx->xrep, 0, rlogger);
        !           158: 
        !           159: #ifdef XML_RPC_DEBUG
        !           160:        printf("%s: got this XML-RPC reply (error=%s):\n",
        !           161:            __FUNCTION__, r == -1 ? strerror(errno) : "none");
        !           162:        (void)structs_xml_output(xrep_type, XML_RPC_REPLY_TAG,
        !           163:            NULL, ctx->xrep, stdout, NULL, 0);
        !           164: #endif
        !           165: 
        !           166:        /* Check error */
        !           167:        if (r == -1)
        !           168:                goto fail;
        !           169: 
        !           170:        /* Check for fault */
        !           171:        if (structs_init(ftype, NULL, &fault) == -1) {
        !           172:                alogf(LOG_ERR, "%s: %m", "structs_init");
        !           173:                goto fail;
        !           174:        }
        !           175:        if (structs_xmlrpc2struct(xrep_type, ctx->xrep,
        !           176:            "fault.value", ftype, &fault, NULL, NULL, 0) == 0) {
        !           177:                if (faultp != NULL)
        !           178:                        *faultp = fault;
        !           179:                else
        !           180:                        structs_free(ftype, NULL, &fault);
        !           181:                ret = -2;                       /* -2 indicates fault */
        !           182:                goto fail;
        !           183:        }
        !           184:        structs_free(ftype, NULL, &fault);
        !           185: 
        !           186:        /* Extract response (if desired) */
        !           187:        if (rep != NULL) {
        !           188:                if (rep_type != NULL) {         /* return compact type */
        !           189:                        if (structs_xmlrpc2struct(xrep_type, ctx->xrep,
        !           190:                            "params.0.value", rep_type, rep, NULL, ebuf,
        !           191:                            sizeof(ebuf)) == -1) {
        !           192:                                (*rlogger)(LOG_ERR, "error decoding XML-RPC"
        !           193:                                    " response: %s", ebuf);
        !           194:                                goto fail;
        !           195:                        }
        !           196:                } else {                        /* return exploded type */
        !           197:                        if (structs_get(&structs_type_xmlrpc_value,
        !           198:                            "params.0.value", ctx->xrep, rep) == -1) {
        !           199:                                alogf(LOG_ERR, "structs_get: %m");
        !           200:                                goto fail;
        !           201:                        }
        !           202:                }
        !           203:        }
        !           204: 
        !           205:        /* OK */
        !           206:        ret = 0;
        !           207: 
        !           208: fail:;
        !           209:        /* Done */
        !           210:        pthread_cleanup_pop(1);
        !           211:        return (ret);
        !           212: }
        !           213: 
        !           214: /*
        !           215:  * Cleanup for http_xml_send_xmlrpc()
        !           216:  */
        !           217: static void
        !           218: http_xml_send_xmlrpc_cleanup(void *arg)
        !           219: {
        !           220:        struct http_xml_send_xmlrpc_ctx *const ctx = arg;
        !           221:        const struct structs_type *const xreq_type
        !           222:            = &structs_type_xmlrpc_request;
        !           223:        const struct structs_type *const xrep_type
        !           224:            = &structs_type_xmlrpc_response;
        !           225: 
        !           226:        if (ctx->xreq != NULL) {
        !           227:                structs_free(xreq_type, NULL, ctx->xreq);
        !           228:                FREE(MEM_TYPE, ctx->xreq);
        !           229:        }
        !           230:        if (ctx->xrep != NULL) {
        !           231:                structs_free(xrep_type, NULL, ctx->xrep);
        !           232:                FREE(MEM_TYPE, ctx->xrep);
        !           233:        }
        !           234:        FREE(MEM_TYPE, ctx);
        !           235: }
        !           236: 
        !           237: /*
        !           238:  * Send a copy of the message, wait for a reply, and return the reply.
        !           239:  *
        !           240:  * The "reply" should already be initialized.
        !           241:  *
        !           242:  * This properly handles the calling thread's being canceled.
        !           243:  */
        !           244: int
        !           245: http_xml_send(struct http_client *client, struct in_addr ip,
        !           246:        u_int16_t port, int https, const char *urlpath, const char *username,
        !           247:        const char *password, const char *ptag, const char *pattrs,
        !           248:        const struct structs_type *ptype, const void *payload, int pflags,
        !           249:        const char *rtag, char **rattrsp, const char *rattrs_mtype,
        !           250:        const struct structs_type *rtype, void *reply, int rflags,
        !           251:        structs_xmllog_t *rlogger)
        !           252: {
        !           253:        struct http_client_connection *cc;
        !           254:        struct http_request *req;
        !           255:        struct http_response *resp;
        !           256:        int ret = -1;
        !           257:        u_int code;
        !           258:        FILE *fp;
        !           259: 
        !           260:        /* Get HTTP connection */
        !           261:        if ((cc = http_client_connect(client, ip, port, https)) == NULL) {
        !           262:                alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           263:                    "get HTTP client", inet_ntoa(ip), port);
        !           264:                return -1;
        !           265:        }
        !           266: 
        !           267:        /* Push cleanup hook */
        !           268:        pthread_cleanup_push(http_xml_send_cleanup, cc);
        !           269: 
        !           270:        /* Set up request */
        !           271:        req = http_client_get_request(cc);
        !           272:        if (http_request_set_method(req,
        !           273:            payload != NULL ? HTTP_METHOD_POST : HTTP_METHOD_GET) == -1) {
        !           274:                alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           275:                    "set method", inet_ntoa(ip), port);
        !           276:                goto fail;
        !           277:        }
        !           278:        if (http_request_set_path(req, urlpath) == -1) {
        !           279:                alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           280:                    "set path", inet_ntoa(ip), port);
        !           281:                goto fail;
        !           282:        }
        !           283:        if (http_request_set_header(req, 0, "Content-Type", "text/xml") == -1) {
        !           284:                alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           285:                    "set content-type", inet_ntoa(ip), port);
        !           286:                goto fail;
        !           287:        }
        !           288:        if (username != NULL && password != NULL) {
        !           289:                char *auth;
        !           290: 
        !           291:                if ((auth = http_request_encode_basic_auth(TYPED_MEM_TEMP,
        !           292:                    username, password)) == NULL) {
        !           293:                        alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           294:                            "encode authorization", inet_ntoa(ip), port);
        !           295:                        goto fail;
        !           296:                }
        !           297:                if (http_request_set_header(req, 0, "Authorization",
        !           298:                    "Basic %s", auth) == -1) {
        !           299:                        alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           300:                            "set authorization header", inet_ntoa(ip), port);
        !           301:                        FREE(TYPED_MEM_TEMP, auth);
        !           302:                        goto fail;
        !           303:                }
        !           304:                FREE(TYPED_MEM_TEMP, auth);
        !           305:        }
        !           306: 
        !           307:        /* Write XML data to HTTP client output stream */
        !           308:        if (payload != NULL) {
        !           309:                if ((fp = http_request_get_output(req, 1)) == NULL) {
        !           310:                        alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           311:                            "get output", inet_ntoa(ip), port);
        !           312:                        goto fail;
        !           313:                }
        !           314:                if (structs_xml_output(ptype,
        !           315:                    ptag, pattrs, payload, fp, NULL, pflags) == -1) {
        !           316:                        alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           317:                            "write XML", inet_ntoa(ip), port);
        !           318:                        goto fail;
        !           319:                }
        !           320:        }
        !           321: 
        !           322:        /* Get response */
        !           323:        if ((resp = http_client_get_response(cc)) == NULL) {
        !           324:                alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           325:                    "get response", inet_ntoa(ip), port);
        !           326:                goto fail;
        !           327:        }
        !           328:        if ((code = http_response_get_code(resp)) != HTTP_STATUS_OK) {
        !           329:                alogf(LOG_ERR, "rec'd HTTP error code %d from"
        !           330:                    "http%s://%s:%u%s: %s", code, https ? "s" : "",
        !           331:                    inet_ntoa(ip), port, urlpath,
        !           332:                    http_response_status_msg(code));
        !           333:                goto fail;
        !           334:        }
        !           335: 
        !           336:        /* Read XML reply from client input stream */
        !           337:        if ((fp = http_response_get_input(resp)) == NULL) {
        !           338:                alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           339:                    "get input", inet_ntoa(ip), port);
        !           340:                goto fail;
        !           341:        }
        !           342:        if (structs_xml_input(rtype, rtag, rattrsp,
        !           343:            rattrs_mtype, fp, reply, rflags, rlogger) == -1) {
        !           344:                alogf(LOG_ERR, "can't %s for %s:%u: %m",
        !           345:                    "read XML reply", inet_ntoa(ip), port);
        !           346:                goto fail;
        !           347:        }
        !           348: 
        !           349:        /* OK */
        !           350:        ret = 0;
        !           351: 
        !           352: fail:;
        !           353:        /* Done */
        !           354:        pthread_cleanup_pop(1);
        !           355:        return (ret);
        !           356: }
        !           357: 
        !           358: /*
        !           359:  * Cleanup for http_xml_send()
        !           360:  */
        !           361: static void
        !           362: http_xml_send_cleanup(void *arg)
        !           363: {
        !           364:        struct http_client_connection *cc = arg;
        !           365: 
        !           366:        http_client_close(&cc);
        !           367: }
        !           368: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>