src/http/modules/ngx_http_static_module.c - nginx source code

Global variables defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r);
  9. static ngx_int_t ngx_http_static_init(ngx_conf_t *cf);


  10. static ngx_http_module_t  ngx_http_static_module_ctx = {
  11.     NULL,                                  /* preconfiguration */
  12.     ngx_http_static_init,                  /* postconfiguration */

  13.     NULL,                                  /* create main configuration */
  14.     NULL,                                  /* init main configuration */

  15.     NULL,                                  /* create server configuration */
  16.     NULL,                                  /* merge server configuration */

  17.     NULL,                                  /* create location configuration */
  18.     NULL                                   /* merge location configuration */
  19. };


  20. ngx_module_t  ngx_http_static_module = {
  21.     NGX_MODULE_V1,
  22.     &ngx_http_static_module_ctx,           /* module context */
  23.     NULL,                                  /* module directives */
  24.     NGX_HTTP_MODULE,                       /* module type */
  25.     NULL,                                  /* init master */
  26.     NULL,                                  /* init module */
  27.     NULL,                                  /* init process */
  28.     NULL,                                  /* init thread */
  29.     NULL,                                  /* exit thread */
  30.     NULL,                                  /* exit process */
  31.     NULL,                                  /* exit master */
  32.     NGX_MODULE_V1_PADDING
  33. };


  34. static ngx_int_t
  35. ngx_http_static_handler(ngx_http_request_t *r)
  36. {
  37.     u_char                    *last, *location;
  38.     size_t                     root, len;
  39.     uintptr_t                  escape;
  40.     ngx_str_t                  path;
  41.     ngx_int_t                  rc;
  42.     ngx_uint_t                 level;
  43.     ngx_log_t                 *log;
  44.     ngx_buf_t                 *b;
  45.     ngx_chain_t                out;
  46.     ngx_open_file_info_t       of;
  47.     ngx_http_core_loc_conf_t  *clcf;

  48.     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
  49.         return NGX_HTTP_NOT_ALLOWED;
  50.     }

  51.     if (r->uri.data[r->uri.len - 1] == '/') {
  52.         return NGX_DECLINED;
  53.     }

  54.     log = r->connection->log;

  55.     /*
  56.      * ngx_http_map_uri_to_path() allocates memory for terminating '\0'
  57.      * so we do not need to reserve memory for '/' for possible redirect
  58.      */

  59.     last = ngx_http_map_uri_to_path(r, &path, &root, 0);
  60.     if (last == NULL) {
  61.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  62.     }

  63.     path.len = last - path.data;

  64.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
  65.                    "http filename: \"%s\"", path.data);

  66.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  67.     ngx_memzero(&of, sizeof(ngx_open_file_info_t));

  68.     of.read_ahead = clcf->read_ahead;
  69.     of.directio = clcf->directio;
  70.     of.valid = clcf->open_file_cache_valid;
  71.     of.min_uses = clcf->open_file_cache_min_uses;
  72.     of.errors = clcf->open_file_cache_errors;
  73.     of.events = clcf->open_file_cache_events;

  74.     if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
  75.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  76.     }

  77.     if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
  78.         != NGX_OK)
  79.     {
  80.         switch (of.err) {

  81.         case 0:
  82.             return NGX_HTTP_INTERNAL_SERVER_ERROR;

  83.         case NGX_ENOENT:
  84.         case NGX_ENOTDIR:
  85.         case NGX_ENAMETOOLONG:

  86.             level = NGX_LOG_ERR;
  87.             rc = NGX_HTTP_NOT_FOUND;
  88.             break;

  89.         case NGX_EACCES:
  90. #if (NGX_HAVE_OPENAT)
  91.         case NGX_EMLINK:
  92.         case NGX_ELOOP:
  93. #endif

  94.             level = NGX_LOG_ERR;
  95.             rc = NGX_HTTP_FORBIDDEN;
  96.             break;

  97.         default:

  98.             level = NGX_LOG_CRIT;
  99.             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
  100.             break;
  101.         }

  102.         if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
  103.             ngx_log_error(level, log, of.err,
  104.                           "%s \"%s\" failed", of.failed, path.data);
  105.         }

  106.         return rc;
  107.     }

  108.     r->root_tested = !r->error_page;

  109.     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);

  110.     if (of.is_dir) {

  111.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");

  112.         ngx_http_clear_location(r);

  113.         r->headers_out.location = ngx_list_push(&r->headers_out.headers);
  114.         if (r->headers_out.location == NULL) {
  115.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  116.         }

  117.         escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
  118.                                     NGX_ESCAPE_URI);

  119.         if (!clcf->alias && r->args.len == 0 && escape == 0) {
  120.             len = r->uri.len + 1;
  121.             location = path.data + root;

  122.             *last = '/';

  123.         } else {
  124.             len = r->uri.len + escape + 1;

  125.             if (r->args.len) {
  126.                 len += r->args.len + 1;
  127.             }

  128.             location = ngx_pnalloc(r->pool, len);
  129.             if (location == NULL) {
  130.                 ngx_http_clear_location(r);
  131.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  132.             }

  133.             if (escape) {
  134.                 last = (u_char *) ngx_escape_uri(location, r->uri.data,
  135.                                                  r->uri.len, NGX_ESCAPE_URI);

  136.             } else {
  137.                 last = ngx_copy(location, r->uri.data, r->uri.len);
  138.             }

  139.             *last = '/';

  140.             if (r->args.len) {
  141.                 *++last = '?';
  142.                 ngx_memcpy(++last, r->args.data, r->args.len);
  143.             }
  144.         }

  145.         r->headers_out.location->hash = 1;
  146.         r->headers_out.location->next = NULL;
  147.         ngx_str_set(&r->headers_out.location->key, "Location");
  148.         r->headers_out.location->value.len = len;
  149.         r->headers_out.location->value.data = location;

  150.         return NGX_HTTP_MOVED_PERMANENTLY;
  151.     }

  152. #if !(NGX_WIN32) /* the not regular files are probably Unix specific */

  153.     if (!of.is_file) {
  154.         ngx_log_error(NGX_LOG_CRIT, log, 0,
  155.                       "\"%s\" is not a regular file", path.data);

  156.         return NGX_HTTP_NOT_FOUND;
  157.     }

  158. #endif

  159.     if (r->method == NGX_HTTP_POST) {
  160.         return NGX_HTTP_NOT_ALLOWED;
  161.     }

  162.     rc = ngx_http_discard_request_body(r);

  163.     if (rc != NGX_OK) {
  164.         return rc;
  165.     }

  166.     log->action = "sending response to client";

  167.     r->headers_out.status = NGX_HTTP_OK;
  168.     r->headers_out.content_length_n = of.size;
  169.     r->headers_out.last_modified_time = of.mtime;

  170.     if (ngx_http_set_etag(r) != NGX_OK) {
  171.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  172.     }

  173.     if (ngx_http_set_content_type(r) != NGX_OK) {
  174.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  175.     }

  176.     r->allow_ranges = 1;

  177.     /* we need to allocate all before the header would be sent */

  178.     b = ngx_calloc_buf(r->pool);
  179.     if (b == NULL) {
  180.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  181.     }

  182.     b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
  183.     if (b->file == NULL) {
  184.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  185.     }

  186.     rc = ngx_http_send_header(r);

  187.     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
  188.         return rc;
  189.     }

  190.     b->file_pos = 0;
  191.     b->file_last = of.size;

  192.     b->in_file = b->file_last ? 1 : 0;
  193.     b->last_buf = (r == r->main) ? 1 : 0;
  194.     b->last_in_chain = 1;
  195.     b->sync = (b->last_buf || b->in_file) ? 0 : 1;

  196.     b->file->fd = of.fd;
  197.     b->file->name = path;
  198.     b->file->log = log;
  199.     b->file->directio = of.is_directio;

  200.     out.buf = b;
  201.     out.next = NULL;

  202.     return ngx_http_output_filter(r, &out);
  203. }


  204. static ngx_int_t
  205. ngx_http_static_init(ngx_conf_t *cf)
  206. {
  207.     ngx_http_handler_pt        *h;
  208.     ngx_http_core_main_conf_t  *cmcf;

  209.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  210.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
  211.     if (h == NULL) {
  212.         return NGX_ERROR;
  213.     }

  214.     *h = ngx_http_static_handler;

  215.     return NGX_OK;
  216. }