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>