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_send_error_page(ngx_http_request_t *r,
15     ngx_http_err_page_t *err_page);
16 static ngx_int_t ngx_http_send_special_response(ngx_http_request_t *r,
17     ngx_http_core_loc_conf_t *clcf, ngx_uint_t err);
18 static ngx_int_t ngx_http_send_refresh(ngx_http_request_t *r);
19 
20 
21 static u_char ngx_http_error_full_tail[] =
22 "<hr><center>" NGINX_VER "</center>" CRLF
23 "</body>" CRLF
24 "</html>" CRLF
25 ;
26 
27 
28 static u_char ngx_http_error_build_tail[] =
29 "<hr><center>" NGINX_VER_BUILD "</center>" CRLF
30 "</body>" CRLF
31 "</html>" CRLF
32 ;
33 
34 
35 static u_char ngx_http_error_tail[] =
36 "<hr><center>nginx</center>" CRLF
37 "</body>" CRLF
38 "</html>" CRLF
39 ;
40 
41 
42 static u_char ngx_http_msie_padding[] =
43 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
44 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
45 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
46 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
47 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
48 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
49 ;
50 
51 
52 static u_char ngx_http_msie_refresh_head[] =
53 "<html><head><meta http-equiv=\"Refresh\" content=\"0; URL=";
54 
55 
56 static u_char ngx_http_msie_refresh_tail[] =
57 "\"></head><body></body></html>" CRLF;
58 
59 
60 static char ngx_http_error_301_page[] =
61 "<html>" CRLF
62 "<head><title>301 Moved Permanently</title></head>" CRLF
63 "<body>" CRLF
64 "<center><h1>301 Moved Permanently</h1></center>" CRLF
65 ;
66 
67 
68 static char ngx_http_error_302_page[] =
69 "<html>" CRLF
70 "<head><title>302 Found</title></head>" CRLF
71 "<body>" CRLF
72 "<center><h1>302 Found</h1></center>" CRLF
73 ;
74 
75 
76 static char ngx_http_error_303_page[] =
77 "<html>" CRLF
78 "<head><title>303 See Other</title></head>" CRLF
79 "<body>" CRLF
80 "<center><h1>303 See Other</h1></center>" CRLF
81 ;
82 
83 
84 static char ngx_http_error_307_page[] =
85 "<html>" CRLF
86 "<head><title>307 Temporary Redirect</title></head>" CRLF
87 "<body>" CRLF
88 "<center><h1>307 Temporary Redirect</h1></center>" CRLF
89 ;
90 
91 
92 static char ngx_http_error_308_page[] =
93 "<html>" CRLF
94 "<head><title>308 Permanent Redirect</title></head>" CRLF
95 "<body>" CRLF
96 "<center><h1>308 Permanent Redirect</h1></center>" CRLF
97 ;
98 
99 
100 static char ngx_http_error_400_page[] =
101 "<html>" CRLF
102 "<head><title>400 Bad Request</title></head>" CRLF
103 "<body>" CRLF
104 "<center><h1>400 Bad Request</h1></center>" CRLF
105 ;
106 
107 
108 static char ngx_http_error_401_page[] =
109 "<html>" CRLF
110 "<head><title>401 Authorization Required</title></head>" CRLF
111 "<body>" CRLF
112 "<center><h1>401 Authorization Required</h1></center>" CRLF
113 ;
114 
115 
116 static char ngx_http_error_402_page[] =
117 "<html>" CRLF
118 "<head><title>402 Payment Required</title></head>" CRLF
119 "<body>" CRLF
120 "<center><h1>402 Payment Required</h1></center>" CRLF
121 ;
122 
123 
124 static char ngx_http_error_403_page[] =
125 "<html>" CRLF
126 "<head><title>403 Forbidden</title></head>" CRLF
127 "<body>" CRLF
128 "<center><h1>403 Forbidden</h1></center>" CRLF
129 ;
130 
131 
132 static char ngx_http_error_404_page[] =
133 "<html>" CRLF
134 "<head><title>404 Not Found</title></head>" CRLF
135 "<body>" CRLF
136 "<center><h1>404 Not Found</h1></center>" CRLF
137 ;
138 
139 
140 static char ngx_http_error_405_page[] =
141 "<html>" CRLF
142 "<head><title>405 Not Allowed</title></head>" CRLF
143 "<body>" CRLF
144 "<center><h1>405 Not Allowed</h1></center>" CRLF
145 ;
146 
147 
148 static char ngx_http_error_406_page[] =
149 "<html>" CRLF
150 "<head><title>406 Not Acceptable</title></head>" CRLF
151 "<body>" CRLF
152 "<center><h1>406 Not Acceptable</h1></center>" CRLF
153 ;
154 
155 
156 static char ngx_http_error_408_page[] =
157 "<html>" CRLF
158 "<head><title>408 Request Time-out</title></head>" CRLF
159 "<body>" CRLF
160 "<center><h1>408 Request Time-out</h1></center>" CRLF
161 ;
162 
163 
164 static char ngx_http_error_409_page[] =
165 "<html>" CRLF
166 "<head><title>409 Conflict</title></head>" CRLF
167 "<body>" CRLF
168 "<center><h1>409 Conflict</h1></center>" CRLF
169 ;
170 
171 
172 static char ngx_http_error_410_page[] =
173 "<html>" CRLF
174 "<head><title>410 Gone</title></head>" CRLF
175 "<body>" CRLF
176 "<center><h1>410 Gone</h1></center>" CRLF
177 ;
178 
179 
180 static char ngx_http_error_411_page[] =
181 "<html>" CRLF
182 "<head><title>411 Length Required</title></head>" CRLF
183 "<body>" CRLF
184 "<center><h1>411 Length Required</h1></center>" CRLF
185 ;
186 
187 
188 static char ngx_http_error_412_page[] =
189 "<html>" CRLF
190 "<head><title>412 Precondition Failed</title></head>" CRLF
191 "<body>" CRLF
192 "<center><h1>412 Precondition Failed</h1></center>" CRLF
193 ;
194 
195 
196 static char ngx_http_error_413_page[] =
197 "<html>" CRLF
198 "<head><title>413 Request Entity Too Large</title></head>" CRLF
199 "<body>" CRLF
200 "<center><h1>413 Request Entity Too Large</h1></center>" CRLF
201 ;
202 
203 
204 static char ngx_http_error_414_page[] =
205 "<html>" CRLF
206 "<head><title>414 Request-URI Too Large</title></head>" CRLF
207 "<body>" CRLF
208 "<center><h1>414 Request-URI Too Large</h1></center>" CRLF
209 ;
210 
211 
212 static char ngx_http_error_415_page[] =
213 "<html>" CRLF
214 "<head><title>415 Unsupported Media Type</title></head>" CRLF
215 "<body>" CRLF
216 "<center><h1>415 Unsupported Media Type</h1></center>" CRLF
217 ;
218 
219 
220 static char ngx_http_error_416_page[] =
221 "<html>" CRLF
222 "<head><title>416 Requested Range Not Satisfiable</title></head>" CRLF
223 "<body>" CRLF
224 "<center><h1>416 Requested Range Not Satisfiable</h1></center>" CRLF
225 ;
226 
227 
228 static char ngx_http_error_421_page[] =
229 "<html>" CRLF
230 "<head><title>421 Misdirected Request</title></head>" CRLF
231 "<body>" CRLF
232 "<center><h1>421 Misdirected Request</h1></center>" CRLF
233 ;
234 
235 
236 static char ngx_http_error_429_page[] =
237 "<html>" CRLF
238 "<head><title>429 Too Many Requests</title></head>" CRLF
239 "<body>" CRLF
240 "<center><h1>429 Too Many Requests</h1></center>" CRLF
241 ;
242 
243 
244 static char ngx_http_error_494_page[] =
245 "<html>" CRLF
246 "<head><title>400 Request Header Or Cookie Too Large</title></head>"
247 CRLF
248 "<body>" CRLF
249 "<center><h1>400 Bad Request</h1></center>" CRLF
250 "<center>Request Header Or Cookie Too Large</center>" CRLF
251 ;
252 
253 
254 static char ngx_http_error_495_page[] =
255 "<html>" CRLF
256 "<head><title>400 The SSL certificate error</title></head>"
257 CRLF
258 "<body>" CRLF
259 "<center><h1>400 Bad Request</h1></center>" CRLF
260 "<center>The SSL certificate error</center>" CRLF
261 ;
262 
263 
264 static char ngx_http_error_496_page[] =
265 "<html>" CRLF
266 "<head><title>400 No required SSL certificate was sent</title></head>"
267 CRLF
268 "<body>" CRLF
269 "<center><h1>400 Bad Request</h1></center>" CRLF
270 "<center>No required SSL certificate was sent</center>" CRLF
271 ;
272 
273 
274 static char ngx_http_error_497_page[] =
275 "<html>" CRLF
276 "<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>"
277 CRLF
278 "<body>" CRLF
279 "<center><h1>400 Bad Request</h1></center>" CRLF
280 "<center>The plain HTTP request was sent to HTTPS port</center>" CRLF
281 ;
282 
283 
284 static char ngx_http_error_500_page[] =
285 "<html>" CRLF
286 "<head><title>500 Internal Server Error</title></head>" CRLF
287 "<body>" CRLF
288 "<center><h1>500 Internal Server Error</h1></center>" CRLF
289 ;
290 
291 
292 static char ngx_http_error_501_page[] =
293 "<html>" CRLF
294 "<head><title>501 Not Implemented</title></head>" CRLF
295 "<body>" CRLF
296 "<center><h1>501 Not Implemented</h1></center>" CRLF
297 ;
298 
299 
300 static char ngx_http_error_502_page[] =
301 "<html>" CRLF
302 "<head><title>502 Bad Gateway</title></head>" CRLF
303 "<body>" CRLF
304 "<center><h1>502 Bad Gateway</h1></center>" CRLF
305 ;
306 
307 
308 static char ngx_http_error_503_page[] =
309 "<html>" CRLF
310 "<head><title>503 Service Temporarily Unavailable</title></head>" CRLF
311 "<body>" CRLF
312 "<center><h1>503 Service Temporarily Unavailable</h1></center>" CRLF
313 ;
314 
315 
316 static char ngx_http_error_504_page[] =
317 "<html>" CRLF
318 "<head><title>504 Gateway Time-out</title></head>" CRLF
319 "<body>" CRLF
320 "<center><h1>504 Gateway Time-out</h1></center>" CRLF
321 ;
322 
323 
324 static char ngx_http_error_505_page[] =
325 "<html>" CRLF
326 "<head><title>505 HTTP Version Not Supported</title></head>" CRLF
327 "<body>" CRLF
328 "<center><h1>505 HTTP Version Not Supported</h1></center>" CRLF
329 ;
330 
331 
332 static char ngx_http_error_507_page[] =
333 "<html>" CRLF
334 "<head><title>507 Insufficient Storage</title></head>" CRLF
335 "<body>" CRLF
336 "<center><h1>507 Insufficient Storage</h1></center>" CRLF
337 ;
338 
339 
340 static ngx_str_t ngx_http_error_pages[] = {
341 
342     ngx_null_string,                     /* 201, 204 */
343 
344 #define NGX_HTTP_LAST_2XX  202
345 #define NGX_HTTP_OFF_3XX   (NGX_HTTP_LAST_2XX - 201)
346 
347     /* ngx_null_string, */               /* 300 */
348     ngx_string(ngx_http_error_301_page),
349     ngx_string(ngx_http_error_302_page),
350     ngx_string(ngx_http_error_303_page),
351     ngx_null_string,                     /* 304 */
352     ngx_null_string,                     /* 305 */
353     ngx_null_string,                     /* 306 */
354     ngx_string(ngx_http_error_307_page),
355     ngx_string(ngx_http_error_308_page),
356 
357 #define NGX_HTTP_LAST_3XX  309
358 #define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)
359 
360     ngx_string(ngx_http_error_400_page),
361     ngx_string(ngx_http_error_401_page),
362     ngx_string(ngx_http_error_402_page),
363     ngx_string(ngx_http_error_403_page),
364     ngx_string(ngx_http_error_404_page),
365     ngx_string(ngx_http_error_405_page),
366     ngx_string(ngx_http_error_406_page),
367     ngx_null_string,                     /* 407 */
368     ngx_string(ngx_http_error_408_page),
369     ngx_string(ngx_http_error_409_page),
370     ngx_string(ngx_http_error_410_page),
371     ngx_string(ngx_http_error_411_page),
372     ngx_string(ngx_http_error_412_page),
373     ngx_string(ngx_http_error_413_page),
374     ngx_string(ngx_http_error_414_page),
375     ngx_string(ngx_http_error_415_page),
376     ngx_string(ngx_http_error_416_page),
377     ngx_null_string,                     /* 417 */
378     ngx_null_string,                     /* 418 */
379     ngx_null_string,                     /* 419 */
380     ngx_null_string,                     /* 420 */
381     ngx_string(ngx_http_error_421_page),
382     ngx_null_string,                     /* 422 */
383     ngx_null_string,                     /* 423 */
384     ngx_null_string,                     /* 424 */
385     ngx_null_string,                     /* 425 */
386     ngx_null_string,                     /* 426 */
387     ngx_null_string,                     /* 427 */
388     ngx_null_string,                     /* 428 */
389     ngx_string(ngx_http_error_429_page),
390 
391 #define NGX_HTTP_LAST_4XX  430
392 #define NGX_HTTP_OFF_5XX   (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)
393 
394     ngx_string(ngx_http_error_494_page), /* 494, request header too large */
395     ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
396     ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
397     ngx_string(ngx_http_error_497_page), /* 497, http to https */
398     ngx_string(ngx_http_error_404_page), /* 498, canceled */
399     ngx_null_string,                     /* 499, client has closed connection */
400 
401     ngx_string(ngx_http_error_500_page),
402     ngx_string(ngx_http_error_501_page),
403     ngx_string(ngx_http_error_502_page),
404     ngx_string(ngx_http_error_503_page),
405     ngx_string(ngx_http_error_504_page),
406     ngx_string(ngx_http_error_505_page),
407     ngx_null_string,                     /* 506 */
408     ngx_string(ngx_http_error_507_page)
409 
410 #define NGX_HTTP_LAST_5XX  508
411 
412 };
413 
414 
415 ngx_int_t
ngx_http_special_response_handler(ngx_http_request_t * r,ngx_int_t error)416 ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
417 {
418     ngx_uint_t                 i, err;
419     ngx_http_err_page_t       *err_page;
420     ngx_http_core_loc_conf_t  *clcf;
421 
422     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
423                    "http special response: %i, \"%V?%V\"",
424                    error, &r->uri, &r->args);
425 
426     r->err_status = error;
427 
428     if (r->keepalive) {
429         switch (error) {
430             case NGX_HTTP_BAD_REQUEST:
431             case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE:
432             case NGX_HTTP_REQUEST_URI_TOO_LARGE:
433             case NGX_HTTP_TO_HTTPS:
434             case NGX_HTTPS_CERT_ERROR:
435             case NGX_HTTPS_NO_CERT:
436             case NGX_HTTP_INTERNAL_SERVER_ERROR:
437             case NGX_HTTP_NOT_IMPLEMENTED:
438                 r->keepalive = 0;
439         }
440     }
441 
442     if (r->lingering_close) {
443         switch (error) {
444             case NGX_HTTP_BAD_REQUEST:
445             case NGX_HTTP_TO_HTTPS:
446             case NGX_HTTPS_CERT_ERROR:
447             case NGX_HTTPS_NO_CERT:
448                 r->lingering_close = 0;
449         }
450     }
451 
452     r->headers_out.content_type.len = 0;
453 
454     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
455 
456     if (!r->error_page && clcf->error_pages && r->uri_changes != 0) {
457 
458         if (clcf->recursive_error_pages == 0) {
459             r->error_page = 1;
460         }
461 
462         err_page = clcf->error_pages->elts;
463 
464         for (i = 0; i < clcf->error_pages->nelts; i++) {
465             if (err_page[i].status == error) {
466                 return ngx_http_send_error_page(r, &err_page[i]);
467             }
468         }
469     }
470 
471     r->expect_tested = 1;
472 
473     if (ngx_http_discard_request_body(r) != NGX_OK) {
474         r->keepalive = 0;
475     }
476 
477     if (clcf->msie_refresh
478         && r->headers_in.msie
479         && (error == NGX_HTTP_MOVED_PERMANENTLY
480             || error == NGX_HTTP_MOVED_TEMPORARILY))
481     {
482         return ngx_http_send_refresh(r);
483     }
484 
485     if (error == NGX_HTTP_CREATED) {
486         /* 201 */
487         err = 0;
488 
489     } else if (error == NGX_HTTP_NO_CONTENT) {
490         /* 204 */
491         err = 0;
492 
493     } else if (error >= NGX_HTTP_MOVED_PERMANENTLY
494                && error < NGX_HTTP_LAST_3XX)
495     {
496         /* 3XX */
497         err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;
498 
499     } else if (error >= NGX_HTTP_BAD_REQUEST
500                && error < NGX_HTTP_LAST_4XX)
501     {
502         /* 4XX */
503         err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX;
504 
505     } else if (error >= NGX_HTTP_NGINX_CODES
506                && error < NGX_HTTP_LAST_5XX)
507     {
508         /* 49X, 5XX */
509         err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_OFF_5XX;
510         switch (error) {
511             case NGX_HTTP_TO_HTTPS:
512             case NGX_HTTPS_CERT_ERROR:
513             case NGX_HTTPS_NO_CERT:
514             case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:
515                 r->err_status = NGX_HTTP_BAD_REQUEST;
516         }
517 
518     } else {
519         /* unknown code, zero body */
520         err = 0;
521     }
522 
523     return ngx_http_send_special_response(r, clcf, err);
524 }
525 
526 
527 ngx_int_t
ngx_http_filter_finalize_request(ngx_http_request_t * r,ngx_module_t * m,ngx_int_t error)528 ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_module_t *m,
529     ngx_int_t error)
530 {
531     void       *ctx;
532     ngx_int_t   rc;
533 
534     ngx_http_clean_header(r);
535 
536     ctx = NULL;
537 
538     if (m) {
539         ctx = r->ctx[m->ctx_index];
540     }
541 
542     /* clear the modules contexts */
543     ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
544 
545     if (m) {
546         r->ctx[m->ctx_index] = ctx;
547     }
548 
549     r->filter_finalize = 1;
550 
551     rc = ngx_http_special_response_handler(r, error);
552 
553     /* NGX_ERROR resets any pending data */
554 
555     switch (rc) {
556 
557     case NGX_OK:
558     case NGX_DONE:
559         return NGX_ERROR;
560 
561     default:
562         return rc;
563     }
564 }
565 
566 
567 void
ngx_http_clean_header(ngx_http_request_t * r)568 ngx_http_clean_header(ngx_http_request_t *r)
569 {
570     ngx_memzero(&r->headers_out.status,
571                 sizeof(ngx_http_headers_out_t)
572                     - offsetof(ngx_http_headers_out_t, status));
573 
574     r->headers_out.headers.part.nelts = 0;
575     r->headers_out.headers.part.next = NULL;
576     r->headers_out.headers.last = &r->headers_out.headers.part;
577 
578     r->headers_out.trailers.part.nelts = 0;
579     r->headers_out.trailers.part.next = NULL;
580     r->headers_out.trailers.last = &r->headers_out.trailers.part;
581 
582     r->headers_out.content_length_n = -1;
583     r->headers_out.last_modified_time = -1;
584 }
585 
586 
587 static ngx_int_t
ngx_http_send_error_page(ngx_http_request_t * r,ngx_http_err_page_t * err_page)588 ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
589 {
590     ngx_int_t                  overwrite;
591     ngx_str_t                  uri, args;
592     ngx_table_elt_t           *location;
593     ngx_http_core_loc_conf_t  *clcf;
594 
595     overwrite = err_page->overwrite;
596 
597     if (overwrite && overwrite != NGX_HTTP_OK) {
598         r->expect_tested = 1;
599     }
600 
601     if (overwrite >= 0) {
602         r->err_status = overwrite;
603     }
604 
605     if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {
606         return NGX_ERROR;
607     }
608 
609     if (uri.len && uri.data[0] == '/') {
610 
611         if (err_page->value.lengths) {
612             ngx_http_split_args(r, &uri, &args);
613 
614         } else {
615             args = err_page->args;
616         }
617 
618         if (r->method != NGX_HTTP_HEAD) {
619             r->method = NGX_HTTP_GET;
620             r->method_name = ngx_http_core_get_method;
621         }
622 
623         return ngx_http_internal_redirect(r, &uri, &args);
624     }
625 
626     if (uri.len && uri.data[0] == '@') {
627         return ngx_http_named_location(r, &uri);
628     }
629 
630     r->expect_tested = 1;
631 
632     if (ngx_http_discard_request_body(r) != NGX_OK) {
633         r->keepalive = 0;
634     }
635 
636     location = ngx_list_push(&r->headers_out.headers);
637 
638     if (location == NULL) {
639         return NGX_ERROR;
640     }
641 
642     if (overwrite != NGX_HTTP_MOVED_PERMANENTLY
643         && overwrite != NGX_HTTP_MOVED_TEMPORARILY
644         && overwrite != NGX_HTTP_SEE_OTHER
645         && overwrite != NGX_HTTP_TEMPORARY_REDIRECT
646         && overwrite != NGX_HTTP_PERMANENT_REDIRECT)
647     {
648         r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
649     }
650 
651     location->hash = 1;
652     ngx_str_set(&location->key, "Location");
653     location->value = uri;
654 
655     ngx_http_clear_location(r);
656 
657     r->headers_out.location = location;
658 
659     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
660 
661     if (clcf->msie_refresh && r->headers_in.msie) {
662         return ngx_http_send_refresh(r);
663     }
664 
665     return ngx_http_send_special_response(r, clcf, r->err_status
666                                                    - NGX_HTTP_MOVED_PERMANENTLY
667                                                    + NGX_HTTP_OFF_3XX);
668 }
669 
670 
671 static ngx_int_t
ngx_http_send_special_response(ngx_http_request_t * r,ngx_http_core_loc_conf_t * clcf,ngx_uint_t err)672 ngx_http_send_special_response(ngx_http_request_t *r,
673     ngx_http_core_loc_conf_t *clcf, ngx_uint_t err)
674 {
675     u_char       *tail;
676     size_t        len;
677     ngx_int_t     rc;
678     ngx_buf_t    *b;
679     ngx_uint_t    msie_padding;
680     ngx_chain_t   out[3];
681 
682     if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
683         len = sizeof(ngx_http_error_full_tail) - 1;
684         tail = ngx_http_error_full_tail;
685 
686     } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
687         len = sizeof(ngx_http_error_build_tail) - 1;
688         tail = ngx_http_error_build_tail;
689 
690     } else {
691         len = sizeof(ngx_http_error_tail) - 1;
692         tail = ngx_http_error_tail;
693     }
694 
695     msie_padding = 0;
696 
697     if (ngx_http_error_pages[err].len) {
698         r->headers_out.content_length_n = ngx_http_error_pages[err].len + len;
699         if (clcf->msie_padding
700             && (r->headers_in.msie || r->headers_in.chrome)
701             && r->http_version >= NGX_HTTP_VERSION_10
702             && err >= NGX_HTTP_OFF_4XX)
703         {
704             r->headers_out.content_length_n +=
705                                          sizeof(ngx_http_msie_padding) - 1;
706             msie_padding = 1;
707         }
708 
709         r->headers_out.content_type_len = sizeof("text/html") - 1;
710         ngx_str_set(&r->headers_out.content_type, "text/html");
711         r->headers_out.content_type_lowcase = NULL;
712 
713     } else {
714         r->headers_out.content_length_n = 0;
715     }
716 
717     if (r->headers_out.content_length) {
718         r->headers_out.content_length->hash = 0;
719         r->headers_out.content_length = NULL;
720     }
721 
722     ngx_http_clear_accept_ranges(r);
723     ngx_http_clear_last_modified(r);
724     ngx_http_clear_etag(r);
725 
726     rc = ngx_http_send_header(r);
727 
728     if (rc == NGX_ERROR || r->header_only) {
729         return rc;
730     }
731 
732     if (ngx_http_error_pages[err].len == 0) {
733         return ngx_http_send_special(r, NGX_HTTP_LAST);
734     }
735 
736     b = ngx_calloc_buf(r->pool);
737     if (b == NULL) {
738         return NGX_ERROR;
739     }
740 
741     b->memory = 1;
742     b->pos = ngx_http_error_pages[err].data;
743     b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len;
744 
745     out[0].buf = b;
746     out[0].next = &out[1];
747 
748     b = ngx_calloc_buf(r->pool);
749     if (b == NULL) {
750         return NGX_ERROR;
751     }
752 
753     b->memory = 1;
754 
755     b->pos = tail;
756     b->last = tail + len;
757 
758     out[1].buf = b;
759     out[1].next = NULL;
760 
761     if (msie_padding) {
762         b = ngx_calloc_buf(r->pool);
763         if (b == NULL) {
764             return NGX_ERROR;
765         }
766 
767         b->memory = 1;
768         b->pos = ngx_http_msie_padding;
769         b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1;
770 
771         out[1].next = &out[2];
772         out[2].buf = b;
773         out[2].next = NULL;
774     }
775 
776     if (r == r->main) {
777         b->last_buf = 1;
778     }
779 
780     b->last_in_chain = 1;
781 
782     return ngx_http_output_filter(r, &out[0]);
783 }
784 
785 
786 static ngx_int_t
ngx_http_send_refresh(ngx_http_request_t * r)787 ngx_http_send_refresh(ngx_http_request_t *r)
788 {
789     u_char       *p, *location;
790     size_t        len, size;
791     uintptr_t     escape;
792     ngx_int_t     rc;
793     ngx_buf_t    *b;
794     ngx_chain_t   out;
795 
796     len = r->headers_out.location->value.len;
797     location = r->headers_out.location->value.data;
798 
799     escape = 2 * ngx_escape_uri(NULL, location, len, NGX_ESCAPE_REFRESH);
800 
801     size = sizeof(ngx_http_msie_refresh_head) - 1
802            + escape + len
803            + sizeof(ngx_http_msie_refresh_tail) - 1;
804 
805     r->err_status = NGX_HTTP_OK;
806 
807     r->headers_out.content_type_len = sizeof("text/html") - 1;
808     ngx_str_set(&r->headers_out.content_type, "text/html");
809     r->headers_out.content_type_lowcase = NULL;
810 
811     r->headers_out.location->hash = 0;
812     r->headers_out.location = NULL;
813 
814     r->headers_out.content_length_n = size;
815 
816     if (r->headers_out.content_length) {
817         r->headers_out.content_length->hash = 0;
818         r->headers_out.content_length = NULL;
819     }
820 
821     ngx_http_clear_accept_ranges(r);
822     ngx_http_clear_last_modified(r);
823     ngx_http_clear_etag(r);
824 
825     rc = ngx_http_send_header(r);
826 
827     if (rc == NGX_ERROR || r->header_only) {
828         return rc;
829     }
830 
831     b = ngx_create_temp_buf(r->pool, size);
832     if (b == NULL) {
833         return NGX_ERROR;
834     }
835 
836     p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head,
837                    sizeof(ngx_http_msie_refresh_head) - 1);
838 
839     if (escape == 0) {
840         p = ngx_cpymem(p, location, len);
841 
842     } else {
843         p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH);
844     }
845 
846     b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail,
847                          sizeof(ngx_http_msie_refresh_tail) - 1);
848 
849     b->last_buf = (r == r->main) ? 1 : 0;
850     b->last_in_chain = 1;
851 
852     out.buf = b;
853     out.next = NULL;
854 
855     return ngx_http_output_filter(r, &out);
856 }
857