request_t.redirect takes variable argument list
[strongswan.git] / src / manager / lib / request.c
1 /**
2 * @file request.c
3 *
4 * @brief Implementation of request_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #define _GNU_SOURCE
24
25 #include "request.h"
26
27 #include <library.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ClearSilver/ClearSilver.h>
31
32 typedef struct private_request_t private_request_t;
33
34 /**
35 * private data of the task manager
36 */
37 struct private_request_t {
38
39 /**
40 * public functions
41 */
42 request_t public;
43
44 /**
45 * FastCGI request object
46 */
47 FCGX_Request *req;
48
49 /**
50 * ClearSilver CGI Kit context
51 */
52 CGI *cgi;
53
54 /**
55 * ClearSilver HDF dataset for this request
56 */
57 HDF *hdf;
58 };
59
60 /**
61 * thread specific FCGX_Request, used for ClearSilver cgiwrap callbacks.
62 * ClearSilver cgiwrap is not threadsave, so we use a private
63 * context for each thread.
64 */
65 static __thread FCGX_Request *req;
66
67 /**
68 * length of param list in req->envp
69 */
70 static __thread int req_env_len;
71
72 /**
73 * fcgiwrap read callback
74 */
75 static int read_cb(void *null, char *buf, int size)
76 {
77 return FCGX_GetStr(buf, size, req->in);
78 }
79
80 /**
81 * fcgiwrap writef callback
82 */
83 static int writef_cb(void *null, const char *format, va_list args)
84 {
85 FCGX_VFPrintF(req->out, format, args);
86 return 0;
87 }
88 /**
89 * fcgiwrap write callback
90 */
91 static int write_cb(void *null, const char *buf, int size)
92 {
93 return FCGX_PutStr(buf, size, req->out);
94 }
95
96 /**
97 * fcgiwrap getenv callback
98 */
99 static char *getenv_cb(void *null, const char *key)
100 {
101 char *value;
102
103 value = FCGX_GetParam(key, req->envp);
104 return value ? strdup(value) : NULL;
105 }
106
107 /**
108 * fcgiwrap getenv callback
109 */
110 static int putenv_cb(void *null, const char *key, const char *value)
111 {
112 /* not supported */
113 return 1;
114 }
115
116 /**
117 * fcgiwrap iterenv callback
118 */
119 static int iterenv_cb(void *null, int num, char **key, char **value)
120 {
121 *key = NULL;
122 *value = NULL;
123
124 if (num < req_env_len)
125 {
126 char *eq;
127
128 eq = strchr(req->envp[num], '=');
129 if (eq)
130 {
131 *key = strndup(req->envp[num], eq - req->envp[num]);
132 *value = strdup(eq + 1);
133 }
134 if (*key == NULL || *value == NULL)
135 {
136 free(*key);
137 free(*value);
138 return 1;
139 }
140 }
141 return 0;
142 }
143
144 /**
145 * Implementation of request_t.get_cookie.
146 */
147 static char* get_cookie(private_request_t *this, char *name)
148 {
149 return hdf_get_valuef(this->hdf, "Cookie.%s", name);
150 }
151
152 /**
153 * Implementation of request_t.get_path.
154 */
155 static char* get_path(private_request_t *this)
156 {
157 char * path = FCGX_GetParam("PATH_INFO", this->req->envp);
158 return path ? path : "";
159 }
160
161 /**
162 * Implementation of request_t.get_post_data.
163 */
164 static char* get_query_data(private_request_t *this, char *name)
165 {
166 return hdf_get_valuef(this->hdf, "Query.%s", name);
167 }
168
169 /**
170 * Implementation of request_t.add_cookie.
171 */
172 static void add_cookie(private_request_t *this, char *name, char *value)
173 {
174 cgi_cookie_set (this->cgi, name, value,
175 FCGX_GetParam("SCRIPT_NAME", this->req->envp),
176 NULL, NULL, 0, 0);
177 }
178
179 /**
180 * Implementation of request_t.redirect.
181 */
182 static void redirect(private_request_t *this, char *fmt, ...)
183 {
184 va_list args;
185
186 FCGX_FPrintF(this->req->out, "Status: 303 See Other\n");
187 FCGX_FPrintF(this->req->out, "Location: %s%s",
188 FCGX_GetParam("SCRIPT_NAME", this->req->envp),
189 *fmt == '/' ? "" : "/");
190 va_start(args, fmt);
191 FCGX_VFPrintF(this->req->out, fmt, args);
192 va_end(args);
193 FCGX_FPrintF(this->req->out, "\n\n");
194 }
195
196 /**
197 * Implementation of request_t.get_base.
198 */
199 static char* get_base(private_request_t *this)
200 {
201 return FCGX_GetParam("SCRIPT_NAME", this->req->envp);
202 }
203
204 /**
205 * Implementation of request_t.serve.
206 */
207 static void serve(private_request_t *this, char *headers, chunk_t chunk)
208 {
209 FCGX_FPrintF(this->req->out, "%s\n\n", headers);
210
211 FCGX_PutStr(chunk.ptr, chunk.len, this->req->out);
212 }
213
214 /**
215 * Implementation of request_t.render.
216 */
217 static void render(private_request_t *this, char *template)
218 {
219 NEOERR* err;
220
221 err = cgi_display(this->cgi, template);
222 if (err)
223 {
224 cgi_neo_error(this->cgi, err);
225 nerr_log_error(err);
226 }
227 return;
228 }
229
230 /**
231 * Implementation of request_t.set.
232 */
233 static void set(private_request_t *this, char *key, char *value)
234 {
235 hdf_set_value(this->hdf, key, value);
236 }
237
238 /**
239 * Implementation of request_t.setf.
240 */
241 static void setf(private_request_t *this, char *format, ...)
242 {
243 va_list args;
244
245 va_start(args, format);
246 hdf_set_valuevf(this->hdf, format, args);
247 va_end(args);
248 }
249
250 /**
251 * Implementation of request_t.destroy
252 */
253 static void destroy(private_request_t *this)
254 {
255 cgi_destroy(&this->cgi);
256 free(this);
257 }
258
259 /*
260 * see header file
261 */
262 request_t *request_create(FCGX_Request *request, bool debug)
263 {
264 NEOERR* err;
265 static bool initialized = FALSE;
266 private_request_t *this = malloc_thing(private_request_t);
267
268 this->public.get_path = (char*(*)(request_t*))get_path;
269 this->public.get_base = (char*(*)(request_t*))get_base;
270 this->public.add_cookie = (void(*)(request_t*, char *name, char *value))add_cookie;
271 this->public.get_cookie = (char*(*)(request_t*,char*))get_cookie;
272 this->public.get_query_data = (char*(*)(request_t*, char *name))get_query_data;
273 this->public.redirect = (void(*)(request_t*, char *fmt,...))redirect;
274 this->public.render = (void(*)(request_t*,char*))render;
275 this->public.serve = (void(*)(request_t*,char*,chunk_t))serve;
276 this->public.set = (void(*)(request_t*, char *, char*))set;
277 this->public.setf = (void(*)(request_t*, char *format, ...))setf;
278 this->public.destroy = (void(*)(request_t*))destroy;
279
280 if (!initialized)
281 {
282 cgiwrap_init_emu(NULL, read_cb, writef_cb, write_cb,
283 getenv_cb, putenv_cb, iterenv_cb);
284 initialized = TRUE;
285 }
286
287 this->req = request;
288 req = request;
289 req_env_len = 0;
290 while (req->envp[req_env_len] != NULL)
291 {
292 req_env_len++;
293 }
294
295 err = hdf_init(&this->hdf);
296 if (!err)
297 {
298 hdf_set_value(this->hdf, "base", get_base(this));
299 hdf_set_value(this->hdf, "Config.NoCache", "true");
300 if (!debug)
301 {
302 hdf_set_value(this->hdf, "Config.TimeFooter", "0");
303 hdf_set_value(this->hdf, "Config.CompressionEnabled", "1");
304 hdf_set_value(this->hdf, "Config.WhiteSpaceStrip", "2");
305 }
306
307 err = cgi_init(&this->cgi, this->hdf);
308 if (!err)
309 {
310 err = cgi_parse(this->cgi);
311 if (!err)
312 {
313 return &this->public;
314 }
315 cgi_destroy(&this->cgi);
316 }
317 }
318 nerr_log_error(err);
319 free(this);
320 return NULL;
321 }
322