src/http/modules/ngx_http_static_module.c - nginx-1.7.10

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. 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.     ngx_str_t                  path;
  40.     ngx_int_t                  rc;
  41.     ngx_uint_t                 level;
  42.     ngx_log_t                 *log;
  43.     ngx_buf_t                 *b;
  44.     ngx_chain_t                out;
  45.     ngx_open_file_info_t       of;
  46.     ngx_http_core_loc_conf_t  *clcf;

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

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

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

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

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

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

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

  65.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

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

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

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

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

  80.         case 0:
  81.             return NGX_HTTP_INTERNAL_SERVER_ERROR;

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

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

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

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

  96.         default:

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

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

  105.         return rc;
  106.     }

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

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

  109.     if (of.is_dir) {

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

  111.         ngx_http_clear_location(r);

  112.         r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
  113.         if (r->headers_out.location == NULL) {
  114.             return NGX_HTTP_INTERNAL_SERVER_ERROR;
  115.         }

  116.         len = r->uri.len + 1;

  117.         if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) {
  118.             location = path.data + clcf->root.len;

  119.             *last = '/';

  120.         } else {
  121.             if (r->args.len) {
  122.                 len += r->args.len + 1;
  123.             }

  124.             location = ngx_pnalloc(r->pool, len);
  125.             if (location == NULL) {
  126.                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
  127.             }

  128.             last = ngx_copy(location, r->uri.data, r->uri.len);

  129.             *last = '/';

  130.             if (r->args.len) {
  131.                 *++last = '?';
  132.                 ngx_memcpy(++last, r->args.data, r->args.len);
  133.             }
  134.         }

  135.         /*
  136.          * we do not need to set the r->headers_out.location->hash and
  137.          * r->headers_out.location->key fields
  138.          */

  139.         r->headers_out.location->value.len = len;
  140.         r->headers_out.location->value.data = location;

  141.         return NGX_HTTP_MOVED_PERMANENTLY;
  142.     }

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

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

  147.         return NGX_HTTP_NOT_FOUND;
  148.     }

  149. #endif

  150.     if (r->method & NGX_HTTP_POST) {
  151.         return NGX_HTTP_NOT_ALLOWED;
  152.     }

  153.     rc = ngx_http_discard_request_body(r);

  154.     if (rc != NGX_OK) {
  155.         return rc;
  156.     }

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

  158.     r->headers_out.status = NGX_HTTP_OK;
  159.     r->headers_out.content_length_n = of.size;
  160.     r->headers_out.last_modified_time = of.mtime;

  161.     if (ngx_http_set_etag(r) != NGX_OK) {
  162.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  163.     }

  164.     if (ngx_http_set_content_type(r) != NGX_OK) {
  165.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  166.     }

  167.     if (r != r->main && of.size == 0) {
  168.         return ngx_http_send_header(r);
  169.     }

  170.     r->allow_ranges = 1;

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

  172.     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
  173.     if (b == NULL) {
  174.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  175.     }

  176.     b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
  177.     if (b->file == NULL) {
  178.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  179.     }

  180.     rc = ngx_http_send_header(r);

  181.     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
  182.         return rc;
  183.     }

  184.     b->file_pos = 0;
  185.     b->file_last = of.size;

  186.     b->in_file = b->file_last ? 1: 0;
  187.     b->last_buf = (r == r->main) ? 1: 0;
  188.     b->last_in_chain = 1;

  189.     b->file->fd = of.fd;
  190.     b->file->name = path;
  191.     b->file->log = log;
  192.     b->file->directio = of.is_directio;

  193.     out.buf = b;
  194.     out.next = NULL;

  195.     return ngx_http_output_filter(r, &out);
  196. }


  197. static ngx_int_t
  198. ngx_http_static_init(ngx_conf_t *cf)
  199. {
  200.     ngx_http_handler_pt        *h;
  201.     ngx_http_core_main_conf_t  *cmcf;

  202.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  203.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
  204.     if (h == NULL) {
  205.         return NGX_ERROR;
  206.     }

  207.     *h = ngx_http_static_handler;

  208.     return NGX_OK;
  209. }