blob: ed360faec52c964a94e0a39d904887e164bb4cc9 [file] [log] [blame]
Igor Sysoev0c331d92002-08-15 17:20:26 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev0c331d92002-08-15 17:20:26 +00007#include <ngx_config.h>
Igor Sysoevd581fd52003-05-13 16:02:32 +00008#include <ngx_core.h>
Igor Sysoev0c331d92002-08-15 17:20:26 +00009#include <ngx_http.h>
Igor Sysoevdc479b42003-03-20 16:09:44 +000010
Igor Sysoev2b542382002-08-20 14:48:28 +000011
Igor Sysoev865c1502003-11-30 20:03:18 +000012typedef struct {
13 ngx_http_cache_hash_t *redirect_cache;
14} ngx_http_static_loc_conf_t;
15
16
17static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r);
18static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf);
19static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf,
Igor Sysoev899b44e2005-05-12 14:58:06 +000020 void *parent, void *child);
Igor Sysoev865c1502003-11-30 20:03:18 +000021static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle);
Igor Sysoevd404c972003-10-16 20:19:16 +000022
23
24static ngx_command_t ngx_http_static_commands[] = {
25
Igor Sysoev67f88e92004-03-12 16:57:08 +000026#if (NGX_HTTP_CACHE)
27
Igor Sysoev865c1502003-11-30 20:03:18 +000028 { ngx_string("redirect_cache"),
29 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3,
30 ngx_http_set_cache_slot,
31 NGX_HTTP_LOC_CONF_OFFSET,
32 offsetof(ngx_http_static_loc_conf_t, redirect_cache),
33 NULL },
34
Igor Sysoev67f88e92004-03-12 16:57:08 +000035#endif
36
Igor Sysoev865c1502003-11-30 20:03:18 +000037 ngx_null_command
Igor Sysoevd404c972003-10-16 20:19:16 +000038};
39
40
Igor Sysoevd404c972003-10-16 20:19:16 +000041ngx_http_module_t ngx_http_static_module_ctx = {
Igor Sysoev899b44e2005-05-12 14:58:06 +000042 NULL, /* preconfiguration */
43 NULL, /* postconfiguration */
Igor Sysoev78329332003-11-10 17:17:31 +000044
Igor Sysoevd404c972003-10-16 20:19:16 +000045 NULL, /* create main configuration */
46 NULL, /* init main configuration */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +000047
Igor Sysoevd404c972003-10-16 20:19:16 +000048 NULL, /* create server configuration */
49 NULL, /* merge server configuration */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +000050
Igor Sysoev865c1502003-11-30 20:03:18 +000051 ngx_http_static_create_loc_conf, /* create location configuration */
52 ngx_http_static_merge_loc_conf /* merge location configuration */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +000053};
Igor Sysoevd404c972003-10-16 20:19:16 +000054
55
56ngx_module_t ngx_http_static_module = {
Igor Sysoev899b44e2005-05-12 14:58:06 +000057 NGX_MODULE_V1,
Igor Sysoevd404c972003-10-16 20:19:16 +000058 &ngx_http_static_module_ctx, /* module context */
59 ngx_http_static_commands, /* module directives */
60 NGX_HTTP_MODULE, /* module type */
Igor Sysoeve5733802005-09-08 14:36:09 +000061 NULL, /* init master */
Igor Sysoevd404c972003-10-16 20:19:16 +000062 ngx_http_static_init, /* init module */
Igor Sysoeve5733802005-09-08 14:36:09 +000063 NULL, /* init process */
64 NULL, /* init thread */
65 NULL, /* exit thread */
66 NULL, /* exit process */
67 NULL, /* exit master */
68 NGX_MODULE_V1_PADDING
Igor Sysoevd404c972003-10-16 20:19:16 +000069};
70
71
Igor Sysoev899b44e2005-05-12 14:58:06 +000072static ngx_int_t
73ngx_http_static_handler(ngx_http_request_t *r)
Igor Sysoevd404c972003-10-16 20:19:16 +000074{
Igor Sysoev208eed22005-10-07 13:30:52 +000075 u_char *last, *location;
76 ngx_fd_t fd;
77 ngx_int_t rc;
78 ngx_uint_t level;
79 ngx_str_t path;
80 ngx_err_t err;
81 ngx_log_t *log;
82 ngx_buf_t *b;
83 ngx_chain_t out;
84 ngx_file_info_t fi;
Igor Sysoevc2068d02005-10-19 12:33:58 +000085 ngx_pool_cleanup_t *cln;
86 ngx_pool_cleanup_file_t *clnf;
Igor Sysoev208eed22005-10-07 13:30:52 +000087 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev865c1502003-11-30 20:03:18 +000088
89 if (r->uri.data[r->uri.len - 1] == '/') {
90 return NGX_DECLINED;
91 }
Igor Sysoevd404c972003-10-16 20:19:16 +000092
Igor Sysoev1ebfead2005-02-16 13:40:36 +000093 /* TODO: Win32 */
94 if (r->zero_in_uri) {
95 return NGX_DECLINED;
96 }
97
Igor Sysoevd404c972003-10-16 20:19:16 +000098 if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
99 return NGX_HTTP_NOT_ALLOWED;
100 }
101
Igor Sysoev865c1502003-11-30 20:03:18 +0000102 rc = ngx_http_discard_body(r);
Igor Sysoevd404c972003-10-16 20:19:16 +0000103
Igor Sysoev89690bf2004-03-23 06:01:52 +0000104 if (rc != NGX_OK && rc != NGX_AGAIN) {
Igor Sysoev865c1502003-11-30 20:03:18 +0000105 return rc;
Igor Sysoevd404c972003-10-16 20:19:16 +0000106 }
107
Igor Sysoev865c1502003-11-30 20:03:18 +0000108 log = r->connection->log;
109
Igor Sysoev865c1502003-11-30 20:03:18 +0000110 /*
Igor Sysoev208eed22005-10-07 13:30:52 +0000111 * ngx_http_map_uri_to_path() allocates memory for terminating '\0'
112 * so we do not need to reserve memory for '/' for possible redirect
Igor Sysoev865c1502003-11-30 20:03:18 +0000113 */
114
Igor Sysoev208eed22005-10-07 13:30:52 +0000115 last = ngx_http_map_uri_to_path(r, &path, 0);
116 if (last == NULL) {
117 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoevea521232004-07-26 16:21:18 +0000118 }
Igor Sysoevd404c972003-10-16 20:19:16 +0000119
Igor Sysoev865c1502003-11-30 20:03:18 +0000120 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
Igor Sysoev208eed22005-10-07 13:30:52 +0000121 "http filename: \"%s\"", path.data);
Igor Sysoevd404c972003-10-16 20:19:16 +0000122
Igor Sysoevc2068d02005-10-19 12:33:58 +0000123 cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
124 if (cln == NULL) {
125 return NGX_HTTP_INTERNAL_SERVER_ERROR;
126 }
127
Igor Sysoev208eed22005-10-07 13:30:52 +0000128 fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
Igor Sysoevd404c972003-10-16 20:19:16 +0000129
Igor Sysoev865c1502003-11-30 20:03:18 +0000130 if (fd == NGX_INVALID_FILE) {
Igor Sysoevd404c972003-10-16 20:19:16 +0000131 err = ngx_errno;
Igor Sysoevd404c972003-10-16 20:19:16 +0000132
Igor Sysoev31eb8c02005-09-23 11:02:22 +0000133 if (err == NGX_ENOENT
134 || err == NGX_ENOTDIR
135 || err == NGX_ENAMETOOLONG)
136 {
Igor Sysoev65977492003-11-02 22:56:18 +0000137 level = NGX_LOG_ERR;
138 rc = NGX_HTTP_NOT_FOUND;
Igor Sysoevd404c972003-10-16 20:19:16 +0000139
140 } else if (err == NGX_EACCES) {
Igor Sysoev65977492003-11-02 22:56:18 +0000141 level = NGX_LOG_ERR;
142 rc = NGX_HTTP_FORBIDDEN;
Igor Sysoevd404c972003-10-16 20:19:16 +0000143
144 } else {
Igor Sysoev65977492003-11-02 22:56:18 +0000145 level = NGX_LOG_CRIT;
146 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoevd404c972003-10-16 20:19:16 +0000147 }
Igor Sysoev65977492003-11-02 22:56:18 +0000148
Igor Sysoev208eed22005-10-07 13:30:52 +0000149 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
150
Igor Sysoev5192b362005-07-08 14:34:20 +0000151 if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
152 ngx_log_error(level, log, err,
Igor Sysoev208eed22005-10-07 13:30:52 +0000153 ngx_open_file_n " \"%s\" failed", path.data);
Igor Sysoev5192b362005-07-08 14:34:20 +0000154 }
Igor Sysoev65977492003-11-02 22:56:18 +0000155
156 return rc;
Igor Sysoevd404c972003-10-16 20:19:16 +0000157 }
158
Igor Sysoev865c1502003-11-30 20:03:18 +0000159 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd);
Igor Sysoevd404c972003-10-16 20:19:16 +0000160
Igor Sysoev865c1502003-11-30 20:03:18 +0000161 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
162 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
Igor Sysoev208eed22005-10-07 13:30:52 +0000163 ngx_fd_info_n " \"%s\" failed", path.data);
Igor Sysoevd404c972003-10-16 20:19:16 +0000164
Igor Sysoev865c1502003-11-30 20:03:18 +0000165 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
166 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
Igor Sysoev208eed22005-10-07 13:30:52 +0000167 ngx_close_file_n " \"%s\" failed", path.data);
Igor Sysoevd404c972003-10-16 20:19:16 +0000168 }
169
Igor Sysoev865c1502003-11-30 20:03:18 +0000170 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoevd404c972003-10-16 20:19:16 +0000171 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000172
Igor Sysoev865c1502003-11-30 20:03:18 +0000173 if (ngx_is_dir(&fi)) {
174
175 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
176
177 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
178 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
Igor Sysoev208eed22005-10-07 13:30:52 +0000179 ngx_close_file_n " \"%s\" failed", path.data);
Igor Sysoev0e499db2003-11-27 07:45:22 +0000180 }
181
Igor Sysoev899b44e2005-05-12 14:58:06 +0000182 r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
Igor Sysoevaab4d8c2004-09-06 18:45:00 +0000183 if (r->headers_out.location == NULL) {
Igor Sysoev14be46e2003-10-29 17:39:05 +0000184 return NGX_HTTP_INTERNAL_SERVER_ERROR;
185 }
Igor Sysoevd404c972003-10-16 20:19:16 +0000186
Igor Sysoev208eed22005-10-07 13:30:52 +0000187 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
188
189 if (!clcf->alias) {
190 location = path.data + clcf->root.len;
191
192 } else {
193 location = ngx_palloc(r->pool, r->uri.len + 1);
194 if (location == NULL) {
195 return NGX_HTTP_INTERNAL_SERVER_ERROR;
196 }
197
Igor Sysoev09c684b2005-11-09 17:25:55 +0000198 last = ngx_copy(location, r->uri.data, r->uri.len);
Igor Sysoev208eed22005-10-07 13:30:52 +0000199 }
200
201 *last = '/';
202
Igor Sysoev899b44e2005-05-12 14:58:06 +0000203 /*
204 * we do not need to set the r->headers_out.location->hash and
205 * r->headers_out.location->key fields
206 */
207
Igor Sysoev208eed22005-10-07 13:30:52 +0000208 r->headers_out.location->value.len = r->uri.len + 1;
209 r->headers_out.location->value.data = location;
Igor Sysoev865c1502003-11-30 20:03:18 +0000210
Igor Sysoevd404c972003-10-16 20:19:16 +0000211 return NGX_HTTP_MOVED_PERMANENTLY;
212 }
213
Igor Sysoev1b735832004-11-11 14:07:14 +0000214#if !(NGX_WIN32) /* the not regular files are probably Unix specific */
Igor Sysoev74e95c22003-11-09 20:03:38 +0000215
Igor Sysoev865c1502003-11-30 20:03:18 +0000216 if (!ngx_is_file(&fi)) {
217 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
Igor Sysoev208eed22005-10-07 13:30:52 +0000218 "\"%s\" is not a regular file", path.data);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000219
Igor Sysoev865c1502003-11-30 20:03:18 +0000220 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
221 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
Igor Sysoev208eed22005-10-07 13:30:52 +0000222 ngx_close_file_n " \"%s\" failed", path.data);
Igor Sysoev865c1502003-11-30 20:03:18 +0000223 }
Igor Sysoev74e95c22003-11-09 20:03:38 +0000224
225 return NGX_HTTP_NOT_FOUND;
226 }
227
228#endif
Igor Sysoev74e95c22003-11-09 20:03:38 +0000229
Igor Sysoeve5a222c2005-01-25 12:27:35 +0000230 log->action = "sending response to client";
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000231
Igor Sysoevc2068d02005-10-19 12:33:58 +0000232 cln->handler = ngx_pool_cleanup_file;
233 clnf = cln->data;
Igor Sysoev899b44e2005-05-12 14:58:06 +0000234
Igor Sysoevc2068d02005-10-19 12:33:58 +0000235 clnf->fd = fd;
236 clnf->name = path.data;
237 clnf->log = r->pool->log;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000238
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000239 r->headers_out.status = NGX_HTTP_OK;
Igor Sysoev865c1502003-11-30 20:03:18 +0000240 r->headers_out.content_length_n = ngx_file_size(&fi);
241 r->headers_out.last_modified_time = ngx_file_mtime(&fi);
Igor Sysoev2b542382002-08-20 14:48:28 +0000242
Igor Sysoev865c1502003-11-30 20:03:18 +0000243 if (ngx_http_set_content_type(r) != NGX_OK) {
Igor Sysoev14be46e2003-10-29 17:39:05 +0000244 return NGX_HTTP_INTERNAL_SERVER_ERROR;
245 }
Igor Sysoev42feecb2002-12-15 06:25:09 +0000246
Igor Sysoevcdc46302005-12-07 14:51:31 +0000247 if (r->main != r && ngx_file_size(&fi) == 0) {
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000248 return ngx_http_send_header(r);
249 }
250
Igor Sysoevcdc46302005-12-07 14:51:31 +0000251 r->allow_ranges = 1;
252
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000253 /* we need to allocate all before the header would be sent */
Igor Sysoev2b542382002-08-20 14:48:28 +0000254
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000255 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
256 if (b == NULL) {
257 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoev865c1502003-11-30 20:03:18 +0000258 }
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000259
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000260 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
261 if (b->file == NULL) {
262 return NGX_HTTP_INTERNAL_SERVER_ERROR;
263 }
264
Igor Sysoev6253ca12003-05-27 12:18:54 +0000265 rc = ngx_http_send_header(r);
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000266
Igor Sysoev23340602005-12-05 16:59:05 +0000267 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000268 return rc;
Igor Sysoev7578ec92003-06-02 15:24:30 +0000269 }
Igor Sysoev6253ca12003-05-27 12:18:54 +0000270
Igor Sysoev369145c2004-05-28 15:49:23 +0000271 b->file_pos = 0;
272 b->file_last = ngx_file_size(&fi);
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000273
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000274 b->in_file = b->file_last ? 1: 0;
275 b->last_buf = (r->main == r) ? 1: 0;
276 b->last_in_chain = 1;
277
Igor Sysoev369145c2004-05-28 15:49:23 +0000278 b->file->fd = fd;
Igor Sysoev208eed22005-10-07 13:30:52 +0000279 b->file->name = path;
Igor Sysoev369145c2004-05-28 15:49:23 +0000280 b->file->log = log;
281
282 out.buf = b;
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000283 out.next = NULL;
284
285 return ngx_http_output_filter(r, &out);
Igor Sysoev0c331d92002-08-15 17:20:26 +0000286}
Igor Sysoevd404c972003-10-16 20:19:16 +0000287
288
Igor Sysoev899b44e2005-05-12 14:58:06 +0000289static void *
290ngx_http_static_create_loc_conf(ngx_conf_t *cf)
Igor Sysoev865c1502003-11-30 20:03:18 +0000291{
292 ngx_http_static_loc_conf_t *conf;
293
Igor Sysoevc1571722005-03-19 12:38:37 +0000294 conf = ngx_palloc(cf->pool, sizeof(ngx_http_static_loc_conf_t));
295 if (conf == NULL) {
Igor Sysoev865c1502003-11-30 20:03:18 +0000296 return NGX_CONF_ERROR;
297 }
298
299 conf->redirect_cache = NULL;
300
301 return conf;
302}
303
304
Igor Sysoev899b44e2005-05-12 14:58:06 +0000305static char *
306ngx_http_static_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
Igor Sysoev865c1502003-11-30 20:03:18 +0000307{
308 ngx_http_static_loc_conf_t *prev = parent;
309 ngx_http_static_loc_conf_t *conf = child;
310
311 if (conf->redirect_cache == NULL) {
312 conf->redirect_cache = prev->redirect_cache;
313 }
314
315 return NGX_CONF_OK;
316}
317
318
Igor Sysoev899b44e2005-05-12 14:58:06 +0000319static ngx_int_t
320ngx_http_static_init(ngx_cycle_t *cycle)
Igor Sysoevd404c972003-10-16 20:19:16 +0000321{
322 ngx_http_handler_pt *h;
Igor Sysoevd404c972003-10-16 20:19:16 +0000323 ngx_http_core_main_conf_t *cmcf;
Igor Sysoev74a5ddb2004-07-18 19:11:20 +0000324
325 cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000326
Igor Sysoevc1571722005-03-19 12:38:37 +0000327 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
Igor Sysoev865c1502003-11-30 20:03:18 +0000328 if (h == NULL) {
329 return NGX_ERROR;
330 }
331
332 *h = ngx_http_static_handler;
Igor Sysoevd404c972003-10-16 20:19:16 +0000333
334 return NGX_OK;
335}