Viewing file: StaticContentHandler.c (6.91 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* * Copyright (C) Igor Sysoev * Copyright (c) 2010-2017 Phusion Holding B.V. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */
#include "StaticContentHandler.h" #include "ngx_http_passenger_module.h"
static void set_request_extension(ngx_http_request_t *r, ngx_str_t *filename) { u_char *tmp;
/* Scan filename from the right until we've found a slash or a dot. */ tmp = filename->data + filename->len - 1; while (tmp >= filename->data && *tmp != '/' && *tmp != '.') { tmp--; } if (tmp >= filename->data && *tmp == '.') { /* We found a dot, and until now we haven't seen any slashes. * So we know that this is the filename's extension. */ tmp++; r->exten.data = tmp; r->exten.len = filename->len - (tmp - filename->data); } }
ngx_int_t passenger_static_content_handler(ngx_http_request_t *r, ngx_str_t *filename) { u_char *last, *location; size_t len; ngx_int_t rc; ngx_uint_t level; ngx_log_t *log; ngx_buf_t *b; ngx_chain_t out; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf;
if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_HTTP_NOT_ALLOWED; }
if (r->uri.data[r->uri.len - 1] == '/') { return NGX_DECLINED; }
log = r->connection->log;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", filename->data);
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.read_ahead = clcf->read_ahead; of.directio = clcf->directio; of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events;
if (ngx_open_cached_file(clcf->open_file_cache, filename, &of, r->pool) != NGX_OK) { switch (of.err) {
case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR;
case NGX_ENOENT: case NGX_ENOTDIR: case NGX_ENAMETOOLONG:
level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; break;
case NGX_EACCES:
level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; break;
default:
level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; break; }
if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { ngx_log_error(level, log, of.err, ngx_open_file_n " \"%s\" failed", filename->data); }
return rc; }
r->root_tested = !r->error_page;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);
if (of.is_dir) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t)); if (r->headers_out.location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; }
len = r->uri.len + 1;
if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { location = filename->data + clcf->root.len;
} else { if (r->args.len) { len += r->args.len + 1; }
location = ngx_pnalloc(r->pool, len); if (location == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; }
last = ngx_copy(location, r->uri.data, r->uri.len);
*last = '/';
if (r->args.len) { *++last = '?'; ngx_memcpy(++last, r->args.data, r->args.len); } }
/* * we do not need to set the r->headers_out.location->hash and * r->headers_out.location->key fields */
r->headers_out.location->value.len = len; r->headers_out.location->value.data = location;
return NGX_HTTP_MOVED_PERMANENTLY; }
#if !(NGX_WIN32) /* the not regular files are probably Unix specific */
if (!of.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, "\"%s\" is not a regular file", filename->data);
return NGX_HTTP_NOT_FOUND; }
#endif
if (r->method & NGX_HTTP_POST) { return NGX_HTTP_NOT_ALLOWED; }
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) { return rc; }
log->action = "sending response to client";
r->headers_out.status = NGX_HTTP_OK; r->headers_out.content_length_n = of.size; r->headers_out.last_modified_time = of.mtime;
set_request_extension(r, filename); if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; }
if (r != r->main && of.size == 0) { return ngx_http_send_header(r); }
r->allow_ranges = 1;
/* we need to allocate all before the header would be sent */
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; }
b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; }
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { return rc; }
b->file_pos = 0; b->file_last = of.size;
b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1;
b->file->fd = of.fd; b->file->name = *filename; b->file->log = log; b->file->directio = of.is_directio;
out.buf = b; out.next = NULL;
return ngx_http_output_filter(r, &out); }
|