2 * Copyright (C) 2007 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
25 #include <ClearSilver/ClearSilver.h>
27 #include <threading/thread.h>
28 #include <threading/thread_value.h>
30 typedef struct private_request_t private_request_t
;
33 * private data of the task manager
35 struct private_request_t
{
43 * FastCGI request object
48 * length of the req.envp array
53 * ClearSilver CGI Kit context
58 * ClearSilver HDF dataset for this request
74 * ClearSilver cgiwrap is not threadsave, so we use a private
75 * context for each thread.
77 static thread_value_t
*thread_this
;
80 * control variable for pthread_once
82 pthread_once_t once
= PTHREAD_ONCE_INIT
;
85 * fcgiwrap read callback
87 static int read_cb(void *null
, char *buf
, int size
)
89 private_request_t
*this = (private_request_t
*)thread_this
->get(thread_this
);
91 return FCGX_GetStr(buf
, size
, this->req
.in
);
95 * fcgiwrap writef callback
97 static int writef_cb(void *null
, const char *format
, va_list args
)
99 private_request_t
*this = (private_request_t
*)thread_this
->get(thread_this
);
101 FCGX_VFPrintF(this->req
.out
, format
, args
);
105 * fcgiwrap write callback
107 static int write_cb(void *null
, const char *buf
, int size
)
109 private_request_t
*this = (private_request_t
*)thread_this
->get(thread_this
);
111 return FCGX_PutStr(buf
, size
, this->req
.out
);
115 * fcgiwrap getenv callback
117 static char *getenv_cb(void *null
, const char *key
)
120 private_request_t
*this = (private_request_t
*)thread_this
->get(thread_this
);
122 value
= FCGX_GetParam(key
, this->req
.envp
);
123 return value ?
strdup(value
) : NULL
;
127 * fcgiwrap getenv callback
129 static int putenv_cb(void *null
, const char *key
, const char *value
)
136 * fcgiwrap iterenv callback
138 static int iterenv_cb(void *null
, int num
, char **key
, char **value
)
142 private_request_t
*this = (private_request_t
*)thread_this
->get(thread_this
);
143 if (num
< this->req_env_len
)
147 eq
= strchr(this->req
.envp
[num
], '=');
150 *key
= strndup(this->req
.envp
[num
], eq
- this->req
.envp
[num
]);
151 *value
= strdup(eq
+ 1);
153 if (*key
== NULL
|| *value
== NULL
)
164 * Implementation of request_t.get_cookie.
166 static char* get_cookie(private_request_t
*this, char *name
)
168 return hdf_get_valuef(this->hdf
, "Cookie.%s", name
);
172 * Implementation of request_t.get_path.
174 static char* get_path(private_request_t
*this)
176 char * path
= FCGX_GetParam("PATH_INFO", this->req
.envp
);
177 return path ? path
: "";
181 * Implementation of request_t.get_host.
183 static char* get_host(private_request_t
*this)
185 char *addr
= FCGX_GetParam("REMOTE_ADDR", this->req
.envp
);
186 return addr ? addr
: "";
190 * Implementation of request_t.get_user_agent.
192 static char* get_user_agent(private_request_t
*this)
194 char *agent
= FCGX_GetParam("HTTP_USER_AGENT", this->req
.envp
);
195 return agent ? agent
: "";
199 * Implementation of request_t.get_post_data.
201 static char* get_query_data(private_request_t
*this, char *name
)
203 return hdf_get_valuef(this->hdf
, "Query.%s", name
);
207 * Implementation of request_t.get_env_var.
209 static char* get_env_var(private_request_t
*this, char *name
)
211 return FCGX_GetParam(name
, this->req
.envp
);
215 * Implementation of request_t.read_data.
217 static int read_data(private_request_t
*this, char *buf
, int len
)
219 return FCGX_GetStr(buf
, len
, this->req
.in
);
223 * Implementation of request_t.get_base.
225 static char* get_base(private_request_t
*this)
227 return FCGX_GetParam("SCRIPT_NAME", this->req
.envp
);
231 * Implementation of request_t.add_cookie.
233 static void add_cookie(private_request_t
*this, char *name
, char *value
)
235 thread_this
->set(thread_this
, this);
236 cgi_cookie_set (this->cgi
, name
, value
, get_base(this), NULL
, NULL
, 0, 0);
240 * Implementation of request_t.redirect.
242 static void redirect(private_request_t
*this, char *fmt
, ...)
246 FCGX_FPrintF(this->req
.out
, "Status: 303 See Other\n");
247 FCGX_FPrintF(this->req
.out
, "Location: %s%s", get_base(this),
248 *fmt
== '/' ?
"" : "/");
250 FCGX_VFPrintF(this->req
.out
, fmt
, args
);
252 FCGX_FPrintF(this->req
.out
, "\n\n");
256 * Implementation of request_t.get_referer.
258 static char* get_referer(private_request_t
*this)
260 return FCGX_GetParam("HTTP_REFERER", this->req
.envp
);
264 * Implementation of request_t.to_referer.
266 static void to_referer(private_request_t
*this)
270 referer
= get_referer(this);
273 FCGX_FPrintF(this->req
.out
, "Status: 303 See Other\n");
274 FCGX_FPrintF(this->req
.out
, "Location: %s\n\n", referer
);
283 * Implementation of request_t.session_closed.
285 static bool session_closed(private_request_t
*this)
291 * Implementation of request_t.close_session.
293 static void close_session(private_request_t
*this)
299 * Implementation of request_t.serve.
301 static void serve(private_request_t
*this, char *headers
, chunk_t chunk
)
303 FCGX_FPrintF(this->req
.out
, "%s\n\n", headers
);
305 FCGX_PutStr(chunk
.ptr
, chunk
.len
, this->req
.out
);
309 * Implementation of request_t.render.
311 static void render(private_request_t
*this, char *template)
315 thread_this
->set(thread_this
, this);
316 err
= cgi_display(this->cgi
, template);
319 cgi_neo_error(this->cgi
, err
);
326 * Implementation of request_t.streamf.
328 static int streamf(private_request_t
*this, char *format
, ...)
333 va_start(args
, format
);
334 written
= FCGX_VFPrintF(this->req
.out
, format
, args
);
337 FCGX_FFlush(this->req
.out
) == -1)
345 * Implementation of request_t.set.
347 static void set(private_request_t
*this, char *key
, char *value
)
349 hdf_set_value(this->hdf
, key
, value
);
353 * Implementation of request_t.setf.
355 static void setf(private_request_t
*this, char *format
, ...)
359 va_start(args
, format
);
360 hdf_set_valuevf(this->hdf
, format
, args
);
365 * Implementation of request_t.get_ref.
367 static request_t
* get_ref(private_request_t
*this)
370 return &this->public;
374 * Implementation of request_t.destroy
376 static void destroy(private_request_t
*this)
378 if (ref_put(&this->ref
))
380 thread_this
->set(thread_this
, this);
381 cgi_destroy(&this->cgi
);
382 FCGX_Finish_r(&this->req
);
388 * This initialization method is guaranteed to run only once
391 static void init(void)
393 cgiwrap_init_emu(NULL
, read_cb
, writef_cb
, write_cb
,
394 getenv_cb
, putenv_cb
, iterenv_cb
);
395 thread_this
= thread_value_create(NULL
);
401 request_t
*request_create(int fd
, bool debug
)
404 private_request_t
*this = malloc_thing(private_request_t
);
407 thread_cleanup_push(free
, this);
408 if (FCGX_InitRequest(&this->req
, fd
, 0) != 0 ||
409 FCGX_Accept_r(&this->req
) != 0)
413 thread_cleanup_pop(failed
);
419 this->public.get_path
= (char*(*)(request_t
*))get_path
;
420 this->public.get_base
= (char*(*)(request_t
*))get_base
;
421 this->public.get_host
= (char*(*)(request_t
*))get_host
;
422 this->public.get_user_agent
= (char*(*)(request_t
*))get_user_agent
;
423 this->public.add_cookie
= (void(*)(request_t
*, char *name
, char *value
))add_cookie
;
424 this->public.get_cookie
= (char*(*)(request_t
*,char*))get_cookie
;
425 this->public.get_query_data
= (char*(*)(request_t
*, char *name
))get_query_data
;
426 this->public.get_env_var
= (char*(*)(request_t
*, char *name
))get_env_var
;
427 this->public.read_data
= (int(*)(request_t
*, char*, int))read_data
;
428 this->public.session_closed
= (bool(*)(request_t
*))session_closed
;
429 this->public.close_session
= (void(*)(request_t
*))close_session
;
430 this->public.redirect
= (void(*)(request_t
*, char *fmt
,...))redirect
;
431 this->public.get_referer
= (char*(*)(request_t
*))get_referer
;
432 this->public.to_referer
= (void(*)(request_t
*))to_referer
;
433 this->public.render
= (void(*)(request_t
*,char*))render
;
434 this->public.streamf
= (int(*)(request_t
*, char *format
, ...))streamf
;
435 this->public.serve
= (void(*)(request_t
*,char*,chunk_t
))serve
;
436 this->public.set
= (void(*)(request_t
*, char *, char*))set
;
437 this->public.setf
= (void(*)(request_t
*, char *format
, ...))setf
;
438 this->public.get_ref
= (request_t
*(*)(request_t
*))get_ref
;
439 this->public.destroy
= (void(*)(request_t
*))destroy
;
441 pthread_once(&once
, init
);
442 thread_this
->set(thread_this
, this);
445 this->closed
= FALSE
;
446 this->req_env_len
= 0;
447 while (this->req
.envp
[this->req_env_len
] != NULL
)
452 err
= hdf_init(&this->hdf
);
455 hdf_set_value(this->hdf
, "base", get_base(this));
456 hdf_set_value(this->hdf
, "Config.NoCache", "true");
459 hdf_set_value(this->hdf
, "Config.TimeFooter", "0");
460 hdf_set_value(this->hdf
, "Config.CompressionEnabled", "1");
461 hdf_set_value(this->hdf
, "Config.WhiteSpaceStrip", "2");
464 err
= cgi_init(&this->cgi
, this->hdf
);
467 err
= cgi_parse(this->cgi
);
470 return &this->public;
472 cgi_destroy(&this->cgi
);
476 FCGX_Finish_r(&this->req
);