Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 #include <nginx.h>
0012 
0013 
0014 static ngx_int_t ngx_http_header_filter_init(ngx_conf_t *cf);
0015 static ngx_int_t ngx_http_header_filter(ngx_http_request_t *r);
0016 
0017 
0018 static ngx_http_module_t  ngx_http_header_filter_module_ctx = {
0019     NULL,                                  /* preconfiguration */
0020     ngx_http_header_filter_init,           /* postconfiguration */
0021 
0022     NULL,                                  /* create main configuration */
0023     NULL,                                  /* init main configuration */
0024 
0025     NULL,                                  /* create server configuration */
0026     NULL,                                  /* merge server configuration */
0027 
0028     NULL,                                  /* create location configuration */
0029     NULL,                                  /* merge location configuration */
0030 };
0031 
0032 
0033 ngx_module_t  ngx_http_header_filter_module = {
0034     NGX_MODULE_V1,
0035     &ngx_http_header_filter_module_ctx,    /* module context */
0036     NULL,                                  /* module directives */
0037     NGX_HTTP_MODULE,                       /* module type */
0038     NULL,                                  /* init master */
0039     NULL,                                  /* init module */
0040     NULL,                                  /* init process */
0041     NULL,                                  /* init thread */
0042     NULL,                                  /* exit thread */
0043     NULL,                                  /* exit process */
0044     NULL,                                  /* exit master */
0045     NGX_MODULE_V1_PADDING
0046 };
0047 
0048 
0049 static u_char ngx_http_server_string[] = "Server: nginx" CRLF;
0050 static u_char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;
0051 static u_char ngx_http_server_build_string[] = "Server: " NGINX_VER_BUILD CRLF;
0052 
0053 
0054 static ngx_str_t ngx_http_status_lines[] = {
0055 
0056     ngx_string("200 OK"),
0057     ngx_string("201 Created"),
0058     ngx_string("202 Accepted"),
0059     ngx_null_string,  /* "203 Non-Authoritative Information" */
0060     ngx_string("204 No Content"),
0061     ngx_null_string,  /* "205 Reset Content" */
0062     ngx_string("206 Partial Content"),
0063 
0064     /* ngx_null_string, */  /* "207 Multi-Status" */
0065 
0066 #define NGX_HTTP_LAST_2XX  207
0067 #define NGX_HTTP_OFF_3XX   (NGX_HTTP_LAST_2XX - 200)
0068 
0069     /* ngx_null_string, */  /* "300 Multiple Choices" */
0070 
0071     ngx_string("301 Moved Permanently"),
0072     ngx_string("302 Moved Temporarily"),
0073     ngx_string("303 See Other"),
0074     ngx_string("304 Not Modified"),
0075     ngx_null_string,  /* "305 Use Proxy" */
0076     ngx_null_string,  /* "306 unused" */
0077     ngx_string("307 Temporary Redirect"),
0078     ngx_string("308 Permanent Redirect"),
0079 
0080 #define NGX_HTTP_LAST_3XX  309
0081 #define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)
0082 
0083     ngx_string("400 Bad Request"),
0084     ngx_string("401 Unauthorized"),
0085     ngx_string("402 Payment Required"),
0086     ngx_string("403 Forbidden"),
0087     ngx_string("404 Not Found"),
0088     ngx_string("405 Not Allowed"),
0089     ngx_string("406 Not Acceptable"),
0090     ngx_null_string,  /* "407 Proxy Authentication Required" */
0091     ngx_string("408 Request Time-out"),
0092     ngx_string("409 Conflict"),
0093     ngx_string("410 Gone"),
0094     ngx_string("411 Length Required"),
0095     ngx_string("412 Precondition Failed"),
0096     ngx_string("413 Request Entity Too Large"),
0097     ngx_string("414 Request-URI Too Large"),
0098     ngx_string("415 Unsupported Media Type"),
0099     ngx_string("416 Requested Range Not Satisfiable"),
0100     ngx_null_string,  /* "417 Expectation Failed" */
0101     ngx_null_string,  /* "418 unused" */
0102     ngx_null_string,  /* "419 unused" */
0103     ngx_null_string,  /* "420 unused" */
0104     ngx_string("421 Misdirected Request"),
0105     ngx_null_string,  /* "422 Unprocessable Entity" */
0106     ngx_null_string,  /* "423 Locked" */
0107     ngx_null_string,  /* "424 Failed Dependency" */
0108     ngx_null_string,  /* "425 unused" */
0109     ngx_null_string,  /* "426 Upgrade Required" */
0110     ngx_null_string,  /* "427 unused" */
0111     ngx_null_string,  /* "428 Precondition Required" */
0112     ngx_string("429 Too Many Requests"),
0113 
0114 #define NGX_HTTP_LAST_4XX  430
0115 #define NGX_HTTP_OFF_5XX   (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)
0116 
0117     ngx_string("500 Internal Server Error"),
0118     ngx_string("501 Not Implemented"),
0119     ngx_string("502 Bad Gateway"),
0120     ngx_string("503 Service Temporarily Unavailable"),
0121     ngx_string("504 Gateway Time-out"),
0122     ngx_string("505 HTTP Version Not Supported"),
0123     ngx_null_string,        /* "506 Variant Also Negotiates" */
0124     ngx_string("507 Insufficient Storage"),
0125 
0126     /* ngx_null_string, */  /* "508 unused" */
0127     /* ngx_null_string, */  /* "509 unused" */
0128     /* ngx_null_string, */  /* "510 Not Extended" */
0129 
0130 #define NGX_HTTP_LAST_5XX  508
0131 
0132 };
0133 
0134 
0135 ngx_http_header_out_t  ngx_http_headers_out[] = {
0136     { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) },
0137     { ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) },
0138     { ngx_string("Content-Length"),
0139                  offsetof(ngx_http_headers_out_t, content_length) },
0140     { ngx_string("Content-Encoding"),
0141                  offsetof(ngx_http_headers_out_t, content_encoding) },
0142     { ngx_string("Location"), offsetof(ngx_http_headers_out_t, location) },
0143     { ngx_string("Last-Modified"),
0144                  offsetof(ngx_http_headers_out_t, last_modified) },
0145     { ngx_string("Accept-Ranges"),
0146                  offsetof(ngx_http_headers_out_t, accept_ranges) },
0147     { ngx_string("Expires"), offsetof(ngx_http_headers_out_t, expires) },
0148     { ngx_string("Cache-Control"),
0149                  offsetof(ngx_http_headers_out_t, cache_control) },
0150     { ngx_string("ETag"), offsetof(ngx_http_headers_out_t, etag) },
0151 
0152     { ngx_null_string, 0 }
0153 };
0154 
0155 
0156 static ngx_int_t
0157 ngx_http_header_filter(ngx_http_request_t *r)
0158 {
0159     u_char                    *p;
0160     size_t                     len;
0161     ngx_str_t                  host, *status_line;
0162     ngx_buf_t                 *b;
0163     ngx_uint_t                 status, i, port;
0164     ngx_chain_t                out;
0165     ngx_list_part_t           *part;
0166     ngx_table_elt_t           *header;
0167     ngx_connection_t          *c;
0168     ngx_http_core_loc_conf_t  *clcf;
0169     ngx_http_core_srv_conf_t  *cscf;
0170     u_char                     addr[NGX_SOCKADDR_STRLEN];
0171 
0172     if (r->header_sent) {
0173         return NGX_OK;
0174     }
0175 
0176     r->header_sent = 1;
0177 
0178     if (r != r->main) {
0179         return NGX_OK;
0180     }
0181 
0182     if (r->http_version < NGX_HTTP_VERSION_10) {
0183         return NGX_OK;
0184     }
0185 
0186     if (r->method == NGX_HTTP_HEAD) {
0187         r->header_only = 1;
0188     }
0189 
0190     if (r->headers_out.last_modified_time != -1) {
0191         if (r->headers_out.status != NGX_HTTP_OK
0192             && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
0193             && r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
0194         {
0195             r->headers_out.last_modified_time = -1;
0196             r->headers_out.last_modified = NULL;
0197         }
0198     }
0199 
0200     len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1
0201           /* the end of the header */
0202           + sizeof(CRLF) - 1;
0203 
0204     /* status line */
0205 
0206     if (r->headers_out.status_line.len) {
0207         len += r->headers_out.status_line.len;
0208         status_line = &r->headers_out.status_line;
0209 #if (NGX_SUPPRESS_WARN)
0210         status = 0;
0211 #endif
0212 
0213     } else {
0214 
0215         status = r->headers_out.status;
0216 
0217         if (status >= NGX_HTTP_OK
0218             && status < NGX_HTTP_LAST_2XX)
0219         {
0220             /* 2XX */
0221 
0222             if (status == NGX_HTTP_NO_CONTENT) {
0223                 r->header_only = 1;
0224                 ngx_str_null(&r->headers_out.content_type);
0225                 r->headers_out.last_modified_time = -1;
0226                 r->headers_out.last_modified = NULL;
0227                 r->headers_out.content_length = NULL;
0228                 r->headers_out.content_length_n = -1;
0229             }
0230 
0231             status -= NGX_HTTP_OK;
0232             status_line = &ngx_http_status_lines[status];
0233             len += ngx_http_status_lines[status].len;
0234 
0235         } else if (status >= NGX_HTTP_MOVED_PERMANENTLY
0236                    && status < NGX_HTTP_LAST_3XX)
0237         {
0238             /* 3XX */
0239 
0240             if (status == NGX_HTTP_NOT_MODIFIED) {
0241                 r->header_only = 1;
0242             }
0243 
0244             status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;
0245             status_line = &ngx_http_status_lines[status];
0246             len += ngx_http_status_lines[status].len;
0247 
0248         } else if (status >= NGX_HTTP_BAD_REQUEST
0249                    && status < NGX_HTTP_LAST_4XX)
0250         {
0251             /* 4XX */
0252             status = status - NGX_HTTP_BAD_REQUEST
0253                             + NGX_HTTP_OFF_4XX;
0254 
0255             status_line = &ngx_http_status_lines[status];
0256             len += ngx_http_status_lines[status].len;
0257 
0258         } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR
0259                    && status < NGX_HTTP_LAST_5XX)
0260         {
0261             /* 5XX */
0262             status = status - NGX_HTTP_INTERNAL_SERVER_ERROR
0263                             + NGX_HTTP_OFF_5XX;
0264 
0265             status_line = &ngx_http_status_lines[status];
0266             len += ngx_http_status_lines[status].len;
0267 
0268         } else {
0269             len += NGX_INT_T_LEN + 1 /* SP */;
0270             status_line = NULL;
0271         }
0272 
0273         if (status_line && status_line->len == 0) {
0274             status = r->headers_out.status;
0275             len += NGX_INT_T_LEN + 1 /* SP */;
0276             status_line = NULL;
0277         }
0278     }
0279 
0280     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
0281 
0282     if (r->headers_out.server == NULL) {
0283         if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
0284             len += sizeof(ngx_http_server_full_string) - 1;
0285 
0286         } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
0287             len += sizeof(ngx_http_server_build_string) - 1;
0288 
0289         } else {
0290             len += sizeof(ngx_http_server_string) - 1;
0291         }
0292     }
0293 
0294     if (r->headers_out.date == NULL) {
0295         len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
0296     }
0297 
0298     if (r->headers_out.content_type.len) {
0299         len += sizeof("Content-Type: ") - 1
0300                + r->headers_out.content_type.len + 2;
0301 
0302         if (r->headers_out.content_type_len == r->headers_out.content_type.len
0303             && r->headers_out.charset.len)
0304         {
0305             len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
0306         }
0307     }
0308 
0309     if (r->headers_out.content_length == NULL
0310         && r->headers_out.content_length_n >= 0)
0311     {
0312         len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
0313     }
0314 
0315     if (r->headers_out.last_modified == NULL
0316         && r->headers_out.last_modified_time != -1)
0317     {
0318         len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
0319     }
0320 
0321     c = r->connection;
0322 
0323     if (r->headers_out.location
0324         && r->headers_out.location->value.len
0325         && r->headers_out.location->value.data[0] == '/'
0326         && clcf->absolute_redirect)
0327     {
0328         r->headers_out.location->hash = 0;
0329 
0330         if (clcf->server_name_in_redirect) {
0331             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
0332             host = cscf->server_name;
0333 
0334         } else if (r->headers_in.server.len) {
0335             host = r->headers_in.server;
0336 
0337         } else {
0338             host.len = NGX_SOCKADDR_STRLEN;
0339             host.data = addr;
0340 
0341             if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
0342                 return NGX_ERROR;
0343             }
0344         }
0345 
0346         port = ngx_inet_get_port(c->local_sockaddr);
0347 
0348         len += sizeof("Location: https://") - 1
0349                + host.len
0350                + r->headers_out.location->value.len + 2;
0351 
0352         if (clcf->port_in_redirect) {
0353 
0354 #if (NGX_HTTP_SSL)
0355             if (c->ssl)
0356                 port = (port == 443) ? 0 : port;
0357             else
0358 #endif
0359                 port = (port == 80) ? 0 : port;
0360 
0361         } else {
0362             port = 0;
0363         }
0364 
0365         if (port) {
0366             len += sizeof(":65535") - 1;
0367         }
0368 
0369     } else {
0370         ngx_str_null(&host);
0371         port = 0;
0372     }
0373 
0374     if (r->chunked) {
0375         len += sizeof("Transfer-Encoding: chunked" CRLF) - 1;
0376     }
0377 
0378     if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
0379         len += sizeof("Connection: upgrade" CRLF) - 1;
0380 
0381     } else if (r->keepalive) {
0382         len += sizeof("Connection: keep-alive" CRLF) - 1;
0383 
0384         /*
0385          * MSIE and Opera ignore the "Keep-Alive: timeout=<N>" header.
0386          * MSIE keeps the connection alive for about 60-65 seconds.
0387          * Opera keeps the connection alive very long.
0388          * Mozilla keeps the connection alive for N plus about 1-10 seconds.
0389          * Konqueror keeps the connection alive for about N seconds.
0390          */
0391 
0392         if (clcf->keepalive_header) {
0393             len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2;
0394         }
0395 
0396     } else {
0397         len += sizeof("Connection: close" CRLF) - 1;
0398     }
0399 
0400 #if (NGX_HTTP_GZIP)
0401     if (r->gzip_vary) {
0402         if (clcf->gzip_vary) {
0403             len += sizeof("Vary: Accept-Encoding" CRLF) - 1;
0404 
0405         } else {
0406             r->gzip_vary = 0;
0407         }
0408     }
0409 #endif
0410 
0411     part = &r->headers_out.headers.part;
0412     header = part->elts;
0413 
0414     for (i = 0; /* void */; i++) {
0415 
0416         if (i >= part->nelts) {
0417             if (part->next == NULL) {
0418                 break;
0419             }
0420 
0421             part = part->next;
0422             header = part->elts;
0423             i = 0;
0424         }
0425 
0426         if (header[i].hash == 0) {
0427             continue;
0428         }
0429 
0430         len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len
0431                + sizeof(CRLF) - 1;
0432     }
0433 
0434     b = ngx_create_temp_buf(r->pool, len);
0435     if (b == NULL) {
0436         return NGX_ERROR;
0437     }
0438 
0439     /* "HTTP/1.x " */
0440     b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1);
0441 
0442     /* status line */
0443     if (status_line) {
0444         b->last = ngx_copy(b->last, status_line->data, status_line->len);
0445 
0446     } else {
0447         b->last = ngx_sprintf(b->last, "%03ui ", status);
0448     }
0449     *b->last++ = CR; *b->last++ = LF;
0450 
0451     if (r->headers_out.server == NULL) {
0452         if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
0453             p = ngx_http_server_full_string;
0454             len = sizeof(ngx_http_server_full_string) - 1;
0455 
0456         } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
0457             p = ngx_http_server_build_string;
0458             len = sizeof(ngx_http_server_build_string) - 1;
0459 
0460         } else {
0461             p = ngx_http_server_string;
0462             len = sizeof(ngx_http_server_string) - 1;
0463         }
0464 
0465         b->last = ngx_cpymem(b->last, p, len);
0466     }
0467 
0468     if (r->headers_out.date == NULL) {
0469         b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1);
0470         b->last = ngx_cpymem(b->last, ngx_cached_http_time.data,
0471                              ngx_cached_http_time.len);
0472 
0473         *b->last++ = CR; *b->last++ = LF;
0474     }
0475 
0476     if (r->headers_out.content_type.len) {
0477         b->last = ngx_cpymem(b->last, "Content-Type: ",
0478                              sizeof("Content-Type: ") - 1);
0479         p = b->last;
0480         b->last = ngx_copy(b->last, r->headers_out.content_type.data,
0481                            r->headers_out.content_type.len);
0482 
0483         if (r->headers_out.content_type_len == r->headers_out.content_type.len
0484             && r->headers_out.charset.len)
0485         {
0486             b->last = ngx_cpymem(b->last, "; charset=",
0487                                  sizeof("; charset=") - 1);
0488             b->last = ngx_copy(b->last, r->headers_out.charset.data,
0489                                r->headers_out.charset.len);
0490 
0491             /* update r->headers_out.content_type for possible logging */
0492 
0493             r->headers_out.content_type.len = b->last - p;
0494             r->headers_out.content_type.data = p;
0495         }
0496 
0497         *b->last++ = CR; *b->last++ = LF;
0498     }
0499 
0500     if (r->headers_out.content_length == NULL
0501         && r->headers_out.content_length_n >= 0)
0502     {
0503         b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF,
0504                               r->headers_out.content_length_n);
0505     }
0506 
0507     if (r->headers_out.last_modified == NULL
0508         && r->headers_out.last_modified_time != -1)
0509     {
0510         b->last = ngx_cpymem(b->last, "Last-Modified: ",
0511                              sizeof("Last-Modified: ") - 1);
0512         b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);
0513 
0514         *b->last++ = CR; *b->last++ = LF;
0515     }
0516 
0517     if (host.data) {
0518 
0519         p = b->last + sizeof("Location: ") - 1;
0520 
0521         b->last = ngx_cpymem(b->last, "Location: http",
0522                              sizeof("Location: http") - 1);
0523 
0524 #if (NGX_HTTP_SSL)
0525         if (c->ssl) {
0526             *b->last++ ='s';
0527         }
0528 #endif
0529 
0530         *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/';
0531         b->last = ngx_copy(b->last, host.data, host.len);
0532 
0533         if (port) {
0534             b->last = ngx_sprintf(b->last, ":%ui", port);
0535         }
0536 
0537         b->last = ngx_copy(b->last, r->headers_out.location->value.data,
0538                            r->headers_out.location->value.len);
0539 
0540         /* update r->headers_out.location->value for possible logging */
0541 
0542         r->headers_out.location->value.len = b->last - p;
0543         r->headers_out.location->value.data = p;
0544         ngx_str_set(&r->headers_out.location->key, "Location");
0545 
0546         *b->last++ = CR; *b->last++ = LF;
0547     }
0548 
0549     if (r->chunked) {
0550         b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF,
0551                              sizeof("Transfer-Encoding: chunked" CRLF) - 1);
0552     }
0553 
0554     if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
0555         b->last = ngx_cpymem(b->last, "Connection: upgrade" CRLF,
0556                              sizeof("Connection: upgrade" CRLF) - 1);
0557 
0558     } else if (r->keepalive) {
0559         b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF,
0560                              sizeof("Connection: keep-alive" CRLF) - 1);
0561 
0562         if (clcf->keepalive_header) {
0563             b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF,
0564                                   clcf->keepalive_header);
0565         }
0566 
0567     } else {
0568         b->last = ngx_cpymem(b->last, "Connection: close" CRLF,
0569                              sizeof("Connection: close" CRLF) - 1);
0570     }
0571 
0572 #if (NGX_HTTP_GZIP)
0573     if (r->gzip_vary) {
0574         b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF,
0575                              sizeof("Vary: Accept-Encoding" CRLF) - 1);
0576     }
0577 #endif
0578 
0579     part = &r->headers_out.headers.part;
0580     header = part->elts;
0581 
0582     for (i = 0; /* void */; i++) {
0583 
0584         if (i >= part->nelts) {
0585             if (part->next == NULL) {
0586                 break;
0587             }
0588 
0589             part = part->next;
0590             header = part->elts;
0591             i = 0;
0592         }
0593 
0594         if (header[i].hash == 0) {
0595             continue;
0596         }
0597 
0598         b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
0599         *b->last++ = ':'; *b->last++ = ' ';
0600 
0601         b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
0602         *b->last++ = CR; *b->last++ = LF;
0603     }
0604 
0605     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
0606                    "%*s", (size_t) (b->last - b->pos), b->pos);
0607 
0608     /* the end of HTTP header */
0609     *b->last++ = CR; *b->last++ = LF;
0610 
0611     r->header_size = b->last - b->pos;
0612 
0613     if (r->header_only) {
0614         b->last_buf = 1;
0615     }
0616 
0617     out.buf = b;
0618     out.next = NULL;
0619 
0620     return ngx_http_write_filter(r, &out);
0621 }
0622 
0623 
0624 static ngx_int_t
0625 ngx_http_header_filter_init(ngx_conf_t *cf)
0626 {
0627     ngx_http_top_header_filter = ngx_http_header_filter;
0628 
0629     return NGX_OK;
0630 }