Annotation of embedaddon/nginx/src/http/ngx_http_header_filter_module.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_http.h>
                     11: #include <nginx.h>
                     12: 
                     13: 
                     14: static ngx_int_t ngx_http_header_filter_init(ngx_conf_t *cf);
                     15: static ngx_int_t ngx_http_header_filter(ngx_http_request_t *r);
                     16: 
                     17: 
                     18: static ngx_http_module_t  ngx_http_header_filter_module_ctx = {
                     19:     NULL,                                  /* preconfiguration */
                     20:     ngx_http_header_filter_init,           /* postconfiguration */
                     21: 
                     22:     NULL,                                  /* create main configuration */
                     23:     NULL,                                  /* init main configuration */
                     24: 
                     25:     NULL,                                  /* create server configuration */
                     26:     NULL,                                  /* merge server configuration */
                     27: 
                     28:     NULL,                                  /* create location configuration */
                     29:     NULL,                                  /* merge location configuration */
                     30: };
                     31: 
                     32: 
                     33: ngx_module_t  ngx_http_header_filter_module = {
                     34:     NGX_MODULE_V1,
                     35:     &ngx_http_header_filter_module_ctx,    /* module context */
                     36:     NULL,                                  /* module directives */
                     37:     NGX_HTTP_MODULE,                       /* module type */
                     38:     NULL,                                  /* init master */
                     39:     NULL,                                  /* init module */
                     40:     NULL,                                  /* init process */
                     41:     NULL,                                  /* init thread */
                     42:     NULL,                                  /* exit thread */
                     43:     NULL,                                  /* exit process */
                     44:     NULL,                                  /* exit master */
                     45:     NGX_MODULE_V1_PADDING
                     46: };
                     47: 
                     48: 
                     49: static char ngx_http_server_string[] = "Server: nginx" CRLF;
                     50: static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;
                     51: 
                     52: 
                     53: static ngx_str_t ngx_http_status_lines[] = {
                     54: 
                     55:     ngx_string("200 OK"),
                     56:     ngx_string("201 Created"),
                     57:     ngx_string("202 Accepted"),
                     58:     ngx_null_string,  /* "203 Non-Authoritative Information" */
                     59:     ngx_string("204 No Content"),
                     60:     ngx_null_string,  /* "205 Reset Content" */
                     61:     ngx_string("206 Partial Content"),
                     62: 
                     63:     /* ngx_null_string, */  /* "207 Multi-Status" */
                     64: 
                     65: #define NGX_HTTP_LAST_2XX  207
                     66: #define NGX_HTTP_OFF_3XX   (NGX_HTTP_LAST_2XX - 200)
                     67: 
                     68:     /* ngx_null_string, */  /* "300 Multiple Choices" */
                     69: 
                     70:     ngx_string("301 Moved Permanently"),
                     71:     ngx_string("302 Moved Temporarily"),
                     72:     ngx_string("303 See Other"),
                     73:     ngx_string("304 Not Modified"),
                     74:     ngx_null_string,  /* "305 Use Proxy" */
                     75:     ngx_null_string,  /* "306 unused" */
                     76:     ngx_string("307 Temporary Redirect"),
                     77: 
                     78: #define NGX_HTTP_LAST_3XX  308
                     79: #define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)
                     80: 
                     81:     ngx_string("400 Bad Request"),
                     82:     ngx_string("401 Unauthorized"),
                     83:     ngx_string("402 Payment Required"),
                     84:     ngx_string("403 Forbidden"),
                     85:     ngx_string("404 Not Found"),
                     86:     ngx_string("405 Not Allowed"),
                     87:     ngx_string("406 Not Acceptable"),
                     88:     ngx_null_string,  /* "407 Proxy Authentication Required" */
                     89:     ngx_string("408 Request Time-out"),
                     90:     ngx_string("409 Conflict"),
                     91:     ngx_string("410 Gone"),
                     92:     ngx_string("411 Length Required"),
                     93:     ngx_string("412 Precondition Failed"),
                     94:     ngx_string("413 Request Entity Too Large"),
                     95:     ngx_null_string,  /* "414 Request-URI Too Large", but we never send it
                     96:                        * because we treat such requests as the HTTP/0.9
                     97:                        * requests and send only a body without a header
                     98:                        */
                     99:     ngx_string("415 Unsupported Media Type"),
                    100:     ngx_string("416 Requested Range Not Satisfiable"),
                    101: 
                    102:     /* ngx_null_string, */  /* "417 Expectation Failed" */
                    103:     /* ngx_null_string, */  /* "418 unused" */
                    104:     /* ngx_null_string, */  /* "419 unused" */
                    105:     /* ngx_null_string, */  /* "420 unused" */
                    106:     /* ngx_null_string, */  /* "421 unused" */
                    107:     /* ngx_null_string, */  /* "422 Unprocessable Entity" */
                    108:     /* ngx_null_string, */  /* "423 Locked" */
                    109:     /* ngx_null_string, */  /* "424 Failed Dependency" */
                    110: 
                    111: #define NGX_HTTP_LAST_4XX  417
                    112: #define NGX_HTTP_OFF_5XX   (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)
                    113: 
                    114:     ngx_string("500 Internal Server Error"),
                    115:     ngx_string("501 Not Implemented"),
                    116:     ngx_string("502 Bad Gateway"),
                    117:     ngx_string("503 Service Temporarily Unavailable"),
                    118:     ngx_string("504 Gateway Time-out"),
                    119: 
                    120:     ngx_null_string,        /* "505 HTTP Version Not Supported" */
                    121:     ngx_null_string,        /* "506 Variant Also Negotiates" */
                    122:     ngx_string("507 Insufficient Storage"),
                    123:     /* ngx_null_string, */  /* "508 unused" */
                    124:     /* ngx_null_string, */  /* "509 unused" */
                    125:     /* ngx_null_string, */  /* "510 Not Extended" */
                    126: 
                    127: #define NGX_HTTP_LAST_5XX  508
                    128: 
                    129: };
                    130: 
                    131: 
                    132: ngx_http_header_out_t  ngx_http_headers_out[] = {
                    133:     { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) },
                    134:     { ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) },
                    135:     { ngx_string("Content-Length"),
                    136:                  offsetof(ngx_http_headers_out_t, content_length) },
                    137:     { ngx_string("Content-Encoding"),
                    138:                  offsetof(ngx_http_headers_out_t, content_encoding) },
                    139:     { ngx_string("Location"), offsetof(ngx_http_headers_out_t, location) },
                    140:     { ngx_string("Last-Modified"),
                    141:                  offsetof(ngx_http_headers_out_t, last_modified) },
                    142:     { ngx_string("Accept-Ranges"),
                    143:                  offsetof(ngx_http_headers_out_t, accept_ranges) },
                    144:     { ngx_string("Expires"), offsetof(ngx_http_headers_out_t, expires) },
                    145:     { ngx_string("Cache-Control"),
                    146:                  offsetof(ngx_http_headers_out_t, cache_control) },
                    147:     { ngx_string("ETag"), offsetof(ngx_http_headers_out_t, etag) },
                    148: 
                    149:     { ngx_null_string, 0 }
                    150: };
                    151: 
                    152: 
                    153: static ngx_int_t
                    154: ngx_http_header_filter(ngx_http_request_t *r)
                    155: {
                    156:     u_char                    *p;
                    157:     size_t                     len;
                    158:     ngx_str_t                  host, *status_line;
                    159:     ngx_buf_t                 *b;
                    160:     ngx_uint_t                 status, i, port;
                    161:     ngx_chain_t                out;
                    162:     ngx_list_part_t           *part;
                    163:     ngx_table_elt_t           *header;
                    164:     ngx_connection_t          *c;
                    165:     ngx_http_core_loc_conf_t  *clcf;
                    166:     ngx_http_core_srv_conf_t  *cscf;
                    167:     struct sockaddr_in        *sin;
                    168: #if (NGX_HAVE_INET6)
                    169:     struct sockaddr_in6       *sin6;
                    170: #endif
                    171:     u_char                     addr[NGX_SOCKADDR_STRLEN];
                    172: 
                    173:     if (r->header_sent) {
                    174:         return NGX_OK;
                    175:     }
                    176: 
                    177:     r->header_sent = 1;
                    178: 
                    179:     if (r != r->main) {
                    180:         return NGX_OK;
                    181:     }
                    182: 
                    183:     if (r->http_version < NGX_HTTP_VERSION_10) {
                    184:         return NGX_OK;
                    185:     }
                    186: 
                    187:     if (r->method == NGX_HTTP_HEAD) {
                    188:         r->header_only = 1;
                    189:     }
                    190: 
                    191:     if (r->headers_out.last_modified_time != -1) {
                    192:         if (r->headers_out.status != NGX_HTTP_OK
                    193:             && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
                    194:             && r->headers_out.status != NGX_HTTP_NOT_MODIFIED)
                    195:         {
                    196:             r->headers_out.last_modified_time = -1;
                    197:             r->headers_out.last_modified = NULL;
                    198:         }
                    199:     }
                    200: 
                    201:     len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1
                    202:           /* the end of the header */
                    203:           + sizeof(CRLF) - 1;
                    204: 
                    205:     /* status line */
                    206: 
                    207:     if (r->headers_out.status_line.len) {
                    208:         len += r->headers_out.status_line.len;
                    209:         status_line = &r->headers_out.status_line;
                    210: #if (NGX_SUPPRESS_WARN)
                    211:         status = 0;
                    212: #endif
                    213: 
                    214:     } else {
                    215: 
                    216:         status = r->headers_out.status;
                    217: 
                    218:         if (status >= NGX_HTTP_OK
                    219:             && status < NGX_HTTP_LAST_2XX)
                    220:         {
                    221:             /* 2XX */
                    222: 
                    223:             if (status == NGX_HTTP_NO_CONTENT) {
                    224:                 r->header_only = 1;
                    225:                 ngx_str_null(&r->headers_out.content_type);
                    226:                 r->headers_out.last_modified_time = -1;
                    227:                 r->headers_out.last_modified = NULL;
                    228:                 r->headers_out.content_length = NULL;
                    229:                 r->headers_out.content_length_n = -1;
                    230:             }
                    231: 
                    232:             status -= NGX_HTTP_OK;
                    233:             status_line = &ngx_http_status_lines[status];
                    234:             len += ngx_http_status_lines[status].len;
                    235: 
                    236:         } else if (status >= NGX_HTTP_MOVED_PERMANENTLY
                    237:                    && status < NGX_HTTP_LAST_3XX)
                    238:         {
                    239:             /* 3XX */
                    240: 
                    241:             if (status == NGX_HTTP_NOT_MODIFIED) {
                    242:                 r->header_only = 1;
                    243:             }
                    244: 
                    245:             status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;
                    246:             status_line = &ngx_http_status_lines[status];
                    247:             len += ngx_http_status_lines[status].len;
                    248: 
                    249:         } else if (status >= NGX_HTTP_BAD_REQUEST
                    250:                    && status < NGX_HTTP_LAST_4XX)
                    251:         {
                    252:             /* 4XX */
                    253:             status = status - NGX_HTTP_BAD_REQUEST
                    254:                             + NGX_HTTP_OFF_4XX;
                    255: 
                    256:             status_line = &ngx_http_status_lines[status];
                    257:             len += ngx_http_status_lines[status].len;
                    258: 
                    259:         } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR
                    260:                    && status < NGX_HTTP_LAST_5XX)
                    261:         {
                    262:             /* 5XX */
                    263:             status = status - NGX_HTTP_INTERNAL_SERVER_ERROR
                    264:                             + NGX_HTTP_OFF_5XX;
                    265: 
                    266:             status_line = &ngx_http_status_lines[status];
                    267:             len += ngx_http_status_lines[status].len;
                    268: 
                    269:         } else {
                    270:             len += NGX_INT_T_LEN;
                    271:             status_line = NULL;
                    272:         }
                    273:     }
                    274: 
                    275:     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
                    276: 
                    277:     if (r->headers_out.server == NULL) {
                    278:         len += clcf->server_tokens ? sizeof(ngx_http_server_full_string) - 1:
                    279:                                      sizeof(ngx_http_server_string) - 1;
                    280:     }
                    281: 
                    282:     if (r->headers_out.date == NULL) {
                    283:         len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
                    284:     }
                    285: 
                    286:     if (r->headers_out.content_type.len) {
                    287:         len += sizeof("Content-Type: ") - 1
                    288:                + r->headers_out.content_type.len + 2;
                    289: 
                    290:         if (r->headers_out.content_type_len == r->headers_out.content_type.len
                    291:             && r->headers_out.charset.len)
                    292:         {
                    293:             len += sizeof("; charset=") - 1 + r->headers_out.charset.len;
                    294:         }
                    295:     }
                    296: 
                    297:     if (r->headers_out.content_length == NULL
                    298:         && r->headers_out.content_length_n >= 0)
                    299:     {
                    300:         len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2;
                    301:     }
                    302: 
                    303:     if (r->headers_out.last_modified == NULL
                    304:         && r->headers_out.last_modified_time != -1)
                    305:     {
                    306:         len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
                    307:     }
                    308: 
                    309:     c = r->connection;
                    310: 
                    311:     if (r->headers_out.location
                    312:         && r->headers_out.location->value.len
                    313:         && r->headers_out.location->value.data[0] == '/')
                    314:     {
                    315:         r->headers_out.location->hash = 0;
                    316: 
                    317:         if (clcf->server_name_in_redirect) {
                    318:             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
                    319:             host = cscf->server_name;
                    320: 
                    321:         } else if (r->headers_in.server.len) {
                    322:             host = r->headers_in.server;
                    323: 
                    324:         } else {
                    325:             host.len = NGX_SOCKADDR_STRLEN;
                    326:             host.data = addr;
                    327: 
                    328:             if (ngx_connection_local_sockaddr(c, &host, 0) != NGX_OK) {
                    329:                 return NGX_ERROR;
                    330:             }
                    331:         }
                    332: 
                    333:         switch (c->local_sockaddr->sa_family) {
                    334: 
                    335: #if (NGX_HAVE_INET6)
                    336:         case AF_INET6:
                    337:             sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
                    338:             port = ntohs(sin6->sin6_port);
                    339:             break;
                    340: #endif
                    341: #if (NGX_HAVE_UNIX_DOMAIN)
                    342:         case AF_UNIX:
                    343:             port = 0;
                    344:             break;
                    345: #endif
                    346:         default: /* AF_INET */
                    347:             sin = (struct sockaddr_in *) c->local_sockaddr;
                    348:             port = ntohs(sin->sin_port);
                    349:             break;
                    350:         }
                    351: 
                    352:         len += sizeof("Location: https://") - 1
                    353:                + host.len
                    354:                + r->headers_out.location->value.len + 2;
                    355: 
                    356:         if (clcf->port_in_redirect) {
                    357: 
                    358: #if (NGX_HTTP_SSL)
                    359:             if (c->ssl)
                    360:                 port = (port == 443) ? 0 : port;
                    361:             else
                    362: #endif
                    363:                 port = (port == 80) ? 0 : port;
                    364: 
                    365:         } else {
                    366:             port = 0;
                    367:         }
                    368: 
                    369:         if (port) {
                    370:             len += sizeof(":65535") - 1;
                    371:         }
                    372: 
                    373:     } else {
                    374:         ngx_str_null(&host);
                    375:         port = 0;
                    376:     }
                    377: 
                    378:     if (r->chunked) {
                    379:         len += sizeof("Transfer-Encoding: chunked" CRLF) - 1;
                    380:     }
                    381: 
                    382:     if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
                    383:         len += sizeof("Connection: upgrade" CRLF) - 1;
                    384: 
                    385:     } else if (r->keepalive) {
                    386:         len += sizeof("Connection: keep-alive" CRLF) - 1;
                    387: 
                    388:         /*
                    389:          * MSIE and Opera ignore the "Keep-Alive: timeout=<N>" header.
                    390:          * MSIE keeps the connection alive for about 60-65 seconds.
                    391:          * Opera keeps the connection alive very long.
                    392:          * Mozilla keeps the connection alive for N plus about 1-10 seconds.
                    393:          * Konqueror keeps the connection alive for about N seconds.
                    394:          */
                    395: 
                    396:         if (clcf->keepalive_header) {
                    397:             len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2;
                    398:         }
                    399: 
                    400:     } else {
                    401:         len += sizeof("Connection: close" CRLF) - 1;
                    402:     }
                    403: 
                    404: #if (NGX_HTTP_GZIP)
                    405:     if (r->gzip_vary) {
                    406:         if (clcf->gzip_vary) {
                    407:             len += sizeof("Vary: Accept-Encoding" CRLF) - 1;
                    408: 
                    409:         } else {
                    410:             r->gzip_vary = 0;
                    411:         }
                    412:     }
                    413: #endif
                    414: 
                    415:     part = &r->headers_out.headers.part;
                    416:     header = part->elts;
                    417: 
                    418:     for (i = 0; /* void */; i++) {
                    419: 
                    420:         if (i >= part->nelts) {
                    421:             if (part->next == NULL) {
                    422:                 break;
                    423:             }
                    424: 
                    425:             part = part->next;
                    426:             header = part->elts;
                    427:             i = 0;
                    428:         }
                    429: 
                    430:         if (header[i].hash == 0) {
                    431:             continue;
                    432:         }
                    433: 
                    434:         len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len
                    435:                + sizeof(CRLF) - 1;
                    436:     }
                    437: 
                    438:     b = ngx_create_temp_buf(r->pool, len);
                    439:     if (b == NULL) {
                    440:         return NGX_ERROR;
                    441:     }
                    442: 
                    443:     /* "HTTP/1.x " */
                    444:     b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1);
                    445: 
                    446:     /* status line */
                    447:     if (status_line) {
                    448:         b->last = ngx_copy(b->last, status_line->data, status_line->len);
                    449: 
                    450:     } else {
                    451:         b->last = ngx_sprintf(b->last, "%03ui", status);
                    452:     }
                    453:     *b->last++ = CR; *b->last++ = LF;
                    454: 
                    455:     if (r->headers_out.server == NULL) {
                    456:         if (clcf->server_tokens) {
                    457:             p = (u_char *) ngx_http_server_full_string;
                    458:             len = sizeof(ngx_http_server_full_string) - 1;
                    459: 
                    460:         } else {
                    461:             p = (u_char *) ngx_http_server_string;
                    462:             len = sizeof(ngx_http_server_string) - 1;
                    463:         }
                    464: 
                    465:         b->last = ngx_cpymem(b->last, p, len);
                    466:     }
                    467: 
                    468:     if (r->headers_out.date == NULL) {
                    469:         b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1);
                    470:         b->last = ngx_cpymem(b->last, ngx_cached_http_time.data,
                    471:                              ngx_cached_http_time.len);
                    472: 
                    473:         *b->last++ = CR; *b->last++ = LF;
                    474:     }
                    475: 
                    476:     if (r->headers_out.content_type.len) {
                    477:         b->last = ngx_cpymem(b->last, "Content-Type: ",
                    478:                              sizeof("Content-Type: ") - 1);
                    479:         p = b->last;
                    480:         b->last = ngx_copy(b->last, r->headers_out.content_type.data,
                    481:                            r->headers_out.content_type.len);
                    482: 
                    483:         if (r->headers_out.content_type_len == r->headers_out.content_type.len
                    484:             && r->headers_out.charset.len)
                    485:         {
                    486:             b->last = ngx_cpymem(b->last, "; charset=",
                    487:                                  sizeof("; charset=") - 1);
                    488:             b->last = ngx_copy(b->last, r->headers_out.charset.data,
                    489:                                r->headers_out.charset.len);
                    490: 
                    491:             /* update r->headers_out.content_type for possible logging */
                    492: 
                    493:             r->headers_out.content_type.len = b->last - p;
                    494:             r->headers_out.content_type.data = p;
                    495:         }
                    496: 
                    497:         *b->last++ = CR; *b->last++ = LF;
                    498:     }
                    499: 
                    500:     if (r->headers_out.content_length == NULL
                    501:         && r->headers_out.content_length_n >= 0)
                    502:     {
                    503:         b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF,
                    504:                               r->headers_out.content_length_n);
                    505:     }
                    506: 
                    507:     if (r->headers_out.last_modified == NULL
                    508:         && r->headers_out.last_modified_time != -1)
                    509:     {
                    510:         b->last = ngx_cpymem(b->last, "Last-Modified: ",
                    511:                              sizeof("Last-Modified: ") - 1);
                    512:         b->last = ngx_http_time(b->last, r->headers_out.last_modified_time);
                    513: 
                    514:         *b->last++ = CR; *b->last++ = LF;
                    515:     }
                    516: 
                    517:     if (host.data) {
                    518: 
                    519:         p = b->last + sizeof("Location: ") - 1;
                    520: 
                    521:         b->last = ngx_cpymem(b->last, "Location: http",
                    522:                              sizeof("Location: http") - 1);
                    523: 
                    524: #if (NGX_HTTP_SSL)
                    525:         if (c->ssl) {
                    526:             *b->last++ ='s';
                    527:         }
                    528: #endif
                    529: 
                    530:         *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/';
                    531:         b->last = ngx_copy(b->last, host.data, host.len);
                    532: 
                    533:         if (port) {
                    534:             b->last = ngx_sprintf(b->last, ":%ui", port);
                    535:         }
                    536: 
                    537:         b->last = ngx_copy(b->last, r->headers_out.location->value.data,
                    538:                            r->headers_out.location->value.len);
                    539: 
                    540:         /* update r->headers_out.location->value for possible logging */
                    541: 
                    542:         r->headers_out.location->value.len = b->last - p;
                    543:         r->headers_out.location->value.data = p;
                    544:         ngx_str_set(&r->headers_out.location->key, "Location");
                    545: 
                    546:         *b->last++ = CR; *b->last++ = LF;
                    547:     }
                    548: 
                    549:     if (r->chunked) {
                    550:         b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF,
                    551:                              sizeof("Transfer-Encoding: chunked" CRLF) - 1);
                    552:     }
                    553: 
                    554:     if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) {
                    555:         b->last = ngx_cpymem(b->last, "Connection: upgrade" CRLF,
                    556:                              sizeof("Connection: upgrade" CRLF) - 1);
                    557: 
                    558:     } else if (r->keepalive) {
                    559:         b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF,
                    560:                              sizeof("Connection: keep-alive" CRLF) - 1);
                    561: 
                    562:         if (clcf->keepalive_header) {
                    563:             b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF,
                    564:                                   clcf->keepalive_header);
                    565:         }
                    566: 
                    567:     } else {
                    568:         b->last = ngx_cpymem(b->last, "Connection: close" CRLF,
                    569:                              sizeof("Connection: close" CRLF) - 1);
                    570:     }
                    571: 
                    572: #if (NGX_HTTP_GZIP)
                    573:     if (r->gzip_vary) {
                    574:         b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF,
                    575:                              sizeof("Vary: Accept-Encoding" CRLF) - 1);
                    576:     }
                    577: #endif
                    578: 
                    579:     part = &r->headers_out.headers.part;
                    580:     header = part->elts;
                    581: 
                    582:     for (i = 0; /* void */; i++) {
                    583: 
                    584:         if (i >= part->nelts) {
                    585:             if (part->next == NULL) {
                    586:                 break;
                    587:             }
                    588: 
                    589:             part = part->next;
                    590:             header = part->elts;
                    591:             i = 0;
                    592:         }
                    593: 
                    594:         if (header[i].hash == 0) {
                    595:             continue;
                    596:         }
                    597: 
                    598:         b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len);
                    599:         *b->last++ = ':'; *b->last++ = ' ';
                    600: 
                    601:         b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len);
                    602:         *b->last++ = CR; *b->last++ = LF;
                    603:     }
                    604: 
                    605:     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    606:                    "%*s", (size_t) (b->last - b->pos), b->pos);
                    607: 
                    608:     /* the end of HTTP header */
                    609:     *b->last++ = CR; *b->last++ = LF;
                    610: 
                    611:     r->header_size = b->last - b->pos;
                    612: 
                    613:     if (r->header_only) {
                    614:         b->last_buf = 1;
                    615:     }
                    616: 
                    617:     out.buf = b;
                    618:     out.next = NULL;
                    619: 
                    620:     return ngx_http_write_filter(r, &out);
                    621: }
                    622: 
                    623: 
                    624: static ngx_int_t
                    625: ngx_http_header_filter_init(ngx_conf_t *cf)
                    626: {
                    627:     ngx_http_top_header_filter = ngx_http_header_filter;
                    628: 
                    629:     return NGX_OK;
                    630: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>