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>