Mercurial > hg > nginx-quic
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 |