Annotation of embedaddon/strongswan/src/libfast/fast_request.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2007 Martin Willi
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: #define _GNU_SOURCE
        !            17: 
        !            18: #include "fast_request.h"
        !            19: 
        !            20: #include <library.h>
        !            21: #include <utils/debug.h>
        !            22: #include <stdlib.h>
        !            23: #include <pthread.h>
        !            24: #include <string.h>
        !            25: #include <unistd.h>
        !            26: #include <sys/stat.h>
        !            27: #include <fcntl.h>
        !            28: #include <inttypes.h>
        !            29: 
        !            30: #include <ClearSilver/ClearSilver.h>
        !            31: 
        !            32: #include <threading/thread.h>
        !            33: #include <threading/thread_value.h>
        !            34: 
        !            35: typedef struct private_fast_request_t private_fast_request_t;
        !            36: 
        !            37: /**
        !            38:  * private data of the task manager
        !            39:  */
        !            40: struct private_fast_request_t {
        !            41: 
        !            42:        /**
        !            43:         * public functions
        !            44:         */
        !            45:        fast_request_t public;
        !            46: 
        !            47:        /**
        !            48:         * FastCGI request object
        !            49:         */
        !            50:        FCGX_Request req;
        !            51: 
        !            52:        /**
        !            53:         * length of the req.envp array
        !            54:         */
        !            55:        int req_env_len;
        !            56: 
        !            57:        /**
        !            58:         * ClearSilver CGI Kit context
        !            59:         */
        !            60:        CGI *cgi;
        !            61: 
        !            62:        /**
        !            63:         * ClearSilver HDF dataset for this request
        !            64:         */
        !            65:        HDF *hdf;
        !            66: 
        !            67:        /**
        !            68:         * close the session?
        !            69:         */
        !            70:        bool closed;
        !            71: 
        !            72:        /**
        !            73:         * reference count
        !            74:         */
        !            75:        refcount_t ref;
        !            76: };
        !            77: 
        !            78: /**
        !            79:  * ClearSilver cgiwrap is not threadsafe, so we use a private
        !            80:  * context for each thread.
        !            81:  */
        !            82: static thread_value_t *thread_this;
        !            83: 
        !            84: /**
        !            85:  * control variable for pthread_once
        !            86:  */
        !            87: pthread_once_t once = PTHREAD_ONCE_INIT;
        !            88: 
        !            89: /**
        !            90:  * fcgiwrap read callback
        !            91:  */
        !            92: static int read_cb(void *null, char *buf, int size)
        !            93: {
        !            94:        private_fast_request_t *this;
        !            95: 
        !            96:        this = (private_fast_request_t*)thread_this->get(thread_this);
        !            97: 
        !            98:        return FCGX_GetStr(buf, size, this->req.in);
        !            99: }
        !           100: 
        !           101: /**
        !           102:  * fcgiwrap writef callback
        !           103:  */
        !           104: static int writef_cb(void *null, const char *format, va_list args)
        !           105: {
        !           106:        private_fast_request_t *this;
        !           107: 
        !           108:        this = (private_fast_request_t*)thread_this->get(thread_this);
        !           109: 
        !           110:        FCGX_VFPrintF(this->req.out, format, args);
        !           111:        return 0;
        !           112: }
        !           113: /**
        !           114:  * fcgiwrap write callback
        !           115:  */
        !           116: static int write_cb(void *null, const char *buf, int size)
        !           117: {
        !           118:        private_fast_request_t *this;
        !           119: 
        !           120:        this = (private_fast_request_t*)thread_this->get(thread_this);
        !           121: 
        !           122:        return FCGX_PutStr(buf, size, this->req.out);
        !           123: }
        !           124: 
        !           125: /**
        !           126:  * fcgiwrap getenv callback
        !           127:  */
        !           128: static char *getenv_cb(void *null, const char *key)
        !           129: {
        !           130:        char *value;
        !           131:        private_fast_request_t *this;
        !           132: 
        !           133:        this = (private_fast_request_t*)thread_this->get(thread_this);
        !           134: 
        !           135:        value = FCGX_GetParam(key, this->req.envp);
        !           136:        return strdupnull(value);
        !           137: }
        !           138: 
        !           139: /**
        !           140:  * fcgiwrap getenv callback
        !           141:  */
        !           142: static int putenv_cb(void *null, const char *key, const char *value)
        !           143: {
        !           144:        /* not supported */
        !           145:        return 1;
        !           146: }
        !           147: 
        !           148: /**
        !           149:  * fcgiwrap iterenv callback
        !           150:  */
        !           151: static int iterenv_cb(void *null, int num, char **key, char **value)
        !           152: {
        !           153:        private_fast_request_t *this;
        !           154: 
        !           155:        *key = NULL;
        !           156:        *value = NULL;
        !           157:        this = (private_fast_request_t*)thread_this->get(thread_this);
        !           158: 
        !           159:        if (num < this->req_env_len)
        !           160:        {
        !           161:                char *eq;
        !           162: 
        !           163:                eq = strchr(this->req.envp[num], '=');
        !           164:                if (eq)
        !           165:                {
        !           166:                        *key = strndup(this->req.envp[num], eq - this->req.envp[num]);
        !           167:                        *value = strdup(eq + 1);
        !           168:                }
        !           169:                if (*key == NULL || *value == NULL)
        !           170:                {
        !           171:                        free(*key);
        !           172:                        free(*value);
        !           173:                        return 1;
        !           174:                }
        !           175:        }
        !           176:        return 0;
        !           177: }
        !           178: 
        !           179: METHOD(fast_request_t, get_cookie, char*,
        !           180:        private_fast_request_t *this, char *name)
        !           181: {
        !           182:        return hdf_get_valuef(this->hdf, "Cookie.%s", name);
        !           183: }
        !           184: 
        !           185: METHOD(fast_request_t, get_path, char*,
        !           186:        private_fast_request_t *this)
        !           187: {
        !           188:        char *path = FCGX_GetParam("PATH_INFO", this->req.envp);
        !           189:        return path ? path : "";
        !           190: }
        !           191: 
        !           192: METHOD(fast_request_t, get_host, char*,
        !           193:        private_fast_request_t *this)
        !           194: {
        !           195:        char *addr = FCGX_GetParam("REMOTE_ADDR", this->req.envp);
        !           196:        return addr ? addr : "";
        !           197: }
        !           198: 
        !           199: METHOD(fast_request_t, get_user_agent, char*,
        !           200:        private_fast_request_t *this)
        !           201: {
        !           202:        char *agent = FCGX_GetParam("HTTP_USER_AGENT", this->req.envp);
        !           203:        return agent ? agent : "";
        !           204: }
        !           205: 
        !           206: METHOD(fast_request_t, get_query_data, char*,
        !           207:        private_fast_request_t *this, char *name)
        !           208: {
        !           209:        return hdf_get_valuef(this->hdf, "Query.%s", name);
        !           210: }
        !           211: 
        !           212: METHOD(fast_request_t, get_env_var, char*,
        !           213:        private_fast_request_t *this, char *name)
        !           214: {
        !           215:        return FCGX_GetParam(name, this->req.envp);
        !           216: }
        !           217: 
        !           218: METHOD(fast_request_t, read_data, int,
        !           219:        private_fast_request_t *this, char *buf, int len)
        !           220: {
        !           221:        return FCGX_GetStr(buf, len, this->req.in);
        !           222: }
        !           223: 
        !           224: METHOD(fast_request_t, get_base, char*,
        !           225:        private_fast_request_t *this)
        !           226: {
        !           227:        return FCGX_GetParam("SCRIPT_NAME", this->req.envp);
        !           228: }
        !           229: 
        !           230: METHOD(fast_request_t, add_cookie, void,
        !           231:        private_fast_request_t *this, char *name, char *value)
        !           232: {
        !           233:        thread_this->set(thread_this, this);
        !           234:        cgi_cookie_set(this->cgi, name, value, NULL, NULL, NULL, 0, 0);
        !           235: }
        !           236: 
        !           237: METHOD(fast_request_t, redirect, void,
        !           238:        private_fast_request_t *this, char *fmt, ...)
        !           239: {
        !           240:        va_list args;
        !           241: 
        !           242:        FCGX_FPrintF(this->req.out, "Status: 303 See Other\n");
        !           243:        FCGX_FPrintF(this->req.out, "Location: %s%s", get_base(this),
        !           244:                                 *fmt == '/' ? "" : "/");
        !           245:        va_start(args, fmt);
        !           246:        FCGX_VFPrintF(this->req.out, fmt, args);
        !           247:        va_end(args);
        !           248:        FCGX_FPrintF(this->req.out, "\n\n");
        !           249: }
        !           250: 
        !           251: METHOD(fast_request_t, get_referer, char*,
        !           252:        private_fast_request_t *this)
        !           253: {
        !           254:        return FCGX_GetParam("HTTP_REFERER", this->req.envp);
        !           255: }
        !           256: 
        !           257: METHOD(fast_request_t, to_referer, void,
        !           258:        private_fast_request_t *this)
        !           259: {
        !           260:        char *referer;
        !           261: 
        !           262:        referer = get_referer(this);
        !           263:        if (referer)
        !           264:        {
        !           265:                FCGX_FPrintF(this->req.out, "Status: 303 See Other\n");
        !           266:                FCGX_FPrintF(this->req.out, "Location: %s\n\n", referer);
        !           267:        }
        !           268:        else
        !           269:        {
        !           270:                redirect(this, "/");
        !           271:        }
        !           272: }
        !           273: 
        !           274: METHOD(fast_request_t, session_closed, bool,
        !           275:        private_fast_request_t *this)
        !           276: {
        !           277:        return this->closed;
        !           278: }
        !           279: 
        !           280: METHOD(fast_request_t, close_session, void,
        !           281:        private_fast_request_t *this)
        !           282: {
        !           283:        this->closed = TRUE;
        !           284: }
        !           285: 
        !           286: METHOD(fast_request_t, serve, void,
        !           287:        private_fast_request_t *this, char *headers, chunk_t chunk)
        !           288: {
        !           289:        FCGX_FPrintF(this->req.out, "%s\n\n", headers);
        !           290: 
        !           291:        FCGX_PutStr(chunk.ptr, chunk.len, this->req.out);
        !           292: }
        !           293: 
        !           294: METHOD(fast_request_t, sendfile, bool,
        !           295:        private_fast_request_t *this, char *path, char *mime)
        !           296: {
        !           297:        chunk_t *data;
        !           298:        int written;
        !           299:        char buf[24];
        !           300: 
        !           301:        data = chunk_map(path, FALSE);
        !           302:        if (!data)
        !           303:        {
        !           304:                return FALSE;
        !           305:        }
        !           306:        /* FCGX does not like large integers, print to a buffer using libc */
        !           307:        snprintf(buf, sizeof(buf), "%"PRId64, (int64_t)data->len);
        !           308:        FCGX_FPrintF(this->req.out, "Content-Length: %s\n", buf);
        !           309:        if (mime)
        !           310:        {
        !           311:                FCGX_FPrintF(this->req.out, "Content-Type: %s\n", mime);
        !           312:        }
        !           313:        FCGX_FPrintF(this->req.out, "\n");
        !           314: 
        !           315:        while (data->len)
        !           316:        {
        !           317:                written = FCGX_PutStr(data->ptr, data->len, this->req.out);
        !           318:                if (written == -1)
        !           319:                {
        !           320:                        chunk_unmap(data);
        !           321:                        return FALSE;
        !           322:                }
        !           323:                *data = chunk_skip(*data, written);
        !           324:        }
        !           325: 
        !           326:        chunk_unmap(data);
        !           327:        return TRUE;
        !           328: }
        !           329: 
        !           330: METHOD(fast_request_t, render, void,
        !           331:        private_fast_request_t *this, char *template)
        !           332: {
        !           333:        NEOERR* err;
        !           334: 
        !           335:        thread_this->set(thread_this, this);
        !           336:        err = cgi_display(this->cgi, template);
        !           337:        if (err)
        !           338:        {
        !           339:                cgi_neo_error(this->cgi, err);
        !           340:                nerr_log_error(err);
        !           341:        }
        !           342: }
        !           343: 
        !           344: METHOD(fast_request_t, streamf, int,
        !           345:        private_fast_request_t *this, char *format, ...)
        !           346: {
        !           347:        va_list args;
        !           348:        int written;
        !           349: 
        !           350:        va_start(args, format);
        !           351:        written = FCGX_VFPrintF(this->req.out, format, args);
        !           352:        va_end(args);
        !           353:        if (written >= 0 &&
        !           354:                FCGX_FFlush(this->req.out) == -1)
        !           355:        {
        !           356:                return -1;
        !           357:        }
        !           358:        return written;
        !           359: }
        !           360: 
        !           361: METHOD(fast_request_t, set, void,
        !           362:        private_fast_request_t *this, char *key, char *value)
        !           363: {
        !           364:        hdf_set_value(this->hdf, key, value);
        !           365: }
        !           366: 
        !           367: METHOD(fast_request_t, setf, void,
        !           368:        private_fast_request_t *this, char *format, ...)
        !           369: {
        !           370:        va_list args;
        !           371: 
        !           372:        va_start(args, format);
        !           373:        hdf_set_valuevf(this->hdf, format, args);
        !           374:        va_end(args);
        !           375: }
        !           376: 
        !           377: METHOD(fast_request_t, get_ref, fast_request_t*,
        !           378:        private_fast_request_t *this)
        !           379: {
        !           380:        ref_get(&this->ref);
        !           381:        return &this->public;
        !           382: }
        !           383: 
        !           384: METHOD(fast_request_t, destroy, void,
        !           385:        private_fast_request_t *this)
        !           386: {
        !           387:        if (ref_put(&this->ref))
        !           388:        {
        !           389:                thread_this->set(thread_this, this);
        !           390:                cgi_destroy(&this->cgi);
        !           391:                FCGX_Finish_r(&this->req);
        !           392:                free(this);
        !           393:        }
        !           394: }
        !           395: 
        !           396: /**
        !           397:  * This initialization method is guaranteed to run only once
        !           398:  * for all threads.
        !           399:  */
        !           400: static void init(void)
        !           401: {
        !           402:        cgiwrap_init_emu(NULL, read_cb, writef_cb, write_cb,
        !           403:                                         getenv_cb, putenv_cb, iterenv_cb);
        !           404:        thread_this = thread_value_create(NULL);
        !           405: }
        !           406: 
        !           407: /*
        !           408:  * see header file
        !           409:  */
        !           410: fast_request_t *fast_request_create(int fd, bool debug)
        !           411: {
        !           412:        NEOERR* err;
        !           413:        private_fast_request_t *this;
        !           414:        bool failed = FALSE;
        !           415: 
        !           416:        INIT(this,
        !           417:                .public = {
        !           418:                        .get_path = _get_path,
        !           419:                        .get_base = _get_base,
        !           420:                        .get_host = _get_host,
        !           421:                        .get_user_agent = _get_user_agent,
        !           422:                        .add_cookie = _add_cookie,
        !           423:                        .get_cookie = _get_cookie,
        !           424:                        .get_query_data = _get_query_data,
        !           425:                        .get_env_var = _get_env_var,
        !           426:                        .read_data = _read_data,
        !           427:                        .session_closed = _session_closed,
        !           428:                        .close_session = _close_session,
        !           429:                        .redirect = _redirect,
        !           430:                        .get_referer = _get_referer,
        !           431:                        .to_referer = _to_referer,
        !           432:                        .render = _render,
        !           433:                        .streamf = _streamf,
        !           434:                        .serve = _serve,
        !           435:                        .sendfile = _sendfile,
        !           436:                        .set = _set,
        !           437:                        .setf = _setf,
        !           438:                        .get_ref = _get_ref,
        !           439:                        .destroy = _destroy,
        !           440:                },
        !           441:                .ref = 1,
        !           442:        );
        !           443: 
        !           444:        thread_cleanup_push(free, this);
        !           445:        if (FCGX_InitRequest(&this->req, fd, 0) != 0 ||
        !           446:                FCGX_Accept_r(&this->req) != 0)
        !           447:        {
        !           448:                failed = TRUE;
        !           449:        }
        !           450:        thread_cleanup_pop(failed);
        !           451:        if (failed)
        !           452:        {
        !           453:                return NULL;
        !           454:        }
        !           455: 
        !           456:        pthread_once(&once, init);
        !           457:        thread_this->set(thread_this, this);
        !           458: 
        !           459:        while (this->req.envp[this->req_env_len] != NULL)
        !           460:        {
        !           461:                this->req_env_len++;
        !           462:        }
        !           463: 
        !           464:        err = hdf_init(&this->hdf);
        !           465:        if (!err)
        !           466:        {
        !           467:                hdf_set_value(this->hdf, "base", get_base(this));
        !           468:                hdf_set_value(this->hdf, "Config.NoCache", "true");
        !           469:                if (!debug)
        !           470:                {
        !           471:                        hdf_set_value(this->hdf, "Config.TimeFooter", "0");
        !           472:                        hdf_set_value(this->hdf, "Config.CompressionEnabled", "1");
        !           473:                        hdf_set_value(this->hdf, "Config.WhiteSpaceStrip", "2");
        !           474:                }
        !           475: 
        !           476:                err = cgi_init(&this->cgi, this->hdf);
        !           477:                if (!err)
        !           478:                {
        !           479:                        err = cgi_parse(this->cgi);
        !           480:                        if (!err)
        !           481:                        {
        !           482:                                return &this->public;
        !           483:                        }
        !           484:                        cgi_destroy(&this->cgi);
        !           485:                }
        !           486:        }
        !           487:        nerr_log_error(err);
        !           488:        FCGX_Finish_r(&this->req);
        !           489:        free(this);
        !           490:        return NULL;
        !           491: }

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