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
27 #include <ClearSilver/ClearSilver.h>
29 typedef struct private_request_t private_request_t
;
32 * private data of the task manager
34 struct private_request_t
{
42 * FastCGI request object
47 * length of the req.envp array
52 * ClearSilver CGI Kit context
57 * ClearSilver HDF dataset for this request
73 * key to a the threads "this" request, used for ClearSilver cgiwrap callbacks.
74 * ClearSilver cgiwrap is not threadsave, so we use a private
75 * context for each thread.
77 static pthread_key_t this_key
;
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
*)pthread_getspecific(this_key
);
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
*)pthread_getspecific(this_key
);
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
*)pthread_getspecific(this_key
);
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
*)pthread_getspecific(this_key
);
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
*)pthread_getspecific(this_key
);
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.add_cookie.
209 static void add_cookie(private_request_t
*this, char *name
, char *value
)
211 pthread_setspecific(this_key
, this);
212 cgi_cookie_set (this->cgi
, name
, value
,
213 FCGX_GetParam("SCRIPT_NAME", this->req
.envp
),
218 * Implementation of request_t.redirect.
220 static void redirect(private_request_t
*this, char *fmt
, ...)
224 FCGX_FPrintF(this->req
.out
, "Status: 303 See Other\n");
225 FCGX_FPrintF(this->req
.out
, "Location: %s%s",
226 FCGX_GetParam("SCRIPT_NAME", this->req
.envp
),
227 *fmt
== '/' ?
"" : "/");
229 FCGX_VFPrintF(this->req
.out
, fmt
, args
);
231 FCGX_FPrintF(this->req
.out
, "\n\n");
235 * Implementation of request_t.to_referer.
237 static void to_referer(private_request_t
*this)
239 FCGX_FPrintF(this->req
.out
, "Status: 303 See Other\n");
240 FCGX_FPrintF(this->req
.out
, "Location: %s\n\n",
241 FCGX_GetParam("HTTP_REFERER", this->req
.envp
));
245 * Implementation of request_t.get_base.
247 static char* get_base(private_request_t
*this)
249 return FCGX_GetParam("SCRIPT_NAME", this->req
.envp
);
253 * Implementation of request_t.session_closed.
255 static bool session_closed(private_request_t
*this)
261 * Implementation of request_t.close_session.
263 static void close_session(private_request_t
*this)
269 * Implementation of request_t.serve.
271 static void serve(private_request_t
*this, char *headers
, chunk_t chunk
)
273 FCGX_FPrintF(this->req
.out
, "%s\n\n", headers
);
275 FCGX_PutStr(chunk
.ptr
, chunk
.len
, this->req
.out
);
279 * Implementation of request_t.render.
281 static void render(private_request_t
*this, char *template)
285 pthread_setspecific(this_key
, this);
286 err
= cgi_display(this->cgi
, template);
289 cgi_neo_error(this->cgi
, err
);
296 * Implementation of request_t.streamf.
298 static int streamf(private_request_t
*this, char *format
, ...)
303 va_start(args
, format
);
304 written
= FCGX_VFPrintF(this->req
.out
, format
, args
);
307 FCGX_FFlush(this->req
.out
) == -1)
315 * Implementation of request_t.set.
317 static void set(private_request_t
*this, char *key
, char *value
)
319 hdf_set_value(this->hdf
, key
, value
);
323 * Implementation of request_t.setf.
325 static void setf(private_request_t
*this, char *format
, ...)
329 va_start(args
, format
);
330 hdf_set_valuevf(this->hdf
, format
, args
);
335 * Implementation of request_t.get_ref.
337 static request_t
* get_ref(private_request_t
*this)
340 return &this->public;
344 * Implementation of request_t.destroy
346 static void destroy(private_request_t
*this)
348 if (ref_put(&this->ref
))
350 pthread_setspecific(this_key
, this);
351 cgi_destroy(&this->cgi
);
352 FCGX_Finish_r(&this->req
);
358 * This initialization method is guaranteed to run only once
361 static void init(void)
363 cgiwrap_init_emu(NULL
, read_cb
, writef_cb
, write_cb
,
364 getenv_cb
, putenv_cb
, iterenv_cb
);
365 pthread_key_create(&this_key
, NULL
);
371 request_t
*request_create(int fd
, bool debug
)
374 private_request_t
*this = malloc_thing(private_request_t
);
377 pthread_cleanup_push(free
, this);
378 if (FCGX_InitRequest(&this->req
, fd
, 0) != 0 ||
379 FCGX_Accept_r(&this->req
) != 0)
383 pthread_cleanup_pop(failed
);
389 this->public.get_path
= (char*(*)(request_t
*))get_path
;
390 this->public.get_base
= (char*(*)(request_t
*))get_base
;
391 this->public.get_host
= (char*(*)(request_t
*))get_host
;
392 this->public.get_user_agent
= (char*(*)(request_t
*))get_user_agent
;
393 this->public.add_cookie
= (void(*)(request_t
*, char *name
, char *value
))add_cookie
;
394 this->public.get_cookie
= (char*(*)(request_t
*,char*))get_cookie
;
395 this->public.get_query_data
= (char*(*)(request_t
*, char *name
))get_query_data
;
396 this->public.session_closed
= (bool(*)(request_t
*))session_closed
;
397 this->public.close_session
= (void(*)(request_t
*))close_session
;
398 this->public.redirect
= (void(*)(request_t
*, char *fmt
,...))redirect
;
399 this->public.to_referer
= (void(*)(request_t
*))to_referer
;
400 this->public.render
= (void(*)(request_t
*,char*))render
;
401 this->public.streamf
= (int(*)(request_t
*, char *format
, ...))streamf
;
402 this->public.serve
= (void(*)(request_t
*,char*,chunk_t
))serve
;
403 this->public.set
= (void(*)(request_t
*, char *, char*))set
;
404 this->public.setf
= (void(*)(request_t
*, char *format
, ...))setf
;
405 this->public.get_ref
= (request_t
*(*)(request_t
*))get_ref
;
406 this->public.destroy
= (void(*)(request_t
*))destroy
;
408 pthread_once(&once
, init
);
409 pthread_setspecific(this_key
, this);
412 this->closed
= FALSE
;
413 this->req_env_len
= 0;
414 while (this->req
.envp
[this->req_env_len
] != NULL
)
419 err
= hdf_init(&this->hdf
);
422 hdf_set_value(this->hdf
, "base", get_base(this));
423 hdf_set_value(this->hdf
, "Config.NoCache", "true");
426 hdf_set_value(this->hdf
, "Config.TimeFooter", "0");
427 hdf_set_value(this->hdf
, "Config.CompressionEnabled", "1");
428 hdf_set_value(this->hdf
, "Config.WhiteSpaceStrip", "2");
431 err
= cgi_init(&this->cgi
, this->hdf
);
434 err
= cgi_parse(this->cgi
);
437 return &this->public;
439 cgi_destroy(&this->cgi
);
443 FCGX_Finish_r(&this->req
);