1#include "base.h" 2#include "log.h" 3#include "buffer.h" 4 5#include "plugin.h" 6 7#include <ctype.h> 8#include <stdlib.h> 9#include <string.h> 10#include <stdio.h> 11 12/* plugin config for all request/connections */ 13typedef struct { 14 array *alias; 15} plugin_config; 16 17typedef struct { 18 PLUGIN_DATA; 19 20 plugin_config **config_storage; 21 22 plugin_config conf; 23} plugin_data; 24 25/* init the plugin data */ 26INIT_FUNC(mod_alias_init) { 27 plugin_data *p; 28 29 p = calloc(1, sizeof(*p)); 30 31 32 33 return p; 34} 35 36/* detroy the plugin data */ 37FREE_FUNC(mod_alias_free) { 38 plugin_data *p = p_d; 39 40 if (!p) return HANDLER_GO_ON; 41 42 if (p->config_storage) { 43 size_t i; 44 45 for (i = 0; i < srv->config_context->used; i++) { 46 plugin_config *s = p->config_storage[i]; 47 48 if (NULL == s) continue; 49 50 array_free(s->alias); 51 52 free(s); 53 } 54 free(p->config_storage); 55 } 56 57 free(p); 58 59 return HANDLER_GO_ON; 60} 61 62/* handle plugin config and check values */ 63 64SETDEFAULTS_FUNC(mod_alias_set_defaults) { 65 plugin_data *p = p_d; 66 size_t i = 0; 67 68 config_values_t cv[] = { 69 { "alias.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ 70 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } 71 }; 72 73 if (!p) return HANDLER_ERROR; 74 75 p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *)); 76 77 for (i = 0; i < srv->config_context->used; i++) { 78 data_config const* config = (data_config const*)srv->config_context->data[i]; 79 plugin_config *s; 80 81 s = calloc(1, sizeof(plugin_config)); 82 s->alias = array_init(); 83 cv[0].destination = s->alias; 84 85 p->config_storage[i] = s; 86 87 if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { 88 return HANDLER_ERROR; 89 } 90 if (s->alias->used >= 2) { 91 const array *a = s->alias; 92 size_t j, k; 93 94 for (j = 0; j < a->used; j ++) { 95 const buffer *prefix = a->data[a->sorted[j]]->key; 96 for (k = j + 1; k < a->used; k ++) { 97 const buffer *key = a->data[a->sorted[k]]->key; 98 99 if (buffer_string_length(key) < buffer_string_length(prefix)) { 100 break; 101 } 102 if (memcmp(key->ptr, prefix->ptr, buffer_string_length(prefix)) != 0) { 103 break; 104 } 105 /* ok, they have same prefix. check position */ 106 if (a->sorted[j] < a->sorted[k]) { 107 log_error_write(srv, __FILE__, __LINE__, "SBSBS", 108 "url.alias: `", key, "' will never match as `", prefix, "' matched first"); 109 return HANDLER_ERROR; 110 } 111 } 112 } 113 } 114 } 115 116 return HANDLER_GO_ON; 117} 118 119#define PATCH(x) \ 120 p->conf.x = s->x; 121static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) { 122 size_t i, j; 123 plugin_config *s = p->config_storage[0]; 124 125 PATCH(alias); 126 127 /* skip the first, the global context */ 128 for (i = 1; i < srv->config_context->used; i++) { 129 data_config *dc = (data_config *)srv->config_context->data[i]; 130 s = p->config_storage[i]; 131 132 /* condition didn't match */ 133 if (!config_check_cond(srv, con, dc)) continue; 134 135 /* merge config */ 136 for (j = 0; j < dc->value->used; j++) { 137 data_unset *du = dc->value->data[j]; 138 139 if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) { 140 PATCH(alias); 141 } 142 } 143 } 144 145 return 0; 146} 147#undef PATCH 148 149PHYSICALPATH_FUNC(mod_alias_physical_handler) { 150 plugin_data *p = p_d; 151 int uri_len, basedir_len; 152 char *uri_ptr; 153 size_t k; 154 155 if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON; 156 157 mod_alias_patch_connection(srv, con, p); 158 159 /* not to include the tailing slash */ 160 basedir_len = buffer_string_length(con->physical.basedir); 161 if ('/' == con->physical.basedir->ptr[basedir_len-1]) --basedir_len; 162 uri_len = buffer_string_length(con->physical.path) - basedir_len; 163 uri_ptr = con->physical.path->ptr + basedir_len; 164 165 for (k = 0; k < p->conf.alias->used; k++) { 166 data_string *ds = (data_string *)p->conf.alias->data[k]; 167 int alias_len = buffer_string_length(ds->key); 168 169 if (alias_len > uri_len) continue; 170 if (buffer_is_empty(ds->key)) continue; 171 172 if (0 == (con->conf.force_lowercase_filenames ? 173 strncasecmp(uri_ptr, ds->key->ptr, alias_len) : 174 strncmp(uri_ptr, ds->key->ptr, alias_len))) { 175 /* matched */ 176 177 buffer_copy_buffer(con->physical.basedir, ds->value); 178 buffer_copy_buffer(srv->tmp_buf, ds->value); 179 buffer_append_string(srv->tmp_buf, uri_ptr + alias_len); 180 buffer_copy_buffer(con->physical.path, srv->tmp_buf); 181 182 return HANDLER_GO_ON; 183 } 184 } 185 186 /* not found */ 187 return HANDLER_GO_ON; 188} 189 190/* this function is called at dlopen() time and inits the callbacks */ 191 192int mod_alias_plugin_init(plugin *p); 193int mod_alias_plugin_init(plugin *p) { 194 p->version = LIGHTTPD_VERSION_ID; 195 p->name = buffer_init_string("alias"); 196 197 p->init = mod_alias_init; 198 p->handle_physical= mod_alias_physical_handler; 199 p->set_defaults = mod_alias_set_defaults; 200 p->cleanup = mod_alias_free; 201 202 p->data = NULL; 203 204 return 0; 205} 206