blob: cc7c92790e79457948bf650159e6dffec49586d9 [file] [log] [blame]
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00001
Igor Sysoev7578ec92003-06-02 15:24:30 +00002#include <ngx_config.h>
3#include <ngx_core.h>
4#include <ngx_http.h>
5
6
7typedef struct {
8 ngx_array_t indices;
9 size_t max_index_len;
10} ngx_http_index_conf_t;
11
12
13#define NGX_HTTP_DEFAULT_INDEX "index.html"
Igor Sysoeve0268b92002-09-11 15:18:33 +000014
15
Igor Sysoeve79c6ac2003-01-10 17:45:47 +000016static int ngx_http_index_test_dir(ngx_http_request_t *r);
Igor Sysoevb2620632003-01-10 06:09:20 +000017static int ngx_http_index_init(ngx_pool_t *pool);
Igor Sysoeve0268b92002-09-11 15:18:33 +000018static void *ngx_http_index_create_conf(ngx_pool_t *pool);
Igor Sysoev6253ca12003-05-27 12:18:54 +000019static char *ngx_http_index_merge_conf(ngx_pool_t *p, void *parent,
20 void *child);
Igor Sysoev207ed5a2002-12-26 16:26:23 +000021static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
Igor Sysoev6253ca12003-05-27 12:18:54 +000022 void *conf);
Igor Sysoeve0268b92002-09-11 15:18:33 +000023
Igor Sysoev42feecb2002-12-15 06:25:09 +000024
25static ngx_command_t ngx_http_index_commands[] = {
26
Igor Sysoev207ed5a2002-12-26 16:26:23 +000027 {ngx_string("index"),
Igor Sysoev7578ec92003-06-02 15:24:30 +000028 NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
Igor Sysoev207ed5a2002-12-26 16:26:23 +000029 ngx_http_index_set_index,
Igor Sysoeve79c6ac2003-01-10 17:45:47 +000030 NGX_HTTP_LOC_CONF_OFFSET,
Igor Sysoev6ddfbf02003-05-15 15:42:53 +000031 0,
32 NULL},
Igor Sysoev42feecb2002-12-15 06:25:09 +000033
Igor Sysoev6253ca12003-05-27 12:18:54 +000034 ngx_null_command
Igor Sysoev42feecb2002-12-15 06:25:09 +000035};
Igor Sysoeve0268b92002-09-11 15:18:33 +000036
37
Igor Sysoev207ed5a2002-12-26 16:26:23 +000038ngx_http_module_t ngx_http_index_module_ctx = {
Igor Sysoeva9830112003-05-19 16:39:14 +000039 NULL, /* create main configuration */
40 NULL, /* init main configuration */
Igor Sysoevdc479b42003-03-20 16:09:44 +000041
Igor Sysoeva9830112003-05-19 16:39:14 +000042 NULL, /* create server configuration */
43 NULL, /* merge server configuration */
44
45 ngx_http_index_create_conf, /* create location configration */
46 ngx_http_index_merge_conf /* merge location configration */
Igor Sysoev207ed5a2002-12-26 16:26:23 +000047};
48
49
50ngx_module_t ngx_http_index_module = {
Igor Sysoev6253ca12003-05-27 12:18:54 +000051 NGX_MODULE,
Igor Sysoev207ed5a2002-12-26 16:26:23 +000052 &ngx_http_index_module_ctx, /* module context */
53 ngx_http_index_commands, /* module directives */
Igor Sysoev6253ca12003-05-27 12:18:54 +000054 NGX_HTTP_MODULE, /* module type */
Igor Sysoevb2620632003-01-10 06:09:20 +000055 ngx_http_index_init /* init module */
Igor Sysoeve0268b92002-09-11 15:18:33 +000056};
57
58
Igor Sysoeve79c6ac2003-01-10 17:45:47 +000059/*
Igor Sysoev7578ec92003-06-02 15:24:30 +000060 Try to open the first index file before the directory existence test
61 because the valid requests should be many more than invalid ones.
Igor Sysoevde8fcea2003-01-19 17:53:14 +000062 If open() failed then stat() should be more quickly because some data
Igor Sysoevfd675862003-04-11 16:01:14 +000063 is already cached in the kernel.
Igor Sysoev6253ca12003-05-27 12:18:54 +000064 Besides Win32 has ERROR_PATH_NOT_FOUND (NGX_ENOTDIR).
65 Unix has ENOTDIR error, although it less helpfull - it shows only
66 that path contains the usual file in place of the directory.
Igor Sysoeve79c6ac2003-01-10 17:45:47 +000067*/
68
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000069int ngx_http_index_handler(ngx_http_request_t *r)
70{
Igor Sysoev7578ec92003-06-02 15:24:30 +000071 int i, rc, test_dir, path_not_found;
Igor Sysoev6253ca12003-05-27 12:18:54 +000072 char *name, *file;
Igor Sysoev13933252003-05-29 13:02:09 +000073 ngx_str_t redirect, *index;
Igor Sysoev6253ca12003-05-27 12:18:54 +000074 ngx_err_t err;
75 ngx_fd_t fd;
76 ngx_http_index_conf_t *icf;
77 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000078
Igor Sysoev6253ca12003-05-27 12:18:54 +000079 icf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
80 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoev4e9393a2003-01-09 05:36:00 +000081
Igor Sysoevb2620632003-01-10 06:09:20 +000082 ngx_test_null(r->path.data,
Igor Sysoevb0869052002-12-10 18:05:12 +000083 ngx_palloc(r->pool,
Igor Sysoev6253ca12003-05-27 12:18:54 +000084 clcf->doc_root.len + r->uri.len
85 + icf->max_index_len),
Igor Sysoev0c331d92002-08-15 17:20:26 +000086 NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000087
Igor Sysoev13933252003-05-29 13:02:09 +000088 redirect.data = ngx_cpymem(r->path.data, clcf->doc_root.data,
89 clcf->doc_root.len);
90 file = ngx_cpystrn(redirect.data, r->uri.data, r->uri.len + 1);
Igor Sysoevb2620632003-01-10 06:09:20 +000091 r->path.len = file - r->path.data;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000092
Igor Sysoevad22e012003-01-15 07:02:27 +000093 test_dir = 1;
Igor Sysoev7578ec92003-06-02 15:24:30 +000094 path_not_found = 1;
Igor Sysoeve79c6ac2003-01-10 17:45:47 +000095
Igor Sysoev13933252003-05-29 13:02:09 +000096 index = icf->indices.elts;
Igor Sysoev6253ca12003-05-27 12:18:54 +000097 for (i = 0; i < icf->indices.nelts; i++) {
Igor Sysoevb2620632003-01-10 06:09:20 +000098
99 if (index[i].data[0] != '/') {
Igor Sysoevb2620632003-01-10 06:09:20 +0000100 ngx_memcpy(file, index[i].data, index[i].len + 1);
101 name = r->path.data;
102
103 } else {
104 name = index[i].data;
105 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000106
Igor Sysoev7578ec92003-06-02 15:24:30 +0000107 fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN);
Igor Sysoev42feecb2002-12-15 06:25:09 +0000108 if (fd == NGX_INVALID_FILE) {
Igor Sysoeve0268b92002-09-11 15:18:33 +0000109 err = ngx_errno;
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000110
Igor Sysoevad22e012003-01-15 07:02:27 +0000111ngx_log_error(NGX_LOG_DEBUG, r->connection->log, err,
112 "DEBUG: " ngx_open_file_n " %s failed", name);
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000113
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000114 if (err == NGX_ENOTDIR) {
Igor Sysoev7578ec92003-06-02 15:24:30 +0000115 path_not_found = 1;
Igor Sysoevad22e012003-01-15 07:02:27 +0000116
117 } else if (err == NGX_EACCES) {
118 r->path_err = err;
119 return NGX_HTTP_FORBIDDEN;
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000120 }
121
122 if (test_dir) {
Igor Sysoev7578ec92003-06-02 15:24:30 +0000123 if (path_not_found) {
Igor Sysoevad22e012003-01-15 07:02:27 +0000124 r->path_err = err;
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000125 return NGX_HTTP_NOT_FOUND;
126 }
127
128 rc = ngx_http_index_test_dir(r);
129 if (rc != NGX_OK) {
130 return rc;
131 }
132
133 test_dir = 0;
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000134 }
135
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000136 if (err == NGX_ENOENT) {
Igor Sysoeve0268b92002-09-11 15:18:33 +0000137 continue;
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000138 }
Igor Sysoeve0268b92002-09-11 15:18:33 +0000139
140 ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
141 ngx_open_file_n " %s failed", name);
142
143 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000144 }
Igor Sysoeve0268b92002-09-11 15:18:33 +0000145
Igor Sysoev6253ca12003-05-27 12:18:54 +0000146 r->file.name.data = name;
147 r->file.fd = fd;
Igor Sysoeve0268b92002-09-11 15:18:33 +0000148
Igor Sysoevb2620632003-01-10 06:09:20 +0000149 if (index[i].data[0] == '/') {
150 r->file.name.len = index[i].len;
Igor Sysoev13933252003-05-29 13:02:09 +0000151 redirect.len = index[i].len;
152 redirect.data = index[i].data;
Igor Sysoevb2620632003-01-10 06:09:20 +0000153
154 } else {
Igor Sysoev13933252003-05-29 13:02:09 +0000155 redirect.len = r->uri.len + index[i].len;
156 r->file.name.len = clcf->doc_root.len + r->uri.len + index[i].len;
Igor Sysoevb2620632003-01-10 06:09:20 +0000157 }
158
Igor Sysoev13933252003-05-29 13:02:09 +0000159 return ngx_http_internal_redirect(r, &redirect, NULL);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000160 }
161
Igor Sysoeve0268b92002-09-11 15:18:33 +0000162 return NGX_DECLINED;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000163}
164
Igor Sysoevb0869052002-12-10 18:05:12 +0000165
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000166static int ngx_http_index_test_dir(ngx_http_request_t *r)
167{
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000168 r->path.data[r->path.len - 1] = '\0';
Igor Sysoevad22e012003-01-15 07:02:27 +0000169 r->path.data[r->path.len] = '\0';
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000170
171ngx_log_debug(r->connection->log, "IS_DIR: %s" _ r->path.data);
172
Igor Sysoevad22e012003-01-15 07:02:27 +0000173#if 0
Igor Sysoev6253ca12003-05-27 12:18:54 +0000174 if (r->path_err == NGX_EACCES) {
175 return NGX_HTTP_FORBIDDEN;
176 }
Igor Sysoevad22e012003-01-15 07:02:27 +0000177#endif
178
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000179 if (ngx_file_type(r->path.data, &r->file.info) == -1) {
Igor Sysoevad22e012003-01-15 07:02:27 +0000180
181 r->path_err = ngx_errno;
182
183 if (r->path_err == NGX_ENOENT) {
184 r->path.data[r->path.len - 1] = '/';
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000185 return NGX_HTTP_NOT_FOUND;
186 }
187
Igor Sysoevad22e012003-01-15 07:02:27 +0000188 ngx_log_error(NGX_LOG_CRIT, r->connection->log, r->path_err,
Igor Sysoevad22e012003-01-15 07:02:27 +0000189 ngx_file_type_n " %s failed", r->path.data);
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000190
191 return NGX_HTTP_INTERNAL_SERVER_ERROR;
192 }
193
Igor Sysoevad22e012003-01-15 07:02:27 +0000194 r->path.data[r->path.len - 1] = '/';
195
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000196 if (ngx_is_dir(r->file.info)) {
Igor Sysoeve79c6ac2003-01-10 17:45:47 +0000197 return NGX_OK;
198
199 } else {
200 return NGX_HTTP_NOT_FOUND;
201 }
202}
203
204
Igor Sysoevb2620632003-01-10 06:09:20 +0000205static int ngx_http_index_init(ngx_pool_t *pool)
206{
207 ngx_http_handler_pt *h;
208
209 ngx_test_null(h, ngx_push_array(&ngx_http_index_handlers), NGX_ERROR);
210
211 *h = ngx_http_index_handler;
212
213 return NGX_OK;
214}
215
216
Igor Sysoeve0268b92002-09-11 15:18:33 +0000217static void *ngx_http_index_create_conf(ngx_pool_t *pool)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000218{
Igor Sysoeve0268b92002-09-11 15:18:33 +0000219 ngx_http_index_conf_t *conf;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000220
Igor Sysoev6253ca12003-05-27 12:18:54 +0000221 ngx_test_null(conf, ngx_palloc(pool, sizeof(ngx_http_index_conf_t)),
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000222 NGX_CONF_ERROR);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000223
Igor Sysoev6253ca12003-05-27 12:18:54 +0000224 ngx_init_array(conf->indices, pool, 3, sizeof(ngx_str_t), NGX_CONF_ERROR);
225 conf->max_index_len = 0;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000226
Igor Sysoeve0268b92002-09-11 15:18:33 +0000227 return conf;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000228}
229
Igor Sysoevb0869052002-12-10 18:05:12 +0000230
Igor Sysoev6253ca12003-05-27 12:18:54 +0000231/* TODO: remove duplicate indices */
232
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000233static char *ngx_http_index_merge_conf(ngx_pool_t *p, void *parent, void *child)
234{
Igor Sysoev6253ca12003-05-27 12:18:54 +0000235 ngx_http_index_conf_t *prev = parent;
236 ngx_http_index_conf_t *conf = child;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000237
Igor Sysoev6253ca12003-05-27 12:18:54 +0000238 int i;
239 ngx_str_t *index, *prev_index;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000240
Igor Sysoeve0268b92002-09-11 15:18:33 +0000241 if (conf->max_index_len == 0) {
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000242 if (prev->max_index_len != 0) {
Igor Sysoev6253ca12003-05-27 12:18:54 +0000243 ngx_memcpy(conf, prev, sizeof(ngx_http_index_conf_t));
244 return NGX_CONF_OK;
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000245 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000246
Igor Sysoev6253ca12003-05-27 12:18:54 +0000247 ngx_test_null(index, ngx_push_array(&conf->indices), NGX_CONF_ERROR);
248 index->len = sizeof(NGX_HTTP_DEFAULT_INDEX) - 1;
249 index->data = NGX_HTTP_DEFAULT_INDEX;
250 conf->max_index_len = sizeof(NGX_HTTP_DEFAULT_INDEX);
251
252 return NGX_CONF_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000253 }
Igor Sysoeve0268b92002-09-11 15:18:33 +0000254
Igor Sysoev6253ca12003-05-27 12:18:54 +0000255 if (prev->max_index_len != 0) {
256
257 prev_index = prev->indices.elts;
258 for (i = 0; i < prev->indices.nelts; i++) {
259 ngx_test_null(index, ngx_push_array(&conf->indices),
260 NGX_CONF_ERROR);
261 index->len = prev_index[i].len;
262 index->data = prev_index[i].data;
263 }
264 }
265
266 if (conf->max_index_len < prev->max_index_len) {
267 conf->max_index_len = prev->max_index_len;
268 }
269
270 return NGX_CONF_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000271}
Igor Sysoev6253ca12003-05-27 12:18:54 +0000272
273
Igor Sysoev13933252003-05-29 13:02:09 +0000274/* TODO: warn about duplicate indices */
Igor Sysoevb0869052002-12-10 18:05:12 +0000275
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000276static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
Igor Sysoev6253ca12003-05-27 12:18:54 +0000277 void *conf)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000278{
Igor Sysoev6253ca12003-05-27 12:18:54 +0000279 ngx_http_index_conf_t *icf = conf;
280
281 int i;
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000282 ngx_str_t *index, *value;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000283
Igor Sysoev6253ca12003-05-27 12:18:54 +0000284 value = cf->args->elts;
285
286 if (value[1].data[0] == '/' && icf->indices.nelts == 0) {
287 ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1,
288 "first index \"%s\" must not be absolute", value[1].data);
289 return ngx_conf_errstr;
290 }
291
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000292 for (i = 1; i < cf->args->nelts; i++) {
Igor Sysoev6253ca12003-05-27 12:18:54 +0000293 if (value[i].len == 0) {
Igor Sysoev13933252003-05-29 13:02:09 +0000294 ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1,
Igor Sysoevaa3436c2003-05-30 14:27:59 +0000295 "index \"%s\" is invalid", value[i].data);
Igor Sysoev13933252003-05-29 13:02:09 +0000296 return ngx_conf_errstr;
Igor Sysoev6253ca12003-05-27 12:18:54 +0000297 }
298
299 ngx_test_null(index, ngx_push_array(&icf->indices), NGX_CONF_ERROR);
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000300 index->len = value[i].len;
301 index->data = value[i].data;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000302
Igor Sysoev6253ca12003-05-27 12:18:54 +0000303 if (icf->max_index_len < index->len + 1) {
304 icf->max_index_len = index->len + 1;
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000305 }
306 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000307
Igor Sysoev13933252003-05-29 13:02:09 +0000308 return NGX_CONF_OK;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000309}