Annotation of embedaddon/strongswan/src/libfast/fast_request.c, revision 1.1.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>