[mod_cgi] fix pipe_cloexec() when no O_CLOEXEC
[lighttpd.git] / src / mod_cml.c
blob28025f00f62f249f330330c1a13d46ab2195ad92
1 #include "first.h"
3 #include "buffer.h"
4 #include "server.h"
5 #include "log.h"
6 #include "plugin.h"
7 #include "response.h"
9 #include "stream.h"
11 #include "mod_cml.h"
13 #include <sys/stat.h>
14 #include <time.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <unistd.h>
20 #include <stdio.h>
22 /* init the plugin data */
23 INIT_FUNC(mod_cml_init) {
24 plugin_data *p;
26 p = calloc(1, sizeof(*p));
28 p->basedir = buffer_init();
29 p->baseurl = buffer_init();
30 p->trigger_handler = buffer_init();
32 return p;
35 /* detroy the plugin data */
36 FREE_FUNC(mod_cml_free) {
37 plugin_data *p = p_d;
39 UNUSED(srv);
41 if (!p) return HANDLER_GO_ON;
43 if (p->config_storage) {
44 size_t i;
45 for (i = 0; i < srv->config_context->used; i++) {
46 plugin_config *s = p->config_storage[i];
48 if (NULL == s) continue;
50 buffer_free(s->ext);
52 buffer_free(s->mc_namespace);
53 buffer_free(s->power_magnet);
54 array_free(s->mc_hosts);
56 #if defined(USE_MEMCACHED)
57 if (s->memc) memcached_free(s->memc);
58 #endif
60 free(s);
62 free(p->config_storage);
65 buffer_free(p->trigger_handler);
66 buffer_free(p->basedir);
67 buffer_free(p->baseurl);
69 free(p);
71 return HANDLER_GO_ON;
74 /* handle plugin config and check values */
76 SETDEFAULTS_FUNC(mod_cml_set_defaults) {
77 plugin_data *p = p_d;
78 size_t i = 0;
80 config_values_t cv[] = {
81 { "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
82 { "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
83 { "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
84 { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
85 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
88 if (!p) return HANDLER_ERROR;
90 p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
92 for (i = 0; i < srv->config_context->used; i++) {
93 data_config const* config = (data_config const*)srv->config_context->data[i];
94 plugin_config *s;
96 s = malloc(sizeof(plugin_config));
97 s->ext = buffer_init();
98 s->mc_hosts = array_init();
99 s->mc_namespace = buffer_init();
100 s->power_magnet = buffer_init();
101 #if defined(USE_MEMCACHED)
102 s->memc = NULL;
103 #endif
105 cv[0].destination = s->ext;
106 cv[1].destination = s->mc_hosts;
107 cv[2].destination = s->mc_namespace;
108 cv[3].destination = s->power_magnet;
110 p->config_storage[i] = s;
112 if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
113 return HANDLER_ERROR;
116 if (s->mc_hosts->used) {
117 #if defined(USE_MEMCACHED)
118 buffer *option_string = buffer_init();
119 size_t k;
122 data_string *ds = (data_string *)s->mc_hosts->data[0];
124 buffer_append_string_len(option_string, CONST_STR_LEN("--SERVER="));
125 buffer_append_string_buffer(option_string, ds->value);
128 for (k = 1; k < s->mc_hosts->used; k++) {
129 data_string *ds = (data_string *)s->mc_hosts->data[k];
131 buffer_append_string_len(option_string, CONST_STR_LEN(" --SERVER="));
132 buffer_append_string_buffer(option_string, ds->value);
135 s->memc = memcached(CONST_BUF_LEN(option_string));
137 if (NULL == s->memc) {
138 log_error_write(srv, __FILE__, __LINE__, "sb",
139 "configuring memcached failed for option string:",
140 option_string);
142 buffer_free(option_string);
144 if (NULL == s->memc) return HANDLER_ERROR;
145 #else
146 log_error_write(srv, __FILE__, __LINE__, "s",
147 "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
148 return HANDLER_ERROR;
149 #endif
153 return HANDLER_GO_ON;
156 #define PATCH(x) \
157 p->conf.x = s->x;
158 static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
159 size_t i, j;
160 plugin_config *s = p->config_storage[0];
162 PATCH(ext);
163 #if defined(USE_MEMCACHED)
164 PATCH(memc);
165 #endif
166 PATCH(mc_namespace);
167 PATCH(power_magnet);
169 /* skip the first, the global context */
170 for (i = 1; i < srv->config_context->used; i++) {
171 data_config *dc = (data_config *)srv->config_context->data[i];
172 s = p->config_storage[i];
174 /* condition didn't match */
175 if (!config_check_cond(srv, con, dc)) continue;
177 /* merge config */
178 for (j = 0; j < dc->value->used; j++) {
179 data_unset *du = dc->value->data[j];
181 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
182 PATCH(ext);
183 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
184 #if defined(USE_MEMCACHED)
185 PATCH(memc);
186 #endif
187 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
188 PATCH(mc_namespace);
189 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
190 PATCH(power_magnet);
195 return 0;
197 #undef PATCH
199 static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
200 buffer *b;
201 char *c;
203 /* cleanup basedir */
204 b = p->baseurl;
205 buffer_copy_buffer(b, con->uri.path);
206 for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--);
208 if (*c == '/') {
209 buffer_string_set_length(b, c - b->ptr + 1);
212 b = p->basedir;
213 buffer_copy_buffer(b, con->physical.path);
214 for (c = b->ptr + buffer_string_length(b); c > b->ptr && *c != '/'; c--);
216 if (*c == '/') {
217 buffer_string_set_length(b, c - b->ptr + 1);
221 /* prepare variables
222 * - cookie-based
223 * - get-param-based
225 return cache_parse_lua(srv, con, p, cml_file);
228 URIHANDLER_FUNC(mod_cml_power_magnet) {
229 plugin_data *p = p_d;
231 mod_cml_patch_connection(srv, con, p);
233 buffer_reset(p->basedir);
234 buffer_reset(p->baseurl);
235 buffer_reset(p->trigger_handler);
237 if (buffer_string_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
240 * power-magnet:
241 * cml.power-magnet = server.docroot + "/rewrite.cml"
243 * is called on EACH request, take the original REQUEST_URI and modifies the
244 * request header as neccesary.
246 * First use:
247 * if file_exists("/maintainance.html") {
248 * output_include = ( "/maintainance.html" )
249 * return CACHE_HIT
252 * as we only want to rewrite HTML like requests we should cover it in a conditional
254 * */
256 switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
257 case -1:
258 /* error */
259 if (con->conf.log_request_handling) {
260 log_error_write(srv, __FILE__, __LINE__, "s", "cache-error");
262 con->http_status = 500;
263 return HANDLER_COMEBACK;
264 case 0:
265 if (con->conf.log_request_handling) {
266 log_error_write(srv, __FILE__, __LINE__, "s", "cache-hit");
268 /* cache-hit */
269 buffer_reset(con->physical.path);
270 return HANDLER_FINISHED;
271 case 1:
272 /* cache miss */
273 return HANDLER_GO_ON;
274 default:
275 con->http_status = 500;
276 return HANDLER_COMEBACK;
280 URIHANDLER_FUNC(mod_cml_is_handled) {
281 plugin_data *p = p_d;
283 if (buffer_string_is_empty(con->physical.path)) return HANDLER_ERROR;
285 mod_cml_patch_connection(srv, con, p);
287 buffer_reset(p->basedir);
288 buffer_reset(p->baseurl);
289 buffer_reset(p->trigger_handler);
291 if (buffer_string_is_empty(p->conf.ext)) return HANDLER_GO_ON;
293 if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, buffer_string_length(p->conf.ext))) {
294 return HANDLER_GO_ON;
297 switch(cache_call_lua(srv, con, p, con->physical.path)) {
298 case -1:
299 /* error */
300 if (con->conf.log_request_handling) {
301 log_error_write(srv, __FILE__, __LINE__, "s", "cache-error");
303 con->http_status = 500;
304 return HANDLER_COMEBACK;
305 case 0:
306 if (con->conf.log_request_handling) {
307 log_error_write(srv, __FILE__, __LINE__, "s", "cache-hit");
309 /* cache-hit */
310 buffer_reset(con->physical.path);
311 return HANDLER_FINISHED;
312 case 1:
313 if (con->conf.log_request_handling) {
314 log_error_write(srv, __FILE__, __LINE__, "s", "cache-miss");
316 /* cache miss */
317 return HANDLER_COMEBACK;
318 default:
319 con->http_status = 500;
320 return HANDLER_COMEBACK;
324 int mod_cml_plugin_init(plugin *p);
325 int mod_cml_plugin_init(plugin *p) {
326 p->version = LIGHTTPD_VERSION_ID;
327 p->name = buffer_init_string("cache");
329 p->init = mod_cml_init;
330 p->cleanup = mod_cml_free;
331 p->set_defaults = mod_cml_set_defaults;
333 p->handle_subrequest_start = mod_cml_is_handled;
334 p->handle_physical = mod_cml_power_magnet;
336 p->data = NULL;
338 return 0;