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