comparison src/http/modules/ngx_http_static_handler.c @ 201:267ea1d98683

nginx-0.0.1-2003-11-30-23:03:18 import
author Igor Sysoev <igor@sysoev.ru>
date Sun, 30 Nov 2003 20:03:18 +0000
parents abeaebe0a33c
children 74994aeef848
comparison
equal deleted inserted replaced
200:abeaebe0a33c 201:267ea1d98683
2 #include <ngx_config.h> 2 #include <ngx_config.h>
3 #include <ngx_core.h> 3 #include <ngx_core.h>
4 #include <ngx_http.h> 4 #include <ngx_http.h>
5 5
6 6
7 static int ngx_http_static_handler(ngx_http_request_t *r); 7 typedef struct {
8 static int ngx_http_static_init(ngx_cycle_t *cycle); 8 ngx_http_cache_hash_t *redirect_cache;
9 } ngx_http_static_loc_conf_t;
10
11
12 static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r);
13 static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf);
14 static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf,
15 void *parent, void *child);
16 static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle);
9 17
10 18
11 static ngx_command_t ngx_http_static_commands[] = { 19 static ngx_command_t ngx_http_static_commands[] = {
12 20
13 ngx_null_command 21 { ngx_string("redirect_cache"),
22 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3,
23 ngx_http_set_cache_slot,
24 NGX_HTTP_LOC_CONF_OFFSET,
25 offsetof(ngx_http_static_loc_conf_t, redirect_cache),
26 NULL },
27
28 ngx_null_command
14 }; 29 };
15 30
16 31
17 32
18 ngx_http_module_t ngx_http_static_module_ctx = { 33 ngx_http_module_t ngx_http_static_module_ctx = {
22 NULL, /* init main configuration */ 37 NULL, /* init main configuration */
23 38
24 NULL, /* create server configuration */ 39 NULL, /* create server configuration */
25 NULL, /* merge server configuration */ 40 NULL, /* merge server configuration */
26 41
27 NULL, /* create location configuration */ 42 ngx_http_static_create_loc_conf, /* create location configuration */
28 NULL /* merge location configuration */ 43 ngx_http_static_merge_loc_conf /* merge location configuration */
29 }; 44 };
30 45
31 46
32 ngx_module_t ngx_http_static_module = { 47 ngx_module_t ngx_http_static_module = {
33 NGX_MODULE, 48 NGX_MODULE,
37 ngx_http_static_init, /* init module */ 52 ngx_http_static_init, /* init module */
38 NULL /* init child */ 53 NULL /* init child */
39 }; 54 };
40 55
41 56
42 ngx_int_t ngx_http_static_translate_handler(ngx_http_request_t *r) 57 static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r)
43 { 58 {
44 char *location, *last, *path; 59 char *last;
45 uint32_t crc; 60 uint32_t file_crc, redirect_crc;
46 ngx_int_t rc, level; 61 ngx_fd_t fd;
47 ngx_str_t name; 62 ngx_int_t rc, level;
48 ngx_err_t err; 63 ngx_str_t name, location;
49 ngx_http_cache_t *cache; 64 ngx_err_t err;
50 ngx_http_cache_conf_t *ccf; 65 ngx_log_t *log;
51 ngx_http_core_loc_conf_t *clcf; 66 ngx_hunk_t *h;
67 ngx_chain_t out;
68 ngx_file_info_t fi;
69 ngx_http_cache_t *file, *redirect;
70 ngx_http_cleanup_t *file_cleanup, *redirect_cleanup;
71 ngx_http_log_ctx_t *ctx;
72 ngx_http_core_loc_conf_t *clcf;
73 ngx_http_static_loc_conf_t *slcf;
74
75 if (r->uri.data[r->uri.len - 1] == '/') {
76 return NGX_DECLINED;
77 }
52 78
53 if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { 79 if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
54 return NGX_HTTP_NOT_ALLOWED; 80 return NGX_HTTP_NOT_ALLOWED;
55 } 81 }
56 82
83 rc = ngx_http_discard_body(r);
84
85 if (rc != NGX_OK) {
86 return rc;
87 }
88
89 /*
90 * there is a valid cached open file, i.e by index handler,
91 * and it must be already registered in r->cleanup
92 */
93
94 if (r->cache && r->cache->valid) {
95 return ngx_http_send_cached(r);
96 }
97
98 log = r->connection->log;
99
57 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 100 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
58 101
59 102 /*
60 if (r->uri.data[r->uri.len - 1] == '/') { 103 * make a file name
61 104 * 2 bytes is for a trailing '/' in a possible redirect and for '\0'
62 /* there is no index handler */ 105 */
63 106
64 if (!(path = ngx_palloc(r->pool, clcf->doc_root.len + r->uri.len))) {
65 return NGX_HTTP_INTERNAL_SERVER_ERROR;
66 }
67
68 ngx_cpystrn(ngx_cpymem(path, clcf->doc_root.data, clcf->doc_root.len),
69 r->uri.data, r->uri.len + 1);
70
71 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
72 "directory index of \"%s\" is forbidden", path);
73
74 return NGX_HTTP_FORBIDDEN;
75 }
76
77
78 /* "+ 2" is for a trailing '/' in a possible redirect and '\0' */
79 ngx_test_null(name.data, 107 ngx_test_null(name.data,
80 ngx_palloc(r->pool, clcf->doc_root.len + r->uri.len + 2), 108 ngx_palloc(r->pool, clcf->doc_root.len + r->uri.len + 2),
81 NGX_HTTP_INTERNAL_SERVER_ERROR); 109 NGX_HTTP_INTERNAL_SERVER_ERROR);
82 110
83 location = ngx_cpymem(name.data, clcf->doc_root.data, clcf->doc_root.len); 111 location.data = ngx_cpymem(name.data, clcf->doc_root.data,
84 last = ngx_cpystrn(location, r->uri.data, r->uri.len + 1); 112 clcf->doc_root.len);
85 113 last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);
86 ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ data); 114 name.len = last - name.data;
87 115 location.len = last - location.data + 1;
88 116
89 if (r->cache == NULL) { 117 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
90 118 "http filename: \"%s\"", name.data);
91 /* look up an open files cache */ 119
92 120
93 ccf = ngx_http_get_module_loc_conf(r, ngx_http_cache_module); 121 /* allocate cleanups */
94 122
95 if (ccf->open_files) { 123 if (!(file_cleanup = ngx_push_array(&r->cleanup))) {
96 cache = ngx_http_cache_get(ccf->open_files, &name, &crc); 124 return NGX_HTTP_INTERNAL_SERVER_ERROR;
97 125 }
98 ngx_log_debug(r->connection->log, "cache get: %x" _ cache); 126 file_cleanup->valid = 0;
99 127
100 if (cache 128 slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module);
101 && ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) 129 if (slcf->redirect_cache) {
102 || ccf->open_files->update 130 if (!(redirect_cleanup = ngx_push_array(&r->cleanup))) {
103 >= ngx_cached_time - cache->updated)) 131 return NGX_HTTP_INTERNAL_SERVER_ERROR;
132 }
133 redirect_cleanup->valid = 0;
134
135 } else {
136 redirect_cleanup = NULL;
137 }
138
139
140 /* look up an open files cache */
141
142 if (clcf->open_files) {
143 file = ngx_http_cache_get(clcf->open_files, file_cleanup,
144 &name, &file_crc);
145
146 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
147 "http open file cache get: " PTR_FMT, file);
148
149 if (file && file->valid) {
150 r->cache = file;
151 return ngx_http_send_cached(r);
152 }
153
154 } else {
155 file = NULL;
156 }
157
158
159 /* look up an redirect cache */
160
161 if (slcf->redirect_cache) {
162 redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup,
163 &name, &redirect_crc);
164
165 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
166 "http redirect cache get: " PTR_FMT, redirect);
167
168 if (redirect && redirect->valid) {
169
170 /*
171 * We do not copy a cached value so the cache entry is locked
172 * until the end of the request. In a single threaded model
173 * the redirected request should complete before other event
174 * will be processed. In a multithreaded model this locking
175 * should keep more popular redirects in cache.
176 */
177
178 if (!(r->headers_out.location =
179 ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
104 { 180 {
105 r->cache = cache; 181 return NGX_HTTP_INTERNAL_SERVER_ERROR;
106 r->content_handler = ngx_http_static_handler; 182 }
107 183
108 return NGX_OK; 184 r->headers_out.location->value = redirect->data.value;
109 } 185
110 186 return NGX_HTTP_MOVED_PERMANENTLY;
111 } else {
112 cache = NULL;
113 } 187 }
114 188
115 } else { 189 } else {
116 cache = r->cache; 190 redirect = NULL;
117 } 191 }
118 192
193
194 /* open file */
119 195
120 #if (WIN9X) 196 #if (WIN9X)
197
198 /* TODO: redirect cache */
121 199
122 if (ngx_win32_version < NGX_WIN_NT) { 200 if (ngx_win32_version < NGX_WIN_NT) {
123 201
124 /* 202 /*
125 * there is no way to open a file or a directory in Win9X with 203 * there is no way to open a file or a directory in Win9X with
126 * one syscall because Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag 204 * one syscall because Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag
127 * so we need to check its type before the opening 205 * so we need to check its type before the opening
128 */ 206 */
129 207
130 if (ngx_file_info(name.data, &r->file.info) == NGX_FILE_ERROR) { 208 if (ngx_file_info(name.data, &fi) == NGX_FILE_ERROR) {
131 err = ngx_errno; 209 err = ngx_errno;
132 ngx_log_error(NGX_LOG_ERR, r->connection->log, err, 210 ngx_log_error(NGX_LOG_ERR, log, err,
133 ngx_file_info_n " \"%s\" failed", name.data); 211 ngx_file_info_n " \"%s\" failed", name.data);
134 212
135 if (err == NGX_ENOENT || err == NGX_ENOTDIR) { 213 if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
136 return NGX_HTTP_NOT_FOUND; 214 return NGX_HTTP_NOT_FOUND;
137 215
141 } else { 219 } else {
142 return NGX_HTTP_INTERNAL_SERVER_ERROR; 220 return NGX_HTTP_INTERNAL_SERVER_ERROR;
143 } 221 }
144 } 222 }
145 223
146 if (ngx_is_dir(&r->file.info)) { 224 if (ngx_is_dir(&fi)) {
147 ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ name.data); 225 ngx_log_debug(log, "HTTP DIR: '%s'" _ name.data);
148 226
149 if (!(r->headers_out.location = 227 if (!(r->headers_out.location =
150 ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) 228 ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
151 { 229 {
152 return NGX_HTTP_INTERNAL_SERVER_ERROR; 230 return NGX_HTTP_INTERNAL_SERVER_ERROR;
153 } 231 }
154 232
155 *last++ = '/'; 233 *last++ = '/';
156 *last = '\0'; 234 *last = '\0';
157 r->headers_out.location->key.len = 8;
158 r->headers_out.location->key.data = "Location" ;
159 r->headers_out.location->value.len = last - location; 235 r->headers_out.location->value.len = last - location;
160 r->headers_out.location->value.data = location; 236 r->headers_out.location->value.data = location;
161 237
162 return NGX_HTTP_MOVED_PERMANENTLY; 238 return NGX_HTTP_MOVED_PERMANENTLY;
163 } 239 }
164 } 240 }
165 241
166 #endif 242 #endif
167 243
168 244
169 if (r->file.fd == NGX_INVALID_FILE) { 245 fd = ngx_open_file(name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
170 r->file.fd = ngx_open_file(r->file.name.data, 246
171 NGX_FILE_RDONLY, NGX_FILE_OPEN); 247 if (fd == NGX_INVALID_FILE) {
172 }
173
174 if (r->file.fd == NGX_INVALID_FILE) {
175 err = ngx_errno; 248 err = ngx_errno;
176 249
177 if (err == NGX_ENOENT || err == NGX_ENOTDIR) { 250 if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
178 level = NGX_LOG_ERR; 251 level = NGX_LOG_ERR;
179 rc = NGX_HTTP_NOT_FOUND; 252 rc = NGX_HTTP_NOT_FOUND;
185 } else { 258 } else {
186 level = NGX_LOG_CRIT; 259 level = NGX_LOG_CRIT;
187 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; 260 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
188 } 261 }
189 262
190 ngx_log_error(level, r->connection->log, ngx_errno, 263 ngx_log_error(level, log, err,
191 ngx_open_file_n " \"%s\" failed", r->file.name.data); 264 ngx_open_file_n " \"%s\" failed", name.data);
192 265
193 return rc; 266 return rc;
194 } 267 }
195 268
196 ngx_log_debug(r->connection->log, "FILE: %d" _ r->file.fd); 269 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd);
197 270
198 if (!r->file.info_valid) { 271 if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
199 if (ngx_fd_info(r->file.fd, &r->file.info) == NGX_FILE_ERROR) { 272 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
200 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, 273 ngx_fd_info_n " \"%s\" failed", name.data);
201 ngx_fd_info_n " \"%s\" failed", r->file.name.data); 274
202 275 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
203 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) { 276 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
204 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, 277 ngx_close_file_n " \"%s\" failed", name.data);
205 ngx_close_file_n " \"%s\" failed", 278 }
206 r->file.name.data); 279
207 } 280 return NGX_HTTP_INTERNAL_SERVER_ERROR;
208 281 }
209 r->file.fd = NGX_INVALID_FILE; 282
210 283 if (ngx_is_dir(&fi)) {
211 return NGX_HTTP_INTERNAL_SERVER_ERROR; 284
212 } 285 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
213 286
214 r->file.info_valid = 1; 287 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
215 } 288 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
216 289 ngx_close_file_n " \"%s\" failed", name.data);
217 if (ccf->open_files) { 290 }
218 if (cache == NULL) { 291
219 cache = ngx_http_cache_alloc(ccf->open_files, &r->file.name, crc, 292 *last++ = '/';
220 r->connection->log); 293 *last = '\0';
221 }
222
223 ngx_log_debug(r->connection->log, "cache alloc: %x" _ cache);
224
225 if (cache) {
226 cache->fd = r->file.fd;
227 cache->data.size = ngx_file_size(&r->file.info);
228 cache->accessed = ngx_time();
229 cache->last_modified = ngx_file_mtime(&r->file.info);
230 cache->updated = ngx_time();
231 }
232 }
233
234 if (ngx_is_dir(&r->file.info)) {
235 ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->file.name.data);
236
237 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
238 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
239 ngx_close_file_n " \"%s\" failed", r->file.name.data);
240 }
241
242 r->file.fd = NGX_INVALID_FILE;
243 r->file.info_valid = 0;
244 294
245 if (!(r->headers_out.location = 295 if (!(r->headers_out.location =
246 ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) 296 ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
247 { 297 {
248 return NGX_HTTP_INTERNAL_SERVER_ERROR; 298 return NGX_HTTP_INTERNAL_SERVER_ERROR;
249 } 299 }
250 300
251 *last++ = '/'; 301 r->headers_out.location->value = location;
252 *last = '\0'; 302
253 #if 0 303 if (slcf->redirect_cache) {
254 r->headers_out.location->key.len = 8; 304 if (redirect) {
255 r->headers_out.location->key.data = "Location" ; 305 if (location.len == redirect->data.value.len
306 && ngx_memcmp(redirect->data.value.data, location.data,
307 location.len) == 0)
308 {
309 redirect->accessed = ngx_cached_time;
310 redirect->updated = ngx_cached_time;
311
312 /*
313 * we can unlock the cache entry because
314 * we have the local copy anyway
315 */
316
317 ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
318 redirect_cleanup->valid = 0;
319
320 return NGX_HTTP_MOVED_PERMANENTLY;
321 }
322 }
323
324 location.len++;
325 redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect,
326 redirect_cleanup,
327 &name, redirect_crc,
328 &location, log);
329 location.len--;
330
331 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
332 "http redirect cache alloc: " PTR_FMT, redirect);
333
334 if (redirect) {
335 redirect->fd = NGX_INVALID_FILE;
336 redirect->accessed = ngx_cached_time;
337 redirect->last_modified = 0;
338 redirect->updated = ngx_cached_time;
339 redirect->valid = 1;
340 redirect->memory = 1;
341 ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
342 redirect_cleanup->valid = 0;
343 }
344
345 }
346
347 return NGX_HTTP_MOVED_PERMANENTLY;
348 }
349
350 #if !(WIN32) /* the not regular files are probably Unix specific */
351
352 if (!ngx_is_file(&fi)) {
353 ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
354 "%s is not a regular file", name.data);
355
356 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
357 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
358 ngx_close_file_n " \"%s\" failed", name.data);
359 }
360
361 return NGX_HTTP_NOT_FOUND;
362 }
363
256 #endif 364 #endif
257 r->headers_out.location->value.len = last - location; 365
258 r->headers_out.location->value.data = location; 366
259 367 if (clcf->open_files) {
260 return NGX_HTTP_MOVED_PERMANENTLY; 368
261 } 369 #if (NGX_USE_HTTP_FILE_CACHE_UNIQ)
262 370
263 #if !(WIN32) /* the not regular files are probably Unix specific */ 371 if (file && file->uniq == ngx_file_uniq(&fi)) {
264 372 if (ngx_close_file(fd) == NGX_FILE_ERROR) {
265 if (!ngx_is_file(&r->file.info)) { 373 ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
266 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, 374 ngx_close_file_n " \"%s\" failed", name.data);
267 "%s is not a regular file", r->file.name.data); 375 }
268 376 file->accessed = ngx_cached_time;
269 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) 377 file->updated = ngx_cached_time;
270 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, 378 file->valid = 1;
271 ngx_close_file_n " %s failed", r->file.name.data); 379 r->cache = file;
272 380
273 return NGX_HTTP_NOT_FOUND; 381 return ngx_http_send_cached(r);
274 } 382
275 383 } else {
384 if (file) {
385 ngx_http_cache_unlock(clcf->open_files, file, log);
386 file = NULL;
387 }
388
389 file = ngx_http_cache_alloc(clcf->open_files, file,
390 file_cleanup,
391 &name, file_crc, NULL, log);
392 if (file) {
393 file->uniq = ngx_file_uniq(&fi);
394 }
395 }
396
397 #else
398 file = ngx_http_cache_alloc(clcf->open_files, file,
399 file_cleanup,
400 &name, file_crc, NULL, log);
276 #endif 401 #endif
277 402
278 r->content_handler = ngx_http_static_handler; 403 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
279 404 "http open file cache alloc: " PTR_FMT, file);
280 return NGX_OK; 405
281 } 406 if (file) {
282 407 file->fd = fd;
283 408 file->data.size = ngx_file_size(&fi);
284 static int ngx_http_static_handler(ngx_http_request_t *r) 409 file->accessed = ngx_cached_time;
285 { 410 file->last_modified = ngx_file_mtime(&fi);
286 int rc, key, i; 411 file->updated = ngx_cached_time;
287 ngx_log_e level; 412 file->valid = 1;
288 ngx_err_t err; 413 r->cache = file;
289 ngx_hunk_t *h; 414 }
290 ngx_chain_t out; 415
291 ngx_http_type_t *type; 416 return ngx_http_send_cached(r);
292 ngx_http_cleanup_t *cleanup; 417 }
293 ngx_http_log_ctx_t *ctx; 418
294 ngx_http_core_loc_conf_t *clcf; 419
295 420 ctx = log->data;
296 rc = ngx_http_discard_body(r);
297
298 if (rc != NGX_OK) {
299 return rc;
300 }
301
302 ctx = r->connection->log->data;
303 ctx->action = "sending response to client"; 421 ctx->action = "sending response to client";
304 422
305 if (!(cleanup = ngx_push_array(&r->cleanup))) { 423 file_cleanup->data.file.fd = fd;
424 file_cleanup->data.file.name = name.data;
425 file_cleanup->valid = 1;
426 file_cleanup->cache = 0;
427
428 r->headers_out.status = NGX_HTTP_OK;
429 r->headers_out.content_length_n = ngx_file_size(&fi);
430 r->headers_out.last_modified_time = ngx_file_mtime(&fi);
431
432 if (ngx_http_set_content_type(r) != NGX_OK) {
306 return NGX_HTTP_INTERNAL_SERVER_ERROR; 433 return NGX_HTTP_INTERNAL_SERVER_ERROR;
307 } 434 }
308 435
309 if (r->file.fd == NGX_INVALID_FILE) { 436
310 r->file.fd = ngx_open_file(r->file.name.data, 437 /* we need to allocate all before the header would be sent */
311 NGX_FILE_RDONLY, NGX_FILE_OPEN); 438
312 439 if (!(h = ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)))) {
313 if (r->file.fd == NGX_INVALID_FILE) {
314 err = ngx_errno;
315
316 if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
317 level = NGX_LOG_ERR;
318 rc = NGX_HTTP_NOT_FOUND;
319
320 } else {
321 level = NGX_LOG_CRIT;
322 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
323 }
324
325 ngx_log_error(level, r->connection->log, ngx_errno,
326 ngx_open_file_n " %s failed", r->file.name.data);
327 return rc;
328 }
329 }
330
331 cleanup->data.file.fd = r->file.fd;
332 cleanup->data.file.name = r->file.name.data;
333 cleanup->cache = 0;
334
335 if (!r->file.info_valid) {
336 if (ngx_fd_info(r->file.fd, &r->file.info) == NGX_FILE_ERROR) {
337 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
338 ngx_fd_info_n " %s failed", r->file.name.data);
339
340 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
341 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
342 ngx_close_file_n " %s failed", r->file.name.data);
343
344 return NGX_HTTP_INTERNAL_SERVER_ERROR;
345 }
346
347 r->file.info_valid = 1;
348 }
349
350 r->headers_out.status = NGX_HTTP_OK;
351 r->headers_out.content_length_n = ngx_file_size(&r->file.info);
352 r->headers_out.last_modified_time = ngx_file_mtime(&r->file.info);
353
354 if (!(r->headers_out.content_type =
355 ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
356 {
357 return NGX_HTTP_INTERNAL_SERVER_ERROR; 440 return NGX_HTTP_INTERNAL_SERVER_ERROR;
358 } 441 }
359 442
360 r->headers_out.content_type->key.len = 0; 443 if (!(h->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) {
361 r->headers_out.content_type->key.data = NULL; 444 return NGX_HTTP_INTERNAL_SERVER_ERROR;
362 r->headers_out.content_type->value.len = 0; 445 }
363 r->headers_out.content_type->value.data = NULL;
364
365 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
366
367 if (r->exten.len) {
368 ngx_http_types_hash_key(key, r->exten);
369
370 type = (ngx_http_type_t *) clcf->types[key].elts;
371 for (i = 0; i < clcf->types[key].nelts; i++) {
372 if (r->exten.len != type[i].exten.len) {
373 continue;
374 }
375
376 if (ngx_strcasecmp(r->exten.data, type[i].exten.data) == 0) {
377 r->headers_out.content_type->value.len = type[i].type.len;
378 r->headers_out.content_type->value.data = type[i].type.data;
379
380 break;
381 }
382 }
383 }
384
385 if (r->headers_out.content_type->value.len == 0) {
386 r->headers_out.content_type->value.len = clcf->default_type.len;
387 r->headers_out.content_type->value.data = clcf->default_type.data;
388 }
389
390 /* we need to allocate all before the header would be sent */
391
392 ngx_test_null(h, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)),
393 NGX_HTTP_INTERNAL_SERVER_ERROR);
394
395 ngx_test_null(h->file, ngx_pcalloc(r->pool, sizeof(ngx_file_t)),
396 NGX_HTTP_INTERNAL_SERVER_ERROR);
397 446
398 rc = ngx_http_send_header(r); 447 rc = ngx_http_send_header(r);
399 448
400 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { 449 if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
401 return rc; 450 return rc;
402 } 451 }
403 452
404 h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST; 453 h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST;
405 454
406 h->file_pos = 0; 455 h->file_pos = 0;
407 h->file_last = ngx_file_size(&r->file.info); 456 h->file_last = ngx_file_size(&fi);
408 457
409 h->file->fd = r->file.fd; 458 h->file->fd = fd;
410 h->file->log = r->connection->log; 459 h->file->log = log;
411 460
412 out.hunk = h; 461 out.hunk = h;
413 out.next = NULL; 462 out.next = NULL;
414 463
415 return ngx_http_output_filter(r, &out); 464 return ngx_http_output_filter(r, &out);
416 } 465 }
417 466
418 467
419 static int ngx_http_static_init(ngx_cycle_t *cycle) 468 static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf)
469 {
470 ngx_http_static_loc_conf_t *conf;
471
472 if (!(conf = ngx_palloc(cf->pool, sizeof(ngx_http_static_loc_conf_t)))) {
473 return NGX_CONF_ERROR;
474 }
475
476 conf->redirect_cache = NULL;
477
478 return conf;
479 }
480
481
482 static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf,
483 void *parent, void *child)
484 {
485 ngx_http_static_loc_conf_t *prev = parent;
486 ngx_http_static_loc_conf_t *conf = child;
487
488 if (conf->redirect_cache == NULL) {
489 conf->redirect_cache = prev->redirect_cache;
490 }
491
492 return NGX_CONF_OK;
493 }
494
495
496 static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle)
420 { 497 {
421 ngx_http_handler_pt *h; 498 ngx_http_handler_pt *h;
422 ngx_http_conf_ctx_t *ctx; 499 ngx_http_conf_ctx_t *ctx;
423 ngx_http_core_main_conf_t *cmcf; 500 ngx_http_core_main_conf_t *cmcf;
424 501
425 ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]; 502 ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index];
426 cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]; 503 cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
427 504
428 ngx_test_null(h, ngx_push_array( 505 h = ngx_push_array(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
429 &cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers), 506 if (h == NULL) {
430 NGX_ERROR); 507 return NGX_ERROR;
431 *h = ngx_http_static_translate_handler; 508 }
509
510 *h = ngx_http_static_handler;
432 511
433 return NGX_OK; 512 return NGX_OK;
434 } 513 }
435