Annotation of embedaddon/lighttpd/src/mod_redirect.c, revision 1.1.1.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>