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

Global variables defined

Data types defined

Functions defined

Macros 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. #define NGX_HTTP_GZIP_STATIC_OFF     0
  9. #define NGX_HTTP_GZIP_STATIC_ON      1
  10. #define NGX_HTTP_GZIP_STATIC_ALWAYS  2


  11. typedef struct {
  12.     ngx_uint_t  enable;
  13. } ngx_http_gzip_static_conf_t;


  14. static ngx_int_t ngx_http_gzip_static_handler(ngx_http_request_t *r);
  15. static void *ngx_http_gzip_static_create_conf(ngx_conf_t *cf);
  16. static char *ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent,
  17.     void *child);
  18. static ngx_int_t ngx_http_gzip_static_init(ngx_conf_t *cf);


  19. static ngx_conf_enum_t  ngx_http_gzip_static[] = {
  20.     { ngx_string("off"), NGX_HTTP_GZIP_STATIC_OFF },
  21.     { ngx_string("on"), NGX_HTTP_GZIP_STATIC_ON },
  22.     { ngx_string("always"), NGX_HTTP_GZIP_STATIC_ALWAYS },
  23.     { ngx_null_string, 0 }
  24. };


  25. static ngx_command_t  ngx_http_gzip_static_commands[] = {

  26.     { ngx_string("gzip_static"),
  27.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  28.       ngx_conf_set_enum_slot,
  29.       NGX_HTTP_LOC_CONF_OFFSET,
  30.       offsetof(ngx_http_gzip_static_conf_t, enable),
  31.       &ngx_http_gzip_static },

  32.       ngx_null_command
  33. };


  34. ngx_http_module_t  ngx_http_gzip_static_module_ctx = {
  35.     NULL,                                  /* preconfiguration */
  36.     ngx_http_gzip_static_init,             /* postconfiguration */

  37.     NULL,                                  /* create main configuration */
  38.     NULL,                                  /* init main configuration */

  39.     NULL,                                  /* create server configuration */
  40.     NULL,                                  /* merge server configuration */

  41.     ngx_http_gzip_static_create_conf,      /* create location configuration */
  42.     ngx_http_gzip_static_merge_conf        /* merge location configuration */
  43. };


  44. ngx_module_t  ngx_http_gzip_static_module = {
  45.     NGX_MODULE_V1,
  46.     &ngx_http_gzip_static_module_ctx,      /* module context */
  47.     ngx_http_gzip_static_commands,         /* module directives */
  48.     NGX_HTTP_MODULE,                       /* module type */
  49.     NULL,                                  /* init master */
  50.     NULL,                                  /* init module */
  51.     NULL,                                  /* init process */
  52.     NULL,                                  /* init thread */
  53.     NULL,                                  /* exit thread */
  54.     NULL,                                  /* exit process */
  55.     NULL,                                  /* exit master */
  56.     NGX_MODULE_V1_PADDING
  57. };


  58. static ngx_int_t
  59. ngx_http_gzip_static_handler(ngx_http_request_t *r)
  60. {
  61.     u_char                       *p;
  62.     size_t                        root;
  63.     ngx_str_t                     path;
  64.     ngx_int_t                     rc;
  65.     ngx_uint_t                    level;
  66.     ngx_log_t                    *log;
  67.     ngx_buf_t                    *b;
  68.     ngx_chain_t                   out;
  69.     ngx_table_elt_t              *h;
  70.     ngx_open_file_info_t          of;
  71.     ngx_http_core_loc_conf_t     *clcf;
  72.     ngx_http_gzip_static_conf_t  *gzcf;

  73.     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
  74.         return NGX_DECLINED;
  75.     }

  76.     if (r->uri.data[r->uri.len - 1] == '/') {
  77.         return NGX_DECLINED;
  78.     }

  79.     gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module);

  80.     if (gzcf->enable == NGX_HTTP_GZIP_STATIC_OFF) {
  81.         return NGX_DECLINED;
  82.     }

  83.     if (gzcf->enable == NGX_HTTP_GZIP_STATIC_ON) {
  84.         rc = ngx_http_gzip_ok(r);

  85.     } else {
  86.         /* always */
  87.         rc = NGX_OK;
  88.     }

  89.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  90.     if (!clcf->gzip_vary && rc != NGX_OK) {
  91.         return NGX_DECLINED;
  92.     }

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

  94.     p = ngx_http_map_uri_to_path(r, &path, &root, sizeof(".gz") - 1);
  95.     if (p == NULL) {
  96.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  97.     }

  98.     *p++ = '.';
  99.     *p++ = 'g';
  100.     *p++ = 'z';
  101.     *p = '\0';

  102.     path.len = p - path.data;

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

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

  106.     of.read_ahead = clcf->read_ahead;
  107.     of.directio = clcf->directio;
  108.     of.valid = clcf->open_file_cache_valid;
  109.     of.min_uses = clcf->open_file_cache_min_uses;
  110.     of.errors = clcf->open_file_cache_errors;
  111.     of.events = clcf->open_file_cache_events;

  112.     if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
  113.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  114.     }

  115.     if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
  116.         != NGX_OK)
  117.     {
  118.         switch (of.err) {

  119.         case 0:
  120.             return NGX_HTTP_INTERNAL_SERVER_ERROR;

  121.         case NGX_ENOENT:
  122.         case NGX_ENOTDIR:
  123.         case NGX_ENAMETOOLONG:

  124.             return NGX_DECLINED;

  125.         case NGX_EACCES:
  126. #if (NGX_HAVE_OPENAT)
  127.         case NGX_EMLINK:
  128.         case NGX_ELOOP:
  129. #endif

  130.             level = NGX_LOG_ERR;
  131.             break;

  132.         default:

  133.             level = NGX_LOG_CRIT;
  134.             break;
  135.         }

  136.         ngx_log_error(level, log, of.err,
  137.                       "%s \"%s\" failed", of.failed, path.data);

  138.         return NGX_DECLINED;
  139.     }

  140.     if (gzcf->enable == NGX_HTTP_GZIP_STATIC_ON) {
  141.         r->gzip_vary = 1;

  142.         if (rc != NGX_OK) {
  143.             return NGX_DECLINED;
  144.         }
  145.     }

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

  147.     if (of.is_dir) {
  148.         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
  149.         return NGX_DECLINED;
  150.     }

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

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

  155.         return NGX_HTTP_NOT_FOUND;
  156.     }

  157. #endif

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

  159.     rc = ngx_http_discard_request_body(r);

  160.     if (rc != NGX_OK) {
  161.         return rc;
  162.     }

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

  164.     r->headers_out.status = NGX_HTTP_OK;
  165.     r->headers_out.content_length_n = of.size;
  166.     r->headers_out.last_modified_time = of.mtime;

  167.     if (ngx_http_set_etag(r) != NGX_OK) {
  168.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  169.     }

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

  173.     h = ngx_list_push(&r->headers_out.headers);
  174.     if (h == NULL) {
  175.         return NGX_ERROR;
  176.     }

  177.     h->hash = 1;
  178.     ngx_str_set(&h->key, "Content-Encoding");
  179.     ngx_str_set(&h->value, "gzip");
  180.     r->headers_out.content_encoding = h;

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

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

  186.     b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
  187.     if (b->file == NULL) {
  188.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  189.     }

  190.     rc = ngx_http_send_header(r);

  191.     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
  192.         return rc;
  193.     }

  194.     b->file_pos = 0;
  195.     b->file_last = of.size;

  196.     b->in_file = b->file_last ? 1 : 0;
  197.     b->last_buf = (r == r->main) ? 1 : 0;
  198.     b->last_in_chain = 1;

  199.     b->file->fd = of.fd;
  200.     b->file->name = path;
  201.     b->file->log = log;
  202.     b->file->directio = of.is_directio;

  203.     out.buf = b;
  204.     out.next = NULL;

  205.     return ngx_http_output_filter(r, &out);
  206. }


  207. static void *
  208. ngx_http_gzip_static_create_conf(ngx_conf_t *cf)
  209. {
  210.     ngx_http_gzip_static_conf_t  *conf;

  211.     conf = ngx_palloc(cf->pool, sizeof(ngx_http_gzip_static_conf_t));
  212.     if (conf == NULL) {
  213.         return NULL;
  214.     }

  215.     conf->enable = NGX_CONF_UNSET_UINT;

  216.     return conf;
  217. }


  218. static char *
  219. ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent, void *child)
  220. {
  221.     ngx_http_gzip_static_conf_t *prev = parent;
  222.     ngx_http_gzip_static_conf_t *conf = child;

  223.     ngx_conf_merge_uint_value(conf->enable, prev->enable,
  224.                               NGX_HTTP_GZIP_STATIC_OFF);

  225.     return NGX_CONF_OK;
  226. }


  227. static ngx_int_t
  228. ngx_http_gzip_static_init(ngx_conf_t *cf)
  229. {
  230.     ngx_http_handler_pt        *h;
  231.     ngx_http_core_main_conf_t  *cmcf;

  232.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  233.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
  234.     if (h == NULL) {
  235.         return NGX_ERROR;
  236.     }

  237.     *h = ngx_http_gzip_static_handler;

  238.     return NGX_OK;
  239. }