blob: 9849dbf34366fb8da8a890fcd03ba2fbb1b00d46 [file] [log] [blame]
Igor Sysoev0c331d92002-08-15 17:20:26 +00001
2#include <ngx_config.h>
Igor Sysoevd581fd52003-05-13 16:02:32 +00003#include <ngx_core.h>
Igor Sysoev0c331d92002-08-15 17:20:26 +00004#include <ngx_http.h>
Igor Sysoevdc479b42003-03-20 16:09:44 +00005
Igor Sysoev2b542382002-08-20 14:48:28 +00006
Igor Sysoevd404c972003-10-16 20:19:16 +00007static int ngx_http_static_handler(ngx_http_request_t *r);
8static int ngx_http_static_init(ngx_cycle_t *cycle);
9
10
11static ngx_command_t ngx_http_static_commands[] = {
12
13 ngx_null_command
14};
15
16
17
18ngx_http_module_t ngx_http_static_module_ctx = {
19 NULL, /* create main configuration */
20 NULL, /* init main configuration */
21
22 NULL, /* create server configuration */
23 NULL, /* merge server configuration */
24
25 NULL, /* create location configuration */
26 NULL /* merge location configuration */
27};
28
29
30ngx_module_t ngx_http_static_module = {
31 NGX_MODULE,
32 &ngx_http_static_module_ctx, /* module context */
33 ngx_http_static_commands, /* module directives */
34 NGX_HTTP_MODULE, /* module type */
35 ngx_http_static_init, /* init module */
36 NULL /* init child */
37};
38
39
40int ngx_http_static_translate_handler(ngx_http_request_t *r)
41{
Igor Sysoev65977492003-11-02 22:56:18 +000042 int rc, level;
Igor Sysoevd404c972003-10-16 20:19:16 +000043 char *location, *last;
44 ngx_err_t err;
Igor Sysoevd404c972003-10-16 20:19:16 +000045 ngx_http_core_loc_conf_t *clcf;
46
47 if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
48 return NGX_HTTP_NOT_ALLOWED;
49 }
50
51 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
52
53 if (r->uri.data[r->uri.len - 1] == '/') {
54 if (r->path.data == NULL) {
55 ngx_test_null(r->path.data,
56 ngx_palloc(r->pool,
57 clcf->doc_root.len + r->uri.len),
58 NGX_HTTP_INTERNAL_SERVER_ERROR);
59
60 ngx_cpystrn(ngx_cpymem(r->path.data, clcf->doc_root.data,
61 clcf->doc_root.len),
62 r->uri.data, r->uri.len + 1);
63
64 } else {
65 r->path.data[r->path.len] = '\0';
66 }
67
68 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
69 "directory index of \"%s\" is forbidden", r->path.data);
70
71 return NGX_HTTP_FORBIDDEN;
72 }
73
74 /* "+ 2" is for trailing '/' in redirect and '\0' */
75 ngx_test_null(r->file.name.data,
76 ngx_palloc(r->pool, clcf->doc_root.len + r->uri.len + 2),
77 NGX_HTTP_INTERNAL_SERVER_ERROR);
78
79 location = ngx_cpymem(r->file.name.data, clcf->doc_root.data,
80 clcf->doc_root.len),
81
82 last = ngx_cpystrn(location, r->uri.data, r->uri.len + 1);
83
84ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->file.name.data);
85
86#if (WIN9X)
87
88 /*
89 * There is no way to open a file or a directory in Win9X with
90 * one syscall: Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag.
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000091 * So we need to check its type before the opening
Igor Sysoevd404c972003-10-16 20:19:16 +000092 */
93
94 r->file.info.dwFileAttributes = GetFileAttributes(r->file.name.data);
95 if (r->file.info.dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
96 err = ngx_errno;
97 ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
98 ngx_file_type_n " \"%s\" failed", r->file.name.data);
99
100 if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
101 return NGX_HTTP_NOT_FOUND;
102
103 } else if (err == NGX_EACCES) {
104 return NGX_HTTP_FORBIDDEN;
105
106 } else {
107 return NGX_HTTP_INTERNAL_SERVER_ERROR;
108 }
109 }
110
111#else
112
113 if (r->file.fd == NGX_INVALID_FILE) {
114 r->file.fd = ngx_open_file(r->file.name.data,
115 NGX_FILE_RDONLY, NGX_FILE_OPEN);
116 }
117
118 if (r->file.fd == NGX_INVALID_FILE) {
119 err = ngx_errno;
Igor Sysoevd404c972003-10-16 20:19:16 +0000120
121 if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
Igor Sysoev65977492003-11-02 22:56:18 +0000122 level = NGX_LOG_ERR;
123 rc = NGX_HTTP_NOT_FOUND;
Igor Sysoevd404c972003-10-16 20:19:16 +0000124
125 } else if (err == NGX_EACCES) {
Igor Sysoev65977492003-11-02 22:56:18 +0000126 level = NGX_LOG_ERR;
127 rc = NGX_HTTP_FORBIDDEN;
Igor Sysoevd404c972003-10-16 20:19:16 +0000128
129 } else {
Igor Sysoev65977492003-11-02 22:56:18 +0000130 level = NGX_LOG_CRIT;
131 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoevd404c972003-10-16 20:19:16 +0000132 }
Igor Sysoev65977492003-11-02 22:56:18 +0000133
134 ngx_log_error(level, r->connection->log, ngx_errno,
135 ngx_open_file_n " \"%s\" failed", r->file.name.data);
136
137 return rc;
Igor Sysoevd404c972003-10-16 20:19:16 +0000138 }
139
140ngx_log_debug(r->connection->log, "FILE: %d" _ r->file.fd);
141
142 if (!r->file.info_valid) {
143 if (ngx_stat_fd(r->file.fd, &r->file.info) == NGX_FILE_ERROR) {
144 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
145 ngx_stat_fd_n " \"%s\" failed", r->file.name.data);
146
147 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
148 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
149 ngx_close_file_n " \"%s\" failed",
150 r->file.name.data);
151 }
152
153 r->file.fd = NGX_INVALID_FILE;
154
155 return NGX_HTTP_INTERNAL_SERVER_ERROR;
156 }
157
158 r->file.info_valid = 1;
159 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000160
Igor Sysoevd404c972003-10-16 20:19:16 +0000161 if (ngx_is_dir(r->file.info)) {
162ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->file.name.data);
163
164#if !(WIN9X)
165 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
166 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
167 ngx_close_file_n " \"%s\" failed", r->file.name.data);
168 }
169
170 r->file.fd = NGX_INVALID_FILE;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000171 r->file.info_valid = 0;
Igor Sysoevd404c972003-10-16 20:19:16 +0000172#endif
173
Igor Sysoev14be46e2003-10-29 17:39:05 +0000174 if (!(r->headers_out.location =
175 ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
176 {
177 return NGX_HTTP_INTERNAL_SERVER_ERROR;
178 }
Igor Sysoevd404c972003-10-16 20:19:16 +0000179
180 *last++ = '/';
181 *last = '\0';
Igor Sysoev14be46e2003-10-29 17:39:05 +0000182 r->headers_out.location->key.len = 8;
183 r->headers_out.location->key.data = "Location" ;
184 r->headers_out.location->value.len = last - location;
185 r->headers_out.location->value.data = location;
Igor Sysoevd404c972003-10-16 20:19:16 +0000186
187 return NGX_HTTP_MOVED_PERMANENTLY;
188 }
189
Igor Sysoev74e95c22003-11-09 20:03:38 +0000190#if !(WIN32) /* the not regular files are probably Unix specific */
191
192 if (!ngx_is_file(r->file.info)) {
193 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
194 "%s is not a regular file", r->file.name.data);
195
196 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
197 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
198 ngx_close_file_n " %s failed", r->file.name.data);
199
200 return NGX_HTTP_NOT_FOUND;
201 }
202
203#endif
204#endif
205
Igor Sysoevd404c972003-10-16 20:19:16 +0000206 r->content_handler = ngx_http_static_handler;
207
208 return NGX_OK;
209}
210
211
212static int ngx_http_static_handler(ngx_http_request_t *r)
Igor Sysoev0c331d92002-08-15 17:20:26 +0000213{
Igor Sysoev6253ca12003-05-27 12:18:54 +0000214 int rc, key, i;
215 ngx_log_e level;
216 ngx_err_t err;
217 ngx_hunk_t *h;
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000218 ngx_chain_t out;
Igor Sysoev6253ca12003-05-27 12:18:54 +0000219 ngx_http_type_t *type;
220 ngx_http_log_ctx_t *ctx;
221 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev0c331d92002-08-15 17:20:26 +0000222
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000223 rc = ngx_http_discard_body(r);
224
225 if (rc != NGX_OK) {
226 return rc;
227 }
228
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000229 ctx = r->connection->log->data;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000230 ctx->action = "sending response to client";
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000231
Igor Sysoev79a80482003-05-14 17:13:13 +0000232 if (r->file.fd == NGX_INVALID_FILE) {
Igor Sysoev7578ec92003-06-02 15:24:30 +0000233 r->file.fd = ngx_open_file(r->file.name.data,
234 NGX_FILE_RDONLY, NGX_FILE_OPEN);
Igor Sysoevb0869052002-12-10 18:05:12 +0000235
Igor Sysoev79a80482003-05-14 17:13:13 +0000236 if (r->file.fd == NGX_INVALID_FILE) {
237 err = ngx_errno;
Igor Sysoeve0268b92002-09-11 15:18:33 +0000238
Igor Sysoev79a80482003-05-14 17:13:13 +0000239 if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
240 level = NGX_LOG_ERR;
241 rc = NGX_HTTP_NOT_FOUND;
Igor Sysoevfd675862003-04-11 16:01:14 +0000242
Igor Sysoev79a80482003-05-14 17:13:13 +0000243 } else {
244 level = NGX_LOG_CRIT;
245 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
246 }
247
248 ngx_log_error(level, r->connection->log, ngx_errno,
249 ngx_open_file_n " %s failed", r->file.name.data);
250 return rc;
Igor Sysoevfd675862003-04-11 16:01:14 +0000251 }
Igor Sysoev2b542382002-08-20 14:48:28 +0000252 }
Igor Sysoev0c331d92002-08-15 17:20:26 +0000253
Igor Sysoev42feecb2002-12-15 06:25:09 +0000254 if (!r->file.info_valid) {
255 if (ngx_stat_fd(r->file.fd, &r->file.info) == NGX_FILE_ERROR) {
Igor Sysoev79a80482003-05-14 17:13:13 +0000256 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
Igor Sysoev42feecb2002-12-15 06:25:09 +0000257 ngx_stat_fd_n " %s failed", r->file.name.data);
258
259 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
Igor Sysoev79a80482003-05-14 17:13:13 +0000260 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
Igor Sysoev42feecb2002-12-15 06:25:09 +0000261 ngx_close_file_n " %s failed", r->file.name.data);
262
263 return NGX_HTTP_INTERNAL_SERVER_ERROR;
264 }
265
266 r->file.info_valid = 1;
267 }
268
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000269 r->headers_out.status = NGX_HTTP_OK;
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000270 r->headers_out.content_length_n = ngx_file_size(r->file.info);
Igor Sysoev42feecb2002-12-15 06:25:09 +0000271 r->headers_out.last_modified_time = ngx_file_mtime(r->file.info);
Igor Sysoev2b542382002-08-20 14:48:28 +0000272
Igor Sysoev14be46e2003-10-29 17:39:05 +0000273 if (!(r->headers_out.content_type =
274 ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
275 {
276 return NGX_HTTP_INTERNAL_SERVER_ERROR;
277 }
Igor Sysoev42feecb2002-12-15 06:25:09 +0000278
Igor Sysoev6253ca12003-05-27 12:18:54 +0000279 r->headers_out.content_type->key.len = 0;
280 r->headers_out.content_type->key.data = NULL;
281 r->headers_out.content_type->value.len = 0;
282 r->headers_out.content_type->value.data = NULL;
283
284 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoevb0869052002-12-10 18:05:12 +0000285
Igor Sysoevb0869052002-12-10 18:05:12 +0000286 if (r->exten.len) {
Igor Sysoev79a80482003-05-14 17:13:13 +0000287 ngx_http_types_hash_key(key, r->exten);
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000288
Igor Sysoev6253ca12003-05-27 12:18:54 +0000289 type = (ngx_http_type_t *) clcf->types[key].elts;
290 for (i = 0; i < clcf->types[key].nelts; i++) {
Igor Sysoev79a80482003-05-14 17:13:13 +0000291 if (r->exten.len != type[i].exten.len) {
292 continue;
293 }
294
295 if (ngx_strcasecmp(r->exten.data, type[i].exten.data) == 0) {
296 r->headers_out.content_type->value.len = type[i].type.len;
297 r->headers_out.content_type->value.data = type[i].type.data;
Igor Sysoev6253ca12003-05-27 12:18:54 +0000298
299 break;
Igor Sysoev79a80482003-05-14 17:13:13 +0000300 }
301 }
302 }
303
304 if (r->headers_out.content_type->value.len == 0) {
Igor Sysoev6253ca12003-05-27 12:18:54 +0000305 r->headers_out.content_type->value.len = clcf->default_type.len;
306 r->headers_out.content_type->value.data = clcf->default_type.data;
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000307 }
Igor Sysoev2b542382002-08-20 14:48:28 +0000308
Igor Sysoev79a80482003-05-14 17:13:13 +0000309 /* we need to allocate all before the header would be sent */
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000310
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000311 ngx_test_null(h, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)),
Igor Sysoev0c331d92002-08-15 17:20:26 +0000312 NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000313
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000314 ngx_test_null(h->file, ngx_pcalloc(r->pool, sizeof(ngx_file_t)),
315 NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoev42feecb2002-12-15 06:25:09 +0000316
Igor Sysoev6253ca12003-05-27 12:18:54 +0000317
318 rc = ngx_http_send_header(r);
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000319
320 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
321 return rc;
Igor Sysoev7578ec92003-06-02 15:24:30 +0000322 }
Igor Sysoev6253ca12003-05-27 12:18:54 +0000323
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000324 h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST;
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000325
Igor Sysoevb7387572003-03-11 20:38:13 +0000326 h->file_pos = 0;
327 h->file_last = ngx_file_size(r->file.info);
Igor Sysoev42feecb2002-12-15 06:25:09 +0000328
329 h->file->fd = r->file.fd;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000330 h->file->log = r->connection->log;
331
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000332 out.hunk = h;
333 out.next = NULL;
334
335 return ngx_http_output_filter(r, &out);
Igor Sysoev0c331d92002-08-15 17:20:26 +0000336}
Igor Sysoevd404c972003-10-16 20:19:16 +0000337
338
339static int ngx_http_static_init(ngx_cycle_t *cycle)
340{
341 ngx_http_handler_pt *h;
342 ngx_http_conf_ctx_t *ctx;
343 ngx_http_core_main_conf_t *cmcf;
344
345 ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index];
346 cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
347
348 ngx_test_null(h, ngx_push_array(
349 &cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
350 NGX_ERROR);
351 *h = ngx_http_static_translate_handler;
352
353 return NGX_OK;
354}
355