src/http/ngx_http_special_response.c - nginx

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_407_page[] =
  114. "<html>" CRLF
  115. "<head><title>407 Proxy Authentication Required</title></head>" CRLF
  116. "<body>" CRLF
  117. "<center><h1>407 Proxy Authentication Required</h1></center>" CRLF
  118. ;


  119. static char ngx_http_error_408_page[] =
  120. "<html>" CRLF
  121. "<head><title>408 Request Time-out</title></head>" CRLF
  122. "<body>" CRLF
  123. "<center><h1>408 Request Time-out</h1></center>" CRLF
  124. ;


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


  131. static char ngx_http_error_410_page[] =
  132. "<html>" CRLF
  133. "<head><title>410 Gone</title></head>" CRLF
  134. "<body>" CRLF
  135. "<center><h1>410 Gone</h1></center>" CRLF
  136. ;


  137. static char ngx_http_error_411_page[] =
  138. "<html>" CRLF
  139. "<head><title>411 Length Required</title></head>" CRLF
  140. "<body>" CRLF
  141. "<center><h1>411 Length Required</h1></center>" CRLF
  142. ;


  143. static char ngx_http_error_412_page[] =
  144. "<html>" CRLF
  145. "<head><title>412 Precondition Failed</title></head>" CRLF
  146. "<body>" CRLF
  147. "<center><h1>412 Precondition Failed</h1></center>" CRLF
  148. ;


  149. static char ngx_http_error_413_page[] =
  150. "<html>" CRLF
  151. "<head><title>413 Request Entity Too Large</title></head>" CRLF
  152. "<body>" CRLF
  153. "<center><h1>413 Request Entity Too Large</h1></center>" CRLF
  154. ;


  155. static char ngx_http_error_414_page[] =
  156. "<html>" CRLF
  157. "<head><title>414 Request-URI Too Large</title></head>" CRLF
  158. "<body>" CRLF
  159. "<center><h1>414 Request-URI Too Large</h1></center>" CRLF
  160. ;


  161. static char ngx_http_error_415_page[] =
  162. "<html>" CRLF
  163. "<head><title>415 Unsupported Media Type</title></head>" CRLF
  164. "<body>" CRLF
  165. "<center><h1>415 Unsupported Media Type</h1></center>" CRLF
  166. ;


  167. static char ngx_http_error_416_page[] =
  168. "<html>" CRLF
  169. "<head><title>416 Requested Range Not Satisfiable</title></head>" CRLF
  170. "<body>" CRLF
  171. "<center><h1>416 Requested Range Not Satisfiable</h1></center>" CRLF
  172. ;


  173. static char ngx_http_error_421_page[] =
  174. "<html>" CRLF
  175. "<head><title>421 Misdirected Request</title></head>" CRLF
  176. "<body>" CRLF
  177. "<center><h1>421 Misdirected Request</h1></center>" CRLF
  178. ;


  179. static char ngx_http_error_429_page[] =
  180. "<html>" CRLF
  181. "<head><title>429 Too Many Requests</title></head>" CRLF
  182. "<body>" CRLF
  183. "<center><h1>429 Too Many Requests</h1></center>" CRLF
  184. ;


  185. static char ngx_http_error_494_page[] =
  186. "<html>" CRLF
  187. "<head><title>400 Request Header Or Cookie Too Large</title></head>"
  188. CRLF
  189. "<body>" CRLF
  190. "<center><h1>400 Bad Request</h1></center>" CRLF
  191. "<center>Request Header Or Cookie Too Large</center>" CRLF
  192. ;


  193. static char ngx_http_error_495_page[] =
  194. "<html>" CRLF
  195. "<head><title>400 The SSL certificate error</title></head>"
  196. CRLF
  197. "<body>" CRLF
  198. "<center><h1>400 Bad Request</h1></center>" CRLF
  199. "<center>The SSL certificate error</center>" CRLF
  200. ;


  201. static char ngx_http_error_496_page[] =
  202. "<html>" CRLF
  203. "<head><title>400 No required SSL certificate was sent</title></head>"
  204. CRLF
  205. "<body>" CRLF
  206. "<center><h1>400 Bad Request</h1></center>" CRLF
  207. "<center>No required SSL certificate was sent</center>" CRLF
  208. ;


  209. static char ngx_http_error_497_page[] =
  210. "<html>" CRLF
  211. "<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>"
  212. CRLF
  213. "<body>" CRLF
  214. "<center><h1>400 Bad Request</h1></center>" CRLF
  215. "<center>The plain HTTP request was sent to HTTPS port</center>" CRLF
  216. ;


  217. static char ngx_http_error_500_page[] =
  218. "<html>" CRLF
  219. "<head><title>500 Internal Server Error</title></head>" CRLF
  220. "<body>" CRLF
  221. "<center><h1>500 Internal Server Error</h1></center>" CRLF
  222. ;


  223. static char ngx_http_error_501_page[] =
  224. "<html>" CRLF
  225. "<head><title>501 Not Implemented</title></head>" CRLF
  226. "<body>" CRLF
  227. "<center><h1>501 Not Implemented</h1></center>" CRLF
  228. ;


  229. static char ngx_http_error_502_page[] =
  230. "<html>" CRLF
  231. "<head><title>502 Bad Gateway</title></head>" CRLF
  232. "<body>" CRLF
  233. "<center><h1>502 Bad Gateway</h1></center>" CRLF
  234. ;


  235. static char ngx_http_error_503_page[] =
  236. "<html>" CRLF
  237. "<head><title>503 Service Temporarily Unavailable</title></head>" CRLF
  238. "<body>" CRLF
  239. "<center><h1>503 Service Temporarily Unavailable</h1></center>" CRLF
  240. ;


  241. static char ngx_http_error_504_page[] =
  242. "<html>" CRLF
  243. "<head><title>504 Gateway Time-out</title></head>" CRLF
  244. "<body>" CRLF
  245. "<center><h1>504 Gateway Time-out</h1></center>" CRLF
  246. ;


  247. static char ngx_http_error_505_page[] =
  248. "<html>" CRLF
  249. "<head><title>505 HTTP Version Not Supported</title></head>" CRLF
  250. "<body>" CRLF
  251. "<center><h1>505 HTTP Version Not Supported</h1></center>" CRLF
  252. ;


  253. static char ngx_http_error_507_page[] =
  254. "<html>" CRLF
  255. "<head><title>507 Insufficient Storage</title></head>" CRLF
  256. "<body>" CRLF
  257. "<center><h1>507 Insufficient Storage</h1></center>" CRLF
  258. ;


  259. static ngx_str_t ngx_http_error_pages[] = {

  260.     ngx_null_string,                     /* 201, 204 */

  261. #define NGX_HTTP_LAST_2XX  202
  262. #define NGX_HTTP_OFF_3XX   (NGX_HTTP_LAST_2XX - 201)

  263.     /* ngx_null_string, */               /* 300 */
  264.     ngx_string(ngx_http_error_301_page),
  265.     ngx_string(ngx_http_error_302_page),
  266.     ngx_string(ngx_http_error_303_page),
  267.     ngx_null_string,                     /* 304 */
  268.     ngx_null_string,                     /* 305 */
  269.     ngx_null_string,                     /* 306 */
  270.     ngx_string(ngx_http_error_307_page),
  271.     ngx_string(ngx_http_error_308_page),

  272. #define NGX_HTTP_LAST_3XX  309
  273. #define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)

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

  304. #define NGX_HTTP_LAST_4XX  430
  305. #define NGX_HTTP_OFF_5XX   (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)

  306.     ngx_string(ngx_http_error_494_page), /* 494, request header too large */
  307.     ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
  308.     ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
  309.     ngx_string(ngx_http_error_497_page), /* 497, http to https */
  310.     ngx_string(ngx_http_error_404_page), /* 498, canceled */
  311.     ngx_null_string,                     /* 499, client has closed connection */

  312.     ngx_string(ngx_http_error_500_page),
  313.     ngx_string(ngx_http_error_501_page),
  314.     ngx_string(ngx_http_error_502_page),
  315.     ngx_string(ngx_http_error_503_page),
  316.     ngx_string(ngx_http_error_504_page),
  317.     ngx_string(ngx_http_error_505_page),
  318.     ngx_null_string,                     /* 506 */
  319.     ngx_string(ngx_http_error_507_page)

  320. #define NGX_HTTP_LAST_5XX  508

  321. };


  322. ngx_int_t
  323. ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
  324. {
  325.     ngx_uint_t                 i, err;
  326.     ngx_http_err_page_t       *err_page;
  327.     ngx_http_core_loc_conf_t  *clcf;

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

  331.     r->err_status = error;

  332.     if (r->keepalive) {
  333.         switch (error) {
  334.             case NGX_HTTP_BAD_REQUEST:
  335.             case NGX_HTTP_REQUEST_ENTITY_TOO_LARGE:
  336.             case NGX_HTTP_REQUEST_URI_TOO_LARGE:
  337.             case NGX_HTTP_TO_HTTPS:
  338.             case NGX_HTTPS_CERT_ERROR:
  339.             case NGX_HTTPS_NO_CERT:
  340.             case NGX_HTTP_INTERNAL_SERVER_ERROR:
  341.             case NGX_HTTP_NOT_IMPLEMENTED:
  342.                 r->keepalive = 0;
  343.         }
  344.     }

  345.     if (r->lingering_close) {
  346.         switch (error) {
  347.             case NGX_HTTP_BAD_REQUEST:
  348.             case NGX_HTTP_TO_HTTPS:
  349.             case NGX_HTTPS_CERT_ERROR:
  350.             case NGX_HTTPS_NO_CERT:
  351.                 r->lingering_close = 0;
  352.         }
  353.     }

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

  355.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

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

  357.         if (clcf->recursive_error_pages == 0) {
  358.             r->error_page = 1;
  359.         }

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

  361.         for (i = 0; i < clcf->error_pages->nelts; i++) {
  362.             if (err_page[i].status == error) {
  363.                 return ngx_http_send_error_page(r, &err_page[i]);
  364.             }
  365.         }
  366.     }

  367.     r->expect_tested = 1;

  368.     if (ngx_http_discard_request_body(r) != NGX_OK) {
  369.         r->keepalive = 0;
  370.     }

  371.     if (clcf->msie_refresh
  372.         && r->headers_in.msie
  373.         && (error == NGX_HTTP_MOVED_PERMANENTLY
  374.             || error == NGX_HTTP_MOVED_TEMPORARILY))
  375.     {
  376.         return ngx_http_send_refresh(r);
  377.     }

  378.     if (error == NGX_HTTP_CREATED) {
  379.         /* 201 */
  380.         err = 0;

  381.     } else if (error == NGX_HTTP_NO_CONTENT) {
  382.         /* 204 */
  383.         err = 0;

  384.     } else if (error >= NGX_HTTP_MOVED_PERMANENTLY
  385.                && error < NGX_HTTP_LAST_3XX)
  386.     {
  387.         /* 3XX */
  388.         err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX;

  389.     } else if (error >= NGX_HTTP_BAD_REQUEST
  390.                && error < NGX_HTTP_LAST_4XX)
  391.     {
  392.         /* 4XX */
  393.         err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX;

  394.     } else if (error >= NGX_HTTP_NGINX_CODES
  395.                && error < NGX_HTTP_LAST_5XX)
  396.     {
  397.         /* 49X, 5XX */
  398.         err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_OFF_5XX;
  399.         switch (error) {
  400.             case NGX_HTTP_TO_HTTPS:
  401.             case NGX_HTTPS_CERT_ERROR:
  402.             case NGX_HTTPS_NO_CERT:
  403.             case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:
  404.                 r->err_status = NGX_HTTP_BAD_REQUEST;
  405.         }

  406.     } else {
  407.         /* unknown code, zero body */
  408.         err = 0;
  409.     }

  410.     return ngx_http_send_special_response(r, clcf, err);
  411. }


  412. ngx_int_t
  413. ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_module_t *m,
  414.     ngx_int_t error)
  415. {
  416.     void       *ctx;
  417.     ngx_int_t   rc;

  418.     ngx_http_clean_header(r);

  419.     ctx = NULL;

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

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

  425.     if (m) {
  426.         r->ctx[m->ctx_index] = ctx;
  427.     }

  428.     r->filter_finalize = 1;

  429.     rc = ngx_http_special_response_handler(r, error);

  430.     /* NGX_ERROR resets any pending data */

  431.     switch (rc) {

  432.     case NGX_OK:
  433.     case NGX_DONE:
  434.         return NGX_ERROR;

  435.     default:
  436.         return rc;
  437.     }
  438. }


  439. void
  440. ngx_http_clean_header(ngx_http_request_t *r)
  441. {
  442.     ngx_memzero(&r->headers_out.status,
  443.                 sizeof(ngx_http_headers_out_t)
  444.                     - offsetof(ngx_http_headers_out_t, status));

  445.     r->headers_out.headers.part.nelts = 0;
  446.     r->headers_out.headers.part.next = NULL;
  447.     r->headers_out.headers.last = &r->headers_out.headers.part;

  448.     r->headers_out.trailers.part.nelts = 0;
  449.     r->headers_out.trailers.part.next = NULL;
  450.     r->headers_out.trailers.last = &r->headers_out.trailers.part;

  451.     r->headers_out.content_length_n = -1;
  452.     r->headers_out.last_modified_time = -1;
  453. }


  454. static ngx_int_t
  455. ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
  456. {
  457.     ngx_int_t                  overwrite;
  458.     ngx_str_t                  uri, args;
  459.     ngx_table_elt_t           *location;
  460.     ngx_http_core_loc_conf_t  *clcf;

  461.     overwrite = err_page->overwrite;

  462.     if (overwrite && overwrite != NGX_HTTP_OK) {
  463.         r->expect_tested = 1;
  464.     }

  465.     if (overwrite >= 0) {
  466.         r->err_status = overwrite;
  467.     }

  468.     if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {
  469.         return NGX_ERROR;
  470.     }

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

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

  474.         } else {
  475.             args = err_page->args;
  476.         }

  477.         if (r->method != NGX_HTTP_HEAD) {
  478.             r->method = NGX_HTTP_GET;
  479.             r->method_name = ngx_http_core_get_method;
  480.         }

  481.         return ngx_http_internal_redirect(r, &uri, &args);
  482.     }

  483.     if (uri.len && uri.data[0] == '@') {
  484.         return ngx_http_named_location(r, &uri);
  485.     }

  486.     r->expect_tested = 1;

  487.     if (ngx_http_discard_request_body(r) != NGX_OK) {
  488.         r->keepalive = 0;
  489.     }

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

  491.     if (location == NULL) {
  492.         return NGX_ERROR;
  493.     }

  494.     if (overwrite != NGX_HTTP_MOVED_PERMANENTLY
  495.         && overwrite != NGX_HTTP_MOVED_TEMPORARILY
  496.         && overwrite != NGX_HTTP_SEE_OTHER
  497.         && overwrite != NGX_HTTP_TEMPORARY_REDIRECT
  498.         && overwrite != NGX_HTTP_PERMANENT_REDIRECT)
  499.     {
  500.         r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
  501.     }

  502.     location->hash = 1;
  503.     location->next = NULL;
  504.     ngx_str_set(&location->key, "Location");
  505.     location->value = uri;

  506.     ngx_http_clear_location(r);

  507.     r->headers_out.location = location;

  508.     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  509.     if (clcf->msie_refresh && r->headers_in.msie) {
  510.         return ngx_http_send_refresh(r);
  511.     }

  512.     return ngx_http_send_special_response(r, clcf, r->err_status
  513.                                                    - NGX_HTTP_MOVED_PERMANENTLY
  514.                                                    + NGX_HTTP_OFF_3XX);
  515. }


  516. static ngx_int_t
  517. ngx_http_send_special_response(ngx_http_request_t *r,
  518.     ngx_http_core_loc_conf_t *clcf, ngx_uint_t err)
  519. {
  520.     u_char       *tail;
  521.     size_t        len;
  522.     ngx_int_t     rc;
  523.     ngx_buf_t    *b;
  524.     ngx_uint_t    msie_padding;
  525.     ngx_chain_t   out[3];

  526.     if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
  527.         len = sizeof(ngx_http_error_full_tail) - 1;
  528.         tail = ngx_http_error_full_tail;

  529.     } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
  530.         len = sizeof(ngx_http_error_build_tail) - 1;
  531.         tail = ngx_http_error_build_tail;

  532.     } else {
  533.         len = sizeof(ngx_http_error_tail) - 1;
  534.         tail = ngx_http_error_tail;
  535.     }

  536.     msie_padding = 0;

  537.     if (ngx_http_error_pages[err].len) {
  538.         r->headers_out.content_length_n = ngx_http_error_pages[err].len + len;
  539.         if (clcf->msie_padding
  540.             && (r->headers_in.msie || r->headers_in.chrome)
  541.             && r->http_version >= NGX_HTTP_VERSION_10
  542.             && err >= NGX_HTTP_OFF_4XX)
  543.         {
  544.             r->headers_out.content_length_n +=
  545.                                          sizeof(ngx_http_msie_padding) - 1;
  546.             msie_padding = 1;
  547.         }

  548.         r->headers_out.content_type_len = sizeof("text/html") - 1;
  549.         ngx_str_set(&r->headers_out.content_type, "text/html");
  550.         r->headers_out.content_type_lowcase = NULL;

  551.     } else {
  552.         r->headers_out.content_length_n = 0;
  553.     }

  554.     if (r->headers_out.content_length) {
  555.         r->headers_out.content_length->hash = 0;
  556.         r->headers_out.content_length = NULL;
  557.     }

  558.     ngx_http_clear_accept_ranges(r);
  559.     ngx_http_clear_last_modified(r);
  560.     ngx_http_clear_etag(r);

  561.     rc = ngx_http_send_header(r);

  562.     if (rc == NGX_ERROR || r->header_only) {
  563.         return rc;
  564.     }

  565.     if (ngx_http_error_pages[err].len == 0) {
  566.         return ngx_http_send_special(r, NGX_HTTP_LAST);
  567.     }

  568.     b = ngx_calloc_buf(r->pool);
  569.     if (b == NULL) {
  570.         return NGX_ERROR;
  571.     }

  572.     b->memory = 1;
  573.     b->pos = ngx_http_error_pages[err].data;
  574.     b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len;

  575.     out[0].buf = b;
  576.     out[0].next = &out[1];

  577.     b = ngx_calloc_buf(r->pool);
  578.     if (b == NULL) {
  579.         return NGX_ERROR;
  580.     }

  581.     b->memory = 1;

  582.     b->pos = tail;
  583.     b->last = tail + len;

  584.     out[1].buf = b;
  585.     out[1].next = NULL;

  586.     if (msie_padding) {
  587.         b = ngx_calloc_buf(r->pool);
  588.         if (b == NULL) {
  589.             return NGX_ERROR;
  590.         }

  591.         b->memory = 1;
  592.         b->pos = ngx_http_msie_padding;
  593.         b->last = ngx_http_msie_padding + sizeof(ngx_http_msie_padding) - 1;

  594.         out[1].next = &out[2];
  595.         out[2].buf = b;
  596.         out[2].next = NULL;
  597.     }

  598.     if (r == r->main) {
  599.         b->last_buf = 1;
  600.     }

  601.     b->last_in_chain = 1;

  602.     return ngx_http_output_filter(r, &out[0]);
  603. }


  604. static ngx_int_t
  605. ngx_http_send_refresh(ngx_http_request_t *r)
  606. {
  607.     u_char       *p, *location;
  608.     size_t        len, size;
  609.     uintptr_t     escape;
  610.     ngx_int_t     rc;
  611.     ngx_buf_t    *b;
  612.     ngx_chain_t   out;

  613.     len = r->headers_out.location->value.len;
  614.     location = r->headers_out.location->value.data;

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

  616.     size = sizeof(ngx_http_msie_refresh_head) - 1
  617.            + escape + len
  618.            + sizeof(ngx_http_msie_refresh_tail) - 1;

  619.     r->err_status = NGX_HTTP_OK;

  620.     r->headers_out.content_type_len = sizeof("text/html") - 1;
  621.     ngx_str_set(&r->headers_out.content_type, "text/html");
  622.     r->headers_out.content_type_lowcase = NULL;

  623.     r->headers_out.location->hash = 0;
  624.     r->headers_out.location = NULL;

  625.     r->headers_out.content_length_n = size;

  626.     if (r->headers_out.content_length) {
  627.         r->headers_out.content_length->hash = 0;
  628.         r->headers_out.content_length = NULL;
  629.     }

  630.     ngx_http_clear_accept_ranges(r);
  631.     ngx_http_clear_last_modified(r);
  632.     ngx_http_clear_etag(r);

  633.     rc = ngx_http_send_header(r);

  634.     if (rc == NGX_ERROR || r->header_only) {
  635.         return rc;
  636.     }

  637.     b = ngx_create_temp_buf(r->pool, size);
  638.     if (b == NULL) {
  639.         return NGX_ERROR;
  640.     }

  641.     p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head,
  642.                    sizeof(ngx_http_msie_refresh_head) - 1);

  643.     if (escape == 0) {
  644.         p = ngx_cpymem(p, location, len);

  645.     } else {
  646.         p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH);
  647.     }

  648.     b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail,
  649.                          sizeof(ngx_http_msie_refresh_tail) - 1);

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

  652.     out.buf = b;
  653.     out.next = NULL;

  654.     return ngx_http_output_filter(r, &out);
  655. }