src/http/modules/ngx_http_not_modified_filter_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_uint_t ngx_http_test_if_unmodified(ngx_http_request_t *r);
  9. static ngx_uint_t ngx_http_test_if_modified(ngx_http_request_t *r);
  10. static ngx_uint_t ngx_http_test_if_match(ngx_http_request_t *r,
  11.     ngx_table_elt_t *header, ngx_uint_t weak);
  12. static ngx_int_t ngx_http_not_modified_filter_init(ngx_conf_t *cf);


  13. static ngx_http_module_t  ngx_http_not_modified_filter_module_ctx = {
  14.     NULL,                                  /* preconfiguration */
  15.     ngx_http_not_modified_filter_init,     /* postconfiguration */

  16.     NULL,                                  /* create main configuration */
  17.     NULL,                                  /* init main configuration */

  18.     NULL,                                  /* create server configuration */
  19.     NULL,                                  /* merge server configuration */

  20.     NULL,                                  /* create location configuration */
  21.     NULL                                   /* merge location configuration */
  22. };


  23. ngx_module_t  ngx_http_not_modified_filter_module = {
  24.     NGX_MODULE_V1,
  25.     &ngx_http_not_modified_filter_module_ctx, /* module context */
  26.     NULL,                                  /* module directives */
  27.     NGX_HTTP_MODULE,                       /* module type */
  28.     NULL,                                  /* init master */
  29.     NULL,                                  /* init module */
  30.     NULL,                                  /* init process */
  31.     NULL,                                  /* init thread */
  32.     NULL,                                  /* exit thread */
  33.     NULL,                                  /* exit process */
  34.     NULL,                                  /* exit master */
  35.     NGX_MODULE_V1_PADDING
  36. };


  37. static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;


  38. static ngx_int_t
  39. ngx_http_not_modified_header_filter(ngx_http_request_t *r)
  40. {
  41.     if (r->headers_out.status != NGX_HTTP_OK
  42.         || r != r->main
  43.         || r->disable_not_modified)
  44.     {
  45.         return ngx_http_next_header_filter(r);
  46.     }

  47.     if (r->headers_in.if_unmodified_since
  48.         && !ngx_http_test_if_unmodified(r))
  49.     {
  50.         return ngx_http_filter_finalize_request(r, NULL,
  51.                                                 NGX_HTTP_PRECONDITION_FAILED);
  52.     }

  53.     if (r->headers_in.if_match
  54.         && !ngx_http_test_if_match(r, r->headers_in.if_match, 0))
  55.     {
  56.         return ngx_http_filter_finalize_request(r, NULL,
  57.                                                 NGX_HTTP_PRECONDITION_FAILED);
  58.     }

  59.     if (r->headers_in.if_modified_since || r->headers_in.if_none_match) {

  60.         if (r->headers_in.if_modified_since
  61.             && ngx_http_test_if_modified(r))
  62.         {
  63.             return ngx_http_next_header_filter(r);
  64.         }

  65.         if (r->headers_in.if_none_match
  66.             && !ngx_http_test_if_match(r, r->headers_in.if_none_match, 1))
  67.         {
  68.             return ngx_http_next_header_filter(r);
  69.         }

  70.         /* not modified */

  71.         r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
  72.         r->headers_out.status_line.len = 0;
  73.         r->headers_out.content_type.len = 0;
  74.         ngx_http_clear_content_length(r);
  75.         ngx_http_clear_accept_ranges(r);

  76.         if (r->headers_out.content_encoding) {
  77.             r->headers_out.content_encoding->hash = 0;
  78.             r->headers_out.content_encoding = NULL;
  79.         }

  80.         return ngx_http_next_header_filter(r);
  81.     }

  82.     return ngx_http_next_header_filter(r);
  83. }


  84. static ngx_uint_t
  85. ngx_http_test_if_unmodified(ngx_http_request_t *r)
  86. {
  87.     time_t  iums;

  88.     if (r->headers_out.last_modified_time == (time_t) -1) {
  89.         return 0;
  90.     }

  91.     iums = ngx_http_parse_time(r->headers_in.if_unmodified_since->value.data,
  92.                                r->headers_in.if_unmodified_since->value.len);

  93.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  94.                  "http iums:%T lm:%T", iums, r->headers_out.last_modified_time);

  95.     if (iums >= r->headers_out.last_modified_time) {
  96.         return 1;
  97.     }

  98.     return 0;
  99. }


  100. static ngx_uint_t
  101. ngx_http_test_if_modified(ngx_http_request_t *r)
  102. {
  103.     time_t                     ims;
  104.     ngx_http_core_loc_conf_t  *clcf;

  105.     if (r->headers_out.last_modified_time == (time_t) -1) {
  106.         return 1;
  107.     }

  108.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  109.     if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) {
  110.         return 1;
  111.     }

  112.     ims = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,
  113.                               r->headers_in.if_modified_since->value.len);

  114.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  115.                    "http ims:%T lm:%T", ims, r->headers_out.last_modified_time);

  116.     if (ims == r->headers_out.last_modified_time) {
  117.         return 0;
  118.     }

  119.     if (clcf->if_modified_since == NGX_HTTP_IMS_EXACT
  120.         || ims < r->headers_out.last_modified_time)
  121.     {
  122.         return 1;
  123.     }

  124.     return 0;
  125. }


  126. static ngx_uint_t
  127. ngx_http_test_if_match(ngx_http_request_t *r, ngx_table_elt_t *header,
  128.     ngx_uint_t weak)
  129. {
  130.     u_char     *start, *end, ch;
  131.     ngx_str_t   etag, *list;

  132.     list = &header->value;

  133.     if (list->len == 1 && list->data[0] == '*') {
  134.         return 1;
  135.     }

  136.     if (r->headers_out.etag == NULL) {
  137.         return 0;
  138.     }

  139.     etag = r->headers_out.etag->value;

  140.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  141.                    "http im:\"%V\" etag:%V", list, &etag);

  142.     if (weak
  143.         && etag.len > 2
  144.         && etag.data[0] == 'W'
  145.         && etag.data[1] == '/')
  146.     {
  147.         etag.len -= 2;
  148.         etag.data += 2;
  149.     }

  150.     start = list->data;
  151.     end = list->data + list->len;

  152.     while (start < end) {

  153.         if (weak
  154.             && end - start > 2
  155.             && start[0] == 'W'
  156.             && start[1] == '/')
  157.         {
  158.             start += 2;
  159.         }

  160.         if (etag.len > (size_t) (end - start)) {
  161.             return 0;
  162.         }

  163.         if (ngx_strncmp(start, etag.data, etag.len) != 0) {
  164.             goto skip;
  165.         }

  166.         start += etag.len;

  167.         while (start < end) {
  168.             ch = *start;

  169.             if (ch == ' ' || ch == '\t') {
  170.                 start++;
  171.                 continue;
  172.             }

  173.             break;
  174.         }

  175.         if (start == end || *start == ',') {
  176.             return 1;
  177.         }

  178.     skip:

  179.         while (start < end && *start != ',') { start++; }
  180.         while (start < end) {
  181.             ch = *start;

  182.             if (ch == ' ' || ch == '\t' || ch == ',') {
  183.                 start++;
  184.                 continue;
  185.             }

  186.             break;
  187.         }
  188.     }

  189.     return 0;
  190. }


  191. static ngx_int_t
  192. ngx_http_not_modified_filter_init(ngx_conf_t *cf)
  193. {
  194.     ngx_http_next_header_filter = ngx_http_top_header_filter;
  195.     ngx_http_top_header_filter = ngx_http_not_modified_header_filter;

  196.     return NGX_OK;
  197. }