Mercurial > hg > nginx-ranges
comparison src/http/modules/ngx_http_index_module.c @ 344:eae74a780a84 NGINX_0_6_16
nginx 0.6.16
*) Change: now the uname(2) is used on Linux instead of procfs.
Thanks to Ilya Novikov.
*) Bugfix: if the "?" character was in a "error_page" directive, then
it was escaped in a proxied request; bug appeared in 0.6.11.
*) Bugfix: compatibility with mget.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 29 Oct 2007 00:00:00 +0300 |
parents | 3a91bfeffaba |
children | 05693816539c |
comparison
equal
deleted
inserted
replaced
343:81bf600d64d5 | 344:eae74a780a84 |
---|---|
20 ngx_array_t *indices; /* array of ngx_http_index_t */ | 20 ngx_array_t *indices; /* array of ngx_http_index_t */ |
21 size_t max_index_len; | 21 size_t max_index_len; |
22 } ngx_http_index_loc_conf_t; | 22 } ngx_http_index_loc_conf_t; |
23 | 23 |
24 | 24 |
25 typedef struct { | |
26 ngx_uint_t current; | |
27 | |
28 ngx_str_t path; | |
29 ngx_str_t index; | |
30 | |
31 size_t root; | |
32 | |
33 ngx_uint_t tested; /* unsigned tested:1 */ | |
34 } ngx_http_index_ctx_t; | |
35 | |
36 | |
37 #define NGX_HTTP_DEFAULT_INDEX "index.html" | 25 #define NGX_HTTP_DEFAULT_INDEX "index.html" |
38 | 26 |
39 | 27 |
40 static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, | 28 static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, |
41 ngx_http_core_loc_conf_t *clcf, ngx_http_index_ctx_t *ctx); | 29 ngx_http_core_loc_conf_t *clcf, u_char *path, u_char *last); |
42 static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, | 30 static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, u_char *file, |
43 ngx_http_index_ctx_t *ctx, ngx_err_t err); | 31 ngx_err_t err); |
44 | 32 |
45 static ngx_int_t ngx_http_index_init(ngx_conf_t *cf); | 33 static ngx_int_t ngx_http_index_init(ngx_conf_t *cf); |
46 static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf); | 34 static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf); |
47 static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf, | 35 static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf, |
48 void *parent, void *child); | 36 void *parent, void *child); |
105 */ | 93 */ |
106 | 94 |
107 static ngx_int_t | 95 static ngx_int_t |
108 ngx_http_index_handler(ngx_http_request_t *r) | 96 ngx_http_index_handler(ngx_http_request_t *r) |
109 { | 97 { |
110 u_char *last; | 98 u_char *p, *name; |
111 size_t len; | 99 size_t len, nlen, root, allocated; |
112 ngx_int_t rc; | 100 ngx_int_t rc; |
113 ngx_str_t path, uri; | 101 ngx_str_t path, uri; |
114 ngx_log_t *log; | 102 ngx_log_t *log; |
115 ngx_uint_t i; | 103 ngx_uint_t i, dir_tested; |
116 ngx_http_index_t *index; | 104 ngx_http_index_t *index; |
117 ngx_http_index_ctx_t *ctx; | |
118 ngx_open_file_info_t of; | 105 ngx_open_file_info_t of; |
119 ngx_http_script_code_pt code; | 106 ngx_http_script_code_pt code; |
120 ngx_http_script_engine_t e; | 107 ngx_http_script_engine_t e; |
121 ngx_http_core_loc_conf_t *clcf; | 108 ngx_http_core_loc_conf_t *clcf; |
122 ngx_http_index_loc_conf_t *ilcf; | 109 ngx_http_index_loc_conf_t *ilcf; |
138 log = r->connection->log; | 125 log = r->connection->log; |
139 | 126 |
140 ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); | 127 ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); |
141 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | 128 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
142 | 129 |
143 /* | 130 allocated = 0; |
144 * we use context because the handler supports an async file opening, | 131 root = 0; |
145 * and may be called several times | 132 dir_tested = 0; |
146 */ | 133 name = NULL; |
147 | 134 path.data = NULL; |
148 ctx = ngx_http_get_module_ctx(r, ngx_http_index_module); | |
149 if (ctx == NULL) { | |
150 | |
151 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_index_ctx_t)); | |
152 if (ctx == NULL) { | |
153 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
154 } | |
155 | |
156 ngx_http_set_ctx(r, ctx, ngx_http_index_module); | |
157 } | |
158 | 135 |
159 index = ilcf->indices->elts; | 136 index = ilcf->indices->elts; |
160 for (i = ctx->current; i < ilcf->indices->nelts; i++) { | 137 for (i = 0; i < ilcf->indices->nelts; i++) { |
161 | 138 |
162 if (index[i].lengths == NULL) { | 139 if (index[i].lengths == NULL) { |
163 | 140 |
164 if (index[i].name.data[0] == '/') { | 141 if (index[i].name.data[0] == '/') { |
165 return ngx_http_internal_redirect(r, &index[i].name, &r->args); | 142 return ngx_http_internal_redirect(r, &index[i].name, &r->args); |
166 } | 143 } |
167 | 144 |
168 len = ilcf->max_index_len; | 145 len = ilcf->max_index_len; |
169 ctx->index.len = index[i].name.len; | 146 nlen = index[i].name.len; |
170 | 147 |
171 } else { | 148 } else { |
172 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); | 149 ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); |
173 | 150 |
174 e.ip = index[i].lengths->elts; | 151 e.ip = index[i].lengths->elts; |
182 while (*(uintptr_t *) e.ip) { | 159 while (*(uintptr_t *) e.ip) { |
183 lcode = *(ngx_http_script_len_code_pt *) e.ip; | 160 lcode = *(ngx_http_script_len_code_pt *) e.ip; |
184 len += lcode(&e); | 161 len += lcode(&e); |
185 } | 162 } |
186 | 163 |
187 ctx->index.len = len; | 164 nlen = len; |
188 | 165 |
189 /* 16 bytes are preallocation */ | 166 /* 16 bytes are preallocation */ |
190 | 167 |
191 len += 16; | 168 len += 16; |
192 } | 169 } |
193 | 170 |
194 if (len > (size_t) (ctx->path.data + ctx->path.len - ctx->index.data)) { | 171 if (len > (size_t) (path.data + allocated - name)) { |
195 | 172 |
196 last = ngx_http_map_uri_to_path(r, &ctx->path, &ctx->root, len); | 173 name = ngx_http_map_uri_to_path(r, &path, &root, len); |
197 if (last == NULL) { | 174 if (name == NULL) { |
198 return NGX_ERROR; | 175 return NGX_ERROR; |
199 } | 176 } |
200 | 177 |
201 ctx->index.data = last; | 178 allocated = path.len; |
202 } | 179 } |
203 | |
204 path.data = ctx->path.data; | |
205 | 180 |
206 if (index[i].values == NULL) { | 181 if (index[i].values == NULL) { |
207 | 182 |
208 /* index[i].name.len includes the terminating '\0' */ | 183 /* index[i].name.len includes the terminating '\0' */ |
209 | 184 |
210 ngx_memcpy(ctx->index.data, index[i].name.data, index[i].name.len); | 185 ngx_memcpy(name, index[i].name.data, index[i].name.len); |
211 | 186 |
212 path.len = (ctx->index.data + index[i].name.len - 1) - path.data; | 187 path.len = (name + index[i].name.len - 1) - path.data; |
213 | 188 |
214 } else { | 189 } else { |
215 e.ip = index[i].values->elts; | 190 e.ip = index[i].values->elts; |
216 e.pos = ctx->index.data; | 191 e.pos = name; |
217 | 192 |
218 while (*(uintptr_t *) e.ip) { | 193 while (*(uintptr_t *) e.ip) { |
219 code = *(ngx_http_script_code_pt *) e.ip; | 194 code = *(ngx_http_script_code_pt *) e.ip; |
220 code((ngx_http_script_engine_t *) &e); | 195 code((ngx_http_script_engine_t *) &e); |
221 } | 196 } |
222 | 197 |
223 if (*ctx->index.data == '/') { | 198 if (*name == '/') { |
224 ctx->index.len--; | 199 uri.len = nlen - 1; |
225 return ngx_http_internal_redirect(r, &ctx->index, &r->args); | 200 uri.data = name; |
201 return ngx_http_internal_redirect(r, &uri, &r->args); | |
226 } | 202 } |
227 | 203 |
228 path.len = e.pos - path.data; | 204 path.len = e.pos - path.data; |
229 | 205 |
230 *e.pos++ = '\0'; | 206 *e.pos++ = '\0'; |
231 } | 207 } |
232 | 208 |
233 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, | 209 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "open index \"%V\"", &path); |
234 "open index \"%V\"", &path); | |
235 | 210 |
236 of.test_dir = 0; | 211 of.test_dir = 0; |
237 of.retest = clcf->open_file_cache_retest; | 212 of.retest = clcf->open_file_cache_retest; |
238 of.errors = clcf->open_file_cache_errors; | 213 of.errors = clcf->open_file_cache_errors; |
239 of.events = clcf->open_file_cache_events; | 214 of.events = clcf->open_file_cache_events; |
240 | 215 |
241 rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool); | 216 rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool); |
242 | 217 |
243 #if 0 | |
244 if (rc == NGX_AGAIN) { | |
245 ctx->current = i; | |
246 return NGX_AGAIN; | |
247 } | |
248 #endif | |
249 | |
250 if (rc == NGX_ERROR) { | 218 if (rc == NGX_ERROR) { |
251 | 219 |
252 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, of.err, | 220 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, of.err, |
253 ngx_open_file_n " \"%s\" failed", ctx->path.data); | 221 ngx_open_file_n " \"%s\" failed", path.data); |
254 | 222 |
255 if (of.err == 0) { | 223 if (of.err == 0) { |
256 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 224 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
257 } | 225 } |
258 | 226 |
259 if (of.err == NGX_ENOTDIR) { | 227 if (of.err == NGX_ENOTDIR || of.err == NGX_EACCES) { |
260 return ngx_http_index_error(r, ctx, of.err); | 228 return ngx_http_index_error(r, path.data, of.err); |
261 | 229 } |
262 } else if (of.err == NGX_EACCES) { | 230 |
263 return ngx_http_index_error(r, ctx, of.err); | 231 if (!dir_tested) { |
264 } | 232 rc = ngx_http_index_test_dir(r, clcf, path.data, name - 1); |
265 | |
266 if (!ctx->tested) { | |
267 rc = ngx_http_index_test_dir(r, clcf, ctx); | |
268 | 233 |
269 if (rc != NGX_OK) { | 234 if (rc != NGX_OK) { |
270 return rc; | 235 return rc; |
271 } | 236 } |
272 | 237 |
273 ctx->tested = 1; | 238 dir_tested = 1; |
274 } | 239 } |
275 | 240 |
276 if (of.err == NGX_ENOENT) { | 241 if (of.err == NGX_ENOENT) { |
277 continue; | 242 continue; |
278 } | 243 } |
279 | 244 |
280 ngx_log_error(NGX_LOG_ERR, log, of.err, | 245 ngx_log_error(NGX_LOG_ERR, log, of.err, |
281 ngx_open_file_n " \"%s\" failed", ctx->path.data); | 246 ngx_open_file_n " \"%s\" failed", path.data); |
282 | 247 |
283 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 248 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
284 } | 249 } |
285 | 250 |
286 uri.len = r->uri.len + ctx->index.len - 1; | 251 uri.len = r->uri.len + nlen - 1; |
287 | 252 |
288 if (!clcf->alias) { | 253 if (!clcf->alias) { |
289 uri.data = ctx->path.data + ctx->root; | 254 uri.data = path.data + root; |
290 | 255 |
291 } else { | 256 } else { |
292 uri.data = ngx_palloc(r->pool, uri.len); | 257 uri.data = ngx_palloc(r->pool, uri.len); |
293 if (uri.data == NULL) { | 258 if (uri.data == NULL) { |
294 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 259 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
295 } | 260 } |
296 | 261 |
297 last = ngx_copy(uri.data, r->uri.data, r->uri.len); | 262 p = ngx_copy(uri.data, r->uri.data, r->uri.len); |
298 ngx_memcpy(last, ctx->index.data, ctx->index.len - 1); | 263 ngx_memcpy(p, name, nlen - 1); |
299 } | 264 } |
300 | 265 |
301 return ngx_http_internal_redirect(r, &uri, &r->args); | 266 return ngx_http_internal_redirect(r, &uri, &r->args); |
302 } | 267 } |
303 | 268 |
305 } | 270 } |
306 | 271 |
307 | 272 |
308 static ngx_int_t | 273 static ngx_int_t |
309 ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, | 274 ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, |
310 ngx_http_index_ctx_t *ctx) | 275 u_char *path, u_char *last) |
311 { | 276 { |
312 u_char c; | 277 u_char c; |
313 ngx_str_t path; | 278 ngx_str_t dir; |
314 ngx_uint_t i; | |
315 ngx_open_file_info_t of; | 279 ngx_open_file_info_t of; |
316 | 280 |
317 c = *(ctx->index.data - 1); | 281 c = *last; |
318 i = (c == '/') ? 1 : 0; | 282 if (c != '/') { |
319 *(ctx->index.data - i) = '\0'; | 283 /* "alias" without trailing slash */ |
320 | 284 c = *(++last); |
321 path.len = (ctx->index.data - i) - ctx->path.data; | 285 } |
322 path.data = ctx->path.data; | 286 *last = '\0'; |
287 | |
288 dir.len = last - path; | |
289 dir.data = path; | |
323 | 290 |
324 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 291 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
325 "http index check dir: \"%V\"", &path); | 292 "http index check dir: \"%V\"", &dir); |
326 | 293 |
327 of.test_dir = 1; | 294 of.test_dir = 1; |
328 of.retest = clcf->open_file_cache_retest; | 295 of.retest = clcf->open_file_cache_retest; |
329 of.errors = clcf->open_file_cache_errors; | 296 of.errors = clcf->open_file_cache_errors; |
330 | 297 |
331 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) | 298 if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool) |
332 != NGX_OK) | 299 != NGX_OK) |
333 { | 300 { |
334 if (of.err) { | 301 if (of.err) { |
335 | 302 |
336 if (of.err == NGX_ENOENT) { | 303 if (of.err == NGX_ENOENT) { |
337 *(ctx->index.data - i) = c; | 304 *last = c; |
338 return ngx_http_index_error(r, ctx, of.err); | 305 return ngx_http_index_error(r, dir.data, NGX_ENOENT); |
339 } | 306 } |
340 | 307 |
341 ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, | 308 ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, |
342 ngx_open_file_n " \"%s\" failed", path.data); | 309 ngx_open_file_n " \"%s\" failed", dir.data); |
343 } | 310 } |
344 | 311 |
345 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 312 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
346 } | 313 } |
347 | 314 |
348 *(ctx->index.data - i) = c; | 315 *last = c; |
349 | 316 |
350 if (of.is_dir) { | 317 if (of.is_dir) { |
351 return NGX_OK; | 318 return NGX_OK; |
352 } | 319 } |
353 | 320 |
354 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | 321 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, |
355 "\"%s\" is not a directory", path.data); | 322 "\"%s\" is not a directory", dir.data); |
356 | 323 |
357 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 324 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
358 } | 325 } |
359 | 326 |
360 | 327 |
361 static ngx_int_t | 328 static ngx_int_t |
362 ngx_http_index_error(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx, | 329 ngx_http_index_error(ngx_http_request_t *r, u_char *file, ngx_err_t err) |
363 ngx_err_t err) | |
364 { | 330 { |
365 if (err == NGX_EACCES) { | 331 if (err == NGX_EACCES) { |
366 ngx_log_error(NGX_LOG_ERR, r->connection->log, err, | 332 ngx_log_error(NGX_LOG_ERR, r->connection->log, err, |
367 "\"%s\" is forbidden", ctx->path.data); | 333 "\"%s\" is forbidden", file); |
368 | 334 |
369 return NGX_HTTP_FORBIDDEN; | 335 return NGX_HTTP_FORBIDDEN; |
370 } | 336 } |
371 | 337 |
372 ngx_log_error(NGX_LOG_ERR, r->connection->log, err, | 338 ngx_log_error(NGX_LOG_ERR, r->connection->log, err, |
373 "\"%s\" is not found", ctx->path.data); | 339 "\"%s\" is not found", file); |
374 | 340 |
375 return NGX_HTTP_NOT_FOUND; | 341 return NGX_HTTP_NOT_FOUND; |
376 } | 342 } |
377 | 343 |
378 | 344 |
470 } | 436 } |
471 | 437 |
472 value = cf->args->elts; | 438 value = cf->args->elts; |
473 | 439 |
474 for (i = 1; i < cf->args->nelts; i++) { | 440 for (i = 1; i < cf->args->nelts; i++) { |
441 | |
475 if (value[i].data[0] == '/' && i != cf->args->nelts - 1) { | 442 if (value[i].data[0] == '/' && i != cf->args->nelts - 1) { |
476 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 443 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
477 "only the last index in \"index\" directive " | 444 "only the last index in \"index\" directive " |
478 "may be absolute"); | 445 "should be absolute"); |
479 return NGX_CONF_ERROR; | |
480 } | 446 } |
481 | 447 |
482 if (value[i].len == 0) { | 448 if (value[i].len == 0) { |
483 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 449 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
484 "index \"%V\" in \"index\" directive is invalid", | 450 "index \"%V\" in \"index\" directive is invalid", |
499 n = ngx_http_script_variables_count(&value[i]); | 465 n = ngx_http_script_variables_count(&value[i]); |
500 | 466 |
501 if (n == 0) { | 467 if (n == 0) { |
502 if (ilcf->max_index_len < index->name.len) { | 468 if (ilcf->max_index_len < index->name.len) { |
503 ilcf->max_index_len = index->name.len; | 469 ilcf->max_index_len = index->name.len; |
470 } | |
471 | |
472 if (index->name.data[0] == '/') { | |
473 continue; | |
504 } | 474 } |
505 | 475 |
506 /* include the terminating '\0' to the length to use ngx_copy() */ | 476 /* include the terminating '\0' to the length to use ngx_copy() */ |
507 index->name.len++; | 477 index->name.len++; |
508 | 478 |