the upcoming 2.0 version
https://redmine.lighttpd.net/projects/lighttpd2
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
5.1 KiB
214 lines
5.1 KiB
/* |
|
* mod_fortune - fortune cookies for everyone |
|
* |
|
* Description: |
|
* mod_fortune loads quotes (aka fortune coookies) from a file and provides actions |
|
* to add a random quote as response header (X-fortune) or display it as a page |
|
* |
|
* Setups: |
|
* fortune.load <filename> - loads cookies from a file, can be called multiple times to load data from multiple files |
|
* Options: |
|
* none |
|
* Actions: |
|
* fortune.header - adds a random quote as response header X-fortune |
|
* fortune.page - returns a random quote as response content |
|
* |
|
* Example config: |
|
* setup { |
|
* fortune.load "/var/www/fortunes.txt"; |
|
* } |
|
* |
|
* req.path == "/fortune" { |
|
* fortune.page; |
|
* } else { |
|
* fortune.header; |
|
* } |
|
*/ |
|
|
|
#include <lighttpd/base.h> |
|
|
|
LI_API gboolean mod_fortune_init(liModules *mods, liModule *mod); |
|
LI_API gboolean mod_fortune_free(liModules *mods, liModule *mod); |
|
|
|
/* globals */ |
|
typedef struct fortune_data fortune_data; |
|
|
|
struct fortune_data { |
|
GRand *rand; |
|
GPtrArray *cookies; |
|
}; |
|
|
|
static GString *fortune_rand(fortune_data *fd) { |
|
guint r = g_rand_int_range(fd->rand, 0, fd->cookies->len); |
|
return g_ptr_array_index(fd->cookies, r); |
|
} |
|
|
|
static liHandlerResult fortune_header_handle(liVRequest *vr, gpointer param, gpointer *context) { |
|
fortune_data *fd = param; |
|
|
|
UNUSED(context); |
|
|
|
if (fd->cookies->len) { |
|
GString *cookie = fortune_rand(fd); |
|
li_http_header_insert(vr->response.headers, CONST_STR_LEN("X-fortune"), GSTR_LEN(cookie)); |
|
} |
|
return LI_HANDLER_GO_ON; |
|
} |
|
|
|
static liAction* fortune_header(liServer *srv, liWorker *wrk, liPlugin* p, liValue *val, gpointer userdata) { |
|
UNUSED(srv); UNUSED(wrk); UNUSED(val); UNUSED(userdata); |
|
return li_action_new_function(fortune_header_handle, NULL, NULL, p->data); |
|
} |
|
|
|
static liHandlerResult fortune_page_handle(liVRequest *vr, gpointer param, gpointer *context) { |
|
fortune_data *fd = param; |
|
UNUSED(context); |
|
|
|
switch (vr->request.http_method) { |
|
case LI_HTTP_METHOD_GET: |
|
case LI_HTTP_METHOD_HEAD: |
|
break; |
|
default: |
|
return LI_HANDLER_GO_ON; |
|
} |
|
|
|
if (!li_vrequest_handle_direct(vr)) |
|
return LI_HANDLER_GO_ON; |
|
|
|
vr->response.http_status = 200; |
|
|
|
if (fd->cookies->len) { |
|
GString *cookie = fortune_rand(fd); |
|
li_chunkqueue_append_mem(vr->out, GSTR_LEN(cookie)); |
|
} else { |
|
li_chunkqueue_append_mem(vr->out, CONST_STR_LEN("no cookies in the cookie box")); |
|
} |
|
|
|
return LI_HANDLER_GO_ON; |
|
} |
|
|
|
static liAction* fortune_page(liServer *srv, liWorker *wrk, liPlugin* p, liValue *val, gpointer userdata) { |
|
UNUSED(srv); UNUSED(wrk); UNUSED(val); UNUSED(userdata); |
|
return li_action_new_function(fortune_page_handle, NULL, NULL, p->data); |
|
} |
|
|
|
static gboolean fortune_load(liServer *srv, liPlugin* p, liValue *val, gpointer userdata) { |
|
gchar *file; |
|
GError *err = NULL; |
|
gchar *data; |
|
gsize len; |
|
guint count = 0; |
|
fortune_data *fd = p->data; |
|
UNUSED(userdata); |
|
|
|
if (!val || val->type != LI_VALUE_STRING) { |
|
ERROR(srv, "fortune.load takes a string as parameter, %s given", val ? li_value_type_string(val->type) : "none"); |
|
return FALSE; |
|
} |
|
|
|
file = val->data.string->str; |
|
|
|
if (!g_file_get_contents(file, &data, &len, &err)) { |
|
ERROR(srv, "could not read fortune file \"%s\". reason: \"%s\" (%d)", file, err->message, err->code); |
|
g_error_free(err); |
|
return FALSE; |
|
} |
|
|
|
/* split lines */ |
|
{ |
|
GString *line = g_string_sized_new(127); |
|
gchar *cur; |
|
for (cur = data; *cur; cur++) { |
|
if (*cur == '\n' && line->len) { |
|
g_ptr_array_add(fd->cookies, line); |
|
line = g_string_sized_new(127); |
|
count++; |
|
} |
|
|
|
/* we ignore non-safe chars */ |
|
if (*cur < ' ' || *cur > '~') |
|
continue; |
|
|
|
g_string_append_c(line, *cur); |
|
} |
|
|
|
g_string_free(line, TRUE); |
|
} |
|
|
|
g_free(data); |
|
|
|
DEBUG(srv, "loaded %u cookies from file '%s'", count, file); |
|
|
|
return TRUE; |
|
} |
|
|
|
|
|
|
|
static const liPluginOption options[] = { |
|
{ NULL, 0, 0, NULL } |
|
}; |
|
|
|
static const liPluginAction actions[] = { |
|
{ "fortune.header", fortune_header, NULL }, |
|
{ "fortune.page", fortune_page, NULL }, |
|
|
|
{ NULL, NULL, NULL } |
|
}; |
|
|
|
static const liPluginSetup setups[] = { |
|
{ "fortune.load", fortune_load, NULL }, |
|
|
|
{ NULL, NULL, NULL } |
|
}; |
|
|
|
|
|
|
|
static void plugin_fortune_free(liServer *srv, liPlugin *p) { |
|
fortune_data *fd = p->data; |
|
UNUSED(srv); |
|
|
|
/* free the cookies! */ |
|
for (guint i = 0; i < fd->cookies->len; i++) |
|
g_string_free(g_ptr_array_index(fd->cookies, i), TRUE); |
|
g_ptr_array_free(fd->cookies, TRUE); |
|
|
|
g_rand_free(fd->rand); |
|
|
|
g_slice_free(fortune_data, fd); |
|
} |
|
|
|
static void plugin_fortune_init(liServer *srv, liPlugin *p, gpointer userdata) { |
|
fortune_data *fd; |
|
UNUSED(srv); UNUSED(userdata); |
|
|
|
p->options = options; |
|
p->actions = actions; |
|
p->setups = setups; |
|
p->free = plugin_fortune_free; |
|
|
|
p->data = fd = g_slice_new(fortune_data); |
|
|
|
fd->rand = g_rand_new(); |
|
fd->cookies = g_ptr_array_new(); |
|
} |
|
|
|
|
|
gboolean mod_fortune_init(liModules *mods, liModule *mod) { |
|
liServer *srv = mods->main; |
|
|
|
MODULE_VERSION_CHECK(mods); |
|
|
|
mod->config = li_plugin_register(srv, "mod_fortune", plugin_fortune_init, NULL); |
|
|
|
if (!mod->config) |
|
return FALSE; |
|
|
|
return TRUE; |
|
} |
|
|
|
gboolean mod_fortune_free(liModules *mods, liModule *mod) { |
|
if (mod->config) |
|
li_plugin_free(mods->main, mod->config); |
|
|
|
return TRUE; |
|
}
|
|
|