1 #include "buffer.h"
2 #include "server.h"
3 #include "log.h"
4 #include "plugin.h"
5 #include "response.h"
6
7 #include "stream.h"
8
9 #include "mod_cml.h"
10
11 #include <sys/stat.h>
12 #include <time.h>
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <stdio.h>
19
20 /* init the plugin data */
INIT_FUNC(mod_cml_init)21 INIT_FUNC(mod_cml_init) {
22 plugin_data *p;
23
24 p = calloc(1, sizeof(*p));
25
26 p->basedir = buffer_init();
27 p->baseurl = buffer_init();
28 p->trigger_handler = buffer_init();
29
30 return p;
31 }
32
33 /* detroy the plugin data */
FREE_FUNC(mod_cml_free)34 FREE_FUNC(mod_cml_free) {
35 plugin_data *p = p_d;
36
37 UNUSED(srv);
38
39 if (!p) return HANDLER_GO_ON;
40
41 if (p->config_storage) {
42 size_t i;
43 for (i = 0; i < srv->config_context->used; i++) {
44 plugin_config *s = p->config_storage[i];
45
46 buffer_free(s->ext);
47
48 buffer_free(s->mc_namespace);
49 buffer_free(s->power_magnet);
50 array_free(s->mc_hosts);
51
52 #if defined(HAVE_MEMCACHE_H)
53 if (s->mc) mc_free(s->mc);
54 #endif
55
56 free(s);
57 }
58 free(p->config_storage);
59 }
60
61 buffer_free(p->trigger_handler);
62 buffer_free(p->basedir);
63 buffer_free(p->baseurl);
64
65 free(p);
66
67 return HANDLER_GO_ON;
68 }
69
70 /* handle plugin config and check values */
71
SETDEFAULTS_FUNC(mod_cml_set_defaults)72 SETDEFAULTS_FUNC(mod_cml_set_defaults) {
73 plugin_data *p = p_d;
74 size_t i = 0;
75
76 config_values_t cv[] = {
77 { "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
78 { "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
79 { "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
80 { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
81 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
82 };
83
84 if (!p) return HANDLER_ERROR;
85
86 p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
87
88 for (i = 0; i < srv->config_context->used; i++) {
89 plugin_config *s;
90
91 s = malloc(sizeof(plugin_config));
92 s->ext = buffer_init();
93 s->mc_hosts = array_init();
94 s->mc_namespace = buffer_init();
95 s->power_magnet = buffer_init();
96 #if defined(HAVE_MEMCACHE_H)
97 s->mc = NULL;
98 #endif
99
100 cv[0].destination = s->ext;
101 cv[1].destination = s->mc_hosts;
102 cv[2].destination = s->mc_namespace;
103 cv[3].destination = s->power_magnet;
104
105 p->config_storage[i] = s;
106
107 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
108 return HANDLER_ERROR;
109 }
110
111 if (s->mc_hosts->used) {
112 #if defined(HAVE_MEMCACHE_H)
113 size_t k;
114 s->mc = mc_new();
115
116 for (k = 0; k < s->mc_hosts->used; k++) {
117 data_string *ds = (data_string *)s->mc_hosts->data[k];
118
119 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
120 log_error_write(srv, __FILE__, __LINE__, "sb",
121 "connection to host failed:",
122 ds->value);
123
124 return HANDLER_ERROR;
125 }
126 }
127 #else
128 log_error_write(srv, __FILE__, __LINE__, "s",
129 "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
130 return HANDLER_ERROR;
131 #endif
132 }
133 }
134
135 return HANDLER_GO_ON;
136 }
137
138 #define PATCH(x) \
139 p->conf.x = s->x;
mod_cml_patch_connection(server * srv,connection * con,plugin_data * p)140 static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
141 size_t i, j;
142 plugin_config *s = p->config_storage[0];
143
144 PATCH(ext);
145 #if defined(HAVE_MEMCACHE_H)
146 PATCH(mc);
147 #endif
148 PATCH(mc_namespace);
149 PATCH(power_magnet);
150
151 /* skip the first, the global context */
152 for (i = 1; i < srv->config_context->used; i++) {
153 data_config *dc = (data_config *)srv->config_context->data[i];
154 s = p->config_storage[i];
155
156 /* condition didn't match */
157 if (!config_check_cond(srv, con, dc)) continue;
158
159 /* merge config */
160 for (j = 0; j < dc->value->used; j++) {
161 data_unset *du = dc->value->data[j];
162
163 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
164 PATCH(ext);
165 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
166 #if defined(HAVE_MEMCACHE_H)
167 PATCH(mc);
168 #endif
169 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
170 PATCH(mc_namespace);
171 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
172 PATCH(power_magnet);
173 }
174 }
175 }
176
177 return 0;
178 }
179 #undef PATCH
180
cache_call_lua(server * srv,connection * con,plugin_data * p,buffer * cml_file)181 static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
182 buffer *b;
183 char *c;
184
185 /* cleanup basedir */
186 b = p->baseurl;
187 buffer_copy_string_buffer(b, con->uri.path);
188 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
189
190 if (*c == '/') {
191 b->used = c - b->ptr + 2;
192 *(c+1) = '\0';
193 }
194
195 b = p->basedir;
196 buffer_copy_string_buffer(b, con->physical.path);
197 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
198
199 if (*c == '/') {
200 b->used = c - b->ptr + 2;
201 *(c+1) = '\0';
202 }
203
204
205 /* prepare variables
206 * - cookie-based
207 * - get-param-based
208 */
209 return cache_parse_lua(srv, con, p, cml_file);
210 }
211
URIHANDLER_FUNC(mod_cml_power_magnet)212 URIHANDLER_FUNC(mod_cml_power_magnet) {
213 plugin_data *p = p_d;
214
215 mod_cml_patch_connection(srv, con, p);
216
217 buffer_reset(p->basedir);
218 buffer_reset(p->baseurl);
219 buffer_reset(p->trigger_handler);
220
221 if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
222
223 /*
224 * power-magnet:
225 * cml.power-magnet = server.docroot + "/rewrite.cml"
226 *
227 * is called on EACH request, take the original REQUEST_URI and modifies the
228 * request header as neccesary.
229 *
230 * First use:
231 * if file_exists("/maintainance.html") {
232 * output_include = ( "/maintainance.html" )
233 * return CACHE_HIT
234 * }
235 *
236 * as we only want to rewrite HTML like requests we should cover it in a conditional
237 *
238 * */
239
240 switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
241 case -1:
242 /* error */
243 if (con->conf.log_request_handling) {
244 log_error_write(srv, __FILE__, __LINE__, "s", "cache-error");
245 }
246 con->http_status = 500;
247 return HANDLER_COMEBACK;
248 case 0:
249 if (con->conf.log_request_handling) {
250 log_error_write(srv, __FILE__, __LINE__, "s", "cache-hit");
251 }
252 /* cache-hit */
253 buffer_reset(con->physical.path);
254 return HANDLER_FINISHED;
255 case 1:
256 /* cache miss */
257 return HANDLER_GO_ON;
258 default:
259 con->http_status = 500;
260 return HANDLER_COMEBACK;
261 }
262 }
263
URIHANDLER_FUNC(mod_cml_is_handled)264 URIHANDLER_FUNC(mod_cml_is_handled) {
265 plugin_data *p = p_d;
266
267 if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
268
269 mod_cml_patch_connection(srv, con, p);
270
271 buffer_reset(p->basedir);
272 buffer_reset(p->baseurl);
273 buffer_reset(p->trigger_handler);
274
275 if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
276
277 if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
278 return HANDLER_GO_ON;
279 }
280
281 switch(cache_call_lua(srv, con, p, con->physical.path)) {
282 case -1:
283 /* error */
284 if (con->conf.log_request_handling) {
285 log_error_write(srv, __FILE__, __LINE__, "s", "cache-error");
286 }
287 con->http_status = 500;
288 return HANDLER_COMEBACK;
289 case 0:
290 if (con->conf.log_request_handling) {
291 log_error_write(srv, __FILE__, __LINE__, "s", "cache-hit");
292 }
293 /* cache-hit */
294 buffer_reset(con->physical.path);
295 return HANDLER_FINISHED;
296 case 1:
297 if (con->conf.log_request_handling) {
298 log_error_write(srv, __FILE__, __LINE__, "s", "cache-miss");
299 }
300 /* cache miss */
301 return HANDLER_COMEBACK;
302 default:
303 con->http_status = 500;
304 return HANDLER_COMEBACK;
305 }
306 }
307
308 int mod_cml_plugin_init(plugin *p);
mod_cml_plugin_init(plugin * p)309 int mod_cml_plugin_init(plugin *p) {
310 p->version = LIGHTTPD_VERSION_ID;
311 p->name = buffer_init_string("cache");
312
313 p->init = mod_cml_init;
314 p->cleanup = mod_cml_free;
315 p->set_defaults = mod_cml_set_defaults;
316
317 p->handle_subrequest_start = mod_cml_is_handled;
318 p->handle_physical = mod_cml_power_magnet;
319
320 p->data = NULL;
321
322 return 0;
323 }
324