comparison src/http/modules/ngx_http_rewrite_handler.c @ 34:aab2ea7c0458 NGINX_0_1_17

nginx 0.1.17 *) Change: the ngx_http_rewrite_module was rewritten from the scratch. Now it is possible to redirect, to return the error codes, to check the variables and referrers. The directives can be used inside locations. The redirect directive was canceled. *) Feature: the ngx_http_geo_module. *) Feature: the proxy_set_x_var and fastcgi_set_var directives. *) Bugfix: the location configuration with "=" modifier may be used in another location. *) Bugfix: the correct content type was set only for requests that use small caps letters in extension. *) Bugfix: if the proxy_pass or fastcgi_pass directives were set in the location, and access was denied, and the error was redirected to a static page, then the segmentation fault occurred. *) Bugfix: if in a proxied "Location" header was a relative URL, then a host name and a slash were added to them; bug appeared in 0.1.14. *) Bugfix: the system error message was not logged on Linux.
author Igor Sysoev <http://sysoev.ru>
date Thu, 03 Feb 2005 00:00:00 +0300
parents da8c190bdaba
children a39d1b793287
comparison
equal deleted inserted replaced
33:27f09a550803 34:aab2ea7c0458
7 #include <ngx_config.h> 7 #include <ngx_config.h>
8 #include <ngx_core.h> 8 #include <ngx_core.h>
9 #include <ngx_http.h> 9 #include <ngx_http.h>
10 10
11 11
12 #define NGX_HTTP_REWRITE_COPY_CAPTURE 0 12 typedef struct ngx_http_rewrite_engine_s ngx_http_rewrite_engine_t;
13 #define NGX_HTTP_REWRITE_COPY_SHORT 1 13
14 #define NGX_HTTP_REWRITE_COPY_LONG 2 14 typedef void (*ngx_http_rewrite_code_pt) (ngx_http_rewrite_engine_t *e);
15 #define NGX_HTTP_REWRITE_START_ARGS 3
16 15
17 16
18 typedef struct { 17 typedef struct {
19 ngx_int_t op; 18 ngx_str_t name;
20 size_t len; 19 ngx_uint_t wildcard;
21 uintptr_t data; 20 } ngx_http_rewrite_referer_t;
22 } ngx_http_rewrite_op_t;
23 21
24 22
25 typedef struct { 23 typedef struct {
26 ngx_regex_t *regex; 24 ngx_array_t *codes; /* uintptr_t */
27 ngx_uint_t ncaptures; 25 ngx_array_t *referers; /* ngx_http_rewrite_referer_t */
28 26
29 ngx_array_t ops; 27 ngx_uint_t max_captures;
30 ngx_uint_t size; 28 ngx_uint_t stack_size;
31 29
32 ngx_str_t re_name; 30 ngx_flag_t log;
33 ngx_str_t s_name; 31
34 32 ngx_flag_t no_referer;
35 ngx_uint_t status; 33 } ngx_http_rewrite_loc_conf_t;
36 unsigned last:1;
37 } ngx_http_rewrite_rule_t;
38 34
39 35
40 typedef struct { 36 typedef struct {
41 ngx_array_t rules; 37 ngx_http_rewrite_code_pt code;
42 ngx_flag_t log; 38 ngx_regex_t *regex;
43 } ngx_http_rewrite_srv_conf_t; 39 uintptr_t size;
40 uintptr_t ncaptures;
41 uintptr_t status;
42 uintptr_t next;
43
44 uintptr_t uri:1;
45
46 /* add the r->args to the new arguments */
47 uintptr_t args:1;
48
49 uintptr_t redirect:1;
50
51 ngx_str_t name;
52 } ngx_http_rewrite_regex_code_t;
44 53
45 54
46 typedef struct { 55 typedef struct {
47 ngx_str_t redirect; 56 ngx_http_rewrite_code_pt code;
48 } ngx_http_rewrite_loc_conf_t; 57
49 58 uintptr_t uri:1;
50 59
51 static void *ngx_http_rewrite_create_srv_conf(ngx_conf_t *cf); 60 /* add the r->args to the new arguments */
52 static char *ngx_http_rewrite_merge_srv_conf(ngx_conf_t *cf, 61 uintptr_t args:1;
62
63 uintptr_t redirect:1;
64 } ngx_http_rewrite_regex_end_code_t;
65
66 typedef struct {
67 ngx_http_rewrite_code_pt code;
68 uintptr_t n;
69 } ngx_http_rewrite_copy_capture_code_t;
70
71
72 typedef struct {
73 ngx_http_rewrite_code_pt code;
74 uintptr_t len;
75 } ngx_http_rewrite_copy_code_t;
76
77
78 typedef struct {
79 ngx_http_rewrite_code_pt code;
80 uintptr_t status;
81 uintptr_t null;
82 } ngx_http_rewrite_return_code_t;
83
84
85 typedef struct {
86 ngx_http_rewrite_code_pt code;
87 uintptr_t next;
88 void **loc_conf;
89 } ngx_http_rewrite_if_code_t;
90
91
92 typedef struct {
93 ngx_http_rewrite_code_pt code;
94 uintptr_t index;
95 } ngx_http_rewrite_var_code_t;
96
97
98 struct ngx_http_rewrite_engine_s {
99 u_char *ip;
100 uintptr_t *sp;
101
102 ngx_str_t buf;
103 ngx_str_t *line;
104
105 u_char *pos;
106
107 /* the start of the rewritten arguments */
108 u_char *args;
109
110 unsigned quote:1;
111
112 ngx_int_t status;
113
114 int *captures;
115
116 ngx_http_request_t *request;
117 ngx_http_rewrite_loc_conf_t *conf;
118 };
119
120
121 static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle);
122 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf);
123 static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
53 void *parent, void *child); 124 void *parent, void *child);
54 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf); 125 static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
55 static char *ngx_http_rewrite_rule(ngx_conf_t *cf, ngx_command_t *cmd, 126 static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
56 void *conf); 127 void *conf);
57 static char *ngx_http_redirect(ngx_conf_t *cf, void *post, void *data); 128 static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd,
58 static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle); 129 void *conf);
59 130 static char *ngx_http_rewrite_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd,
60 131 void *conf);
61 static ngx_conf_post_handler_pt ngx_http_redirect_p = ngx_http_redirect; 132 static void *ngx_http_rewrite_start_code(ngx_pool_t *pool,
133 ngx_array_t **codes, size_t size);
134 static void *ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size,
135 u_char **main);
62 136
63 137
64 static ngx_command_t ngx_http_rewrite_commands[] = { 138 static ngx_command_t ngx_http_rewrite_commands[] = {
65 139
66 { ngx_string("rewrite"), 140 { ngx_string("rewrite"),
67 NGX_HTTP_SRV_CONF|NGX_CONF_TAKE23, 141 NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
68 ngx_http_rewrite_rule, 142 |NGX_CONF_TAKE23,
69 NGX_HTTP_SRV_CONF_OFFSET, 143 ngx_http_rewrite,
144 NGX_HTTP_LOC_CONF_OFFSET,
70 0, 145 0,
71 NULL }, 146 NULL },
72 147
73 { ngx_string("redirect"), 148 { ngx_string("return"),
74 NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 149 NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
75 ngx_conf_set_str_slot, 150 |NGX_CONF_TAKE1,
151 ngx_http_rewrite_return,
76 NGX_HTTP_LOC_CONF_OFFSET, 152 NGX_HTTP_LOC_CONF_OFFSET,
77 0, 153 0,
78 &ngx_http_redirect_p }, 154 NULL },
155
156 { ngx_string("if"),
157 NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE,
158 ngx_http_rewrite_if,
159 NGX_HTTP_LOC_CONF_OFFSET,
160 0,
161 NULL },
162
163 { ngx_string("valid_referers"),
164 NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
165 ngx_http_rewrite_valid_referers,
166 NGX_HTTP_LOC_CONF_OFFSET,
167 0,
168 NULL },
79 169
80 { ngx_string("rewrite_log"), 170 { ngx_string("rewrite_log"),
81 NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, 171 NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
172 |NGX_CONF_TAKE1,
82 ngx_conf_set_flag_slot, 173 ngx_conf_set_flag_slot,
83 NGX_HTTP_SRV_CONF_OFFSET, 174 NGX_HTTP_LOC_CONF_OFFSET,
84 offsetof(ngx_http_rewrite_srv_conf_t, log), 175 offsetof(ngx_http_rewrite_loc_conf_t, log),
85 NULL }, 176 NULL },
86 177
87 ngx_null_command 178 ngx_null_command
88 }; 179 };
89 180
92 NULL, /* pre conf */ 183 NULL, /* pre conf */
93 184
94 NULL, /* create main configuration */ 185 NULL, /* create main configuration */
95 NULL, /* init main configuration */ 186 NULL, /* init main configuration */
96 187
97 ngx_http_rewrite_create_srv_conf, /* create server configuration */ 188 NULL, /* create server configuration */
98 ngx_http_rewrite_merge_srv_conf, /* merge server configuration */ 189 NULL, /* merge server configuration */
99 190
100 ngx_http_rewrite_create_loc_conf, /* create location configration */ 191 ngx_http_rewrite_create_loc_conf, /* create location configration */
101 NULL, /* merge location configration */ 192 ngx_http_rewrite_merge_loc_conf /* merge location configration */
102 }; 193 };
103 194
104 195
105 ngx_module_t ngx_http_rewrite_module = { 196 ngx_module_t ngx_http_rewrite_module = {
106 NGX_MODULE, 197 NGX_MODULE,
107 &ngx_http_rewrite_module_ctx, /* module context */ 198 &ngx_http_rewrite_module_ctx, /* module context */
108 ngx_http_rewrite_commands, /* module directives */ 199 ngx_http_rewrite_commands, /* module directives */
109 NGX_HTTP_MODULE, /* module type */ 200 NGX_HTTP_MODULE, /* module type */
110 ngx_http_rewrite_init, /* init module */ 201 ngx_http_rewrite_init, /* init module */
111 NULL /* init child */ 202 NULL /* init process */
112 }; 203 };
113 204
114 205
206 #define ngx_http_rewrite_exit (u_char *) &ngx_http_rewrite_exit_code
207
208 uintptr_t ngx_http_rewrite_exit_code = (uintptr_t) NULL;
209
210
115 static ngx_int_t ngx_http_rewrite_handler(ngx_http_request_t *r) 211 static ngx_int_t ngx_http_rewrite_handler(ngx_http_request_t *r)
116 { 212 {
117 int *captures; 213 ngx_http_rewrite_code_pt code;
118 u_char *p; 214 ngx_http_rewrite_engine_t *e;
119 size_t len; 215 ngx_http_rewrite_loc_conf_t *cf;
120 uintptr_t data; 216
121 ngx_int_t rc; 217 cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
122 ngx_uint_t i, m, n; 218
123 ngx_str_t uri, args; 219 if (cf->codes == NULL) {
124 ngx_http_rewrite_op_t *op; 220 return NGX_DECLINED;
125 ngx_http_rewrite_rule_t *rule; 221 }
126 ngx_http_rewrite_srv_conf_t *scf; 222
223 if (!(e = ngx_palloc(r->pool, sizeof(ngx_http_rewrite_engine_t)))) {
224 return NGX_HTTP_INTERNAL_SERVER_ERROR;
225 }
226
227 e->sp = ngx_palloc(r->pool, cf->stack_size * sizeof(ngx_int_t));
228 if (e->sp == NULL) {
229 return NGX_HTTP_INTERNAL_SERVER_ERROR;
230 }
231
232 if (cf->max_captures) {
233 e->captures = ngx_palloc(r->pool, cf->max_captures * sizeof(int));
234 if (e->captures == NULL) {
235 return NGX_HTTP_INTERNAL_SERVER_ERROR;
236 }
237
238 } else {
239 e->captures = NULL;
240 }
241
242 e->ip = cf->codes->elts;
243 e->buf.len = 0;
244 e->buf.data = NULL;
245 e->line = NULL;
246 e->pos = NULL;
247 e->args = NULL;
248 e->quote = 1;
249 e->status = NGX_DECLINED;
250 e->request = r;
251 e->conf = cf;
252
253 while (*(uintptr_t *) e->ip) {
254 code = *(ngx_http_rewrite_code_pt *) e->ip;
255 code(e);
256 }
257
258 return e->status;
259 }
260
261
262 static void ngx_http_rewrite_regex_start_code(ngx_http_rewrite_engine_t *e)
263 {
264 ngx_int_t rc;
265 ngx_uint_t n;
266 ngx_http_request_t *r;
267 ngx_http_rewrite_regex_code_t *code;
268
269 code = (ngx_http_rewrite_regex_code_t *) e->ip;
270
271 r = e->request;
272
273 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
274 "http rewrite start: \"%V\"", &code->name);
275
276 if (code->uri) {
277 e->line = &r->uri;
278 } else {
279 e->line = *(ngx_str_t **) e->sp--;
280 }
281
282 rc = ngx_regex_exec(code->regex, e->line, e->captures, code->ncaptures);
283
284 if (rc == NGX_REGEX_NO_MATCHED) {
285 if (e->conf->log) {
286 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
287 "\"%V\" does not match \"%V\"", &code->name, e->line);
288 }
289
290 e->ip += code->next;
291 return;
292 }
293
294 if (rc < 0) {
295 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
296 ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"",
297 rc, e->line, &code->name);
298
299 e->ip = ngx_http_rewrite_exit;
300 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
301 return;
302 }
303
304 if (e->conf->log) {
305 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
306 "\"%V\" matches \"%V\"", &code->name, e->line);
307 }
308
309 if (code->status) {
310 e->status = code->status;
311
312 if (!code->redirect) {
313 e->ip = ngx_http_rewrite_exit;
314 return;
315 }
316 }
317
318 e->buf.len = code->size;
319
320 if (code->uri) {
321 r->uri_changed = 1;
322
323 if (rc && (r->quoted_uri || r->plus_in_uri)) {
324 e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
325 NGX_ESCAPE_ARGS);
326 }
327 }
328
329 for (n = 1; n < (ngx_uint_t) rc; n++) {
330 e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n];
331 }
332
333 if (code->args && r->args.len) {
334 e->buf.len += r->args.len + 1;
335 }
336
337 if (!(e->buf.data = ngx_palloc(r->pool, e->buf.len))) {
338 e->ip = ngx_http_rewrite_exit;
339 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
340 return;
341 }
342
343 e->quote = code->redirect;
344
345 e->pos = e->buf.data;
346
347 e->ip += sizeof(ngx_http_rewrite_regex_code_t);
348 }
349
350
351 static void ngx_http_rewrite_regex_end_code(ngx_http_rewrite_engine_t *e)
352 {
353 ngx_http_request_t *r;
354 ngx_http_rewrite_regex_end_code_t *code;
355
356 code = (ngx_http_rewrite_regex_end_code_t *) e->ip;
357
358 r = e->request;
359
360 e->quote = 0;
127 361
128 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 362 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
129 "http rewrite handler"); 363 "http rewrite end");
130 364
131 scf = ngx_http_get_module_srv_conf(r, ngx_http_rewrite_module); 365 if (e->args) {
132 366 e->buf.len = e->args - e->buf.data;
133 rule = scf->rules.elts; 367
134 for (i = 0; i < scf->rules.nelts; i++) { 368 if (code->args && r->args.len) {
135 369 *e->pos++ = '&';
136 if (rule[i].ncaptures) { 370 e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
137 captures = ngx_palloc(r->pool, rule[i].ncaptures * sizeof(int)); 371 }
138 if (captures == NULL) { 372
139 return NGX_HTTP_INTERNAL_SERVER_ERROR; 373 r->args.len = e->pos - e->args;
374 r->args.data = e->args;
375
376 e->args = NULL;
377
378 } else {
379 if (code->args && r->args.len) {
380 *e->pos++ = '&';
381 e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len);
382 }
383
384 e->buf.len = e->pos - e->buf.data;
385 }
386
387 if (!code->redirect) {
388 if (e->conf->log) {
389 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
390 "rewritten data: \"%V\", args: \"%V\"",
391 &e->buf, &r->args);
392 }
393
394 if (code->uri) {
395 r->uri = e->buf;
396
397 if (ngx_http_set_exten(r) != NGX_OK) {
398 e->ip = ngx_http_rewrite_exit;
399 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
400 return;
140 } 401 }
141 402 }
142 } else { 403
143 captures = NULL; 404 e->ip += sizeof(ngx_http_rewrite_regex_end_code_t);
144 } 405 return;
145 406 }
146 rc = ngx_regex_exec(rule[i].regex, &r->uri, 407
147 captures, rule[i].ncaptures); 408 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
148 409 "rewritten redirect: \"%V\"", &e->buf);
149 if (rc == NGX_REGEX_NO_MATCHED) { 410
150 if (scf->log) { 411 if (!(r->headers_out.location = ngx_list_push(&r->headers_out.headers))) {
151 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, 412 e->ip = ngx_http_rewrite_exit;
152 "\"%V\" does not match \"%V\"", 413 e->status = NGX_HTTP_INTERNAL_SERVER_ERROR;
153 &rule[i].re_name, &r->uri); 414 return;
154 } 415 }
155 416
156 continue; 417 if (e->buf.data[0] != '/') {
157 }
158
159 if (rc < 0) {
160 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
161 ngx_regex_exec_n
162 " failed: %d on \"%V\" using \"%V\"",
163 rc, &r->uri, &rule[i].re_name);
164 return NGX_HTTP_INTERNAL_SERVER_ERROR;
165 }
166
167 if (scf->log) {
168 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
169 "\"%V\" matches \"%V\"",
170 &rule[i].re_name, &r->uri);
171 }
172
173 if (rule[i].status) {
174 return rule[i].status;
175 }
176
177 uri.len = rule[i].size;
178
179 for (n = 1; n < (ngx_uint_t) rc; n++) {
180 uri.len += captures[2 * n + 1] - captures[2 * n];
181 }
182
183 if (!(uri.data = ngx_palloc(r->pool, uri.len))) {
184 return NGX_HTTP_INTERNAL_SERVER_ERROR;
185 }
186
187 args.data = NULL;
188 p = uri.data;
189
190 op = rule[i].ops.elts;
191 for (n = 0; n < rule[i].ops.nelts; n++) {
192 if (op[n].op == NGX_HTTP_REWRITE_COPY_SHORT) {
193 len = op[n].len;
194 data = op[n].data;
195 while (len--) {
196 *p++ = (char) (data & 0xff);
197 data >>= 8;
198 }
199
200 } else if (op[n].op == NGX_HTTP_REWRITE_COPY_LONG) {
201 p = ngx_cpymem(p, (void *) op[n].data, op[n].len);
202
203 } else if (op[n].op == NGX_HTTP_REWRITE_START_ARGS) {
204 args.data = p;
205
206 } else { /* NGX_HTTP_REWRITE_COPY_CAPTURE */
207 m = 2 * op[n].data;
208 p = ngx_cpymem(p, &r->uri.data[captures[m]],
209 captures[m + 1] - captures[m]);
210 }
211 }
212
213 if (args.data) {
214 uri.len = args.data - uri.data;
215 args.len = p - args.data;
216
217 r->args = args;
218
219 } else {
220 uri.len = p - uri.data;
221 args.len = 0;
222 }
223
224 r->uri = uri;
225
226 if (scf->log) {
227 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
228 "rewritten uri: \"%V\", args: \"%V\"", &uri, &args);
229 }
230
231 if (ngx_http_set_exten(r) != NGX_OK) {
232 return NGX_HTTP_INTERNAL_SERVER_ERROR;
233 }
234
235 if (rule[i].last) {
236 return NGX_DECLINED;
237 }
238 }
239
240 return NGX_DECLINED;
241 }
242
243
244 static ngx_int_t ngx_http_redirect_handler(ngx_http_request_t *r)
245 {
246 u_char *p;
247 ngx_http_rewrite_loc_conf_t *rlcf;
248
249 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
250 "http redirect handler");
251
252 rlcf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
253
254 r->headers_out.location = ngx_list_push(&r->headers_out.headers);
255 if (r->headers_out.location == NULL) {
256 return NGX_HTTP_INTERNAL_SERVER_ERROR;
257 }
258
259 if (rlcf->redirect.data[0] != '/') {
260 r->headers_out.location->key.len = sizeof("Location") - 1; 418 r->headers_out.location->key.len = sizeof("Location") - 1;
261 r->headers_out.location->key.data = (u_char *) "Location"; 419 r->headers_out.location->key.data = (u_char *) "Location";
262 } 420 }
263 421
264 r->headers_out.location->value.len = rlcf->redirect.len 422 r->headers_out.location->value = e->buf;
265 + r->unparsed_uri.len; 423
266 r->headers_out.location->value.data = ngx_palloc(r->pool, 424 e->ip += sizeof(ngx_http_rewrite_regex_end_code_t);
267 r->headers_out.location->value.len); 425 }
268 426
269 if (r->headers_out.location->value.data == NULL) { 427
270 return NGX_HTTP_INTERNAL_SERVER_ERROR; 428 static void ngx_http_rewrite_copy_capture_code(ngx_http_rewrite_engine_t *e)
271 } 429 {
272 430 ngx_http_rewrite_copy_capture_code_t *code;
273 p = ngx_cpymem(r->headers_out.location->value.data, rlcf->redirect.data, 431
274 rlcf->redirect.len); 432 code = (ngx_http_rewrite_copy_capture_code_t *) e->ip;
275 p = ngx_cpystrn(p, r->unparsed_uri.data + 1, r->unparsed_uri.len); 433
276 434 e->ip += sizeof(ngx_http_rewrite_copy_capture_code_t);
277 return NGX_HTTP_MOVED_TEMPORARILY; 435
278 } 436 if ((e->args || e->quote)
279 437 && (e->request->quoted_uri || e->request->plus_in_uri))
280 438 {
281 static void *ngx_http_rewrite_create_srv_conf(ngx_conf_t *cf) 439 e->pos = (u_char *) ngx_escape_uri(e->pos,
282 { 440 &e->line->data[e->captures[code->n]],
283 ngx_http_rewrite_srv_conf_t *conf; 441 e->captures[code->n + 1] - e->captures[code->n],
284 442 NGX_ESCAPE_ARGS);
285 if (!(conf = ngx_palloc(cf->pool, sizeof(ngx_http_rewrite_srv_conf_t)))) { 443 } else {
286 return NGX_CONF_ERROR; 444 e->pos = ngx_cpymem(e->pos, &e->line->data[e->captures[code->n]],
287 } 445 e->captures[code->n + 1] - e->captures[code->n]);
288 446 }
289 ngx_init_array(conf->rules, cf->pool, 5, sizeof(ngx_http_rewrite_rule_t), 447
290 NGX_CONF_ERROR); 448 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
291 449 "http rewrite capture: \"%V\"", &e->buf);
292 conf->log = NGX_CONF_UNSET; 450 }
293 451
294 return conf; 452
295 } 453 static void ngx_http_rewrite_copy_code(ngx_http_rewrite_engine_t *e)
296 454 {
297 455 ngx_http_rewrite_copy_code_t *code;
298 static char *ngx_http_rewrite_merge_srv_conf(ngx_conf_t *cf, 456
299 void *parent, void *child) 457 code = (ngx_http_rewrite_copy_code_t *) e->ip;
300 { 458
301 ngx_http_rewrite_srv_conf_t *prev = parent; 459 e->pos = ngx_cpymem(e->pos, e->ip + sizeof(ngx_http_rewrite_copy_code_t),
302 ngx_http_rewrite_srv_conf_t *conf = child; 460 code->len);
303 461
304 ngx_conf_merge_value(conf->log, prev->log, 0); 462 e->ip += sizeof(ngx_http_rewrite_copy_code_t)
305 463 + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
306 return NGX_CONF_OK; 464
307 } 465 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
466 "http rewrite copy: \"%V\"", &e->buf);
467 }
468
469
470 static void ngx_http_rewrite_start_args_code(ngx_http_rewrite_engine_t *e)
471 {
472 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
473 "http rewrite args");
474
475 e->args = e->pos;
476 e->ip += sizeof(uintptr_t);
477 }
478
479
480 static void ngx_http_rewrite_return_code(ngx_http_rewrite_engine_t *e)
481 {
482 ngx_http_rewrite_return_code_t *code;
483
484 code = (ngx_http_rewrite_return_code_t *) e->ip;
485
486 e->status = code->status;
487
488 e->ip += sizeof(ngx_http_rewrite_return_code_t) - sizeof(uintptr_t);
489 }
490
491
492 static void ngx_http_rewrite_if_code(ngx_http_rewrite_engine_t *e)
493 {
494 ngx_http_rewrite_if_code_t *code;
495
496 code = (ngx_http_rewrite_if_code_t *) e->ip;
497
498 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
499 "http rewrite if");
500
501 if (*e->sp--) {
502 if (code->loc_conf) {
503 e->request->loc_conf = code->loc_conf;
504 }
505
506 e->ip += sizeof(ngx_http_rewrite_if_code_t);
507 return;
508 }
509
510 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
511 "http rewrite if false");
512
513 e->ip += code->next;
514 }
515
516
517 static void ngx_http_rewrite_var_code(ngx_http_rewrite_engine_t *e)
518 {
519 ngx_http_variable_value_t *value;
520 ngx_http_rewrite_var_code_t *code;
521
522 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
523 "http rewrite var");
524
525 code = (ngx_http_rewrite_var_code_t *) e->ip;
526
527 e->sp++;
528
529 e->ip += sizeof(ngx_http_rewrite_var_code_t);
530
531 if (!(value = ngx_http_get_variable(e->request, code->index))) {
532 *e->sp = (uintptr_t) 0;
533 return;
534 }
535
536 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
537 "http rewrite var: %p", value->value);
538
539 *e->sp = value->value;
540 }
541
542
543 static void ngx_http_rewrite_invalid_referer_code(ngx_http_rewrite_engine_t *e)
544 {
545 u_char *ref;
546 size_t len;
547 ngx_uint_t i, n;
548 ngx_http_request_t *r;
549 ngx_http_rewrite_referer_t *refs;
550 ngx_http_rewrite_loc_conf_t *cf;
551
552 r = e->request;
553
554 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
555 "http rewrite invalid referer");
556
557 cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module);
558
559 e->sp++;
560 e->ip += sizeof(uintptr_t);
561
562 if (cf->referers == NULL) {
563 *e->sp = (uintptr_t) 0;
564 return;
565 }
566
567 if (r->headers_in.referer == NULL) {
568 if (cf->no_referer) {
569 *e->sp = (uintptr_t) 0;
570 return;
571 } else {
572 *e->sp = (uintptr_t) 1;
573 return;
574 }
575 }
576
577 len = r->headers_in.referer->value.len;
578 ref = r->headers_in.referer->value.data;
579
580 if (len < sizeof("http://i.ru") - 1
581 || (ngx_strncasecmp(ref, "http://", 7) != 0))
582 {
583 *e->sp = (uintptr_t) 1;
584 return;
585 }
586
587 len -= 7;
588 ref += 7;
589
590 refs = cf->referers->elts;
591 for (i = 0; i < cf->referers->nelts; i++ ){
592
593 if (refs[i].name.len > len) {
594 continue;
595 }
596
597 if (refs[i].wildcard) {
598 for (n = 0; n < len; n++) {
599 if (ref[n] == '/' || ref[n] == ':') {
600 break;
601 }
602
603 if (ref[n] != '.') {
604 continue;
605 }
606
607 if (ngx_strncmp(&ref[n], refs[i].name.data,
608 refs[i].name.len) == 0)
609 {
610 *e->sp = (uintptr_t) 0;
611 return;
612 }
613 }
614
615 } else {
616 if (ngx_strncasecmp(refs[i].name.data, ref, refs[i].name.len) == 0)
617 {
618 *e->sp = (uintptr_t) 0;
619 return;
620 }
621 }
622 }
623
624 *e->sp = (uintptr_t) 1;
625 }
626
627
628 static void ngx_http_rewrite_nop_code(ngx_http_rewrite_engine_t *e)
629 {
630 e->ip += sizeof(uintptr_t);
631 }
632
633
634 static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle)
635 {
636 ngx_http_handler_pt *h;
637 ngx_http_core_main_conf_t *cmcf;
638
639 cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
640
641 h = ngx_push_array(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers);
642 if (h == NULL) {
643 return NGX_ERROR;
644 }
645
646 *h = ngx_http_rewrite_handler;
647
648 return NGX_OK;
649 }
308 650
309 651
310 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf) 652 static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf)
311 { 653 {
312 ngx_http_rewrite_loc_conf_t *conf; 654 ngx_http_rewrite_loc_conf_t *conf;
313 655
314 if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t)))) { 656 if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t)))) {
315 return NGX_CONF_ERROR; 657 return NGX_CONF_ERROR;
316 } 658 }
317 659
660 conf->stack_size = NGX_CONF_UNSET_UINT;
661 conf->log = NGX_CONF_UNSET;
662 conf->no_referer = NGX_CONF_UNSET;
663
318 return conf; 664 return conf;
319 } 665 }
320 666
321 667
322 static char *ngx_http_rewrite_rule(ngx_conf_t *cf, ngx_command_t *cmd, 668 static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf,
323 void *conf) 669 void *parent, void *child)
324 { 670 {
325 ngx_http_rewrite_srv_conf_t *scf = conf; 671 ngx_http_rewrite_loc_conf_t *prev = parent;
326 672 ngx_http_rewrite_loc_conf_t *conf = child;
327 u_char *data, *p; 673
328 size_t len; 674 uintptr_t *code, *last;
329 ngx_str_t *value, err; 675 ngx_http_rewrite_regex_code_t *regex;
330 ngx_uint_t i, n; 676
331 ngx_http_rewrite_op_t *op; 677 ngx_conf_merge_value(conf->log, prev->log, 0);
332 ngx_http_rewrite_rule_t *rule; 678 ngx_conf_merge_unsigned_value(conf->stack_size, prev->stack_size, 10);
333 u_char errstr[NGX_MAX_CONF_ERRSTR]; 679
334 680 if (conf->referers == NULL) {
335 if (!(rule = ngx_push_array(&scf->rules))) { 681 conf->referers = prev->referers;
682 ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0);
683 }
684
685 if (conf->codes == NULL) {
686 return NGX_CONF_OK;
687 }
688
689 if (conf->codes == prev->codes) {
690 return NGX_CONF_OK;
691 }
692
693 code = conf->codes->elts;
694 last = (uintptr_t *) ((u_char *) code + conf->codes->nelts);
695
696 while (code < last) {
697 if (*code == (uintptr_t) NULL) {
698 return NGX_CONF_OK;
699 }
700
701 if (*code == (uintptr_t) &ngx_http_rewrite_regex_start_code) {
702 regex = (ngx_http_rewrite_regex_code_t *) code;
703 if (conf->max_captures < regex->ncaptures) {
704 conf->max_captures = regex->ncaptures;
705 }
706 code = (uintptr_t *) ((u_char *) code + regex->next);
707 }
708
709 if (*code == (uintptr_t) &ngx_http_rewrite_if_code) {
710 code += sizeof(ngx_http_rewrite_if_code_t) / sizeof(uintptr_t);
711 }
712
713 if (*code == (uintptr_t) &ngx_http_rewrite_return_code) {
714 code += sizeof(ngx_http_rewrite_return_code_t) / sizeof(uintptr_t);
715 }
716
717 if (*code == (uintptr_t) &ngx_http_rewrite_var_code) {
718 code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t);
719 }
720
721 if (*code == (uintptr_t) &ngx_http_rewrite_invalid_referer_code) {
722 code++;
723 }
724
725 if (*code == (uintptr_t) &ngx_http_rewrite_nop_code) {
726 code++;
727 }
728 }
729
730 if (!(code = ngx_array_push_n(conf->codes, sizeof(uintptr_t)))) {
336 return NGX_CONF_ERROR; 731 return NGX_CONF_ERROR;
337 } 732 }
338 733
339 ngx_init_array(rule->ops, cf->pool, 5, sizeof(ngx_http_rewrite_op_t), 734 *code = (uintptr_t) NULL;
340 NGX_CONF_ERROR); 735
341 736 return NGX_CONF_OK;
342 rule->ncaptures = 0; 737 }
343 rule->size = 0; 738
344 rule->status = 0; 739
345 rule->last = 0; 740 static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
741 {
742 ngx_http_rewrite_loc_conf_t *lcf = conf;
743
744 u_char *data;
745 size_t len, size;
746 ngx_str_t *value, err;
747 ngx_uint_t i, n, last;
748 ngx_http_rewrite_code_pt *code;
749 ngx_http_rewrite_copy_code_t *copy;
750 ngx_http_rewrite_regex_code_t *regex;
751 ngx_http_rewrite_regex_end_code_t *regex_end;
752 ngx_http_rewrite_copy_capture_code_t *copy_capture;
753 u_char errstr[NGX_MAX_CONF_ERRSTR];
754
755 regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
756 sizeof(ngx_http_rewrite_regex_code_t));
757 if (regex == NULL) {
758 return NGX_CONF_ERROR;
759 }
346 760
347 value = cf->args->elts; 761 value = cf->args->elts;
348 762
349 /* STUB */ { 763 err.len = NGX_MAX_CONF_ERRSTR;
350 err.len = NGX_MAX_CONF_ERRSTR; 764 err.data = errstr;
351 err.data = errstr; 765
352 766 /* TODO: NGX_REGEX_CASELESS */
353 rule->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err); 767
354 768 regex->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err);
355 if (rule->regex == NULL) { 769
356 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); 770 if (regex->regex == NULL) {
357 return NGX_CONF_ERROR; 771 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data);
358 } 772 return NGX_CONF_ERROR;
359 773 }
360 rule->re_name = value[1]; 774
361 rule->s_name = value[2]; 775 regex->code = ngx_http_rewrite_regex_start_code;
362 776 regex->size = 0;
363 if (ngx_strcasecmp(value[2].data, "forbidden:") == 0) { 777 regex->ncaptures = 0;
364 778 regex->status = 0;
365 if (cf->args->nelts == 3) { 779 regex->uri = 1;
366 rule->status = NGX_HTTP_FORBIDDEN; 780 regex->args = 1;
367 rule->last = 1; 781 regex->redirect = 0;
368 return NGX_CONF_OK; 782 regex->name = value[1];
369 } 783
370 784 last = 0;
785
786 if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0) {
787 regex->status = NGX_HTTP_MOVED_TEMPORARILY;
788 regex->redirect = 1;
789 last = 1;
790 }
791
792 if (cf->args->nelts == 4) {
793 if (ngx_strcmp(value[3].data, "last") == 0) {
794 last = 1;
795
796 } else if (ngx_strcmp(value[3].data, "redirect") == 0) {
797 regex->status = NGX_HTTP_MOVED_TEMPORARILY;
798 regex->redirect = 1;
799 last = 1;
800
801 } else if (ngx_strcmp(value[3].data, "permanent") == 0) {
802 regex->status = NGX_HTTP_MOVED_PERMANENTLY;
803 regex->redirect = 1;
804 last = 1;
805
806 } else {
371 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 807 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
372 "invalid parameter \"%V\"", &value[3]); 808 "invalid parameter \"%V\"", &value[3]);
373 return NGX_CONF_ERROR; 809 return NGX_CONF_ERROR;
374 } 810 }
375 811 }
376 i = 0; 812
377 813 i = 0;
378 while (i < value[2].len) { 814
379 815 while (i < value[2].len) {
380 if (!(op = ngx_push_array(&rule->ops))) { 816
817 data = &value[2].data[i];
818
819 if (value[2].data[i] == '$' && i < value[2].len
820 && value[2].data[i + 1] >= '1' && value[2].data[i + 1] <= '9')
821 {
822
823 /* the "$1" - "$9" captures */
824
825 copy_capture = ngx_http_rewrite_add_code(lcf->codes,
826 sizeof(ngx_http_rewrite_copy_capture_code_t),
827 (u_char **) &regex);
828 if (copy_capture == NULL) {
381 return NGX_CONF_ERROR; 829 return NGX_CONF_ERROR;
382 } 830 }
383 831
384 data = &value[2].data[i]; 832 i++;
385 833
386 if (value[2].data[i] == '$' 834 copy_capture->code = ngx_http_rewrite_copy_capture_code;
387 && i < value[2].len 835 copy_capture->n = value[2].data[i] - '0';
388 && value[2].data[i + 1] >= '1' 836
389 && value[2].data[i + 1] <= '9') 837 if (regex->ncaptures < copy_capture->n) {
390 { 838 regex->ncaptures = copy_capture->n;
391 op->op = NGX_HTTP_REWRITE_COPY_CAPTURE; 839 }
392 op->len = 0; 840
393 op->data = value[2].data[++i] - '0'; 841 copy_capture->n *= 2;
394 842
395 if (rule->ncaptures < op->data) { 843 i++;
396 rule->ncaptures = op->data; 844
845 continue;
846 }
847
848 if (value[2].data[i] == '?') {
849
850 /* the arguments */
851
852 if (i == value[2].len - 1) {
853 /* the last "?" drops the original arguments */
854 regex->args = 0;
855 break;
856 }
857
858 if (!regex->redirect) {
859 code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t),
860 (u_char **) &regex);
861 if (code == NULL) {
862 return NGX_CONF_ERROR;
397 } 863 }
864
865 *code = ngx_http_rewrite_start_args_code;
398 866
399 i++; 867 i++;
400 868
401 continue; 869 continue;
402 } 870 }
871 }
872
873 i++;
874
875 /* the substituion strings */
876
877 while (i < value[2].len && value[2].data[i] != '$') {
403 878
404 if (value[2].data[i] == '?') { 879 if (value[2].data[i] == '?') {
405 op->op = NGX_HTTP_REWRITE_START_ARGS; 880
406 op->len = 0; 881 if (i == value[2].len - 1) {
407 op->data = 0; 882 /*
408 883 * the last "?" drops the original arguments,
409 i++; 884 * and it should not be copied to a substituion
410 885 */
886 regex->args = 0;
887 break;
888 }
889
890 if (!regex->redirect) {
891 break;
892 }
893 }
894
895 i++;
896 }
897
898 len = &value[2].data[i] - data;
899
900 if (len == 0) {
901 continue;
902 }
903
904 regex->size += len;
905
906 size = (len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
907
908 copy = ngx_http_rewrite_add_code(lcf->codes,
909 sizeof(ngx_http_rewrite_copy_code_t) + size,
910 (u_char **) &regex);
911 if (copy == NULL) {
912 return NGX_CONF_ERROR;
913 }
914
915 copy->code = ngx_http_rewrite_copy_code;
916 copy->len = len;
917
918 ngx_memcpy((u_char *) copy + sizeof(ngx_http_rewrite_copy_code_t),
919 data, len);
920 }
921
922 n = ngx_regex_capture_count(regex->regex);
923
924 if (regex->ncaptures > n) {
925 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
926 "pattern \"%V\" has less captures "
927 "than referrenced in substitution \"%V\"",
928 &value[1], &value[2]);
929 return NGX_CONF_ERROR;
930 }
931
932 if (regex->ncaptures < n) {
933 regex->ncaptures = n;
934 }
935
936 if (regex->ncaptures) {
937 regex->ncaptures = (regex->ncaptures + 1) * 3;
938 }
939
940 regex_end = ngx_http_rewrite_add_code(lcf->codes,
941 sizeof(ngx_http_rewrite_regex_end_code_t),
942 (u_char **) &regex);
943 if (regex_end == NULL) {
944 return NGX_CONF_ERROR;
945 }
946
947 regex_end->code = ngx_http_rewrite_regex_end_code;
948 regex_end->uri = regex->uri;
949 regex_end->args = regex->args;
950 regex_end->redirect = regex->redirect;
951
952 if (last) {
953 code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t),
954 (u_char **) &regex);
955 if (code == NULL) {
956 return NGX_CONF_ERROR;
957 }
958
959 *code = (uintptr_t) NULL;
960 }
961
962 regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
963 - (u_char *) regex;
964
965 return NGX_CONF_OK;
966 }
967
968
969
970 static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd,
971 void *conf)
972 {
973 ngx_http_rewrite_loc_conf_t *lcf = conf;
974
975 ngx_str_t *value;
976 ngx_http_rewrite_return_code_t *ret;
977
978 ret = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
979 sizeof(ngx_http_rewrite_return_code_t));
980 if (ret == NULL) {
981 return NGX_CONF_ERROR;
982 }
983
984 value = cf->args->elts;
985
986 ret->code = ngx_http_rewrite_return_code;
987 ret->null = (uintptr_t) NULL;
988
989 ret->status = ngx_atoi(value[1].data, value[1].len);
990
991 if (ret->status == (uintptr_t) NGX_ERROR) {
992 return NGX_CONF_ERROR;
993 }
994
995 return NGX_CONF_OK;
996 }
997
998
999 static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
1000 {
1001 ngx_http_rewrite_loc_conf_t *lcf = conf;
1002
1003 void *mconf;
1004 char *rv;
1005 u_char *elts;
1006 ngx_str_t *value;
1007 ngx_uint_t i;
1008 ngx_conf_t save;
1009 ngx_http_rewrite_code_pt *code;
1010 ngx_http_module_t *module;
1011 ngx_http_conf_ctx_t *ctx, *pctx;
1012 ngx_http_variable_t *var;
1013 ngx_http_core_loc_conf_t *clcf, *pclcf, **clcfp;
1014 ngx_http_core_main_conf_t *cmcf;
1015 ngx_http_rewrite_if_code_t *if_code;
1016 ngx_http_rewrite_var_code_t *var_code;
1017 ngx_http_rewrite_loc_conf_t *nlcf;
1018
1019 if (!(ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)))) {
1020 return NGX_CONF_ERROR;
1021 }
1022
1023 pctx = cf->ctx;
1024 ctx->main_conf = pctx->main_conf;
1025 ctx->srv_conf = pctx->srv_conf;
1026
1027 ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
1028 if (ctx->loc_conf == NULL) {
1029 return NGX_CONF_ERROR;
1030 }
1031
1032 for (i = 0; ngx_modules[i]; i++) {
1033 if (ngx_modules[i]->type != NGX_HTTP_MODULE) {
1034 continue;
1035 }
1036
1037 module = ngx_modules[i]->ctx;
1038
1039 if (module->create_loc_conf) {
1040
1041 if (!(mconf = module->create_loc_conf(cf))) {
1042 return NGX_CONF_ERROR;
1043 }
1044
1045 ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf;
1046 }
1047 }
1048
1049 pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
1050
1051 clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
1052 clcf->loc_conf = ctx->loc_conf;
1053 clcf->name = pclcf->name;
1054 clcf->noname = 1;
1055
1056 if (pclcf->locations.elts == NULL) {
1057 if (ngx_array_init(&pclcf->locations, cf->pool, 4, sizeof(void *))
1058 == NGX_ERROR)
1059 {
1060 return NGX_CONF_ERROR;
1061 }
1062 }
1063
1064 if (!(clcfp = ngx_push_array(&pclcf->locations))) {
1065 return NGX_CONF_ERROR;
1066 }
1067
1068 *clcfp = clcf;
1069
1070
1071 /* STUB: "if ($var)" */
1072
1073 value = cf->args->elts;
1074
1075 if (value[1].len < 2
1076 || value[1].data[0] != '('
1077 || value[1].data[1] != '$'
1078 || value[1].data[value[1].len - 1] != ')')
1079 {
1080 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1081 "invalid condition \"%V\"", &value[1]);
1082 return NGX_CONF_ERROR;
1083 }
1084
1085 value[1].len -= 3;
1086 value[1].data += 2;
1087
1088 if (value[1].len == sizeof("invalid_referer") - 1
1089 && ngx_strncmp(value[1].data, "invalid_referer",
1090 sizeof("invalid_referer") - 1) == 0)
1091 {
1092 code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
1093 sizeof(ngx_http_rewrite_code_pt));
1094 if (code == NULL) {
1095 return NGX_CONF_ERROR;
1096 }
1097
1098 *code = ngx_http_rewrite_invalid_referer_code;
1099
1100 } else {
1101
1102 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
1103
1104 var = cmcf->variables.elts;
1105 for (i = 0; i < cmcf->variables.nelts; i++) {
1106 if (var[i].name.len != value[1].len) {
411 continue; 1107 continue;
412 } 1108 }
413 1109
414 i++; 1110 if (ngx_strncasecmp(var[i].name.data, value[1].data,
415 1111 var[i].name.len) == 0)
416 while (i < value[2].len
417 && value[2].data[i] != '$'
418 && value[2].data[i] != '?')
419 { 1112 {
420 i++; 1113 break;
421 } 1114 }
422 1115 }
423 len = &value[2].data[i] - data; 1116
424 rule->size += len; 1117 if (i == cmcf->variables.nelts) {
425
426 if (len) {
427
428 op->len = len;
429
430 if (len <= sizeof(uintptr_t)) {
431 op->op = NGX_HTTP_REWRITE_COPY_SHORT;
432 op->data = 0;
433
434 while (len--) {
435 op->data <<= 8;
436 op->data |= data[len];
437 }
438
439 } else {
440 op->op = NGX_HTTP_REWRITE_COPY_LONG;
441
442 if (!(p = ngx_palloc(cf->pool, len))) {
443 return NGX_CONF_ERROR;
444 }
445
446 ngx_memcpy(p, data, len);
447 op->data = (uintptr_t) p;
448 }
449 }
450 }
451
452 n = ngx_regex_capture_count(rule->regex);
453
454 if (rule->ncaptures > n) {
455 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1118 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
456 "pattern \"%V\" has less captures " 1119 "unknown variable name \"%V\"", &value[1]);
457 "than referrenced in substitution \"%V\"",
458 &value[1], &value[2]);
459 return NGX_CONF_ERROR; 1120 return NGX_CONF_ERROR;
460 } 1121 }
461 1122
462 if (rule->ncaptures < n) { 1123 var_code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes,
463 rule->ncaptures = n; 1124 sizeof(ngx_http_rewrite_var_code_t));
464 } 1125 if (var_code == NULL) {
465 1126 return NGX_CONF_ERROR;
466 if (rule->ncaptures) { 1127 }
467 rule->ncaptures = (rule->ncaptures + 1) * 3; 1128
468 } 1129 var_code->code = ngx_http_rewrite_var_code;
469 1130 var_code->index = var[i].index;
470 if (cf->args->nelts > 3) { 1131 }
471 if (ngx_strcmp(value[3].data, "last") == 0) { 1132
472 rule->last = 1; 1133 if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_rewrite_if_code_t));
473 1134 if (if_code == NULL) {
474 } else { 1135 return NULL;
475 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 1136 }
476 "invalid parameter \"%V\"", &value[3]); 1137
477 return NGX_CONF_ERROR; 1138 if_code->code = ngx_http_rewrite_if_code;
478 } 1139
479 } 1140 elts = lcf->codes->elts;
480 } 1141
1142
1143 /* the inside directives must compile to the same code array */
1144
1145 nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index];
1146 nlcf->codes = lcf->codes;
1147
1148
1149 save = *cf;
1150 cf->ctx = ctx;
1151
1152 if (pclcf->name.len == 0) {
1153 if_code->loc_conf = NULL;
1154 cf->cmd_type = NGX_HTTP_SIF_CONF;
1155
1156 } else {
1157 if_code->loc_conf = ctx->loc_conf;
1158 cf->cmd_type = NGX_HTTP_LIF_CONF;
1159 }
1160
1161 rv = ngx_conf_parse(cf, NULL);
1162
1163 *cf = save;
1164
1165 if (rv != NGX_CONF_OK) {
1166 return rv;
1167 }
1168
1169
1170 if (elts != lcf->codes->elts) {
1171 if_code = (ngx_http_rewrite_if_code_t *)
1172 ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts));
1173 }
1174
1175 if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts
1176 - (u_char *) if_code;
481 1177
482 return NGX_CONF_OK; 1178 return NGX_CONF_OK;
483 } 1179 }
484 1180
485 1181
486 static char *ngx_http_redirect(ngx_conf_t *cf, void *post, void *data) 1182 static char *ngx_http_rewrite_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd,
487 { 1183 void *conf)
488 ngx_http_core_loc_conf_t *clcf; 1184 {
489 1185 ngx_http_rewrite_loc_conf_t *lcf = conf;
490 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 1186
491 clcf->handler = ngx_http_redirect_handler; 1187 ngx_uint_t i, server_names;
1188 ngx_str_t *value;
1189 ngx_http_server_name_t *sn;
1190 ngx_http_core_srv_conf_t *cscf;
1191 ngx_http_rewrite_referer_t *ref;
1192
1193 cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module);
1194
1195 if (lcf->referers == NULL) {
1196 lcf->referers = ngx_array_create(cf->pool,
1197 cf->args->nelts + cscf->server_names.nelts,
1198 sizeof(ngx_http_rewrite_referer_t));
1199 if (lcf->referers == NULL) {
1200 return NGX_CONF_ERROR;
1201 }
1202 }
1203
1204 value = cf->args->elts;
1205 server_names = 0;
1206
1207 for (i = 1; i < cf->args->nelts; i++) {
1208 if (value[i].len == 0) {
1209 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1210 "invalid referer \"%V\"", &value[i]);
1211 return NGX_CONF_ERROR;
1212 }
1213
1214 if (ngx_strcmp(value[i].data, "none") == 0) {
1215 lcf->no_referer = 1;
1216 continue;
1217 }
1218
1219 if (ngx_strcmp(value[i].data, "server_names") == 0) {
1220 server_names = 1;
1221 continue;
1222 }
1223
1224 if (!(ref = ngx_array_push(lcf->referers))) {
1225 return NGX_CONF_ERROR;
1226 }
1227
1228 if (value[i].data[0] != '*') {
1229 ref->name = value[i];
1230 ref->wildcard = 0;
1231 continue;
1232 }
1233
1234 if (value[i].data[1] != '.') {
1235 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
1236 "invalid wildcard referer \"%V\"", &value[i]);
1237 return NGX_CONF_ERROR;
1238 }
1239
1240 ref->name.len = value[i].len - 1;
1241 ref->name.data = value[i].data + 1;
1242 ref->wildcard = 1;
1243 }
1244
1245 if (!server_names) {
1246 return NGX_CONF_OK;
1247 }
1248
1249 sn = cscf->server_names.elts;
1250 for (i = 0; i < cscf->server_names.nelts; i++) {
1251 if (!(ref = ngx_array_push(lcf->referers))) {
1252 return NGX_CONF_ERROR;
1253 }
1254
1255 ref->name.len = sn[i].name.len + 1;
1256 if (!(ref->name.data = ngx_palloc(cf->pool, ref->name.len))) {
1257 return NGX_CONF_ERROR;
1258 }
1259
1260 ngx_memcpy(ref->name.data, sn[i].name.data, sn[i].name.len);
1261 ref->name.data[sn[i].name.len] = '/';
1262 ref->wildcard = sn[i].wildcard;
1263 }
492 1264
493 return NGX_CONF_OK; 1265 return NGX_CONF_OK;
494 } 1266 }
495 1267
496 1268
497 static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle) 1269 static void *ngx_http_rewrite_start_code(ngx_pool_t *pool,
498 { 1270 ngx_array_t **codes, size_t size)
499 ngx_http_handler_pt *h; 1271 {
500 ngx_http_core_main_conf_t *cmcf; 1272 if (*codes == NULL) {
501 1273 if (!(*codes = ngx_array_create(pool, 256, 1))) {
502 cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); 1274 return NULL;
503 1275 }
504 h = ngx_push_array(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); 1276 }
505 if (h == NULL) { 1277
506 return NGX_ERROR; 1278 return ngx_array_push_n(*codes, size);
507 } 1279 }
508 1280
509 *h = ngx_http_rewrite_handler; 1281
510 1282 static void *ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size,
511 return NGX_OK; 1283 u_char **main)
512 } 1284 {
1285 u_char *elts;
1286 void *new;
1287
1288 elts = codes->elts;
1289
1290 if (!(new = ngx_array_push_n(codes, size))) {
1291 return NGX_CONF_ERROR;
1292 }
1293
1294 if (elts != codes->elts) {
1295 *main += (u_char *) codes->elts - elts;
1296 }
1297
1298 return new;
1299 }