src/http/ngx_http_special_response.c - nginx-1.7.10

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_tail[] =
  20. "<hr><center>nginx</center>" CRLF
  21. "</body>" CRLF
  22. "</html>" CRLF
  23. ;


  24. static u_char ngx_http_msie_padding[] =
  25. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  26. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  27. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  28. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  29. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  30. "<!-- a padding to disable MSIE and Chrome friendly error page -->" CRLF
  31. ;


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


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


  36. static char ngx_http_error_301_page[] =
  37. "<html>" CRLF
  38. "<head><title>301 Moved Permanently</title></head>" CRLF
  39. "<body bgcolor=\"white\">" CRLF
  40. "<center><h1>301 Moved Permanently</h1></center>" CRLF
  41. ;


  42. static char ngx_http_error_302_page[] =
  43. "<html>" CRLF
  44. "<head><title>302 Found</title></head>" CRLF
  45. "<body bgcolor=\"white\">" CRLF
  46. "<center><h1>302 Found</h1></center>" CRLF
  47. ;


  48. static char ngx_http_error_303_page[] =
  49. "<html>" CRLF
  50. "<head><title>303 See Other</title></head>" CRLF
  51. "<body bgcolor=\"white\">" CRLF
  52. "<center><h1>303 See Other</h1></center>" CRLF
  53. ;


  54. static char ngx_http_error_307_page[] =
  55. "<html>" CRLF
  56. "<head><title>307 Temporary Redirect</title></head>" CRLF
  57. "<body bgcolor=\"white\">" CRLF
  58. "<center><h1>307 Temporary Redirect</h1></center>" CRLF
  59. ;


  60. static char ngx_http_error_400_page[] =
  61. "<html>" CRLF
  62. "<head><title>400 Bad Request</title></head>" CRLF
  63. "<body bgcolor=\"white\">" CRLF
  64. "<center><h1>400 Bad Request</h1></center>" CRLF
  65. ;


  66. static char ngx_http_error_401_page[] =
  67. "<html>" CRLF
  68. "<head><title>401 Authorization Required</title></head>" CRLF
  69. "<body bgcolor=\"white\">" CRLF
  70. "<center><h1>401 Authorization Required</h1></center>" CRLF
  71. ;


  72. static char ngx_http_error_402_page[] =
  73. "<html>" CRLF
  74. "<head><title>402 Payment Required</title></head>" CRLF
  75. "<body bgcolor=\"white\">" CRLF
  76. "<center><h1>402 Payment Required</h1></center>" CRLF
  77. ;


  78. static char ngx_http_error_403_page[] =
  79. "<html>" CRLF
  80. "<head><title>403 Forbidden</title></head>" CRLF
  81. "<body bgcolor=\"white\">" CRLF
  82. "<center><h1>403 Forbidden</h1></center>" CRLF
  83. ;


  84. static char ngx_http_error_404_page[] =
  85. "<html>" CRLF
  86. "<head><title>404 Not Found</title></head>" CRLF
  87. "<body bgcolor=\"white\">" CRLF
  88. "<center><h1>404 Not Found</h1></center>" CRLF
  89. ;


  90. static char ngx_http_error_405_page[] =
  91. "<html>" CRLF
  92. "<head><title>405 Not Allowed</title></head>" CRLF
  93. "<body bgcolor=\"white\">" CRLF
  94. "<center><h1>405 Not Allowed</h1></center>" CRLF
  95. ;


  96. static char ngx_http_error_406_page[] =
  97. "<html>" CRLF
  98. "<head><title>406 Not Acceptable</title></head>" CRLF
  99. "<body bgcolor=\"white\">" CRLF
  100. "<center><h1>406 Not Acceptable</h1></center>" CRLF
  101. ;


  102. static char ngx_http_error_408_page[] =
  103. "<html>" CRLF
  104. "<head><title>408 Request Time-out</title></head>" CRLF
  105. "<body bgcolor=\"white\">" CRLF
  106. "<center><h1>408 Request Time-out</h1></center>" CRLF
  107. ;


  108. static char ngx_http_error_409_page[] =
  109. "<html>" CRLF
  110. "<head><title>409 Conflict</title></head>" CRLF
  111. "<body bgcolor=\"white\">" CRLF
  112. "<center><h1>409 Conflict</h1></center>" CRLF
  113. ;


  114. static char ngx_http_error_410_page[] =
  115. "<html>" CRLF
  116. "<head><title>410 Gone</title></head>" CRLF
  117. "<body bgcolor=\"white\">" CRLF
  118. "<center><h1>410 Gone</h1></center>" CRLF
  119. ;


  120. static char ngx_http_error_411_page[] =
  121. "<html>" CRLF
  122. "<head><title>411 Length Required</title></head>" CRLF
  123. "<body bgcolor=\"white\">" CRLF
  124. "<center><h1>411 Length Required</h1></center>" CRLF
  125. ;


  126. static char ngx_http_error_412_page[] =
  127. "<html>" CRLF
  128. "<head><title>412 Precondition Failed</title></head>" CRLF
  129. "<body bgcolor=\"white\">" CRLF
  130. "<center><h1>412 Precondition Failed</h1></center>" CRLF
  131. ;


  132. static char ngx_http_error_413_page[] =
  133. "<html>" CRLF
  134. "<head><title>413 Request Entity Too Large</title></head>" CRLF
  135. "<body bgcolor=\"white\">" CRLF
  136. "<center><h1>413 Request Entity Too Large</h1></center>" CRLF
  137. ;


  138. static char ngx_http_error_414_page[] =
  139. "<html>" CRLF
  140. "<head><title>414 Request-URI Too Large</title></head>" CRLF
  141. "<body bgcolor=\"white\">" CRLF
  142. "<center><h1>414 Request-URI Too Large</h1></center>" CRLF
  143. ;


  144. static char ngx_http_error_415_page[] =
  145. "<html>" CRLF
  146. "<head><title>415 Unsupported Media Type</title></head>" CRLF
  147. "<body bgcolor=\"white\">" CRLF
  148. "<center><h1>415 Unsupported Media Type</h1></center>" CRLF
  149. ;


  150. static char ngx_http_error_416_page[] =
  151. "<html>" CRLF
  152. "<head><title>416 Requested Range Not Satisfiable</title></head>" CRLF
  153. "<body bgcolor=\"white\">" CRLF
  154. "<center><h1>416 Requested Range Not Satisfiable</h1></center>" CRLF
  155. ;


  156. static char ngx_http_error_494_page[] =
  157. "<html>" CRLF
  158. "<head><title>400 Request Header Or Cookie Too Large</title></head>"
  159. CRLF
  160. "<body bgcolor=\"white\">" CRLF
  161. "<center><h1>400 Bad Request</h1></center>" CRLF
  162. "<center>Request Header Or Cookie Too Large</center>" CRLF
  163. ;


  164. static char ngx_http_error_495_page[] =
  165. "<html>" CRLF
  166. "<head><title>400 The SSL certificate error</title></head>"
  167. CRLF
  168. "<body bgcolor=\"white\">" CRLF
  169. "<center><h1>400 Bad Request</h1></center>" CRLF
  170. "<center>The SSL certificate error</center>" CRLF
  171. ;


  172. static char ngx_http_error_496_page[] =
  173. "<html>" CRLF
  174. "<head><title>400 No required SSL certificate was sent</title></head>"
  175. CRLF
  176. "<body bgcolor=\"white\">" CRLF
  177. "<center><h1>400 Bad Request</h1></center>" CRLF
  178. "<center>No required SSL certificate was sent</center>" CRLF
  179. ;


  180. static char ngx_http_error_497_page[] =
  181. "<html>" CRLF
  182. "<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>"
  183. CRLF
  184. "<body bgcolor=\"white\">" CRLF
  185. "<center><h1>400 Bad Request</h1></center>" CRLF
  186. "<center>The plain HTTP request was sent to HTTPS port</center>" CRLF
  187. ;


  188. static char ngx_http_error_500_page[] =
  189. "<html>" CRLF
  190. "<head><title>500 Internal Server Error</title></head>" CRLF
  191. "<body bgcolor=\"white\">" CRLF
  192. "<center><h1>500 Internal Server Error</h1></center>" CRLF
  193. ;


  194. static char ngx_http_error_501_page[] =
  195. "<html>" CRLF
  196. "<head><title>501 Not Implemented</title></head>" CRLF
  197. "<body bgcolor=\"white\">" CRLF
  198. "<center><h1>501 Not Implemented</h1></center>" CRLF
  199. ;


  200. static char ngx_http_error_502_page[] =
  201. "<html>" CRLF
  202. "<head><title>502 Bad Gateway</title></head>" CRLF
  203. "<body bgcolor=\"white\">" CRLF
  204. "<center><h1>502 Bad Gateway</h1></center>" CRLF
  205. ;


  206. static char ngx_http_error_503_page[] =
  207. "<html>" CRLF
  208. "<head><title>503 Service Temporarily Unavailable</title></head>" CRLF
  209. "<body bgcolor=\"white\">" CRLF
  210. "<center><h1>503 Service Temporarily Unavailable</h1></center>" CRLF
  211. ;


  212. static char ngx_http_error_504_page[] =
  213. "<html>" CRLF
  214. "<head><title>504 Gateway Time-out</title></head>" CRLF
  215. "<body bgcolor=\"white\">" CRLF
  216. "<center><h1>504 Gateway Time-out</h1></center>" CRLF
  217. ;


  218. static char ngx_http_error_507_page[] =
  219. "<html>" CRLF
  220. "<head><title>507 Insufficient Storage</title></head>" CRLF
  221. "<body bgcolor=\"white\">" CRLF
  222. "<center><h1>507 Insufficient Storage</h1></center>" CRLF
  223. ;


  224. static ngx_str_t ngx_http_error_pages[] = {

  225.     ngx_null_string,                     /* 201, 204 */

  226. #define NGX_HTTP_LAST_2XX  202
  227. #define NGX_HTTP_OFF_3XX   (NGX_HTTP_LAST_2XX - 201)

  228.     /* ngx_null_string, */               /* 300 */
  229.     ngx_string(ngx_http_error_301_page),
  230.     ngx_string(ngx_http_error_302_page),
  231.     ngx_string(ngx_http_error_303_page),
  232.     ngx_null_string,                     /* 304 */
  233.     ngx_null_string,                     /* 305 */
  234.     ngx_null_string,                     /* 306 */
  235.     ngx_string(ngx_http_error_307_page),

  236. #define NGX_HTTP_LAST_3XX  308
  237. #define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)

  238.     ngx_string(ngx_http_error_400_page),
  239.     ngx_string(ngx_http_error_401_page),
  240.     ngx_string(ngx_http_error_402_page),
  241.     ngx_string(ngx_http_error_403_page),
  242.     ngx_string(ngx_http_error_404_page),
  243.     ngx_string(ngx_http_error_405_page),
  244.     ngx_string(ngx_http_error_406_page),
  245.     ngx_null_string,                     /* 407 */
  246.     ngx_string(ngx_http_error_408_page),
  247.     ngx_string(ngx_http_error_409_page),
  248.     ngx_string(ngx_http_error_410_page),
  249.     ngx_string(ngx_http_error_411_page),
  250.     ngx_string(ngx_http_error_412_page),
  251.     ngx_string(ngx_http_error_413_page),
  252.     ngx_string(ngx_http_error_414_page),
  253.     ngx_string(ngx_http_error_415_page),
  254.     ngx_string(ngx_http_error_416_page),

  255. #define NGX_HTTP_LAST_4XX  417
  256. #define NGX_HTTP_OFF_5XX   (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)

  257.     ngx_string(ngx_http_error_494_page), /* 494, request header too large */
  258.     ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
  259.     ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
  260.     ngx_string(ngx_http_error_497_page), /* 497, http to https */
  261.     ngx_string(ngx_http_error_404_page), /* 498, canceled */
  262.     ngx_null_string,                     /* 499, client has closed connection */

  263.     ngx_string(ngx_http_error_500_page),
  264.     ngx_string(ngx_http_error_501_page),
  265.     ngx_string(ngx_http_error_502_page),
  266.     ngx_string(ngx_http_error_503_page),
  267.     ngx_string(ngx_http_error_504_page),
  268.     ngx_null_string,                     /* 505 */
  269.     ngx_null_string,                     /* 506 */
  270.     ngx_string(ngx_http_error_507_page)

  271. #define NGX_HTTP_LAST_5XX  508

  272. };


  273. static ngx_str_t  ngx_http_get_name = { 3, (u_char *) "GET " };


  274. ngx_int_t
  275. ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
  276. {
  277.     ngx_uint_t                 i, err;
  278.     ngx_http_err_page_t       *err_page;
  279.     ngx_http_core_loc_conf_t  *clcf;

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

  283.     r->err_status = error;

  284.     if (r->keepalive) {
  285.         switch (error) {
  286.             case NGX_HTTP_BAD_REQUEST:
  287.             case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE:
  288.             case NGX_HTTP_REQUEST_URI_TOO_LARGE:
  289.             case NGX_HTTP_TO_HTTPS:
  290.             case NGX_HTTPS_CERT_ERROR:
  291.             case NGX_HTTPS_NO_CERT:
  292.             case NGX_HTTP_INTERNAL_SERVER_ERROR:
  293.             case NGX_HTTP_NOT_IMPLEMENTED:
  294.                 r->keepalive = 0;
  295.         }
  296.     }

  297.     if (r->lingering_close) {
  298.         switch (error) {
  299.             case NGX_HTTP_BAD_REQUEST:
  300.             case NGX_HTTP_TO_HTTPS:
  301.             case NGX_HTTPS_CERT_ERROR:
  302.             case NGX_HTTPS_NO_CERT:
  303.                 r->lingering_close = 0;
  304.         }
  305.     }

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

  307.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

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

  309.         if (clcf->recursive_error_pages == 0) {
  310.             r->error_page = 1;
  311.         }

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

  313.         for (i = 0; i < clcf->error_pages->nelts; i++) {
  314.             if (err_page[i].status == error) {
  315.                 return ngx_http_send_error_page(r, &err_page[i]);
  316.             }
  317.         }
  318.     }

  319.     r->expect_tested = 1;

  320.     if (ngx_http_discard_request_body(r) != NGX_OK) {
  321.         r->keepalive = 0;
  322.     }

  323.     if (clcf->msie_refresh
  324.         && r->headers_in.msie
  325.         && (error == NGX_HTTP_MOVED_PERMANENTLY
  326.             || error == NGX_HTTP_MOVED_TEMPORARILY))
  327.     {
  328.         return ngx_http_send_refresh(r);
  329.     }

  330.     if (error == NGX_HTTP_CREATED) {
  331.         /* 201 */
  332.         err = 0;

  333.     } else if (error == NGX_HTTP_NO_CONTENT) {
  334.         /* 204 */
  335.         err = 0;

  336.     } else if (error >= NGX_HTTP_MOVED_PERMANENTLY
  337.                && error < NGX_HTTP_LAST_3XX)
  338.     {
  339.         /* 3XX */
  340.         err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;

  341.     } else if (error >= NGX_HTTP_BAD_REQUEST
  342.                && error < NGX_HTTP_LAST_4XX)
  343.     {
  344.         /* 4XX */
  345.         err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX;

  346.     } else if (error >= NGX_HTTP_NGINX_CODES
  347.                && error < NGX_HTTP_LAST_5XX)
  348.     {
  349.         /* 49X, 5XX */
  350.         err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_OFF_5XX;
  351.         switch (error) {
  352.             case NGX_HTTP_TO_HTTPS:
  353.             case NGX_HTTPS_CERT_ERROR:
  354.             case NGX_HTTPS_NO_CERT:
  355.             case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:
  356.                 r->err_status = NGX_HTTP_BAD_REQUEST;
  357.                 break;
  358.         }

  359.     } else {
  360.         /* unknown code, zero body */
  361.         err = 0;
  362.     }

  363.     return ngx_http_send_special_response(r, clcf, err);
  364. }


  365. ngx_int_t
  366. ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_module_t *m,
  367.     ngx_int_t error)
  368. {
  369.     void       *ctx;
  370.     ngx_int_t   rc;

  371.     ngx_http_clean_header(r);

  372.     ctx = NULL;

  373.     if (m) {
  374.         ctx = r->ctx[m->ctx_index];
  375.     }

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

  378.     if (m) {
  379.         r->ctx[m->ctx_index] = ctx;
  380.     }

  381.     r->filter_finalize = 1;

  382.     rc = ngx_http_special_response_handler(r, error);

  383.     /* NGX_ERROR resets any pending data */

  384.     switch (rc) {

  385.     case NGX_OK:
  386.     case NGX_DONE:
  387.         return NGX_ERROR;

  388.     default:
  389.         return rc;
  390.     }
  391. }


  392. void
  393. ngx_http_clean_header(ngx_http_request_t *r)
  394. {
  395.     ngx_memzero(&r->headers_out.status,
  396.                 sizeof(ngx_http_headers_out_t)
  397.                     - offsetof(ngx_http_headers_out_t, status));

  398.     r->headers_out.headers.part.nelts = 0;
  399.     r->headers_out.headers.part.next = NULL;
  400.     r->headers_out.headers.last = &r->headers_out.headers.part;

  401.     r->headers_out.content_length_n = -1;
  402.     r->headers_out.last_modified_time = -1;
  403. }


  404. static ngx_int_t
  405. ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
  406. {
  407.     ngx_int_t                  overwrite;
  408.     ngx_str_t                  uri, args;
  409.     ngx_table_elt_t           *location;
  410.     ngx_http_core_loc_conf_t  *clcf;

  411.     overwrite = err_page->overwrite;

  412.     if (overwrite && overwrite != NGX_HTTP_OK) {
  413.         r->expect_tested = 1;
  414.     }

  415.     if (overwrite >= 0) {
  416.         r->err_status = overwrite;
  417.     }

  418.     if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {
  419.         return NGX_ERROR;
  420.     }

  421.     if (uri.data[0] == '/') {

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

  424.         } else {
  425.             args = err_page->args;
  426.         }

  427.         if (r->method != NGX_HTTP_HEAD) {
  428.             r->method = NGX_HTTP_GET;
  429.             r->method_name = ngx_http_get_name;
  430.         }

  431.         return ngx_http_internal_redirect(r, &uri, &args);
  432.     }

  433.     if (uri.data[0] == '@') {
  434.         return ngx_http_named_location(r, &uri);
  435.     }

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

  437.     if (location == NULL) {
  438.         return NGX_ERROR;
  439.     }

  440.     if (overwrite != NGX_HTTP_MOVED_PERMANENTLY
  441.         && overwrite != NGX_HTTP_MOVED_TEMPORARILY
  442.         && overwrite != NGX_HTTP_SEE_OTHER
  443.         && overwrite != NGX_HTTP_TEMPORARY_REDIRECT)
  444.     {
  445.         r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
  446.     }

  447.     location->hash = 1;
  448.     ngx_str_set(&location->key, "Location");
  449.     location->value = uri;

  450.     ngx_http_clear_location(r);

  451.     r->headers_out.location = location;

  452.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  453.     if (clcf->msie_refresh && r->headers_in.msie) {
  454.         return ngx_http_send_refresh(r);
  455.     }

  456.     return ngx_http_send_special_response(r, clcf, r->err_status
  457.                                                    - NGX_HTTP_MOVED_PERMANENTLY
  458.                                                    + NGX_HTTP_OFF_3XX);
  459. }


  460. static ngx_int_t
  461. ngx_http_send_special_response(ngx_http_request_t *r,
  462.     ngx_http_core_loc_conf_t *clcf, ngx_uint_t err)
  463. {
  464.     u_char       *tail;
  465.     size_t        len;
  466.     ngx_int_t     rc;
  467.     ngx_buf_t    *b;
  468.     ngx_uint_t    msie_padding;
  469.     ngx_chain_t   out[3];

  470.     if (clcf->server_tokens) {
  471.         len = sizeof(ngx_http_error_full_tail) - 1;
  472.         tail = ngx_http_error_full_tail;

  473.     } else {
  474.         len = sizeof(ngx_http_error_tail) - 1;
  475.         tail = ngx_http_error_tail;
  476.     }

  477.     msie_padding = 0;

  478.     if (ngx_http_error_pages[err].len) {
  479.         r->headers_out.content_length_n = ngx_http_error_pages[err].len + len;
  480.         if (clcf->msie_padding
  481.             && (r->headers_in.msie || r->headers_in.chrome)
  482.             && r->http_version >= NGX_HTTP_VERSION_10
  483.             && err >= NGX_HTTP_OFF_4XX)
  484.         {
  485.             r->headers_out.content_length_n +=
  486.                                          sizeof(ngx_http_msie_padding) - 1;
  487.             msie_padding = 1;
  488.         }

  489.         r->headers_out.content_type_len = sizeof("text/html") - 1;
  490.         ngx_str_set(&r->headers_out.content_type, "text/html");
  491.         r->headers_out.content_type_lowcase = NULL;

  492.     } else {
  493.         r->headers_out.content_length_n = 0;
  494.     }

  495.     if (r->headers_out.content_length) {
  496.         r->headers_out.content_length->hash = 0;
  497.         r->headers_out.content_length = NULL;
  498.     }

  499.     ngx_http_clear_accept_ranges(r);
  500.     ngx_http_clear_last_modified(r);
  501.     ngx_http_clear_etag(r);

  502.     rc = ngx_http_send_header(r);

  503.     if (rc == NGX_ERROR || r->header_only) {
  504.         return rc;
  505.     }

  506.     if (ngx_http_error_pages[err].len == 0) {
  507.         return ngx_http_send_special(r, NGX_HTTP_LAST);
  508.     }

  509.     b = ngx_calloc_buf(r->pool);
  510.     if (b == NULL) {
  511.         return NGX_ERROR;
  512.     }

  513.     b->memory = 1;
  514.     b->pos = ngx_http_error_pages[err].data;
  515.     b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len;

  516.     out[0].buf = b;
  517.     out[0].next = &out[1];

  518.     b = ngx_calloc_buf(r->pool);
  519.     if (b == NULL) {
  520.         return NGX_ERROR;
  521.     }

  522.     b->memory = 1;

  523.     b->pos = tail;
  524.     b->last = tail + len;

  525.     out[1].buf = b;
  526.     out[1].next = NULL;

  527.     if (msie_padding) {
  528.         b = ngx_calloc_buf(r->pool);
  529.         if (b == NULL) {
  530.             return NGX_ERROR;
  531.         }

  532.         b->memory = 1;
  533.         b->pos = ngx_http_msie_padding;
  534.         b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1;

  535.         out[1].next = &out[2];
  536.         out[2].buf = b;
  537.         out[2].next = NULL;
  538.     }

  539.     if (r == r->main) {
  540.         b->last_buf = 1;
  541.     }

  542.     b->last_in_chain = 1;

  543.     return ngx_http_output_filter(r, &out[0]);
  544. }


  545. static ngx_int_t
  546. ngx_http_send_refresh(ngx_http_request_t *r)
  547. {
  548.     u_char       *p, *location;
  549.     size_t        len, size;
  550.     uintptr_t     escape;
  551.     ngx_int_t     rc;
  552.     ngx_buf_t    *b;
  553.     ngx_chain_t   out;

  554.     len = r->headers_out.location->value.len;
  555.     location = r->headers_out.location->value.data;

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

  557.     size = sizeof(ngx_http_msie_refresh_head) - 1
  558.            + escape + len
  559.            + sizeof(ngx_http_msie_refresh_tail) - 1;

  560.     r->err_status = NGX_HTTP_OK;

  561.     r->headers_out.content_type_len = sizeof("text/html") - 1;
  562.     ngx_str_set(&r->headers_out.content_type, "text/html");
  563.     r->headers_out.content_type_lowcase = NULL;

  564.     r->headers_out.location->hash = 0;
  565.     r->headers_out.location = NULL;

  566.     r->headers_out.content_length_n = size;

  567.     if (r->headers_out.content_length) {
  568.         r->headers_out.content_length->hash = 0;
  569.         r->headers_out.content_length = NULL;
  570.     }

  571.     ngx_http_clear_accept_ranges(r);
  572.     ngx_http_clear_last_modified(r);
  573.     ngx_http_clear_etag(r);

  574.     rc = ngx_http_send_header(r);

  575.     if (rc == NGX_ERROR || r->header_only) {
  576.         return rc;
  577.     }

  578.     b = ngx_create_temp_buf(r->pool, size);
  579.     if (b == NULL) {
  580.         return NGX_ERROR;
  581.     }

  582.     p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head,
  583.                    sizeof(ngx_http_msie_refresh_head) - 1);

  584.     if (escape == 0) {
  585.         p = ngx_cpymem(p, location, len);

  586.     } else {
  587.         p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH);
  588.     }

  589.     b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail,
  590.                          sizeof(ngx_http_msie_refresh_tail) - 1);

  591.     b->last_buf = 1;
  592.     b->last_in_chain = 1;

  593.     out.buf = b;
  594.     out.next = NULL;

  595.     return ngx_http_output_filter(r, &out);
  596. }