1#include "base.h" 2#include "log.h" 3#include "buffer.h" 4 5#include "plugin.h" 6 7#include "stat_cache.h" 8 9#include <ctype.h> 10#include <stdlib.h> 11#include <string.h> 12#include <errno.h> 13 14/* plugin config for all request/connections */ 15 16typedef struct { 17 array *indexfiles; 18} plugin_config; 19 20typedef struct { 21 PLUGIN_DATA; 22 23 buffer *tmp_buf; 24 25 plugin_config **config_storage; 26 27 plugin_config conf; 28} plugin_data; 29 30/* init the plugin data */ 31INIT_FUNC(mod_indexfile_init) { 32 plugin_data *p; 33 34 p = calloc(1, sizeof(*p)); 35 36 p->tmp_buf = buffer_init(); 37 38 return p; 39} 40 41/* detroy the plugin data */ 42FREE_FUNC(mod_indexfile_free) { 43 plugin_data *p = p_d; 44 45 UNUSED(srv); 46 47 if (!p) return HANDLER_GO_ON; 48 49 if (p->config_storage) { 50 size_t i; 51 for (i = 0; i < srv->config_context->used; i++) { 52 plugin_config *s = p->config_storage[i]; 53 54 if (NULL == s) continue; 55 56 array_free(s->indexfiles); 57 58 free(s); 59 } 60 free(p->config_storage); 61 } 62 63 buffer_free(p->tmp_buf); 64 65 free(p); 66 67 return HANDLER_GO_ON; 68} 69 70/* handle plugin config and check values */ 71 72SETDEFAULTS_FUNC(mod_indexfile_set_defaults) { 73 plugin_data *p = p_d; 74 size_t i = 0; 75 76 config_values_t cv[] = { 77 { "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ 78 { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ 79 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } 80 }; 81 82 if (!p) return HANDLER_ERROR; 83 84 p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *)); 85 86 for (i = 0; i < srv->config_context->used; i++) { 87 data_config const* config = (data_config const*)srv->config_context->data[i]; 88 plugin_config *s; 89 90 s = calloc(1, sizeof(plugin_config)); 91 s->indexfiles = array_init(); 92 93 cv[0].destination = s->indexfiles; 94 cv[1].destination = s->indexfiles; /* old name for [0] */ 95 96 p->config_storage[i] = s; 97 98 if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { 99 return HANDLER_ERROR; 100 } 101 } 102 103 return HANDLER_GO_ON; 104} 105 106#define PATCH(x) \ 107 p->conf.x = s->x; 108static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) { 109 size_t i, j; 110 plugin_config *s = p->config_storage[0]; 111 112 PATCH(indexfiles); 113 114 /* skip the first, the global context */ 115 for (i = 1; i < srv->config_context->used; i++) { 116 data_config *dc = (data_config *)srv->config_context->data[i]; 117 s = p->config_storage[i]; 118 119 /* condition didn't match */ 120 if (!config_check_cond(srv, con, dc)) continue; 121 122 /* merge config */ 123 for (j = 0; j < dc->value->used; j++) { 124 data_unset *du = dc->value->data[j]; 125 126 if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) { 127 PATCH(indexfiles); 128 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) { 129 PATCH(indexfiles); 130 } 131 } 132 } 133 134 return 0; 135} 136#undef PATCH 137 138URIHANDLER_FUNC(mod_indexfile_subrequest) { 139 plugin_data *p = p_d; 140 size_t k; 141 stat_cache_entry *sce = NULL; 142 143 if (con->mode != DIRECT) return HANDLER_GO_ON; 144 145 if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON; 146 if (con->uri.path->ptr[buffer_string_length(con->uri.path) - 1] != '/') return HANDLER_GO_ON; 147 148 mod_indexfile_patch_connection(srv, con, p); 149 150 if (con->conf.log_request_handling) { 151 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile"); 152 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path); 153 } 154 155 /* indexfile */ 156 for (k = 0; k < p->conf.indexfiles->used; k++) { 157 data_string *ds = (data_string *)p->conf.indexfiles->data[k]; 158 159 if (ds->value && ds->value->ptr[0] == '/') { 160 /* if the index-file starts with a prefix as use this file as 161 * index-generator */ 162 buffer_copy_buffer(p->tmp_buf, con->physical.doc_root); 163 } else { 164 buffer_copy_buffer(p->tmp_buf, con->physical.path); 165 } 166 buffer_append_string_buffer(p->tmp_buf, ds->value); 167 168 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) { 169 if (errno == EACCES) { 170 con->http_status = 403; 171 buffer_reset(con->physical.path); 172 173 return HANDLER_FINISHED; 174 } 175 176 if (errno != ENOENT && 177 errno != ENOTDIR) { 178 /* we have no idea what happend. let's tell the user so. */ 179 180 con->http_status = 500; 181 182 log_error_write(srv, __FILE__, __LINE__, "ssbsb", 183 "file not found ... or so: ", strerror(errno), 184 con->uri.path, 185 "->", con->physical.path); 186 187 buffer_reset(con->physical.path); 188 189 return HANDLER_FINISHED; 190 } 191 continue; 192 } 193 194 /* rewrite uri.path to the real path (/ -> /index.php) */ 195 buffer_append_string_buffer(con->uri.path, ds->value); 196 buffer_copy_buffer(con->physical.path, p->tmp_buf); 197 198 /* fce is already set up a few lines above */ 199 200 return HANDLER_GO_ON; 201 } 202 203 /* not found */ 204 return HANDLER_GO_ON; 205} 206 207/* this function is called at dlopen() time and inits the callbacks */ 208 209int mod_indexfile_plugin_init(plugin *p); 210int mod_indexfile_plugin_init(plugin *p) { 211 p->version = LIGHTTPD_VERSION_ID; 212 p->name = buffer_init_string("indexfile"); 213 214 p->init = mod_indexfile_init; 215 p->handle_subrequest_start = mod_indexfile_subrequest; 216 p->set_defaults = mod_indexfile_set_defaults; 217 p->cleanup = mod_indexfile_free; 218 219 p->data = NULL; 220 221 return 0; 222} 223