src/http/ngx_http_header_filter_module.c - nginx-1.7.10

Global variables 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. #include <nginx.h>


  9. static ngx_int_t ngx_http_header_filter_init(ngx_conf_t *cf);
  10. static ngx_int_t ngx_http_header_filter(ngx_http_request_t *r);


  11. static ngx_http_module_t  ngx_http_header_filter_module_ctx = {
  12.     NULL,                                  /* preconfiguration */
  13.     ngx_http_header_filter_init,           /* postconfiguration */

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

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

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


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


  35. static char ngx_http_server_string[] = "Server: nginx" CRLF;
  36. static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;


  37. static ngx_str_t ngx_http_status_lines[] = {

  38.     ngx_string("200 OK"),
  39.     ngx_string("201 Created"),
  40.     ngx_string("202 Accepted"),
  41.     ngx_null_string/* "203 Non-Authoritative Information" */
  42.     ngx_string("204 No Content"),
  43.     ngx_null_string/* "205 Reset Content" */
  44.     ngx_string("206 Partial Content"),

  45.     /* ngx_null_string, */  /* "207 Multi-Status" */

  46. #define NGX_HTTP_LAST_2XX  207
  47. #define NGX_HTTP_OFF_3XX   (NGX_HTTP_LAST_2XX - 200)

  48.     /* ngx_null_string, */  /* "300 Multiple Choices" */

  49.     ngx_string("301 Moved Permanently"),
  50.     ngx_string("302 Moved Temporarily"),
  51.     ngx_string("303 See Other"),
  52.     ngx_string("304 Not Modified"),
  53.     ngx_null_string/* "305 Use Proxy" */
  54.     ngx_null_string/* "306 unused" */
  55.     ngx_string("307 Temporary Redirect"),

  56. #define NGX_HTTP_LAST_3XX  308
  57. #define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)

  58.     ngx_string("400 Bad Request"),
  59.     ngx_string("401 Unauthorized"),
  60.     ngx_string("402 Payment Required"),
  61.     ngx_string("403 Forbidden"),
  62.     ngx_string("404 Not Found"),
  63.     ngx_string("405 Not Allowed"),
  64.     ngx_string("406 Not Acceptable"),
  65.     ngx_null_string/* "407 Proxy Authentication Required" */
  66.     ngx_string("408 Request Time-out"),
  67.     ngx_string("409 Conflict"),
  68.     ngx_string("410 Gone"),
  69.     ngx_string("411 Length Required"),
  70.     ngx_string("412 Precondition Failed"),
  71.     ngx_string("413 Request Entity Too Large"),
  72.     ngx_string("414 Request-URI Too Large"),
  73.     ngx_string("415 Unsupported Media Type"),
  74.     ngx_string("416 Requested Range Not Satisfiable"),

  75.     /* ngx_null_string, */  /* "417 Expectation Failed" */
  76.     /* ngx_null_string, */  /* "418 unused" */
  77.     /* ngx_null_string, */  /* "419 unused" */
  78.     /* ngx_null_string, */  /* "420 unused" */
  79.     /* ngx_null_string, */  /* "421 unused" */
  80.     /* ngx_null_string, */  /* "422 Unprocessable Entity" */
  81.     /* ngx_null_string, */  /* "423 Locked" */
  82.     /* ngx_null_string, */  /* "424 Failed Dependency" */

  83. #define NGX_HTTP_LAST_4XX  417
  84. #define NGX_HTTP_OFF_5XX   (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)

  85.     ngx_string("500 Internal Server Error"),
  86.     ngx_string("501 Not Implemented"),
  87.     ngx_string("502 Bad Gateway"),
  88.     ngx_string("503 Service Temporarily Unavailable"),
  89.     ngx_string("504 Gateway Time-out"),

  90.     ngx_null_string,        /* "505 HTTP Version Not Supported" */
  91.     ngx_null_string,        /* "506 Variant Also Negotiates" */
  92.     ngx_string("507 Insufficient Storage"),
  93.     /* ngx_null_string, */  /* "508 unused" */
  94.     /* ngx_null_string, */  /* "509 unused" */
  95.     /* ngx_null_string, */  /* "510 Not Extended" */

  96. #define NGX_HTTP_LAST_5XX  508

  97. };


  98. ngx_http_header_out_t  ngx_http_headers_out[] = {
  99.     { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) },
  100.     { ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) },
  101.     { ngx_string("Content-Length"),
  102.                  offsetof(ngx_http_headers_out_t, content_length) },
  103.     { ngx_string("Content-Encoding"),
  104.                  offsetof(ngx_http_headers_out_t, content_encoding) },
  105.     { ngx_string("Location"), offsetof(ngx_http_headers_out_t, location) },
  106.     { ngx_string("Last-Modified"),
  107.                  offsetof(ngx_http_headers_out_t, last_modified) },
  108.     { ngx_string("Accept-Ranges"),
  109.                  offsetof(ngx_http_headers_out_t, accept_ranges) },
  110.     { ngx_string("Expires"), offsetof(ngx_http_headers_out_t, expires) },
  111.     { ngx_string("Cache-Control"),
  112.                  offsetof(ngx_http_headers_out_t, cache_control) },
  113.     { ngx_string("ETag"), offsetof(ngx_http_headers_out_t, etag) },

  114.     { ngx_null_string, 0 }
  115. };


  116. static ngx_int_t
  117. ngx_http_header_filter(ngx_http_request_t *r)
  118. {
  119.     u_char                    *p;
  120.     size_t                     len;
  121.     ngx_str_t                  host, *status_line;
  122.     ngx_buf_t                 *b;
  123.     ngx_uint_t                 status, i, port;
  124.     ngx_chain_t                out;
  125.     ngx_list_part_t           *part;
  126.     ngx_table_elt_t           *header;
  127.     ngx_connection_t          *c;
  128.     ngx_http_core_loc_conf_t  *clcf;
  129.     ngx_http_core_srv_conf_t  *cscf;
  130.     struct sockaddr_in        *sin;
  131. #if (NGX_HAVE_INET6)
  132.     struct sockaddr_in6       *sin6;
  133. #endif
  134.     u_char                     addr[NGX_SOCKADDR_STRLEN];

  135.     if (r->header_sent) {
  136.         return NGX_OK;
  137.     }

  138.     r->header_sent = 1;

  139.     if (r != r->main) {
  140.         return NGX_OK;
  141.     }

  142.     if (r->http_version < NGX_HTTP_VERSION_10) {
  143.         return NGX_OK;
  144.     }

  145.     if (r->method == NGX_HTTP_HEAD) {
  146.         r->header_only = 1;
  147.     }

  148.     if (r->headers_out.last_modified_time != -1) {
  149.         if (r->headers_out.status != NGX_HTTP_OK
  150.             && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
  151.             && r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
  152.         {
  153.             r->headers_out.last_modified_time = -1;
  154.             r->headers_out.last_modified = NULL;
  155.         }
  156.     }

  157.     len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1
  158.           /* the end of the header */
  159.           + sizeof(CRLF) - 1;

  160.     /* status line */

  161.     if (r->headers_out.status_line.len) {
  162.         len += r->headers_out.status_line.len;
  163.         status_line = &r->headers_out.status_line;
  164. #if (NGX_SUPPRESS_WARN)
  165.         status = 0;
  166. #endif

  167.     } else {

  168.         status = r->headers_out.status;

  169.         if (status >= NGX_HTTP_OK
  170.             && status < NGX_HTTP_LAST_2XX)
  171.         {
  172.             /* 2XX */

  173.             if (status == NGX_HTTP_NO_CONTENT) {
  174.                 r->header_only = 1;
  175.                 ngx_str_null(&r->headers_out.content_type);
  176.                 r->headers_out.last_modified_time = -1;
  177.                 r->headers_out.last_modified = NULL;
  178.                 r->headers_out.content_length = NULL;
  179.                 r->headers_out.content_length_n = -1;
  180.             }

  181.             status -= NGX_HTTP_OK;
  182.             status_line = &ngx_http_status_lines[status];
  183.             len += ngx_http_status_lines[status].len;

  184.         } else if (status >= NGX_HTTP_MOVED_PERMANENTLY
  185.                    && status < NGX_HTTP_LAST_3XX)
  186.         {
  187.             /* 3XX */

  188.             if (status == NGX_HTTP_NOT_MODIFIED) {
  189.                 r->header_only = 1;
  190.             }

  191.             status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;
  192.             status_line = &ngx_http_status_lines[status];
  193.             len += ngx_http_status_lines[status].len;

  194.         } else if (status >= NGX_HTTP_BAD_REQUEST
  195.                    && status < NGX_HTTP_LAST_4XX)
  196.         {
  197.             /* 4XX */
  198.             status = status - NGX_HTTP_BAD_REQUEST
  199.                             + NGX_HTTP_OFF_4XX;

  200.             status_line = &ngx_http_status_lines[status];
  201.             len += ngx_http_status_lines[status].len;

  202.         } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR
  203.                    && status < NGX_HTTP_LAST_5XX)
  204.         {
  205.             /* 5XX */
  206.             status = status - NGX_HTTP_INTERNAL_SERVER_ERROR
  207.                             + NGX_HTTP_OFF_5XX;

  208.             status_line = &ngx_http_status_lines[status];
  209.             len += ngx_http_status_lines[status].len;

  210.         } else {
  211.             len += NGX_INT_T_LEN + 1 /* SP */;
  212.             status_line = NULL;
  213.         }

  214.         if (status_line && status_line->len == 0) {
  215.             status = r->headers_out.status;
  216.             len += NGX_INT_T_LEN + 1 /* SP */;
  217.             status_line = NULL;
  218.         }
  219.     }

  220.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  221.     if (r->headers_out.server == NULL) {
  222.         len += clcf->server_tokens ? sizeof(ngx_http_server_full_string) - 1:
  223.                                      sizeof(ngx_http_server_string) - 1;
  224.     }

  225.     if (r->headers_out.date == NULL) {
  226.         len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
  227.     }

  228.     if (r->headers_out.content_type.len) {
  229.         len += sizeof("Content-Type: ") - 1
  230.                + r->headers_out.content_type.len + 2;

  231.         if (r->headers_out.content_type_len == r->headers_out.content_type.len
  232.             && r->headers_out.charset.len)
  233.         {
  234.             len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
  235.         }
  236.     }

  237.     if (r->headers_out.content_length == NULL
  238.         && r->headers_out.content_length_n >= 0)
  239.     {
  240.         len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
  241.     }

  242.     if (r->headers_out.last_modified == NULL
  243.         && r->headers_out.last_modified_time != -1)
  244.     {
  245.         len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
  246.     }

  247.     c = r->connection;

  248.     if (r->headers_out.location
  249.         && r->headers_out.location->value.len
  250.         && r->headers_out.location->value.data[0] == '/')
  251.     {
  252.         r->headers_out.location->hash = 0;

  253.         if (clcf->server_name_in_redirect) {
  254.             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
  255.             host = cscf->server_name;

  256.         } else if (r->headers_in.server.len) {
  257.             host = r->headers_in.server;

  258.         } else {
  259.             host.len = NGX_SOCKADDR_STRLEN;
  260.             host.data = addr;

  261.             if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
  262.                 return NGX_ERROR;
  263.             }
  264.         }

  265.         switch (c->local_sockaddr->sa_family) {

  266. #if (NGX_HAVE_INET6)
  267.         case AF_INET6:
  268.             sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
  269.             port = ntohs(sin6->sin6_port);
  270.             break;
  271. #endif
  272. #if (NGX_HAVE_UNIX_DOMAIN)
  273.         case AF_UNIX:
  274.             port = 0;
  275.             break;
  276. #endif
  277.         default: /* AF_INET */
  278.             sin = (struct sockaddr_in *) c->local_sockaddr;
  279.             port = ntohs(sin->sin_port);
  280.             break;
  281.         }

  282.         len += sizeof("Location: https://") - 1
  283.                + host.len
  284.                + r->headers_out.location->value.len + 2;

  285.         if (clcf->port_in_redirect) {

  286. #if (NGX_HTTP_SSL)
  287.             if (c->ssl)
  288.                 port = (port == 443) ? 0 : port;
  289.             else
  290. #endif
  291.                 port = (port == 80) ? 0 : port;

  292.         } else {
  293.             port = 0;
  294.         }

  295.         if (port) {
  296.             len += sizeof(":65535") - 1;
  297.         }

  298.     } else {
  299.         ngx_str_null(&host);
  300.         port = 0;
  301.     }

  302.     if (r->chunked) {
  303.         len += sizeof("Transfer-Encoding: chunked" CRLF) - 1;
  304.     }

  305.     if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
  306.         len += sizeof("Connection: upgrade" CRLF) - 1;

  307.     } else if (r->keepalive) {
  308.         len += sizeof("Connection: keep-alive" CRLF) - 1;

  309.         /*
  310.          * MSIE and Opera ignore the "Keep-Alive: timeout=<N>" header.
  311.          * MSIE keeps the connection alive for about 60-65 seconds.
  312.          * Opera keeps the connection alive very long.
  313.          * Mozilla keeps the connection alive for N plus about 1-10 seconds.
  314.          * Konqueror keeps the connection alive for about N seconds.
  315.          */

  316.         if (clcf->keepalive_header) {
  317.             len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2;
  318.         }

  319.     } else {
  320.         len += sizeof("Connection: close" CRLF) - 1;
  321.     }

  322. #if (NGX_HTTP_GZIP)
  323.     if (r->gzip_vary) {
  324.         if (clcf->gzip_vary) {
  325.             len += sizeof("Vary: Accept-Encoding" CRLF) - 1;

  326.         } else {
  327.             r->gzip_vary = 0;
  328.         }
  329.     }
  330. #endif

  331.     part = &r->headers_out.headers.part;
  332.     header = part->elts;

  333.     for (i = 0; /* void */; i++) {

  334.         if (i >= part->nelts) {
  335.             if (part->next == NULL) {
  336.                 break;
  337.             }

  338.             part = part->next;
  339.             header = part->elts;
  340.             i = 0;
  341.         }

  342.         if (header[i].hash == 0) {
  343.             continue;
  344.         }

  345.         len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len
  346.                + sizeof(CRLF) - 1;
  347.     }

  348.     b = ngx_create_temp_buf(r->pool, len);
  349.     if (b == NULL) {
  350.         return NGX_ERROR;
  351.     }

  352.     /* "HTTP/1.x " */
  353.     b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1);

  354.     /* status line */
  355.     if (status_line) {
  356.         b->last = ngx_copy(b->last, status_line->data, status_line->len);

  357.     } else {
  358.         b->last = ngx_sprintf(b->last, "%03ui ", status);
  359.     }
  360.     *b->last++ = CR; *b->last++ = LF;

  361.     if (r->headers_out.server == NULL) {
  362.         if (clcf->server_tokens) {
  363.             p = (u_char *) ngx_http_server_full_string;
  364.             len = sizeof(ngx_http_server_full_string) - 1;

  365.         } else {
  366.             p = (u_char *) ngx_http_server_string;
  367.             len = sizeof(ngx_http_server_string) - 1;
  368.         }

  369.         b->last = ngx_cpymem(b->last, p, len);
  370.     }

  371.     if (r->headers_out.date == NULL) {
  372.         b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1);
  373.         b->last = ngx_cpymem(b->last, ngx_cached_http_time.data,
  374.                              ngx_cached_http_time.len);

  375.         *b->last++ = CR; *b->last++ = LF;
  376.     }

  377.     if (r->headers_out.content_type.len) {
  378.         b->last = ngx_cpymem(b->last, "Content-Type: ",
  379.                              sizeof("Content-Type: ") - 1);
  380.         p = b->last;
  381.         b->last = ngx_copy(b->last, r->headers_out.content_type.data,
  382.                            r->headers_out.content_type.len);

  383.         if (r->headers_out.content_type_len == r->headers_out.content_type.len
  384.             && r->headers_out.charset.len)
  385.         {
  386.             b->last = ngx_cpymem(b->last, "; charset=",
  387.                                  sizeof("; charset=") - 1);
  388.             b->last = ngx_copy(b->last, r->headers_out.charset.data,
  389.                                r->headers_out.charset.len);

  390.             /* update r->headers_out.content_type for possible logging */

  391.             r->headers_out.content_type.len = b->last - p;
  392.             r->headers_out.content_type.data = p;
  393.         }

  394.         *b->last++ = CR; *b->last++ = LF;
  395.     }

  396.     if (r->headers_out.content_length == NULL
  397.         && r->headers_out.content_length_n >= 0)
  398.     {
  399.         b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF,
  400.                               r->headers_out.content_length_n);
  401.     }

  402.     if (r->headers_out.last_modified == NULL
  403.         && r->headers_out.last_modified_time != -1)
  404.     {
  405.         b->last = ngx_cpymem(b->last, "Last-Modified: ",
  406.                              sizeof("Last-Modified: ") - 1);
  407.         b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);

  408.         *b->last++ = CR; *b->last++ = LF;
  409.     }

  410.     if (host.data) {

  411.         p = b->last + sizeof("Location: ") - 1;

  412.         b->last = ngx_cpymem(b->last, "Location: http",
  413.                              sizeof("Location: http") - 1);

  414. #if (NGX_HTTP_SSL)
  415.         if (c->ssl) {
  416.             *b->last++ ='s';
  417.         }
  418. #endif

  419.         *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/';
  420.         b->last = ngx_copy(b->last, host.data, host.len);

  421.         if (port) {
  422.             b->last = ngx_sprintf(b->last, ":%ui", port);
  423.         }

  424.         b->last = ngx_copy(b->last, r->headers_out.location->value.data,
  425.                            r->headers_out.location->value.len);

  426.         /* update r->headers_out.location->value for possible logging */

  427.         r->headers_out.location->value.len = b->last - p;
  428.         r->headers_out.location->value.data = p;
  429.         ngx_str_set(&r->headers_out.location->key, "Location");

  430.         *b->last++ = CR; *b->last++ = LF;
  431.     }

  432.     if (r->chunked) {
  433.         b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF,
  434.                              sizeof("Transfer-Encoding: chunked" CRLF) - 1);
  435.     }

  436.     if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
  437.         b->last = ngx_cpymem(b->last, "Connection: upgrade" CRLF,
  438.                              sizeof("Connection: upgrade" CRLF) - 1);

  439.     } else if (r->keepalive) {
  440.         b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF,
  441.                              sizeof("Connection: keep-alive" CRLF) - 1);

  442.         if (clcf->keepalive_header) {
  443.             b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF,
  444.                                   clcf->keepalive_header);
  445.         }

  446.     } else {
  447.         b->last = ngx_cpymem(b->last, "Connection: close" CRLF,
  448.                              sizeof("Connection: close" CRLF) - 1);
  449.     }

  450. #if (NGX_HTTP_GZIP)
  451.     if (r->gzip_vary) {
  452.         b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF,
  453.                              sizeof("Vary: Accept-Encoding" CRLF) - 1);
  454.     }
  455. #endif

  456.     part = &r->headers_out.headers.part;
  457.     header = part->elts;

  458.     for (i = 0; /* void */; i++) {

  459.         if (i >= part->nelts) {
  460.             if (part->next == NULL) {
  461.                 break;
  462.             }

  463.             part = part->next;
  464.             header = part->elts;
  465.             i = 0;
  466.         }

  467.         if (header[i].hash == 0) {
  468.             continue;
  469.         }

  470.         b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
  471.         *b->last++ = ':'; *b->last++ = ' ';

  472.         b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
  473.         *b->last++ = CR; *b->last++ = LF;
  474.     }

  475.     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
  476.                    "%*s", (size_t) (b->last - b->pos), b->pos);

  477.     /* the end of HTTP header */
  478.     *b->last++ = CR; *b->last++ = LF;

  479.     r->header_size = b->last - b->pos;

  480.     if (r->header_only) {
  481.         b->last_buf = 1;
  482.     }

  483.     out.buf = b;
  484.     out.next = NULL;

  485.     return ngx_http_write_filter(r, &out);
  486. }


  487. static ngx_int_t
  488. ngx_http_header_filter_init(ngx_conf_t *cf)
  489. {
  490.     ngx_http_top_header_filter = ngx_http_header_filter;

  491.     return NGX_OK;
  492. }