3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
13 static ngx_int_t
ngx_http_static_handler(ngx_http_request_t
*r
);
14 static ngx_int_t
ngx_http_static_init(ngx_conf_t
*cf
);
17 ngx_http_module_t ngx_http_static_module_ctx
= {
18 NULL
, /* preconfiguration */
19 ngx_http_static_init
, /* postconfiguration */
21 NULL
, /* create main configuration */
22 NULL
, /* init main configuration */
24 NULL
, /* create server configuration */
25 NULL
, /* merge server configuration */
27 NULL
, /* create location configuration */
28 NULL
/* merge location configuration */
32 ngx_module_t ngx_http_static_module
= {
34 &ngx_http_static_module_ctx
, /* module context */
35 NULL
, /* module directives */
36 NGX_HTTP_MODULE
, /* module type */
37 NULL
, /* init master */
38 NULL
, /* init module */
39 NULL
, /* init process */
40 NULL
, /* init thread */
41 NULL
, /* exit thread */
42 NULL
, /* exit process */
43 NULL
, /* exit master */
49 ngx_http_static_handler(ngx_http_request_t
*r
)
51 u_char
*last
, *location
;
59 ngx_open_file_info_t of
;
60 ngx_http_core_loc_conf_t
*clcf
;
62 if (!(r
->method
& (NGX_HTTP_GET
|NGX_HTTP_HEAD
|NGX_HTTP_POST
))) {
63 return NGX_HTTP_NOT_ALLOWED
;
66 if (r
->uri
.data
[r
->uri
.len
- 1] == '/') {
70 log
= r
->connection
->log
;
73 * ngx_http_map_uri_to_path() allocates memory for terminating '\0'
74 * so we do not need to reserve memory for '/' for possible redirect
77 last
= ngx_http_map_uri_to_path(r
, &path
, &root
, 0);
79 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
82 path
.len
= last
- path
.data
;
84 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, log
, 0,
85 "http filename: \"%s\"", path
.data
);
87 clcf
= ngx_http_get_module_loc_conf(r
, ngx_http_core_module
);
89 ngx_memzero(&of
, sizeof(ngx_open_file_info_t
));
91 of
.read_ahead
= clcf
->read_ahead
;
92 of
.directio
= clcf
->directio
;
93 of
.valid
= clcf
->open_file_cache_valid
;
94 of
.min_uses
= clcf
->open_file_cache_min_uses
;
95 of
.errors
= clcf
->open_file_cache_errors
;
96 of
.events
= clcf
->open_file_cache_events
;
98 if (ngx_http_set_disable_symlinks(r
, clcf
, &path
, &of
) != NGX_OK
) {
99 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
102 if (ngx_open_cached_file(clcf
->open_file_cache
, &path
, &of
, r
->pool
)
108 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
112 case NGX_ENAMETOOLONG
:
115 rc
= NGX_HTTP_NOT_FOUND
;
119 #if (NGX_HAVE_OPENAT)
125 rc
= NGX_HTTP_FORBIDDEN
;
130 level
= NGX_LOG_CRIT
;
131 rc
= NGX_HTTP_INTERNAL_SERVER_ERROR
;
135 if (rc
!= NGX_HTTP_NOT_FOUND
|| clcf
->log_not_found
) {
136 ngx_log_error(level
, log
, of
.err
,
137 "%s \"%s\" failed", of
.failed
, path
.data
);
143 r
->root_tested
= !r
->error_page
;
145 ngx_log_debug1(NGX_LOG_DEBUG_HTTP
, log
, 0, "http static fd: %d", of
.fd
);
149 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, log
, 0, "http dir");
151 ngx_http_clear_location(r
);
153 r
->headers_out
.location
= ngx_palloc(r
->pool
, sizeof(ngx_table_elt_t
));
154 if (r
->headers_out
.location
== NULL
) {
155 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
158 len
= r
->uri
.len
+ 1;
160 if (!clcf
->alias
&& clcf
->root_lengths
== NULL
&& r
->args
.len
== 0) {
161 location
= path
.data
+ clcf
->root
.len
;
167 len
+= r
->args
.len
+ 1;
170 location
= ngx_pnalloc(r
->pool
, len
);
171 if (location
== NULL
) {
172 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
175 last
= ngx_copy(location
, r
->uri
.data
, r
->uri
.len
);
181 ngx_memcpy(++last
, r
->args
.data
, r
->args
.len
);
186 * we do not need to set the r->headers_out.location->hash and
187 * r->headers_out.location->key fields
190 r
->headers_out
.location
->value
.len
= len
;
191 r
->headers_out
.location
->value
.data
= location
;
193 return NGX_HTTP_MOVED_PERMANENTLY
;
196 #if !(NGX_WIN32) /* the not regular files are probably Unix specific */
199 ngx_log_error(NGX_LOG_CRIT
, log
, 0,
200 "\"%s\" is not a regular file", path
.data
);
202 return NGX_HTTP_NOT_FOUND
;
207 if (r
->method
& NGX_HTTP_POST
) {
208 return NGX_HTTP_NOT_ALLOWED
;
211 rc
= ngx_http_discard_request_body(r
);
217 log
->action
= "sending response to client";
219 r
->headers_out
.status
= NGX_HTTP_OK
;
220 r
->headers_out
.content_length_n
= of
.size
;
221 r
->headers_out
.last_modified_time
= of
.mtime
;
223 if (ngx_http_set_etag(r
) != NGX_OK
) {
224 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
227 if (ngx_http_set_content_type(r
) != NGX_OK
) {
228 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
231 if (r
!= r
->main
&& of
.size
== 0) {
232 return ngx_http_send_header(r
);
237 /* we need to allocate all before the header would be sent */
239 b
= ngx_pcalloc(r
->pool
, sizeof(ngx_buf_t
));
241 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
244 b
->file
= ngx_pcalloc(r
->pool
, sizeof(ngx_file_t
));
245 if (b
->file
== NULL
) {
246 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
249 rc
= ngx_http_send_header(r
);
251 if (rc
== NGX_ERROR
|| rc
> NGX_OK
|| r
->header_only
) {
256 b
->file_last
= of
.size
;
258 b
->in_file
= b
->file_last
? 1: 0;
259 b
->last_buf
= (r
== r
->main
) ? 1: 0;
260 b
->last_in_chain
= 1;
263 b
->file
->name
= path
;
265 b
->file
->directio
= of
.is_directio
;
270 return ngx_http_output_filter(r
, &out
);
275 ngx_http_static_init(ngx_conf_t
*cf
)
277 ngx_http_handler_pt
*h
;
278 ngx_http_core_main_conf_t
*cmcf
;
280 cmcf
= ngx_http_conf_get_module_main_conf(cf
, ngx_http_core_module
);
282 h
= ngx_array_push(&cmcf
->phases
[NGX_HTTP_CONTENT_PHASE
].handlers
);
287 *h
= ngx_http_static_handler
;