4 * @brief Implementation of request_t.
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
31 #include <ClearSilver/ClearSilver.h>
33 typedef struct private_request_t private_request_t
;
36 * private data of the task manager
38 struct private_request_t
{
46 * FastCGI request object
51 * ClearSilver CGI Kit context
56 * ClearSilver HDF dataset for this request
62 * key to a thread specific FCGX_Request, used for ClearSilver cgiwrap callbacks.
63 * ClearSilver cgiwrap is not threadsave, so we use a private
64 * context for each thread.
66 static pthread_key_t req_key
;
69 * length of param list in req->envp
71 static pthread_key_t req_env_len_key
;
74 * control variable for pthread_once
76 pthread_once_t once
= PTHREAD_ONCE_INIT
;
79 * fcgiwrap read callback
81 static int read_cb(void *null
, char *buf
, int size
)
83 FCGX_Request
*req
= (FCGX_Request
*)pthread_getspecific(req_key
);
84 return FCGX_GetStr(buf
, size
, req
->in
);
88 * fcgiwrap writef callback
90 static int writef_cb(void *null
, const char *format
, va_list args
)
92 FCGX_Request
*req
= (FCGX_Request
*)pthread_getspecific(req_key
);
93 FCGX_VFPrintF(req
->out
, format
, args
);
97 * fcgiwrap write callback
99 static int write_cb(void *null
, const char *buf
, int size
)
101 FCGX_Request
*req
= (FCGX_Request
*)pthread_getspecific(req_key
);
102 return FCGX_PutStr(buf
, size
, req
->out
);
106 * fcgiwrap getenv callback
108 static char *getenv_cb(void *null
, const char *key
)
111 FCGX_Request
*req
= (FCGX_Request
*)pthread_getspecific(req_key
);
112 value
= FCGX_GetParam(key
, req
->envp
);
113 return value ?
strdup(value
) : NULL
;
117 * fcgiwrap getenv callback
119 static int putenv_cb(void *null
, const char *key
, const char *value
)
126 * fcgiwrap iterenv callback
128 static int iterenv_cb(void *null
, int num
, char **key
, char **value
)
132 FCGX_Request
*req
= (FCGX_Request
*)pthread_getspecific(req_key
);
133 int req_env_len
= (int)pthread_getspecific(req_env_len_key
);
134 if (num
< req_env_len
)
138 eq
= strchr(req
->envp
[num
], '=');
141 *key
= strndup(req
->envp
[num
], eq
- req
->envp
[num
]);
142 *value
= strdup(eq
+ 1);
144 if (*key
== NULL
|| *value
== NULL
)
155 * Implementation of request_t.get_cookie.
157 static char* get_cookie(private_request_t
*this, char *name
)
159 return hdf_get_valuef(this->hdf
, "Cookie.%s", name
);
163 * Implementation of request_t.get_path.
165 static char* get_path(private_request_t
*this)
167 char * path
= FCGX_GetParam("PATH_INFO", this->req
->envp
);
168 return path ? path
: "";
172 * Implementation of request_t.get_post_data.
174 static char* get_query_data(private_request_t
*this, char *name
)
176 return hdf_get_valuef(this->hdf
, "Query.%s", name
);
180 * Implementation of request_t.add_cookie.
182 static void add_cookie(private_request_t
*this, char *name
, char *value
)
184 cgi_cookie_set (this->cgi
, name
, value
,
185 FCGX_GetParam("SCRIPT_NAME", this->req
->envp
),
190 * Implementation of request_t.redirect.
192 static void redirect(private_request_t
*this, char *fmt
, ...)
196 FCGX_FPrintF(this->req
->out
, "Status: 303 See Other\n");
197 FCGX_FPrintF(this->req
->out
, "Location: %s%s",
198 FCGX_GetParam("SCRIPT_NAME", this->req
->envp
),
199 *fmt
== '/' ?
"" : "/");
201 FCGX_VFPrintF(this->req
->out
, fmt
, args
);
203 FCGX_FPrintF(this->req
->out
, "\n\n");
207 * Implementation of request_t.get_base.
209 static char* get_base(private_request_t
*this)
211 return FCGX_GetParam("SCRIPT_NAME", this->req
->envp
);
215 * Implementation of request_t.serve.
217 static void serve(private_request_t
*this, char *headers
, chunk_t chunk
)
219 FCGX_FPrintF(this->req
->out
, "%s\n\n", headers
);
221 FCGX_PutStr(chunk
.ptr
, chunk
.len
, this->req
->out
);
225 * Implementation of request_t.render.
227 static void render(private_request_t
*this, char *template)
231 err
= cgi_display(this->cgi
, template);
234 cgi_neo_error(this->cgi
, err
);
241 * Implementation of request_t.set.
243 static void set(private_request_t
*this, char *key
, char *value
)
245 hdf_set_value(this->hdf
, key
, value
);
249 * Implementation of request_t.setf.
251 static void setf(private_request_t
*this, char *format
, ...)
255 va_start(args
, format
);
256 hdf_set_valuevf(this->hdf
, format
, args
);
261 * Implementation of request_t.destroy
263 static void destroy(private_request_t
*this)
265 cgi_destroy(&this->cgi
);
270 * This initialization method is guaranteed to run only once
273 static void init(void)
275 cgiwrap_init_emu(NULL
, read_cb
, writef_cb
, write_cb
,
276 getenv_cb
, putenv_cb
, iterenv_cb
);
277 pthread_key_create(&req_key
, NULL
);
278 pthread_key_create(&req_env_len_key
, NULL
);
284 request_t
*request_create(FCGX_Request
*request
, bool debug
)
287 private_request_t
*this = malloc_thing(private_request_t
);
289 this->public.get_path
= (char*(*)(request_t
*))get_path
;
290 this->public.get_base
= (char*(*)(request_t
*))get_base
;
291 this->public.add_cookie
= (void(*)(request_t
*, char *name
, char *value
))add_cookie
;
292 this->public.get_cookie
= (char*(*)(request_t
*,char*))get_cookie
;
293 this->public.get_query_data
= (char*(*)(request_t
*, char *name
))get_query_data
;
294 this->public.redirect
= (void(*)(request_t
*, char *fmt
,...))redirect
;
295 this->public.render
= (void(*)(request_t
*,char*))render
;
296 this->public.serve
= (void(*)(request_t
*,char*,chunk_t
))serve
;
297 this->public.set
= (void(*)(request_t
*, char *, char*))set
;
298 this->public.setf
= (void(*)(request_t
*, char *format
, ...))setf
;
299 this->public.destroy
= (void(*)(request_t
*))destroy
;
301 pthread_once(&once
, init
);
304 pthread_setspecific(req_key
, (void*)request
);
307 while (request
->envp
[req_env_len
] != NULL
)
312 pthread_setspecific(req_env_len_key
, (void*)req_env_len
);
314 err
= hdf_init(&this->hdf
);
317 hdf_set_value(this->hdf
, "base", get_base(this));
318 hdf_set_value(this->hdf
, "Config.NoCache", "true");
321 hdf_set_value(this->hdf
, "Config.TimeFooter", "0");
322 hdf_set_value(this->hdf
, "Config.CompressionEnabled", "1");
323 hdf_set_value(this->hdf
, "Config.WhiteSpaceStrip", "2");
326 err
= cgi_init(&this->cgi
, this->hdf
);
329 err
= cgi_parse(this->cgi
);
332 return &this->public;
334 cgi_destroy(&this->cgi
);