comparison src/http/modules/ngx_http_rewrite_handler.c @ 0:f0b350454894 NGINX_0_1_0

nginx 0.1.0 *) The first public version.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Oct 2004 00:00:00 +0400
parents
children 46833bd150cb
comparison
equal deleted inserted replaced
-1:000000000000 0:f0b350454894
1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 #define NGX_HTTP_REWRITE_COPY_MATCH 0
13 #define NGX_HTTP_REWRITE_COPY_SHORT 1
14 #define NGX_HTTP_REWRITE_COPY_LONG 2
15
16
17 typedef struct {
18 ngx_int_t op;
19 size_t len;
20 uintptr_t data;
21 } ngx_http_rewrite_op_t;
22
23
24 typedef struct {
25 ngx_regex_t *regex;
26 ngx_uint_t msize;
27
28 ngx_array_t ops;
29 ngx_uint_t size;
30
31 ngx_str_t re_name;
32 ngx_str_t s_name;
33
34 ngx_uint_t status;
35 unsigned last:1;
36 } ngx_http_rewrite_rule_t;
37
38
39 typedef struct {
40 ngx_array_t rules;
41 ngx_flag_t log;
42 } ngx_http_rewrite_srv_conf_t;
43
44
45 typedef struct {
46 ngx_str_t redirect;
47 } ngx_http_rewrite_loc_conf_t;
48
49
50 static void *ngx_http_rewrite_create_srv_conf(ngx_conf_t *cf);
51 static char *ngx_http_rewrite_merge_srv_conf(ngx_conf_t *cf,
52 void *parent, void *child);
53 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
54 static char *ngx_http_rewrite_rule(ngx_conf_t *cf, ngx_command_t *cmd,
55 void *conf);
56 static char *ngx_http_redirect(ngx_conf_t *cf, void *post, void *data);
57 static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle);
58
59
60 static ngx_conf_post_handler_pt ngx_http_redirect_p = ngx_http_redirect;
61
62
63 static ngx_command_t ngx_http_rewrite_commands[] = {
64
65 { ngx_string("rewrite"),
66 NGX_HTTP_SRV_CONF|NGX_CONF_TAKE23,
67 ngx_http_rewrite_rule,
68 NGX_HTTP_SRV_CONF_OFFSET,
69 0,
70 NULL },
71
72 { ngx_string("redirect"),
73 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
74 ngx_conf_set_str_slot,
75 NGX_HTTP_LOC_CONF_OFFSET,
76 0,
77 &ngx_http_redirect_p },
78
79 { ngx_string("rewrite_log"),
80 NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
81 ngx_conf_set_flag_slot,
82 NGX_HTTP_SRV_CONF_OFFSET,
83 offsetof(ngx_http_rewrite_srv_conf_t, log),
84 NULL },
85
86 ngx_null_command
87 };
88
89
90 ngx_http_module_t ngx_http_rewrite_module_ctx = {
91 NULL, /* pre conf */
92
93 NULL, /* create main configuration */
94 NULL, /* init main configuration */
95
96 ngx_http_rewrite_create_srv_conf, /* create server configuration */
97 ngx_http_rewrite_merge_srv_conf, /* merge server configuration */
98
99 ngx_http_rewrite_create_loc_conf, /* create location configration */
100 NULL, /* merge location configration */
101 };
102
103
104 ngx_module_t ngx_http_rewrite_module = {
105 NGX_MODULE,
106 &ngx_http_rewrite_module_ctx, /* module context */
107 ngx_http_rewrite_commands, /* module directives */
108 NGX_HTTP_MODULE, /* module type */
109 ngx_http_rewrite_init, /* init module */
110 NULL /* init child */
111 };
112
113
114 static ngx_int_t ngx_http_rewrite_handler(ngx_http_request_t *r)
115 {
116 int *matches;
117 u_char *p;
118 size_t len;
119 uintptr_t data;
120 ngx_int_t rc;
121 ngx_uint_t i, m, n;
122 ngx_str_t uri;
123 ngx_http_rewrite_op_t *op;
124 ngx_http_rewrite_rule_t *rule;
125 ngx_http_rewrite_srv_conf_t *scf;
126
127 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
128 "http rewrite handler");
129
130 scf = ngx_http_get_module_srv_conf(r, ngx_http_rewrite_module);
131
132 rule = scf->rules.elts;
133 for (i = 0; i < scf->rules.nelts; i++) {
134
135 if (rule[i].msize) {
136 if (!(matches = ngx_palloc(r->pool, rule[i].msize * sizeof(int)))) {
137 return NGX_HTTP_INTERNAL_SERVER_ERROR;
138 }
139
140 } else {
141 matches = NULL;
142 }
143
144 rc = ngx_regex_exec(rule[i].regex, &r->uri, matches, rule[i].msize);
145
146 if (rc == NGX_DECLINED) {
147 if (scf->log) {
148 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
149 "\"%s\" does not match \"%s\"",
150 rule[i].re_name.data, r->uri.data);
151 }
152
153 continue;
154 }
155
156 if (rc < 0) {
157 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
158 ngx_regex_exec_n
159 " failed: %d on \"%s\" using \"%s\"",
160 rc, r->uri.data, rule[i].re_name.data);
161 return NGX_HTTP_INTERNAL_SERVER_ERROR;
162 }
163
164 if (scf->log) {
165 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
166 "\"%s\" matches \"%s\"",
167 rule[i].re_name.data, r->uri.data);
168 }
169
170 if (rule[i].status) {
171 return rule[i].status;
172 }
173
174 uri.len = rule[i].size;
175
176 for (n = 1; n < (ngx_uint_t) rc; n++) {
177 uri.len += matches[2 * n + 1] - matches[2 * n];
178 }
179
180 if (!(uri.data = ngx_palloc(r->pool, uri.len + 1))) {
181 return NGX_HTTP_INTERNAL_SERVER_ERROR;
182 }
183
184 p = uri.data;
185
186 op = rule[i].ops.elts;
187 for (n = 0; n < rule[i].ops.nelts; n++) {
188 if (op[n].op == NGX_HTTP_REWRITE_COPY_SHORT) {
189 len = op[n].len;
190 data = op[n].data;
191 while (len--) {
192 *p++ = (char) (data & 0xff);
193 data >>= 8;
194 }
195
196 } else if (op[n].op == NGX_HTTP_REWRITE_COPY_LONG) {
197 p = ngx_cpymem(p, (void *) op[n].data, op[n].len);
198
199 } else { /* NGX_HTTP_REWRITE_COPY_MATCH */
200 m = 2 * op[n].data;
201 p = ngx_cpymem(p, &r->uri.data[matches[m]],
202 matches[m + 1] - matches[m]);
203 }
204 }
205
206 *p = '\0';
207
208 if (scf->log) {
209 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
210 "rewritten uri: \"%s\"", uri.data);
211 }
212
213 r->uri = uri;
214
215 if (ngx_http_set_exten(r) != NGX_OK) {
216 return NGX_HTTP_INTERNAL_SERVER_ERROR;
217 }
218
219 if (rule[i].last) {
220 return NGX_DECLINED;
221 }
222 }
223
224 return NGX_DECLINED;
225 }
226
227
228 static ngx_int_t ngx_http_redirect_handler(ngx_http_request_t *r)
229 {
230 u_char *p;
231 ngx_http_rewrite_loc_conf_t *rlcf;
232
233 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
234 "http redirect handler");
235
236 rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
237
238 r->headers_out.location = ngx_list_push(&r->headers_out.headers);
239 if (r->headers_out.location == NULL) {
240 return NGX_HTTP_INTERNAL_SERVER_ERROR;
241 }
242
243 if (rlcf->redirect.data[0] != '/') {
244 r->headers_out.location->key.len = sizeof("Location") - 1;
245 r->headers_out.location->key.data = (u_char *) "Location";
246 }
247
248 r->headers_out.location->value.len = rlcf->redirect.len
249 + r->unparsed_uri.len;
250 r->headers_out.location->value.data = ngx_palloc(r->pool,
251 r->headers_out.location->value.len);
252
253 if (r->headers_out.location->value.data == NULL) {
254 return NGX_HTTP_INTERNAL_SERVER_ERROR;
255 }
256
257 p = ngx_cpymem(r->headers_out.location->value.data, rlcf->redirect.data,
258 rlcf->redirect.len);
259 p = ngx_cpystrn(p, r->unparsed_uri.data + 1, r->unparsed_uri.len);
260
261 return NGX_HTTP_MOVED_TEMPORARILY;
262 }
263
264
265 static void *ngx_http_rewrite_create_srv_conf(ngx_conf_t *cf)
266 {
267 ngx_http_rewrite_srv_conf_t *conf;
268
269 if (!(conf = ngx_palloc(cf->pool, sizeof(ngx_http_rewrite_srv_conf_t)))) {
270 return NGX_CONF_ERROR;
271 }
272
273 ngx_init_array(conf->rules, cf->pool, 5, sizeof(ngx_http_rewrite_rule_t),
274 NGX_CONF_ERROR);
275
276 conf->log = NGX_CONF_UNSET;
277
278 return conf;
279 }
280
281
282 static char *ngx_http_rewrite_merge_srv_conf(ngx_conf_t *cf,
283 void *parent, void *child)
284 {
285 ngx_http_rewrite_srv_conf_t *prev = parent;
286 ngx_http_rewrite_srv_conf_t *conf = child;
287
288 ngx_conf_merge_value(conf->log, prev->log, 0);
289
290 return NGX_CONF_OK;
291 }
292
293
294 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
295 {
296 ngx_http_rewrite_loc_conf_t *conf;
297
298 if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t)))) {
299 return NGX_CONF_ERROR;
300 }
301
302 return conf;
303 }
304
305
306 static char *ngx_http_rewrite_rule(ngx_conf_t *cf, ngx_command_t *cmd,
307 void *conf)
308 {
309 ngx_http_rewrite_srv_conf_t *scf = conf;
310
311 u_char *data, *p;
312 size_t len;
313 ngx_str_t *value, err;
314 ngx_uint_t i;
315 ngx_http_rewrite_op_t *op;
316 ngx_http_rewrite_rule_t *rule;
317 u_char errstr[NGX_MAX_CONF_ERRSTR];
318
319 if (!(rule = ngx_push_array(&scf->rules))) {
320 return NGX_CONF_ERROR;
321 }
322
323 ngx_init_array(rule->ops, cf->pool, 5, sizeof(ngx_http_rewrite_op_t),
324 NGX_CONF_ERROR);
325
326 rule->msize = 0;
327 rule->size = 0;
328 rule->status = 0;
329 rule->last = 0;
330
331 value = cf->args->elts;
332
333 /* STUB */ {
334 err.len = NGX_MAX_CONF_ERRSTR;
335 err.data = errstr;
336
337 rule->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err);
338
339 if (rule->regex == NULL) {
340 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
341 return NGX_CONF_ERROR;
342 }
343
344 rule->re_name = value[1];
345 rule->s_name = value[2];
346
347 if (ngx_strcasecmp(value[2].data, "forbidden:") == 0) {
348
349 if (cf->args->nelts == 3) {
350 rule->status = NGX_HTTP_FORBIDDEN;
351 rule->last = 1;
352 return NGX_CONF_OK;
353 }
354
355 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
356 "invalid parameter \"%s\"", value[3].data);
357 return NGX_CONF_ERROR;
358 }
359
360 for (i = 0; i < value[2].len; /* void */) {
361
362 if (!(op = ngx_push_array(&rule->ops))) {
363 return NGX_CONF_ERROR;
364 }
365
366 data = &value[2].data[i];
367
368 if (value[2].data[i] == '$'
369 && i < value[2].len
370 && value[2].data[i + 1] >= '1'
371 && value[2].data[i + 1] <= '9')
372 {
373 op->op = NGX_HTTP_REWRITE_COPY_MATCH;
374 op->data = value[2].data[++i] - '0';
375
376 if (rule->msize < op->data) {
377 rule->msize = op->data;
378 }
379
380 i++;
381
382 } else {
383 i++;
384
385 while (i < value[2].len && value[2].data[i] != '$') {
386 i++;
387 }
388
389 len = &value[2].data[i] - data;
390 rule->size += len;
391
392 if (len) {
393
394 op->len = len;
395
396 if (len <= sizeof(uintptr_t)) {
397 op->op = NGX_HTTP_REWRITE_COPY_SHORT;
398 op->data = 0;
399
400 while (len--) {
401 op->data <<= 8;
402 op->data |= data[len];
403 }
404
405 } else {
406 op->op = NGX_HTTP_REWRITE_COPY_LONG;
407
408 if (!(p = ngx_palloc(cf->pool, len))) {
409 return NGX_CONF_ERROR;
410 }
411
412 ngx_memcpy(p, data, len);
413 op->data = (uintptr_t) p;
414 }
415 }
416 }
417 }
418
419 if (rule->msize) {
420 rule->msize++;
421 rule->msize *= 3;
422 }
423
424 if (cf->args->nelts > 3) {
425 if (ngx_strcmp(value[3].data, "last") == 0) {
426 rule->last = 1;
427
428 } else {
429 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
430 "invalid parameter \"%s\"", value[3].data);
431 return NGX_CONF_ERROR;
432 }
433 }
434 }
435
436 return NGX_CONF_OK;
437 }
438
439
440 static char *ngx_http_redirect(ngx_conf_t *cf, void *post, void *data)
441 {
442 ngx_http_core_loc_conf_t *clcf;
443
444 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
445 clcf->handler = ngx_http_redirect_handler;
446
447 return NGX_CONF_OK;
448 }
449
450
451 static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle)
452 {
453 ngx_http_handler_pt *h;
454 ngx_http_core_main_conf_t *cmcf;
455
456 cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
457
458 h = ngx_push_array(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
459 if (h == NULL) {
460 return NGX_ERROR;
461 }
462
463 *h = ngx_http_rewrite_handler;
464
465 return NGX_OK;
466 }