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