blob: 5b9a0ebf44bf9190e9d6dfe3c8a1f3a38026fa04 [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 +000012static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r);
Igor Sysoevda173ab2006-08-30 10:39:17 +000013static ngx_int_t ngx_http_static_init(ngx_conf_t *cf);
Igor Sysoevd404c972003-10-16 20:19:16 +000014
15
Igor Sysoevd404c972003-10-16 20:19:16 +000016ngx_http_module_t ngx_http_static_module_ctx = {
Igor Sysoev899b44e2005-05-12 14:58:06 +000017 NULL, /* preconfiguration */
Igor Sysoevda173ab2006-08-30 10:39:17 +000018 ngx_http_static_init, /* postconfiguration */
Igor Sysoev78329332003-11-10 17:17:31 +000019
Igor Sysoevd404c972003-10-16 20:19:16 +000020 NULL, /* create main configuration */
21 NULL, /* init main configuration */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +000022
Igor Sysoevd404c972003-10-16 20:19:16 +000023 NULL, /* create server configuration */
24 NULL, /* merge server configuration */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +000025
Igor Sysoev140c7552007-09-01 12:12:48 +000026 NULL, /* create location configuration */
27 NULL /* merge location configuration */
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +000028};
Igor Sysoevd404c972003-10-16 20:19:16 +000029
30
31ngx_module_t ngx_http_static_module = {
Igor Sysoev899b44e2005-05-12 14:58:06 +000032 NGX_MODULE_V1,
Igor Sysoevd404c972003-10-16 20:19:16 +000033 &ngx_http_static_module_ctx, /* module context */
Igor Sysoev140c7552007-09-01 12:12:48 +000034 NULL, /* module directives */
Igor Sysoevd404c972003-10-16 20:19:16 +000035 NGX_HTTP_MODULE, /* module type */
Igor Sysoeve5733802005-09-08 14:36:09 +000036 NULL, /* init master */
Igor Sysoevda173ab2006-08-30 10:39:17 +000037 NULL, /* init module */
Igor Sysoeve5733802005-09-08 14:36:09 +000038 NULL, /* init process */
39 NULL, /* init thread */
40 NULL, /* exit thread */
41 NULL, /* exit process */
42 NULL, /* exit master */
43 NGX_MODULE_V1_PADDING
Igor Sysoevd404c972003-10-16 20:19:16 +000044};
45
46
Igor Sysoev899b44e2005-05-12 14:58:06 +000047static ngx_int_t
48ngx_http_static_handler(ngx_http_request_t *r)
Igor Sysoevd404c972003-10-16 20:19:16 +000049{
Igor Sysoev208eed22005-10-07 13:30:52 +000050 u_char *last, *location;
Igor Sysoev626cd7e2008-05-26 18:57:43 +000051 size_t root, len;
Igor Sysoev140c7552007-09-01 12:12:48 +000052 ngx_str_t path;
Igor Sysoev208eed22005-10-07 13:30:52 +000053 ngx_int_t rc;
54 ngx_uint_t level;
Igor Sysoev208eed22005-10-07 13:30:52 +000055 ngx_log_t *log;
56 ngx_buf_t *b;
57 ngx_chain_t out;
Igor Sysoev140c7552007-09-01 12:12:48 +000058 ngx_open_file_info_t of;
Igor Sysoev208eed22005-10-07 13:30:52 +000059 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev865c1502003-11-30 20:03:18 +000060
Igor Sysoevd3cbd872008-08-17 17:42:42 +000061 if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
Igor Sysoev4ecb4d72006-04-21 12:06:44 +000062 return NGX_HTTP_NOT_ALLOWED;
63 }
64
Igor Sysoev865c1502003-11-30 20:03:18 +000065 if (r->uri.data[r->uri.len - 1] == '/') {
66 return NGX_DECLINED;
67 }
Igor Sysoevd404c972003-10-16 20:19:16 +000068
Igor Sysoev1ebfead2005-02-16 13:40:36 +000069 /* TODO: Win32 */
70 if (r->zero_in_uri) {
71 return NGX_DECLINED;
72 }
73
Igor Sysoev865c1502003-11-30 20:03:18 +000074 log = r->connection->log;
75
Igor Sysoev865c1502003-11-30 20:03:18 +000076 /*
Igor Sysoev208eed22005-10-07 13:30:52 +000077 * ngx_http_map_uri_to_path() allocates memory for terminating '\0'
78 * so we do not need to reserve memory for '/' for possible redirect
Igor Sysoev865c1502003-11-30 20:03:18 +000079 */
80
Igor Sysoev0e5f86d2006-10-12 13:36:54 +000081 last = ngx_http_map_uri_to_path(r, &path, &root, 0);
Igor Sysoev208eed22005-10-07 13:30:52 +000082 if (last == NULL) {
83 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoevea521232004-07-26 16:21:18 +000084 }
Igor Sysoevd404c972003-10-16 20:19:16 +000085
Igor Sysoev140c7552007-09-01 12:12:48 +000086 path.len = last - path.data;
87
Igor Sysoev865c1502003-11-30 20:03:18 +000088 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
Igor Sysoev208eed22005-10-07 13:30:52 +000089 "http filename: \"%s\"", path.data);
Igor Sysoevd404c972003-10-16 20:19:16 +000090
Igor Sysoev140c7552007-09-01 12:12:48 +000091 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoevc2068d02005-10-19 12:33:58 +000092
Igor Sysoev5a0eac82008-06-26 14:07:59 +000093 ngx_memzero(&of, sizeof(ngx_open_file_info_t));
94
Igor Sysoev385af282008-07-30 12:34:04 +000095 of.directio = clcf->directio;
Igor Sysoev9b9616e2007-12-21 16:19:48 +000096 of.valid = clcf->open_file_cache_valid;
Igor Sysoevf3b0e492007-12-22 13:19:39 +000097 of.min_uses = clcf->open_file_cache_min_uses;
Igor Sysoev140c7552007-09-01 12:12:48 +000098 of.errors = clcf->open_file_cache_errors;
Igor Sysoev9afd58f2007-09-03 08:41:42 +000099 of.events = clcf->open_file_cache_events;
Igor Sysoevd404c972003-10-16 20:19:16 +0000100
Igor Sysoev86b91592007-12-27 20:32:43 +0000101 if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
102 != NGX_OK)
103 {
Igor Sysoev140c7552007-09-01 12:12:48 +0000104 switch (of.err) {
105
106 case 0:
107 return NGX_HTTP_INTERNAL_SERVER_ERROR;
108
109 case NGX_ENOENT:
110 case NGX_ENOTDIR:
111 case NGX_ENAMETOOLONG:
112
Igor Sysoev65977492003-11-02 22:56:18 +0000113 level = NGX_LOG_ERR;
114 rc = NGX_HTTP_NOT_FOUND;
Igor Sysoev140c7552007-09-01 12:12:48 +0000115 break;
Igor Sysoevd404c972003-10-16 20:19:16 +0000116
Igor Sysoev140c7552007-09-01 12:12:48 +0000117 case NGX_EACCES:
118
Igor Sysoev65977492003-11-02 22:56:18 +0000119 level = NGX_LOG_ERR;
120 rc = NGX_HTTP_FORBIDDEN;
Igor Sysoev140c7552007-09-01 12:12:48 +0000121 break;
Igor Sysoevd404c972003-10-16 20:19:16 +0000122
Igor Sysoev140c7552007-09-01 12:12:48 +0000123 default:
124
Igor Sysoev65977492003-11-02 22:56:18 +0000125 level = NGX_LOG_CRIT;
126 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoev140c7552007-09-01 12:12:48 +0000127 break;
Igor Sysoevd404c972003-10-16 20:19:16 +0000128 }
Igor Sysoev65977492003-11-02 22:56:18 +0000129
Igor Sysoev5192b362005-07-08 14:34:20 +0000130 if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
Igor Sysoev140c7552007-09-01 12:12:48 +0000131 ngx_log_error(level, log, of.err,
Igor Sysoev208eed22005-10-07 13:30:52 +0000132 ngx_open_file_n " \"%s\" failed", path.data);
Igor Sysoev5192b362005-07-08 14:34:20 +0000133 }
Igor Sysoev65977492003-11-02 22:56:18 +0000134
135 return rc;
Igor Sysoevd404c972003-10-16 20:19:16 +0000136 }
137
Igor Sysoevf1bde242009-01-16 13:53:08 +0000138 r->root_tested = !r->error_page;
Igor Sysoevedf1c8c2008-07-07 09:26:13 +0000139
Igor Sysoevf4f2efa2007-12-07 20:57:38 +0000140 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);
Igor Sysoevd404c972003-10-16 20:19:16 +0000141
Igor Sysoev140c7552007-09-01 12:12:48 +0000142 if (of.is_dir) {
Igor Sysoev865c1502003-11-30 20:03:18 +0000143
144 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
145
Igor Sysoev899b44e2005-05-12 14:58:06 +0000146 r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
Igor Sysoevaab4d8c2004-09-06 18:45:00 +0000147 if (r->headers_out.location == NULL) {
Igor Sysoev14be46e2003-10-29 17:39:05 +0000148 return NGX_HTTP_INTERNAL_SERVER_ERROR;
149 }
Igor Sysoevd404c972003-10-16 20:19:16 +0000150
Igor Sysoev626cd7e2008-05-26 18:57:43 +0000151 len = r->uri.len + 1;
152
153 if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) {
Igor Sysoev208eed22005-10-07 13:30:52 +0000154 location = path.data + clcf->root.len;
155
Igor Sysoev626cd7e2008-05-26 18:57:43 +0000156 *last = '/';
157
Igor Sysoev208eed22005-10-07 13:30:52 +0000158 } else {
Igor Sysoev626cd7e2008-05-26 18:57:43 +0000159 if (r->args.len) {
160 len += r->args.len + 1;
161 }
162
Igor Sysoev7f6b2ff2008-06-17 15:00:30 +0000163 location = ngx_pnalloc(r->pool, len);
Igor Sysoev208eed22005-10-07 13:30:52 +0000164 if (location == NULL) {
165 return NGX_HTTP_INTERNAL_SERVER_ERROR;
166 }
167
Igor Sysoev09c684b2005-11-09 17:25:55 +0000168 last = ngx_copy(location, r->uri.data, r->uri.len);
Igor Sysoev208eed22005-10-07 13:30:52 +0000169
Igor Sysoev626cd7e2008-05-26 18:57:43 +0000170 *last = '/';
171
172 if (r->args.len) {
173 *++last = '?';
174 ngx_memcpy(++last, r->args.data, r->args.len);
175 }
176 }
Igor Sysoev208eed22005-10-07 13:30:52 +0000177
Igor Sysoev899b44e2005-05-12 14:58:06 +0000178 /*
179 * we do not need to set the r->headers_out.location->hash and
180 * r->headers_out.location->key fields
181 */
182
Igor Sysoev626cd7e2008-05-26 18:57:43 +0000183 r->headers_out.location->value.len = len;
Igor Sysoev208eed22005-10-07 13:30:52 +0000184 r->headers_out.location->value.data = location;
Igor Sysoev865c1502003-11-30 20:03:18 +0000185
Igor Sysoevd404c972003-10-16 20:19:16 +0000186 return NGX_HTTP_MOVED_PERMANENTLY;
187 }
188
Igor Sysoev1b735832004-11-11 14:07:14 +0000189#if !(NGX_WIN32) /* the not regular files are probably Unix specific */
Igor Sysoev74e95c22003-11-09 20:03:38 +0000190
Igor Sysoev140c7552007-09-01 12:12:48 +0000191 if (!of.is_file) {
Igor Sysoev865c1502003-11-30 20:03:18 +0000192 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
Igor Sysoev208eed22005-10-07 13:30:52 +0000193 "\"%s\" is not a regular file", path.data);
Igor Sysoev74e95c22003-11-09 20:03:38 +0000194
Igor Sysoev74e95c22003-11-09 20:03:38 +0000195 return NGX_HTTP_NOT_FOUND;
196 }
197
198#endif
Igor Sysoev74e95c22003-11-09 20:03:38 +0000199
Igor Sysoevd3cbd872008-08-17 17:42:42 +0000200 if (r->method & NGX_HTTP_POST) {
201 return NGX_HTTP_NOT_ALLOWED;
202 }
203
204 rc = ngx_http_discard_request_body(r);
205
206 if (rc != NGX_OK) {
207 return rc;
208 }
209
Igor Sysoeve5a222c2005-01-25 12:27:35 +0000210 log->action = "sending response to client";
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000211
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000212 r->headers_out.status = NGX_HTTP_OK;
Igor Sysoev140c7552007-09-01 12:12:48 +0000213 r->headers_out.content_length_n = of.size;
214 r->headers_out.last_modified_time = of.mtime;
Igor Sysoev2b542382002-08-20 14:48:28 +0000215
Igor Sysoev865c1502003-11-30 20:03:18 +0000216 if (ngx_http_set_content_type(r) != NGX_OK) {
Igor Sysoev14be46e2003-10-29 17:39:05 +0000217 return NGX_HTTP_INTERNAL_SERVER_ERROR;
218 }
Igor Sysoev42feecb2002-12-15 06:25:09 +0000219
Igor Sysoevac662fb2008-12-11 15:57:14 +0000220 if (r != r->main && of.size == 0) {
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000221 return ngx_http_send_header(r);
222 }
223
Igor Sysoevcdc46302005-12-07 14:51:31 +0000224 r->allow_ranges = 1;
225
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000226 /* we need to allocate all before the header would be sent */
Igor Sysoev2b542382002-08-20 14:48:28 +0000227
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000228 b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
229 if (b == NULL) {
230 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoev865c1502003-11-30 20:03:18 +0000231 }
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000232
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000233 b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
234 if (b->file == NULL) {
235 return NGX_HTTP_INTERNAL_SERVER_ERROR;
236 }
237
Igor Sysoev6253ca12003-05-27 12:18:54 +0000238 rc = ngx_http_send_header(r);
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000239
Igor Sysoev23340602005-12-05 16:59:05 +0000240 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000241 return rc;
Igor Sysoev7578ec92003-06-02 15:24:30 +0000242 }
Igor Sysoev6253ca12003-05-27 12:18:54 +0000243
Igor Sysoev369145c2004-05-28 15:49:23 +0000244 b->file_pos = 0;
Igor Sysoev140c7552007-09-01 12:12:48 +0000245 b->file_last = of.size;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000246
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000247 b->in_file = b->file_last ? 1: 0;
Igor Sysoevdf3254a2006-01-11 15:26:57 +0000248 b->last_buf = (r == r->main) ? 1: 0;
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000249 b->last_in_chain = 1;
250
Igor Sysoevf4f2efa2007-12-07 20:57:38 +0000251 b->file->fd = of.fd;
Igor Sysoev208eed22005-10-07 13:30:52 +0000252 b->file->name = path;
Igor Sysoev369145c2004-05-28 15:49:23 +0000253 b->file->log = log;
Igor Sysoev8633e1f2008-09-05 14:48:47 +0000254 b->file->directio = of.is_directio;
Igor Sysoev369145c2004-05-28 15:49:23 +0000255
256 out.buf = b;
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000257 out.next = NULL;
258
259 return ngx_http_output_filter(r, &out);
Igor Sysoev0c331d92002-08-15 17:20:26 +0000260}
Igor Sysoevd404c972003-10-16 20:19:16 +0000261
262
Igor Sysoev899b44e2005-05-12 14:58:06 +0000263static ngx_int_t
Igor Sysoevda173ab2006-08-30 10:39:17 +0000264ngx_http_static_init(ngx_conf_t *cf)
Igor Sysoevd404c972003-10-16 20:19:16 +0000265{
266 ngx_http_handler_pt *h;
Igor Sysoevd404c972003-10-16 20:19:16 +0000267 ngx_http_core_main_conf_t *cmcf;
Igor Sysoev74a5ddb2004-07-18 19:11:20 +0000268
Igor Sysoevda173ab2006-08-30 10:39:17 +0000269 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000270
Igor Sysoevc1571722005-03-19 12:38:37 +0000271 h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
Igor Sysoev865c1502003-11-30 20:03:18 +0000272 if (h == NULL) {
273 return NGX_ERROR;
274 }
275
276 *h = ngx_http_static_handler;
Igor Sysoevd404c972003-10-16 20:19:16 +0000277
278 return NGX_OK;
279}