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