Annotation of embedaddon/lighttpd/src/mod_redirect.c, revision 1.1
1.1 ! misho 1: #include "base.h"
! 2: #include "log.h"
! 3: #include "buffer.h"
! 4:
! 5: #include "plugin.h"
! 6: #include "response.h"
! 7:
! 8: #include <ctype.h>
! 9: #include <stdlib.h>
! 10: #include <string.h>
! 11:
! 12: typedef struct {
! 13: pcre_keyvalue_buffer *redirect;
! 14: data_config *context; /* to which apply me */
! 15:
! 16: unsigned short redirect_code;
! 17: } plugin_config;
! 18:
! 19: typedef struct {
! 20: PLUGIN_DATA;
! 21: buffer *match_buf;
! 22: buffer *location;
! 23:
! 24: plugin_config **config_storage;
! 25:
! 26: plugin_config conf;
! 27: } plugin_data;
! 28:
! 29: INIT_FUNC(mod_redirect_init) {
! 30: plugin_data *p;
! 31:
! 32: p = calloc(1, sizeof(*p));
! 33:
! 34: p->match_buf = buffer_init();
! 35: p->location = buffer_init();
! 36:
! 37: return p;
! 38: }
! 39:
! 40: FREE_FUNC(mod_redirect_free) {
! 41: plugin_data *p = p_d;
! 42:
! 43: if (!p) return HANDLER_GO_ON;
! 44:
! 45: if (p->config_storage) {
! 46: size_t i;
! 47: for (i = 0; i < srv->config_context->used; i++) {
! 48: plugin_config *s = p->config_storage[i];
! 49:
! 50: pcre_keyvalue_buffer_free(s->redirect);
! 51:
! 52: free(s);
! 53: }
! 54: free(p->config_storage);
! 55: }
! 56:
! 57:
! 58: buffer_free(p->match_buf);
! 59: buffer_free(p->location);
! 60:
! 61: free(p);
! 62:
! 63: return HANDLER_GO_ON;
! 64: }
! 65:
! 66: SETDEFAULTS_FUNC(mod_redirect_set_defaults) {
! 67: plugin_data *p = p_d;
! 68: size_t i = 0;
! 69:
! 70: config_values_t cv[] = {
! 71: { "url.redirect", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
! 72: { "url.redirect-code", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
! 73: { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
! 74: };
! 75:
! 76: if (!p) return HANDLER_ERROR;
! 77:
! 78: /* 0 */
! 79: p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
! 80:
! 81: for (i = 0; i < srv->config_context->used; i++) {
! 82: plugin_config *s;
! 83: size_t j;
! 84: array *ca;
! 85: data_unset *du;
! 86: data_array *da;
! 87:
! 88: s = calloc(1, sizeof(plugin_config));
! 89: s->redirect = pcre_keyvalue_buffer_init();
! 90: s->redirect_code = 301;
! 91:
! 92: cv[0].destination = s->redirect;
! 93: cv[1].destination = &(s->redirect_code);
! 94:
! 95: p->config_storage[i] = s;
! 96: ca = ((data_config *)srv->config_context->data[i])->value;
! 97:
! 98: if (0 != config_insert_values_global(srv, ca, cv)) {
! 99: return HANDLER_ERROR;
! 100: }
! 101:
! 102: if (NULL == (du = array_get_element(ca, "url.redirect"))) {
! 103: /* no url.redirect defined */
! 104: continue;
! 105: }
! 106:
! 107: if (du->type != TYPE_ARRAY) {
! 108: log_error_write(srv, __FILE__, __LINE__, "sss",
! 109: "unexpected type for key: ", "url.redirect", "array of strings");
! 110:
! 111: return HANDLER_ERROR;
! 112: }
! 113:
! 114: da = (data_array *)du;
! 115:
! 116: for (j = 0; j < da->value->used; j++) {
! 117: if (da->value->data[j]->type != TYPE_STRING) {
! 118: log_error_write(srv, __FILE__, __LINE__, "sssbs",
! 119: "unexpected type for key: ",
! 120: "url.redirect",
! 121: "[", da->value->data[j]->key, "](string)");
! 122:
! 123: return HANDLER_ERROR;
! 124: }
! 125:
! 126: if (0 != pcre_keyvalue_buffer_append(srv, s->redirect,
! 127: ((data_string *)(da->value->data[j]))->key->ptr,
! 128: ((data_string *)(da->value->data[j]))->value->ptr)) {
! 129:
! 130: log_error_write(srv, __FILE__, __LINE__, "sb",
! 131: "pcre-compile failed for", da->value->data[j]->key);
! 132: }
! 133: }
! 134: }
! 135:
! 136: return HANDLER_GO_ON;
! 137: }
! 138: #ifdef HAVE_PCRE_H
! 139: static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
! 140: size_t i, j;
! 141: plugin_config *s = p->config_storage[0];
! 142:
! 143: p->conf.redirect = s->redirect;
! 144: p->conf.redirect_code = s->redirect_code;
! 145: p->conf.context = NULL;
! 146:
! 147: /* skip the first, the global context */
! 148: for (i = 1; i < srv->config_context->used; i++) {
! 149: data_config *dc = (data_config *)srv->config_context->data[i];
! 150: s = p->config_storage[i];
! 151:
! 152: /* condition didn't match */
! 153: if (!config_check_cond(srv, con, dc)) continue;
! 154:
! 155: /* merge config */
! 156: for (j = 0; j < dc->value->used; j++) {
! 157: data_unset *du = dc->value->data[j];
! 158:
! 159: if (0 == strcmp(du->key->ptr, "url.redirect")) {
! 160: p->conf.redirect = s->redirect;
! 161: p->conf.context = dc;
! 162: } else if (0 == strcmp(du->key->ptr, "url.redirect-code")) {
! 163: p->conf.redirect_code = s->redirect_code;
! 164: }
! 165: }
! 166: }
! 167:
! 168: return 0;
! 169: }
! 170: #endif
! 171: static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
! 172: #ifdef HAVE_PCRE_H
! 173: plugin_data *p = p_data;
! 174: size_t i;
! 175:
! 176: /*
! 177: * REWRITE URL
! 178: *
! 179: * e.g. redirect /base/ to /index.php?section=base
! 180: *
! 181: */
! 182:
! 183: mod_redirect_patch_connection(srv, con, p);
! 184:
! 185: buffer_copy_string_buffer(p->match_buf, con->request.uri);
! 186:
! 187: for (i = 0; i < p->conf.redirect->used; i++) {
! 188: pcre *match;
! 189: pcre_extra *extra;
! 190: const char *pattern;
! 191: size_t pattern_len;
! 192: int n;
! 193: pcre_keyvalue *kv = p->conf.redirect->kv[i];
! 194: # define N 10
! 195: int ovec[N * 3];
! 196:
! 197: match = kv->key;
! 198: extra = kv->key_extra;
! 199: pattern = kv->value->ptr;
! 200: pattern_len = kv->value->used - 1;
! 201:
! 202: if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
! 203: if (n != PCRE_ERROR_NOMATCH) {
! 204: log_error_write(srv, __FILE__, __LINE__, "sd",
! 205: "execution error while matching: ", n);
! 206: return HANDLER_ERROR;
! 207: }
! 208: } else {
! 209: const char **list;
! 210: size_t start;
! 211: size_t k;
! 212:
! 213: /* it matched */
! 214: pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
! 215:
! 216: /* search for $[0-9] */
! 217:
! 218: buffer_reset(p->location);
! 219:
! 220: start = 0;
! 221: for (k = 0; k + 1 < pattern_len; k++) {
! 222: if (pattern[k] == '$' || pattern[k] == '%') {
! 223: /* got one */
! 224:
! 225: size_t num = pattern[k + 1] - '0';
! 226:
! 227: buffer_append_string_len(p->location, pattern + start, k - start);
! 228:
! 229: if (!isdigit((unsigned char)pattern[k + 1])) {
! 230: /* enable escape: "%%" => "%", "%a" => "%a", "$$" => "$" */
! 231: buffer_append_string_len(p->location, pattern+k, pattern[k] == pattern[k+1] ? 1 : 2);
! 232: } else if (pattern[k] == '$') {
! 233: /* n is always > 0 */
! 234: if (num < (size_t)n) {
! 235: buffer_append_string(p->location, list[num]);
! 236: }
! 237: } else if (p->conf.context == NULL) {
! 238: /* we have no context, we are global */
! 239: log_error_write(srv, __FILE__, __LINE__, "sb",
! 240: "used a rewrite containing a %[0-9]+ in the global scope, ignored:",
! 241: kv->value);
! 242: } else {
! 243: config_append_cond_match_buffer(con, p->conf.context, p->location, num);
! 244: }
! 245:
! 246: k++;
! 247: start = k + 1;
! 248: }
! 249: }
! 250:
! 251: buffer_append_string_len(p->location, pattern + start, pattern_len - start);
! 252:
! 253: pcre_free(list);
! 254:
! 255: response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
! 256:
! 257: con->http_status = p->conf.redirect_code > 99 && p->conf.redirect_code < 1000 ? p->conf.redirect_code : 301;
! 258: con->mode = DIRECT;
! 259: con->file_finished = 1;
! 260:
! 261: return HANDLER_FINISHED;
! 262: }
! 263: }
! 264: #undef N
! 265:
! 266: #else
! 267: UNUSED(srv);
! 268: UNUSED(con);
! 269: UNUSED(p_data);
! 270: #endif
! 271:
! 272: return HANDLER_GO_ON;
! 273: }
! 274:
! 275:
! 276: int mod_redirect_plugin_init(plugin *p);
! 277: int mod_redirect_plugin_init(plugin *p) {
! 278: p->version = LIGHTTPD_VERSION_ID;
! 279: p->name = buffer_init_string("redirect");
! 280:
! 281: p->init = mod_redirect_init;
! 282: p->handle_uri_clean = mod_redirect_uri_handler;
! 283: p->set_defaults = mod_redirect_set_defaults;
! 284: p->cleanup = mod_redirect_free;
! 285:
! 286: p->data = NULL;
! 287:
! 288: return 0;
! 289: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>