3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
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
);
21 static u_char ngx_http_error_full_tail
[] =
22 "<hr><center>" NGINX_VER
"</center>" CRLF
28 static u_char ngx_http_error_tail
[] =
29 "<hr><center>nginx</center>" CRLF
35 static u_char ngx_http_msie_padding
[] =
36 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
37 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
38 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
39 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
40 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
41 "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
45 static u_char ngx_http_msie_refresh_head
[] =
46 "<html><head><meta http-equiv=\"Refresh\" content=\"0; URL=";
49 static u_char ngx_http_msie_refresh_tail
[] =
50 "\"></head><body></body></html>" CRLF
;
53 static char ngx_http_error_301_page
[] =
55 "<head><title>301 Moved Permanently</title></head>" CRLF
56 "<body bgcolor=\"white\">" CRLF
57 "<center><h1>301 Moved Permanently</h1></center>" CRLF
61 static char ngx_http_error_302_page
[] =
63 "<head><title>302 Found</title></head>" CRLF
64 "<body bgcolor=\"white\">" CRLF
65 "<center><h1>302 Found</h1></center>" CRLF
69 static char ngx_http_error_303_page
[] =
71 "<head><title>303 See Other</title></head>" CRLF
72 "<body bgcolor=\"white\">" CRLF
73 "<center><h1>303 See Other</h1></center>" CRLF
77 static char ngx_http_error_307_page
[] =
79 "<head><title>307 Temporary Redirect</title></head>" CRLF
80 "<body bgcolor=\"white\">" CRLF
81 "<center><h1>307 Temporary Redirect</h1></center>" CRLF
85 static char ngx_http_error_400_page
[] =
87 "<head><title>400 Bad Request</title></head>" CRLF
88 "<body bgcolor=\"white\">" CRLF
89 "<center><h1>400 Bad Request</h1></center>" CRLF
93 static char ngx_http_error_401_page
[] =
95 "<head><title>401 Authorization Required</title></head>" CRLF
96 "<body bgcolor=\"white\">" CRLF
97 "<center><h1>401 Authorization Required</h1></center>" CRLF
101 static char ngx_http_error_402_page
[] =
103 "<head><title>402 Payment Required</title></head>" CRLF
104 "<body bgcolor=\"white\">" CRLF
105 "<center><h1>402 Payment Required</h1></center>" CRLF
109 static char ngx_http_error_403_page
[] =
111 "<head><title>403 Forbidden</title></head>" CRLF
112 "<body bgcolor=\"white\">" CRLF
113 "<center><h1>403 Forbidden</h1></center>" CRLF
117 static char ngx_http_error_404_page
[] =
119 "<head><title>404 Not Found</title></head>" CRLF
120 "<body bgcolor=\"white\">" CRLF
121 "<center><h1>404 Not Found</h1></center>" CRLF
125 static char ngx_http_error_405_page
[] =
127 "<head><title>405 Not Allowed</title></head>" CRLF
128 "<body bgcolor=\"white\">" CRLF
129 "<center><h1>405 Not Allowed</h1></center>" CRLF
133 static char ngx_http_error_406_page
[] =
135 "<head><title>406 Not Acceptable</title></head>" CRLF
136 "<body bgcolor=\"white\">" CRLF
137 "<center><h1>406 Not Acceptable</h1></center>" CRLF
141 static char ngx_http_error_408_page
[] =
143 "<head><title>408 Request Time-out</title></head>" CRLF
144 "<body bgcolor=\"white\">" CRLF
145 "<center><h1>408 Request Time-out</h1></center>" CRLF
149 static char ngx_http_error_409_page
[] =
151 "<head><title>409 Conflict</title></head>" CRLF
152 "<body bgcolor=\"white\">" CRLF
153 "<center><h1>409 Conflict</h1></center>" CRLF
157 static char ngx_http_error_410_page
[] =
159 "<head><title>410 Gone</title></head>" CRLF
160 "<body bgcolor=\"white\">" CRLF
161 "<center><h1>410 Gone</h1></center>" CRLF
165 static char ngx_http_error_411_page
[] =
167 "<head><title>411 Length Required</title></head>" CRLF
168 "<body bgcolor=\"white\">" CRLF
169 "<center><h1>411 Length Required</h1></center>" CRLF
173 static char ngx_http_error_412_page
[] =
175 "<head><title>412 Precondition Failed</title></head>" CRLF
176 "<body bgcolor=\"white\">" CRLF
177 "<center><h1>412 Precondition Failed</h1></center>" CRLF
181 static char ngx_http_error_413_page
[] =
183 "<head><title>413 Request Entity Too Large</title></head>" CRLF
184 "<body bgcolor=\"white\">" CRLF
185 "<center><h1>413 Request Entity Too Large</h1></center>" CRLF
189 static char ngx_http_error_414_page
[] =
191 "<head><title>414 Request-URI Too Large</title></head>" CRLF
192 "<body bgcolor=\"white\">" CRLF
193 "<center><h1>414 Request-URI Too Large</h1></center>" CRLF
197 static char ngx_http_error_415_page
[] =
199 "<head><title>415 Unsupported Media Type</title></head>" CRLF
200 "<body bgcolor=\"white\">" CRLF
201 "<center><h1>415 Unsupported Media Type</h1></center>" CRLF
205 static char ngx_http_error_416_page
[] =
207 "<head><title>416 Requested Range Not Satisfiable</title></head>" CRLF
208 "<body bgcolor=\"white\">" CRLF
209 "<center><h1>416 Requested Range Not Satisfiable</h1></center>" CRLF
213 static char ngx_http_error_494_page
[] =
215 "<head><title>400 Request Header Or Cookie Too Large</title></head>"
217 "<body bgcolor=\"white\">" CRLF
218 "<center><h1>400 Bad Request</h1></center>" CRLF
219 "<center>Request Header Or Cookie Too Large</center>" CRLF
223 static char ngx_http_error_495_page
[] =
225 "<head><title>400 The SSL certificate error</title></head>"
227 "<body bgcolor=\"white\">" CRLF
228 "<center><h1>400 Bad Request</h1></center>" CRLF
229 "<center>The SSL certificate error</center>" CRLF
233 static char ngx_http_error_496_page
[] =
235 "<head><title>400 No required SSL certificate was sent</title></head>"
237 "<body bgcolor=\"white\">" CRLF
238 "<center><h1>400 Bad Request</h1></center>" CRLF
239 "<center>No required SSL certificate was sent</center>" CRLF
243 static char ngx_http_error_497_page
[] =
245 "<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>"
247 "<body bgcolor=\"white\">" CRLF
248 "<center><h1>400 Bad Request</h1></center>" CRLF
249 "<center>The plain HTTP request was sent to HTTPS port</center>" CRLF
253 static char ngx_http_error_500_page
[] =
255 "<head><title>500 Internal Server Error</title></head>" CRLF
256 "<body bgcolor=\"white\">" CRLF
257 "<center><h1>500 Internal Server Error</h1></center>" CRLF
261 static char ngx_http_error_501_page
[] =
263 "<head><title>501 Not Implemented</title></head>" CRLF
264 "<body bgcolor=\"white\">" CRLF
265 "<center><h1>501 Not Implemented</h1></center>" CRLF
269 static char ngx_http_error_502_page
[] =
271 "<head><title>502 Bad Gateway</title></head>" CRLF
272 "<body bgcolor=\"white\">" CRLF
273 "<center><h1>502 Bad Gateway</h1></center>" CRLF
277 static char ngx_http_error_503_page
[] =
279 "<head><title>503 Service Temporarily Unavailable</title></head>" CRLF
280 "<body bgcolor=\"white\">" CRLF
281 "<center><h1>503 Service Temporarily Unavailable</h1></center>" CRLF
285 static char ngx_http_error_504_page
[] =
287 "<head><title>504 Gateway Time-out</title></head>" CRLF
288 "<body bgcolor=\"white\">" CRLF
289 "<center><h1>504 Gateway Time-out</h1></center>" CRLF
293 static char ngx_http_error_507_page
[] =
295 "<head><title>507 Insufficient Storage</title></head>" CRLF
296 "<body bgcolor=\"white\">" CRLF
297 "<center><h1>507 Insufficient Storage</h1></center>" CRLF
301 static ngx_str_t ngx_http_error_pages
[] = {
303 ngx_null_string
, /* 201, 204 */
305 #define NGX_HTTP_LAST_2XX 202
306 #define NGX_HTTP_OFF_3XX (NGX_HTTP_LAST_2XX - 201)
308 /* ngx_null_string, */ /* 300 */
309 ngx_string(ngx_http_error_301_page
),
310 ngx_string(ngx_http_error_302_page
),
311 ngx_string(ngx_http_error_303_page
),
312 ngx_null_string
, /* 304 */
313 ngx_null_string
, /* 305 */
314 ngx_null_string
, /* 306 */
315 ngx_string(ngx_http_error_307_page
),
317 #define NGX_HTTP_LAST_3XX 308
318 #define NGX_HTTP_OFF_4XX (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)
320 ngx_string(ngx_http_error_400_page
),
321 ngx_string(ngx_http_error_401_page
),
322 ngx_string(ngx_http_error_402_page
),
323 ngx_string(ngx_http_error_403_page
),
324 ngx_string(ngx_http_error_404_page
),
325 ngx_string(ngx_http_error_405_page
),
326 ngx_string(ngx_http_error_406_page
),
327 ngx_null_string
, /* 407 */
328 ngx_string(ngx_http_error_408_page
),
329 ngx_string(ngx_http_error_409_page
),
330 ngx_string(ngx_http_error_410_page
),
331 ngx_string(ngx_http_error_411_page
),
332 ngx_string(ngx_http_error_412_page
),
333 ngx_string(ngx_http_error_413_page
),
334 ngx_string(ngx_http_error_414_page
),
335 ngx_string(ngx_http_error_415_page
),
336 ngx_string(ngx_http_error_416_page
),
338 #define NGX_HTTP_LAST_4XX 417
339 #define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)
341 ngx_string(ngx_http_error_494_page
), /* 494, request header too large */
342 ngx_string(ngx_http_error_495_page
), /* 495, https certificate error */
343 ngx_string(ngx_http_error_496_page
), /* 496, https no certificate */
344 ngx_string(ngx_http_error_497_page
), /* 497, http to https */
345 ngx_string(ngx_http_error_404_page
), /* 498, canceled */
346 ngx_null_string
, /* 499, client has closed connection */
348 ngx_string(ngx_http_error_500_page
),
349 ngx_string(ngx_http_error_501_page
),
350 ngx_string(ngx_http_error_502_page
),
351 ngx_string(ngx_http_error_503_page
),
352 ngx_string(ngx_http_error_504_page
),
353 ngx_null_string
, /* 505 */
354 ngx_null_string
, /* 506 */
355 ngx_string(ngx_http_error_507_page
)
357 #define NGX_HTTP_LAST_5XX 508
362 static ngx_str_t ngx_http_get_name
= { 3, (u_char
*) "GET " };
366 ngx_http_special_response_handler(ngx_http_request_t
*r
, ngx_int_t error
)
369 ngx_http_err_page_t
*err_page
;
370 ngx_http_core_loc_conf_t
*clcf
;
372 ngx_log_debug3(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
373 "http special response: %d, \"%V?%V\"",
374 error
, &r
->uri
, &r
->args
);
376 r
->err_status
= error
;
380 case NGX_HTTP_BAD_REQUEST
:
381 case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE
:
382 case NGX_HTTP_REQUEST_URI_TOO_LARGE
:
383 case NGX_HTTP_TO_HTTPS
:
384 case NGX_HTTPS_CERT_ERROR
:
385 case NGX_HTTPS_NO_CERT
:
386 case NGX_HTTP_INTERNAL_SERVER_ERROR
:
387 case NGX_HTTP_NOT_IMPLEMENTED
:
392 if (r
->lingering_close
) {
394 case NGX_HTTP_BAD_REQUEST
:
395 case NGX_HTTP_TO_HTTPS
:
396 case NGX_HTTPS_CERT_ERROR
:
397 case NGX_HTTPS_NO_CERT
:
398 r
->lingering_close
= 0;
402 r
->headers_out
.content_type
.len
= 0;
404 clcf
= ngx_http_get_module_loc_conf(r
, ngx_http_core_module
);
406 if (!r
->error_page
&& clcf
->error_pages
&& r
->uri_changes
!= 0) {
408 if (clcf
->recursive_error_pages
== 0) {
412 err_page
= clcf
->error_pages
->elts
;
414 for (i
= 0; i
< clcf
->error_pages
->nelts
; i
++) {
415 if (err_page
[i
].status
== error
) {
416 return ngx_http_send_error_page(r
, &err_page
[i
]);
421 r
->expect_tested
= 1;
423 if (ngx_http_discard_request_body(r
) != NGX_OK
) {
427 if (clcf
->msie_refresh
428 && r
->headers_in
.msie
429 && (error
== NGX_HTTP_MOVED_PERMANENTLY
430 || error
== NGX_HTTP_MOVED_TEMPORARILY
))
432 return ngx_http_send_refresh(r
);
435 if (error
== NGX_HTTP_CREATED
) {
439 } else if (error
== NGX_HTTP_NO_CONTENT
) {
443 } else if (error
>= NGX_HTTP_MOVED_PERMANENTLY
444 && error
< NGX_HTTP_LAST_3XX
)
447 err
= error
- NGX_HTTP_MOVED_PERMANENTLY
+ NGX_HTTP_OFF_3XX
;
449 } else if (error
>= NGX_HTTP_BAD_REQUEST
450 && error
< NGX_HTTP_LAST_4XX
)
453 err
= error
- NGX_HTTP_BAD_REQUEST
+ NGX_HTTP_OFF_4XX
;
455 } else if (error
>= NGX_HTTP_NGINX_CODES
456 && error
< NGX_HTTP_LAST_5XX
)
459 err
= error
- NGX_HTTP_NGINX_CODES
+ NGX_HTTP_OFF_5XX
;
461 case NGX_HTTP_TO_HTTPS
:
462 case NGX_HTTPS_CERT_ERROR
:
463 case NGX_HTTPS_NO_CERT
:
464 case NGX_HTTP_REQUEST_HEADER_TOO_LARGE
:
465 r
->err_status
= NGX_HTTP_BAD_REQUEST
;
470 /* unknown code, zero body */
474 return ngx_http_send_special_response(r
, clcf
, err
);
479 ngx_http_filter_finalize_request(ngx_http_request_t
*r
, ngx_module_t
*m
,
485 ngx_http_clean_header(r
);
490 ctx
= r
->ctx
[m
->ctx_index
];
493 /* clear the modules contexts */
494 ngx_memzero(r
->ctx
, sizeof(void *) * ngx_http_max_module
);
497 r
->ctx
[m
->ctx_index
] = ctx
;
500 r
->filter_finalize
= 1;
502 rc
= ngx_http_special_response_handler(r
, error
);
504 /* NGX_ERROR resets any pending data */
519 ngx_http_clean_header(ngx_http_request_t
*r
)
521 ngx_memzero(&r
->headers_out
.status
,
522 sizeof(ngx_http_headers_out_t
)
523 - offsetof(ngx_http_headers_out_t
, status
));
525 r
->headers_out
.headers
.part
.nelts
= 0;
526 r
->headers_out
.headers
.part
.next
= NULL
;
527 r
->headers_out
.headers
.last
= &r
->headers_out
.headers
.part
;
529 r
->headers_out
.content_length_n
= -1;
530 r
->headers_out
.last_modified_time
= -1;
535 ngx_http_send_error_page(ngx_http_request_t
*r
, ngx_http_err_page_t
*err_page
)
539 ngx_table_elt_t
*location
;
540 ngx_http_core_loc_conf_t
*clcf
;
542 overwrite
= err_page
->overwrite
;
544 if (overwrite
&& overwrite
!= NGX_HTTP_OK
) {
545 r
->expect_tested
= 1;
548 if (overwrite
>= 0) {
549 r
->err_status
= overwrite
;
552 if (ngx_http_complex_value(r
, &err_page
->value
, &uri
) != NGX_OK
) {
556 if (uri
.data
[0] == '/') {
558 if (err_page
->value
.lengths
) {
559 ngx_http_split_args(r
, &uri
, &args
);
562 args
= err_page
->args
;
565 if (r
->method
!= NGX_HTTP_HEAD
) {
566 r
->method
= NGX_HTTP_GET
;
567 r
->method_name
= ngx_http_get_name
;
570 return ngx_http_internal_redirect(r
, &uri
, &args
);
573 if (uri
.data
[0] == '@') {
574 return ngx_http_named_location(r
, &uri
);
577 location
= ngx_list_push(&r
->headers_out
.headers
);
579 if (location
== NULL
) {
583 if (overwrite
!= NGX_HTTP_MOVED_PERMANENTLY
584 && overwrite
!= NGX_HTTP_MOVED_TEMPORARILY
585 && overwrite
!= NGX_HTTP_SEE_OTHER
586 && overwrite
!= NGX_HTTP_TEMPORARY_REDIRECT
)
588 r
->err_status
= NGX_HTTP_MOVED_TEMPORARILY
;
592 ngx_str_set(&location
->key
, "Location");
593 location
->value
= uri
;
595 ngx_http_clear_location(r
);
597 r
->headers_out
.location
= location
;
599 clcf
= ngx_http_get_module_loc_conf(r
, ngx_http_core_module
);
601 if (clcf
->msie_refresh
&& r
->headers_in
.msie
) {
602 return ngx_http_send_refresh(r
);
605 return ngx_http_send_special_response(r
, clcf
, r
->err_status
606 - NGX_HTTP_MOVED_PERMANENTLY
612 ngx_http_send_special_response(ngx_http_request_t
*r
,
613 ngx_http_core_loc_conf_t
*clcf
, ngx_uint_t err
)
619 ngx_uint_t msie_padding
;
622 if (clcf
->server_tokens
) {
623 len
= sizeof(ngx_http_error_full_tail
) - 1;
624 tail
= ngx_http_error_full_tail
;
627 len
= sizeof(ngx_http_error_tail
) - 1;
628 tail
= ngx_http_error_tail
;
633 if (ngx_http_error_pages
[err
].len
) {
634 r
->headers_out
.content_length_n
= ngx_http_error_pages
[err
].len
+ len
;
635 if (clcf
->msie_padding
636 && (r
->headers_in
.msie
|| r
->headers_in
.chrome
)
637 && r
->http_version
>= NGX_HTTP_VERSION_10
638 && err
>= NGX_HTTP_OFF_4XX
)
640 r
->headers_out
.content_length_n
+=
641 sizeof(ngx_http_msie_padding
) - 1;
645 r
->headers_out
.content_type_len
= sizeof("text/html") - 1;
646 ngx_str_set(&r
->headers_out
.content_type
, "text/html");
647 r
->headers_out
.content_type_lowcase
= NULL
;
650 r
->headers_out
.content_length_n
= 0;
653 if (r
->headers_out
.content_length
) {
654 r
->headers_out
.content_length
->hash
= 0;
655 r
->headers_out
.content_length
= NULL
;
658 ngx_http_clear_accept_ranges(r
);
659 ngx_http_clear_last_modified(r
);
660 ngx_http_clear_etag(r
);
662 rc
= ngx_http_send_header(r
);
664 if (rc
== NGX_ERROR
|| r
->header_only
) {
668 if (ngx_http_error_pages
[err
].len
== 0) {
669 return ngx_http_send_special(r
, NGX_HTTP_LAST
);
672 b
= ngx_calloc_buf(r
->pool
);
678 b
->pos
= ngx_http_error_pages
[err
].data
;
679 b
->last
= ngx_http_error_pages
[err
].data
+ ngx_http_error_pages
[err
].len
;
682 out
[0].next
= &out
[1];
684 b
= ngx_calloc_buf(r
->pool
);
692 b
->last
= tail
+ len
;
698 b
= ngx_calloc_buf(r
->pool
);
704 b
->pos
= ngx_http_msie_padding
;
705 b
->last
= ngx_http_msie_padding
+ sizeof(ngx_http_msie_padding
) - 1;
707 out
[1].next
= &out
[2];
716 b
->last_in_chain
= 1;
718 return ngx_http_output_filter(r
, &out
[0]);
723 ngx_http_send_refresh(ngx_http_request_t
*r
)
725 u_char
*p
, *location
;
732 len
= r
->headers_out
.location
->value
.len
;
733 location
= r
->headers_out
.location
->value
.data
;
735 escape
= 2 * ngx_escape_uri(NULL
, location
, len
, NGX_ESCAPE_REFRESH
);
737 size
= sizeof(ngx_http_msie_refresh_head
) - 1
739 + sizeof(ngx_http_msie_refresh_tail
) - 1;
741 r
->err_status
= NGX_HTTP_OK
;
743 r
->headers_out
.content_type_len
= sizeof("text/html") - 1;
744 ngx_str_set(&r
->headers_out
.content_type
, "text/html");
745 r
->headers_out
.content_type_lowcase
= NULL
;
747 r
->headers_out
.location
->hash
= 0;
748 r
->headers_out
.location
= NULL
;
750 r
->headers_out
.content_length_n
= size
;
752 if (r
->headers_out
.content_length
) {
753 r
->headers_out
.content_length
->hash
= 0;
754 r
->headers_out
.content_length
= NULL
;
757 ngx_http_clear_accept_ranges(r
);
758 ngx_http_clear_last_modified(r
);
759 ngx_http_clear_etag(r
);
761 rc
= ngx_http_send_header(r
);
763 if (rc
== NGX_ERROR
|| r
->header_only
) {
767 b
= ngx_create_temp_buf(r
->pool
, size
);
772 p
= ngx_cpymem(b
->pos
, ngx_http_msie_refresh_head
,
773 sizeof(ngx_http_msie_refresh_head
) - 1);
776 p
= ngx_cpymem(p
, location
, len
);
779 p
= (u_char
*) ngx_escape_uri(p
, location
, len
, NGX_ESCAPE_REFRESH
);
782 b
->last
= ngx_cpymem(p
, ngx_http_msie_refresh_tail
,
783 sizeof(ngx_http_msie_refresh_tail
) - 1);
786 b
->last_in_chain
= 1;
791 return ngx_http_output_filter(r
, &out
);