Project

General

Profile

Feature #61 ยป mod_redirect.c

Source code that adds support for url.redirect-found to return status code 302 rather than status code 301 -- angelo - Anonymous, 2007-11-11 03:32

 
1
#include <ctype.h>
2
#include <stdlib.h>
3
#include <string.h>
4

    
5
#include "base.h"
6
#include "log.h"
7
#include "buffer.h"
8

    
9
#include "plugin.h"
10
#include "response.h"
11

    
12
#ifdef HAVE_CONFIG_H
13
#include "config.h"
14
#endif
15

    
16
typedef struct {
17
	pcre_keyvalue_buffer *redirect;
18
	data_config *context; /* to which apply me */
19
} plugin_config;
20

    
21
typedef struct {
22
	PLUGIN_DATA;
23
	buffer *match_buf;
24
	buffer *location;
25
	size_t status;
26

    
27
	plugin_config **config_storage;
28

    
29
	plugin_config conf;
30
} plugin_data;
31

    
32
INIT_FUNC(mod_redirect_init) {
33
	plugin_data *p;
34

    
35
	p = calloc(1, sizeof(*p));
36

    
37
	p->match_buf = buffer_init();
38
	p->location = buffer_init();
39

    
40
	return p;
41
}
42

    
43
FREE_FUNC(mod_redirect_free) {
44
	plugin_data *p = p_d;
45

    
46
	if (!p) return HANDLER_GO_ON;
47

    
48
	if (p->config_storage) {
49
		size_t i;
50
		for (i = 0; i < srv->config_context->used; i++) {
51
			plugin_config *s = p->config_storage[i];
52

    
53
			pcre_keyvalue_buffer_free(s->redirect);
54

    
55
			free(s);
56
		}
57
		free(p->config_storage);
58
	}
59

    
60

    
61
	buffer_free(p->match_buf);
62
	buffer_free(p->location);
63
	p->status = 0;
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
	data_unset *du;
73
	size_t i = 0;
74

    
75
	config_values_t cv[] = {
76
		{ "url.redirect",               NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
77
		{ NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
78
	};
79

    
80
	if (!p) return HANDLER_ERROR;
81

    
82
	/* 0 */
83
	p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
84

    
85
	for (i = 0; i < srv->config_context->used; i++) {
86
		plugin_config *s;
87
		size_t j;
88
		array *ca;
89
		data_array *da = (data_array *)du;
90

    
91
		s = calloc(1, sizeof(plugin_config));
92
		s->redirect   = pcre_keyvalue_buffer_init();
93

    
94
		cv[0].destination = s->redirect;
95

    
96
		p->config_storage[i] = s;
97
		ca = ((data_config *)srv->config_context->data[i])->value;
98

    
99
		if (0 != config_insert_values_global(srv, ca, cv)) {
100
			return HANDLER_ERROR;
101
		}
102

    
103
		if (NULL == (du = array_get_element(ca, "url.redirect"))) {
104
			/* no url.redirect defined */
105
			if (NULL == (du = array_get_element(ca, "url.redirect-found"))) {
106
				continue;
107
			}
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(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);
135
			}
136
		}
137
	}
138

    
139
	return HANDLER_GO_ON;
140
}
141
#ifdef HAVE_PCRE_H
142
static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
143
	size_t i, j;
144
	plugin_config *s = p->config_storage[0];
145

    
146
	p->conf.redirect = s->redirect;
147
	p->conf.context = NULL;
148

    
149
	/* skip the first, the global context */
150
	for (i = 1; i < srv->config_context->used; i++) {
151
		data_config *dc = (data_config *)srv->config_context->data[i];
152
		s = p->config_storage[i];
153

    
154
		/* condition didn't match */
155
		if (!config_check_cond(srv, con, dc)) continue;
156

    
157
		/* merge config */
158
		for (j = 0; j < dc->value->used; j++) {
159
			data_unset *du = dc->value->data[j];
160

    
161
			if (0 == strcmp(du->key->ptr, "url.redirect-found")) {
162
                                p->conf.redirect = s->redirect;
163
                                p->conf.context = dc;
164
				p->status = 302;
165
                        }
166
			else
167
			if (0 == strcmp(du->key->ptr, "url.redirect")) {
168
				p->conf.redirect = s->redirect;
169
				p->conf.context = dc;
170
				p->status = 301;
171
			}
172
		}
173
	}
174

    
175
	return 0;
176
}
177
#endif
178
static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
179
#ifdef HAVE_PCRE_H
180
	plugin_data *p = p_data;
181
	size_t i;
182

    
183
	/*
184
	 * REWRITE URL
185
	 *
186
	 * e.g. redirect /base/ to /index.php?section=base
187
	 *
188
	 */
189

    
190
	mod_redirect_patch_connection(srv, con, p);
191

    
192
	buffer_copy_string_buffer(p->match_buf, con->request.uri);
193

    
194
	for (i = 0; i < p->conf.redirect->used; i++) {
195
		pcre *match;
196
		pcre_extra *extra;
197
		const char *pattern;
198
		size_t pattern_len;
199
		int n;
200
		pcre_keyvalue *kv = p->conf.redirect->kv[i];
201
# define N 10
202
		int ovec[N * 3];
203

    
204
		match       = kv->key;
205
		extra       = kv->key_extra;
206
		pattern     = kv->value->ptr;
207
		pattern_len = kv->value->used - 1;
208

    
209
		if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
210
			if (n != PCRE_ERROR_NOMATCH) {
211
				log_error_write(srv, __FILE__, __LINE__, "sd",
212
						"execution error while matching: ", n);
213
				return HANDLER_ERROR;
214
			}
215
		} else {
216
			const char **list;
217
			size_t start, end;
218
			size_t k;
219

    
220
			/* it matched */
221
			pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
222

    
223
			/* search for $[0-9] */
224

    
225
			buffer_reset(p->location);
226

    
227
			start = 0; end = pattern_len;
228
			for (k = 0; k < pattern_len; k++) {
229
				if ((pattern[k] == '$' || pattern[k] == '%') &&
230
				    isdigit((unsigned char)pattern[k + 1])) {
231
					/* got one */
232

    
233
					size_t num = pattern[k + 1] - '0';
234

    
235
					end = k;
236

    
237
					buffer_append_string_len(p->location, pattern + start, end - start);
238

    
239
					if (pattern[k] == '$') {
240
						/* n is always > 0 */
241
						if (num < (size_t)n) {
242
							buffer_append_string(p->location, list[num]);
243
						}
244
					} else if (p->conf.context == NULL) {
245
						/* we have no context, we are global */
246
						log_error_write(srv, __FILE__, __LINE__, "sb",
247
								"used a rewrite containing a %[0-9]+ in the global scope, ignored:",
248
								kv->value);
249
					} else {
250
						config_append_cond_match_buffer(con, p->conf.context, p->location, num);
251
					}
252

    
253
					k++;
254
					start = k + 1;
255
				}
256
			}
257

    
258
			buffer_append_string_len(p->location, pattern + start, pattern_len - start);
259

    
260
			pcre_free(list);
261

    
262
			response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
263

    
264
			con->http_status = p->status;
265
			con->file_finished = 1;
266

    
267
			return HANDLER_FINISHED;
268
		}
269
	}
270
#undef N
271

    
272
#else
273
	UNUSED(srv);
274
	UNUSED(con);
275
	UNUSED(p_data);
276
#endif
277

    
278
	return HANDLER_GO_ON;
279
}
280

    
281

    
282
int mod_redirect_plugin_init(plugin *p) {
283
	p->version     = LIGHTTPD_VERSION_ID;
284
	p->name        = buffer_init_string("redirect");
285

    
286
	p->init        = mod_redirect_init;
287
	p->handle_uri_clean  = mod_redirect_uri_handler;
288
	p->set_defaults  = mod_redirect_set_defaults;
289
	p->cleanup     = mod_redirect_free;
290

    
291
	p->data        = NULL;
292

    
293
	return 0;
294
}
    (1-1/1)