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>