src/http/ngx_http_special_response.c - nginx source code

Global variables defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>
  8. #include <nginx.h>


  9. static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r,
  10.     ngx_http_err_page_t *err_page);
  11. static ngx_int_t ngx_http_send_special_response(ngx_http_request_t *r,
  12.     ngx_http_core_loc_conf_t *clcf, ngx_uint_t err);
  13. static ngx_int_t ngx_http_send_refresh(ngx_http_request_t *r);


  14. static u_char ngx_http_error_full_tail[] =
  15. "<hr><center>" NGINX_VER "</center>" CRLF
  16. "</body>" CRLF
  17. "</html>" CRLF
  18. ;


  19. static u_char ngx_http_error_build_tail[] =
  20. "<hr><center>" NGINX_VER_BUILD "</center>" CRLF
  21. "</body>" CRLF
  22. "</html>" CRLF
  23. ;


  24. static u_char ngx_http_error_tail[] =
  25. "<hr><center>nginx</center>" CRLF
  26. "</body>" CRLF
  27. "</html>" CRLF
  28. ;


  29. static u_char ngx_http_msie_padding[] =
  30. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  31. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  32. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  33. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  34. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  35. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  36. ;


  37. static u_char ngx_http_msie_refresh_head[] =
  38. "<html><head><meta http-equiv=\"Refresh\" content=\"0; URL=";


  39. static u_char ngx_http_msie_refresh_tail[] =
  40. "\"></head><body></body></html>" CRLF;


  41. static char ngx_http_error_301_page[] =
  42. "<html>" CRLF
  43. "<head><title>301 Moved Permanently</title></head>" CRLF
  44. "<body>" CRLF
  45. "<center><h1>301 Moved Permanently</h1></center>" CRLF
  46. ;


  47. static char ngx_http_error_302_page[] =
  48. "<html>" CRLF
  49. "<head><title>302 Found</title></head>" CRLF
  50. "<body>" CRLF
  51. "<center><h1>302 Found</h1></center>" CRLF
  52. ;


  53. static char ngx_http_error_303_page[] =
  54. "<html>" CRLF
  55. "<head><title>303 See Other</title></head>" CRLF
  56. "<body>" CRLF
  57. "<center><h1>303 See Other</h1></center>" CRLF
  58. ;


  59. static char ngx_http_error_307_page[] =
  60. "<html>" CRLF
  61. "<head><title>307 Temporary Redirect</title></head>" CRLF
  62. "<body>" CRLF
  63. "<center><h1>307 Temporary Redirect</h1></center>" CRLF
  64. ;


  65. static char ngx_http_error_308_page[] =
  66. "<html>" CRLF
  67. "<head><title>308 Permanent Redirect</title></head>" CRLF
  68. "<body>" CRLF
  69. "<center><h1>308 Permanent Redirect</h1></center>" CRLF
  70. ;


  71. static char ngx_http_error_400_page[] =
  72. "<html>" CRLF
  73. "<head><title>400 Bad Request</title></head>" CRLF
  74. "<body>" CRLF
  75. "<center><h1>400 Bad Request</h1></center>" CRLF
  76. ;


  77. static char ngx_http_error_401_page[] =
  78. "<html>" CRLF
  79. "<head><title>401 Authorization Required</title></head>" CRLF
  80. "<body>" CRLF
  81. "<center><h1>401 Authorization Required</h1></center>" CRLF
  82. ;


  83. static char ngx_http_error_402_page[] =
  84. "<html>" CRLF
  85. "<head><title>402 Payment Required</title></head>" CRLF
  86. "<body>" CRLF
  87. "<center><h1>402 Payment Required</h1></center>" CRLF
  88. ;


  89. static char ngx_http_error_403_page[] =
  90. "<html>" CRLF
  91. "<head><title>403 Forbidden</title></head>" CRLF
  92. "<body>" CRLF
  93. "<center><h1>403 Forbidden</h1></center>" CRLF
  94. ;


  95. static char ngx_http_error_404_page[] =
  96. "<html>" CRLF
  97. "<head><title>404 Not Found</title></head>" CRLF
  98. "<body>" CRLF
  99. "<center><h1>404 Not Found</h1></center>" CRLF
  100. ;


  101. static char ngx_http_error_405_page[] =
  102. "<html>" CRLF
  103. "<head><title>405 Not Allowed</title></head>" CRLF
  104. "<body>" CRLF
  105. "<center><h1>405 Not Allowed</h1></center>" CRLF
  106. ;


  107. static char ngx_http_error_406_page[] =
  108. "<html>" CRLF
  109. "<head><title>406 Not Acceptable</title></head>" CRLF
  110. "<body>" CRLF
  111. "<center><h1>406 Not Acceptable</h1></center>" CRLF
  112. ;


  113. static char ngx_http_error_408_page[] =
  114. "<html>" CRLF
  115. "<head><title>408 Request Time-out</title></head>" CRLF
  116. "<body>" CRLF
  117. "<center><h1>408 Request Time-out</h1></center>" CRLF
  118. ;


  119. static char ngx_http_error_409_page[] =
  120. "<html>" CRLF
  121. "<head><title>409 Conflict</title></head>" CRLF
  122. "<body>" CRLF
  123. "<center><h1>409 Conflict</h1></center>" CRLF
  124. ;


  125. static char ngx_http_error_410_page[] =
  126. "<html>" CRLF
  127. "<head><title>410 Gone</title></head>" CRLF
  128. "<body>" CRLF
  129. "<center><h1>410 Gone</h1></center>" CRLF
  130. ;


  131. static char ngx_http_error_411_page[] =
  132. "<html>" CRLF
  133. "<head><title>411 Length Required</title></head>" CRLF
  134. "<body>" CRLF
  135. "<center><h1>411 Length Required</h1></center>" CRLF
  136. ;


  137. static char ngx_http_error_412_page[] =
  138. "<html>" CRLF
  139. "<head><title>412 Precondition Failed</title></head>" CRLF
  140. "<body>" CRLF
  141. "<center><h1>412 Precondition Failed</h1></center>" CRLF
  142. ;


  143. static char ngx_http_error_413_page[] =
  144. "<html>" CRLF
  145. "<head><title>413 Request Entity Too Large</title></head>" CRLF
  146. "<body>" CRLF
  147. "<center><h1>413 Request Entity Too Large</h1></center>" CRLF
  148. ;


  149. static char ngx_http_error_414_page[] =
  150. "<html>" CRLF
  151. "<head><title>414 Request-URI Too Large</title></head>" CRLF
  152. "<body>" CRLF
  153. "<center><h1>414 Request-URI Too Large</h1></center>" CRLF
  154. ;


  155. static char ngx_http_error_415_page[] =
  156. "<html>" CRLF
  157. "<head><title>415 Unsupported Media Type</title></head>" CRLF
  158. "<body>" CRLF
  159. "<center><h1>415 Unsupported Media Type</h1></center>" CRLF
  160. ;


  161. static char ngx_http_error_416_page[] =
  162. "<html>" CRLF
  163. "<head><title>416 Requested Range Not Satisfiable</title></head>" CRLF
  164. "<body>" CRLF
  165. "<center><h1>416 Requested Range Not Satisfiable</h1></center>" CRLF
  166. ;


  167. static char ngx_http_error_421_page[] =
  168. "<html>" CRLF
  169. "<head><title>421 Misdirected Request</title></head>" CRLF
  170. "<body>" CRLF
  171. "<center><h1>421 Misdirected Request</h1></center>" CRLF
  172. ;


  173. static char ngx_http_error_429_page[] =
  174. "<html>" CRLF
  175. "<head><title>429 Too Many Requests</title></head>" CRLF
  176. "<body>" CRLF
  177. "<center><h1>429 Too Many Requests</h1></center>" CRLF
  178. ;


  179. static char ngx_http_error_494_page[] =
  180. "<html>" CRLF
  181. "<head><title>400 Request Header Or Cookie Too Large</title></head>"
  182. CRLF
  183. "<body>" CRLF
  184. "<center><h1>400 Bad Request</h1></center>" CRLF
  185. "<center>Request Header Or Cookie Too Large</center>" CRLF
  186. ;


  187. static char ngx_http_error_495_page[] =
  188. "<html>" CRLF
  189. "<head><title>400 The SSL certificate error</title></head>"
  190. CRLF
  191. "<body>" CRLF
  192. "<center><h1>400 Bad Request</h1></center>" CRLF
  193. "<center>The SSL certificate error</center>" CRLF
  194. ;


  195. static char ngx_http_error_496_page[] =
  196. "<html>" CRLF
  197. "<head><title>400 No required SSL certificate was sent</title></head>"
  198. CRLF
  199. "<body>" CRLF
  200. "<center><h1>400 Bad Request</h1></center>" CRLF
  201. "<center>No required SSL certificate was sent</center>" CRLF
  202. ;


  203. static char ngx_http_error_497_page[] =
  204. "<html>" CRLF
  205. "<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>"
  206. CRLF
  207. "<body>" CRLF
  208. "<center><h1>400 Bad Request</h1></center>" CRLF
  209. "<center>The plain HTTP request was sent to HTTPS port</center>" CRLF
  210. ;


  211. static char ngx_http_error_500_page[] =
  212. "<html>" CRLF
  213. "<head><title>500 Internal Server Error</title></head>" CRLF
  214. "<body>" CRLF
  215. "<center><h1>500 Internal Server Error</h1></center>" CRLF
  216. ;


  217. static char ngx_http_error_501_page[] =
  218. "<html>" CRLF
  219. "<head><title>501 Not Implemented</title></head>" CRLF
  220. "<body>" CRLF
  221. "<center><h1>501 Not Implemented</h1></center>" CRLF
  222. ;


  223. static char ngx_http_error_502_page[] =
  224. "<html>" CRLF
  225. "<head><title>502 Bad Gateway</title></head>" CRLF
  226. "<body>" CRLF
  227. "<center><h1>502 Bad Gateway</h1></center>" CRLF
  228. ;


  229. static char ngx_http_error_503_page[] =
  230. "<html>" CRLF
  231. "<head><title>503 Service Temporarily Unavailable</title></head>" CRLF
  232. "<body>" CRLF
  233. "<center><h1>503 Service Temporarily Unavailable</h1></center>" CRLF
  234. ;


  235. static char ngx_http_error_504_page[] =
  236. "<html>" CRLF
  237. "<head><title>504 Gateway Time-out</title></head>" CRLF
  238. "<body>" CRLF
  239. "<center><h1>504 Gateway Time-out</h1></center>" CRLF
  240. ;


  241. static char ngx_http_error_505_page[] =
  242. "<html>" CRLF
  243. "<head><title>505 HTTP Version Not Supported</title></head>" CRLF
  244. "<body>" CRLF
  245. "<center><h1>505 HTTP Version Not Supported</h1></center>" CRLF
  246. ;


  247. static char ngx_http_error_507_page[] =
  248. "<html>" CRLF
  249. "<head><title>507 Insufficient Storage</title></head>" CRLF
  250. "<body>" CRLF
  251. "<center><h1>507 Insufficient Storage</h1></center>" CRLF
  252. ;


  253. static ngx_str_t ngx_http_error_pages[] = {

  254.     ngx_null_string,                     /* 201, 204 */

  255. #define NGX_HTTP_LAST_2XX  202
  256. #define NGX_HTTP_OFF_3XX   (NGX_HTTP_LAST_2XX - 201)

  257.     /* ngx_null_string, */               /* 300 */
  258.     ngx_string(ngx_http_error_301_page),
  259.     ngx_string(ngx_http_error_302_page),
  260.     ngx_string(ngx_http_error_303_page),
  261.     ngx_null_string,                     /* 304 */
  262.     ngx_null_string,                     /* 305 */
  263.     ngx_null_string,                     /* 306 */
  264.     ngx_string(ngx_http_error_307_page),
  265.     ngx_string(ngx_http_error_308_page),

  266. #define NGX_HTTP_LAST_3XX  309
  267. #define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)

  268.     ngx_string(ngx_http_error_400_page),
  269.     ngx_string(ngx_http_error_401_page),
  270.     ngx_string(ngx_http_error_402_page),
  271.     ngx_string(ngx_http_error_403_page),
  272.     ngx_string(ngx_http_error_404_page),
  273.     ngx_string(ngx_http_error_405_page),
  274.     ngx_string(ngx_http_error_406_page),
  275.     ngx_null_string,                     /* 407 */
  276.     ngx_string(ngx_http_error_408_page),
  277.     ngx_string(ngx_http_error_409_page),
  278.     ngx_string(ngx_http_error_410_page),
  279.     ngx_string(ngx_http_error_411_page),
  280.     ngx_string(ngx_http_error_412_page),
  281.     ngx_string(ngx_http_error_413_page),
  282.     ngx_string(ngx_http_error_414_page),
  283.     ngx_string(ngx_http_error_415_page),
  284.     ngx_string(ngx_http_error_416_page),
  285.     ngx_null_string,                     /* 417 */
  286.     ngx_null_string,                     /* 418 */
  287.     ngx_null_string,                     /* 419 */
  288.     ngx_null_string,                     /* 420 */
  289.     ngx_string(ngx_http_error_421_page),
  290.     ngx_null_string,                     /* 422 */
  291.     ngx_null_string,                     /* 423 */
  292.     ngx_null_string,                     /* 424 */
  293.     ngx_null_string,                     /* 425 */
  294.     ngx_null_string,                     /* 426 */
  295.     ngx_null_string,                     /* 427 */
  296.     ngx_null_string,                     /* 428 */
  297.     ngx_string(ngx_http_error_429_page),

  298. #define NGX_HTTP_LAST_4XX  430
  299. #define NGX_HTTP_OFF_5XX   (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)

  300.     ngx_string(ngx_http_error_494_page), /* 494, request header too large */
  301.     ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
  302.     ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
  303.     ngx_string(ngx_http_error_497_page), /* 497, http to https */
  304.     ngx_string(ngx_http_error_404_page), /* 498, canceled */
  305.     ngx_null_string,                     /* 499, client has closed connection */

  306.     ngx_string(ngx_http_error_500_page),
  307.     ngx_string(ngx_http_error_501_page),
  308.     ngx_string(ngx_http_error_502_page),
  309.     ngx_string(ngx_http_error_503_page),
  310.     ngx_string(ngx_http_error_504_page),
  311.     ngx_string(ngx_http_error_505_page),
  312.     ngx_null_string,                     /* 506 */
  313.     ngx_string(ngx_http_error_507_page)

  314. #define NGX_HTTP_LAST_5XX  508

  315. };


  316. ngx_int_t
  317. ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
  318. {
  319.     ngx_uint_t                 i, err;
  320.     ngx_http_err_page_t       *err_page;
  321.     ngx_http_core_loc_conf_t  *clcf;

  322.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  323.                    "http special response: %i, \"%V?%V\"",
  324.                    error, &r->uri, &r->args);

  325.     r->err_status = error;

  326.     if (r->keepalive) {
  327.         switch (error) {
  328.             case NGX_HTTP_BAD_REQUEST:
  329.             case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE:
  330.             case NGX_HTTP_REQUEST_URI_TOO_LARGE:
  331.             case NGX_HTTP_TO_HTTPS:
  332.             case NGX_HTTPS_CERT_ERROR:
  333.             case NGX_HTTPS_NO_CERT:
  334.             case NGX_HTTP_INTERNAL_SERVER_ERROR:
  335.             case NGX_HTTP_NOT_IMPLEMENTED:
  336.                 r->keepalive = 0;
  337.         }
  338.     }

  339.     if (r->lingering_close) {
  340.         switch (error) {
  341.             case NGX_HTTP_BAD_REQUEST:
  342.             case NGX_HTTP_TO_HTTPS:
  343.             case NGX_HTTPS_CERT_ERROR:
  344.             case NGX_HTTPS_NO_CERT:
  345.                 r->lingering_close = 0;
  346.         }
  347.     }

  348.     r->headers_out.content_type.len = 0;

  349.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  350.     if (!r->error_page && clcf->error_pages && r->uri_changes != 0) {

  351.         if (clcf->recursive_error_pages == 0) {
  352.             r->error_page = 1;
  353.         }

  354.         err_page = clcf->error_pages->elts;

  355.         for (i = 0; i < clcf->error_pages->nelts; i++) {
  356.             if (err_page[i].status == error) {
  357.                 return ngx_http_send_error_page(r, &err_page[i]);
  358.             }
  359.         }
  360.     }

  361.     r->expect_tested = 1;

  362.     if (ngx_http_discard_request_body(r) != NGX_OK) {
  363.         r->keepalive = 0;
  364.     }

  365.     if (clcf->msie_refresh
  366.         && r->headers_in.msie
  367.         && (error == NGX_HTTP_MOVED_PERMANENTLY
  368.             || error == NGX_HTTP_MOVED_TEMPORARILY))
  369.     {
  370.         return ngx_http_send_refresh(r);
  371.     }

  372.     if (error == NGX_HTTP_CREATED) {
  373.         /* 201 */
  374.         err = 0;

  375.     } else if (error == NGX_HTTP_NO_CONTENT) {
  376.         /* 204 */
  377.         err = 0;

  378.     } else if (error >= NGX_HTTP_MOVED_PERMANENTLY
  379.                && error < NGX_HTTP_LAST_3XX)
  380.     {
  381.         /* 3XX */
  382.         err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;

  383.     } else if (error >= NGX_HTTP_BAD_REQUEST
  384.                && error < NGX_HTTP_LAST_4XX)
  385.     {
  386.         /* 4XX */
  387.         err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX;

  388.     } else if (error >= NGX_HTTP_NGINX_CODES
  389.                && error < NGX_HTTP_LAST_5XX)
  390.     {
  391.         /* 49X, 5XX */
  392.         err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_OFF_5XX;
  393.         switch (error) {
  394.             case NGX_HTTP_TO_HTTPS:
  395.             case NGX_HTTPS_CERT_ERROR:
  396.             case NGX_HTTPS_NO_CERT:
  397.             case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:
  398.                 r->err_status = NGX_HTTP_BAD_REQUEST;
  399.         }

  400.     } else {
  401.         /* unknown code, zero body */
  402.         err = 0;
  403.     }

  404.     return ngx_http_send_special_response(r, clcf, err);
  405. }


  406. ngx_int_t
  407. ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_module_t *m,
  408.     ngx_int_t error)
  409. {
  410.     void       *ctx;
  411.     ngx_int_t   rc;

  412.     ngx_http_clean_header(r);

  413.     ctx = NULL;

  414.     if (m) {
  415.         ctx = r->ctx[m->ctx_index];
  416.     }

  417.     /* clear the modules contexts */
  418.     ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);

  419.     if (m) {
  420.         r->ctx[m->ctx_index] = ctx;
  421.     }

  422.     r->filter_finalize = 1;

  423.     rc = ngx_http_special_response_handler(r, error);

  424.     /* NGX_ERROR resets any pending data */

  425.     switch (rc) {

  426.     case NGX_OK:
  427.     case NGX_DONE:
  428.         return NGX_ERROR;

  429.     default:
  430.         return rc;
  431.     }
  432. }


  433. void
  434. ngx_http_clean_header(ngx_http_request_t *r)
  435. {
  436.     ngx_memzero(&r->headers_out.status,
  437.                 sizeof(ngx_http_headers_out_t)
  438.                     - offsetof(ngx_http_headers_out_t, status));

  439.     r->headers_out.headers.part.nelts = 0;
  440.     r->headers_out.headers.part.next = NULL;
  441.     r->headers_out.headers.last = &r->headers_out.headers.part;

  442.     r->headers_out.trailers.part.nelts = 0;
  443.     r->headers_out.trailers.part.next = NULL;
  444.     r->headers_out.trailers.last = &r->headers_out.trailers.part;

  445.     r->headers_out.content_length_n = -1;
  446.     r->headers_out.last_modified_time = -1;
  447. }


  448. static ngx_int_t
  449. ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
  450. {
  451.     ngx_int_t                  overwrite;
  452.     ngx_str_t                  uri, args;
  453.     ngx_table_elt_t           *location;
  454.     ngx_http_core_loc_conf_t  *clcf;

  455.     overwrite = err_page->overwrite;

  456.     if (overwrite && overwrite != NGX_HTTP_OK) {
  457.         r->expect_tested = 1;
  458.     }

  459.     if (overwrite >= 0) {
  460.         r->err_status = overwrite;
  461.     }

  462.     if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {
  463.         return NGX_ERROR;
  464.     }

  465.     if (uri.len && uri.data[0] == '/') {

  466.         if (err_page->value.lengths) {
  467.             ngx_http_split_args(r, &uri, &args);

  468.         } else {
  469.             args = err_page->args;
  470.         }

  471.         if (r->method != NGX_HTTP_HEAD) {
  472.             r->method = NGX_HTTP_GET;
  473.             r->method_name = ngx_http_core_get_method;
  474.         }

  475.         return ngx_http_internal_redirect(r, &uri, &args);
  476.     }

  477.     if (uri.len && uri.data[0] == '@') {
  478.         return ngx_http_named_location(r, &uri);
  479.     }

  480.     r->expect_tested = 1;

  481.     if (ngx_http_discard_request_body(r) != NGX_OK) {
  482.         r->keepalive = 0;
  483.     }

  484.     location = ngx_list_push(&r->headers_out.headers);

  485.     if (location == NULL) {
  486.         return NGX_ERROR;
  487.     }

  488.     if (overwrite != NGX_HTTP_MOVED_PERMANENTLY
  489.         && overwrite != NGX_HTTP_MOVED_TEMPORARILY
  490.         && overwrite != NGX_HTTP_SEE_OTHER
  491.         && overwrite != NGX_HTTP_TEMPORARY_REDIRECT
  492.         && overwrite != NGX_HTTP_PERMANENT_REDIRECT)
  493.     {
  494.         r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
  495.     }

  496.     location->hash = 1;
  497.     location->next = NULL;
  498.     ngx_str_set(&location->key, "Location");
  499.     location->value = uri;

  500.     ngx_http_clear_location(r);

  501.     r->headers_out.location = location;

  502.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  503.     if (clcf->msie_refresh && r->headers_in.msie) {
  504.         return ngx_http_send_refresh(r);
  505.     }

  506.     return ngx_http_send_special_response(r, clcf, r->err_status
  507.                                                    - NGX_HTTP_MOVED_PERMANENTLY
  508.                                                    + NGX_HTTP_OFF_3XX);
  509. }


  510. static ngx_int_t
  511. ngx_http_send_special_response(ngx_http_request_t *r,
  512.     ngx_http_core_loc_conf_t *clcf, ngx_uint_t err)
  513. {
  514.     u_char       *tail;
  515.     size_t        len;
  516.     ngx_int_t     rc;
  517.     ngx_buf_t    *b;
  518.     ngx_uint_t    msie_padding;
  519.     ngx_chain_t   out[3];

  520.     if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
  521.         len = sizeof(ngx_http_error_full_tail) - 1;
  522.         tail = ngx_http_error_full_tail;

  523.     } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
  524.         len = sizeof(ngx_http_error_build_tail) - 1;
  525.         tail = ngx_http_error_build_tail;

  526.     } else {
  527.         len = sizeof(ngx_http_error_tail) - 1;
  528.         tail = ngx_http_error_tail;
  529.     }

  530.     msie_padding = 0;

  531.     if (ngx_http_error_pages[err].len) {
  532.         r->headers_out.content_length_n = ngx_http_error_pages[err].len + len;
  533.         if (clcf->msie_padding
  534.             && (r->headers_in.msie || r->headers_in.chrome)
  535.             && r->http_version >= NGX_HTTP_VERSION_10
  536.             && err >= NGX_HTTP_OFF_4XX)
  537.         {
  538.             r->headers_out.content_length_n +=
  539.                                          sizeof(ngx_http_msie_padding) - 1;
  540.             msie_padding = 1;
  541.         }

  542.         r->headers_out.content_type_len = sizeof("text/html") - 1;
  543.         ngx_str_set(&r->headers_out.content_type, "text/html");
  544.         r->headers_out.content_type_lowcase = NULL;

  545.     } else {
  546.         r->headers_out.content_length_n = 0;
  547.     }

  548.     if (r->headers_out.content_length) {
  549.         r->headers_out.content_length->hash = 0;
  550.         r->headers_out.content_length = NULL;
  551.     }

  552.     ngx_http_clear_accept_ranges(r);
  553.     ngx_http_clear_last_modified(r);
  554.     ngx_http_clear_etag(r);

  555.     rc = ngx_http_send_header(r);

  556.     if (rc == NGX_ERROR || r->header_only) {
  557.         return rc;
  558.     }

  559.     if (ngx_http_error_pages[err].len == 0) {
  560.         return ngx_http_send_special(r, NGX_HTTP_LAST);
  561.     }

  562.     b = ngx_calloc_buf(r->pool);
  563.     if (b == NULL) {
  564.         return NGX_ERROR;
  565.     }

  566.     b->memory = 1;
  567.     b->pos = ngx_http_error_pages[err].data;
  568.     b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len;

  569.     out[0].buf = b;
  570.     out[0].next = &out[1];

  571.     b = ngx_calloc_buf(r->pool);
  572.     if (b == NULL) {
  573.         return NGX_ERROR;
  574.     }

  575.     b->memory = 1;

  576.     b->pos = tail;
  577.     b->last = tail + len;

  578.     out[1].buf = b;
  579.     out[1].next = NULL;

  580.     if (msie_padding) {
  581.         b = ngx_calloc_buf(r->pool);
  582.         if (b == NULL) {
  583.             return NGX_ERROR;
  584.         }

  585.         b->memory = 1;
  586.         b->pos = ngx_http_msie_padding;
  587.         b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1;

  588.         out[1].next = &out[2];
  589.         out[2].buf = b;
  590.         out[2].next = NULL;
  591.     }

  592.     if (r == r->main) {
  593.         b->last_buf = 1;
  594.     }

  595.     b->last_in_chain = 1;

  596.     return ngx_http_output_filter(r, &out[0]);
  597. }


  598. static ngx_int_t
  599. ngx_http_send_refresh(ngx_http_request_t *r)
  600. {
  601.     u_char       *p, *location;
  602.     size_t        len, size;
  603.     uintptr_t     escape;
  604.     ngx_int_t     rc;
  605.     ngx_buf_t    *b;
  606.     ngx_chain_t   out;

  607.     len = r->headers_out.location->value.len;
  608.     location = r->headers_out.location->value.data;

  609.     escape = 2 * ngx_escape_uri(NULL, location, len, NGX_ESCAPE_REFRESH);

  610.     size = sizeof(ngx_http_msie_refresh_head) - 1
  611.            + escape + len
  612.            + sizeof(ngx_http_msie_refresh_tail) - 1;

  613.     r->err_status = NGX_HTTP_OK;

  614.     r->headers_out.content_type_len = sizeof("text/html") - 1;
  615.     ngx_str_set(&r->headers_out.content_type, "text/html");
  616.     r->headers_out.content_type_lowcase = NULL;

  617.     r->headers_out.location->hash = 0;
  618.     r->headers_out.location = NULL;

  619.     r->headers_out.content_length_n = size;

  620.     if (r->headers_out.content_length) {
  621.         r->headers_out.content_length->hash = 0;
  622.         r->headers_out.content_length = NULL;
  623.     }

  624.     ngx_http_clear_accept_ranges(r);
  625.     ngx_http_clear_last_modified(r);
  626.     ngx_http_clear_etag(r);

  627.     rc = ngx_http_send_header(r);

  628.     if (rc == NGX_ERROR || r->header_only) {
  629.         return rc;
  630.     }

  631.     b = ngx_create_temp_buf(r->pool, size);
  632.     if (b == NULL) {
  633.         return NGX_ERROR;
  634.     }

  635.     p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head,
  636.                    sizeof(ngx_http_msie_refresh_head) - 1);

  637.     if (escape == 0) {
  638.         p = ngx_cpymem(p, location, len);

  639.     } else {
  640.         p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH);
  641.     }

  642.     b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail,
  643.                          sizeof(ngx_http_msie_refresh_tail) - 1);

  644.     b->last_buf = (r == r->main) ? 1 : 0;
  645.     b->last_in_chain = 1;

  646.     out.buf = b;
  647.     out.next = NULL;

  648.     return ngx_http_output_filter(r, &out);
  649. }