divide special response handling into several functions
fix "?" escaping introduced in r1467
Igor Sysoev
14 years ago
9 | 9 | #include <nginx.h> |
10 | 10 | |
11 | 11 | |
12 | static u_char error_full_tail[] = | |
12 | static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r, | |
13 | ngx_http_err_page_t *err_page); | |
14 | static ngx_int_t ngx_http_send_special_response(ngx_http_request_t *r, | |
15 | ngx_http_core_loc_conf_t *clcf, ngx_uint_t err); | |
16 | static ngx_int_t ngx_http_send_refresh(ngx_http_request_t *r); | |
17 | ||
18 | ||
19 | static u_char ngx_http_error_full_tail[] = | |
13 | 20 | "<hr><center>" NGINX_VER "</center>" CRLF |
14 | 21 | "</body>" CRLF |
15 | 22 | "</html>" CRLF |
16 | 23 | ; |
17 | 24 | |
18 | 25 | |
19 | static u_char error_tail[] = | |
26 | static u_char ngx_http_error_tail[] = | |
20 | 27 | "<hr><center>nginx</center>" CRLF |
21 | 28 | "</body>" CRLF |
22 | 29 | "</html>" CRLF |
41 | 48 | "\"></head><body></body></html>" CRLF; |
42 | 49 | |
43 | 50 | |
44 | static char error_301_page[] = | |
51 | static char ngx_http_error_301_page[] = | |
45 | 52 | "<html>" CRLF |
46 | 53 | "<head><title>301 Moved Permanently</title></head>" CRLF |
47 | 54 | "<body bgcolor=\"white\">" CRLF |
49 | 56 | ; |
50 | 57 | |
51 | 58 | |
52 | static char error_302_page[] = | |
59 | static char ngx_http_error_302_page[] = | |
53 | 60 | "<html>" CRLF |
54 | 61 | "<head><title>302 Found</title></head>" CRLF |
55 | 62 | "<body bgcolor=\"white\">" CRLF |
57 | 64 | ; |
58 | 65 | |
59 | 66 | |
60 | static char error_400_page[] = | |
67 | static char ngx_http_error_400_page[] = | |
61 | 68 | "<html>" CRLF |
62 | 69 | "<head><title>400 Bad Request</title></head>" CRLF |
63 | 70 | "<body bgcolor=\"white\">" CRLF |
65 | 72 | ; |
66 | 73 | |
67 | 74 | |
68 | static char error_401_page[] = | |
75 | static char ngx_http_error_401_page[] = | |
69 | 76 | "<html>" CRLF |
70 | 77 | "<head><title>401 Authorization Required</title></head>" CRLF |
71 | 78 | "<body bgcolor=\"white\">" CRLF |
73 | 80 | ; |
74 | 81 | |
75 | 82 | |
76 | static char error_402_page[] = | |
83 | static char ngx_http_error_402_page[] = | |
77 | 84 | "<html>" CRLF |
78 | 85 | "<head><title>402 Payment Required</title></head>" CRLF |
79 | 86 | "<body bgcolor=\"white\">" CRLF |
81 | 88 | ; |
82 | 89 | |
83 | 90 | |
84 | static char error_403_page[] = | |
91 | static char ngx_http_error_403_page[] = | |
85 | 92 | "<html>" CRLF |
86 | 93 | "<head><title>403 Forbidden</title></head>" CRLF |
87 | 94 | "<body bgcolor=\"white\">" CRLF |
89 | 96 | ; |
90 | 97 | |
91 | 98 | |
92 | static char error_404_page[] = | |
99 | static char ngx_http_error_404_page[] = | |
93 | 100 | "<html>" CRLF |
94 | 101 | "<head><title>404 Not Found</title></head>" CRLF |
95 | 102 | "<body bgcolor=\"white\">" CRLF |
97 | 104 | ; |
98 | 105 | |
99 | 106 | |
100 | static char error_405_page[] = | |
107 | static char ngx_http_error_405_page[] = | |
101 | 108 | "<html>" CRLF |
102 | 109 | "<head><title>405 Not Allowed</title></head>" CRLF |
103 | 110 | "<body bgcolor=\"white\">" CRLF |
105 | 112 | ; |
106 | 113 | |
107 | 114 | |
108 | static char error_406_page[] = | |
115 | static char ngx_http_error_406_page[] = | |
109 | 116 | "<html>" CRLF |
110 | 117 | "<head><title>406 Not Acceptable</title></head>" CRLF |
111 | 118 | "<body bgcolor=\"white\">" CRLF |
113 | 120 | ; |
114 | 121 | |
115 | 122 | |
116 | static char error_408_page[] = | |
123 | static char ngx_http_error_408_page[] = | |
117 | 124 | "<html>" CRLF |
118 | 125 | "<head><title>408 Request Time-out</title></head>" CRLF |
119 | 126 | "<body bgcolor=\"white\">" CRLF |
121 | 128 | ; |
122 | 129 | |
123 | 130 | |
124 | static char error_409_page[] = | |
131 | static char ngx_http_error_409_page[] = | |
125 | 132 | "<html>" CRLF |
126 | 133 | "<head><title>409 Conflict</title></head>" CRLF |
127 | 134 | "<body bgcolor=\"white\">" CRLF |
129 | 136 | ; |
130 | 137 | |
131 | 138 | |
132 | static char error_410_page[] = | |
139 | static char ngx_http_error_410_page[] = | |
133 | 140 | "<html>" CRLF |
134 | 141 | "<head><title>410 Gone</title></head>" CRLF |
135 | 142 | "<body bgcolor=\"white\">" CRLF |
137 | 144 | ; |
138 | 145 | |
139 | 146 | |
140 | static char error_411_page[] = | |
147 | static char ngx_http_error_411_page[] = | |
141 | 148 | "<html>" CRLF |
142 | 149 | "<head><title>411 Length Required</title></head>" CRLF |
143 | 150 | "<body bgcolor=\"white\">" CRLF |
145 | 152 | ; |
146 | 153 | |
147 | 154 | |
148 | static char error_412_page[] = | |
155 | static char ngx_http_error_412_page[] = | |
149 | 156 | "<html>" CRLF |
150 | 157 | "<head><title>412 Precondition Failed</title></head>" CRLF |
151 | 158 | "<body bgcolor=\"white\">" CRLF |
153 | 160 | ; |
154 | 161 | |
155 | 162 | |
156 | static char error_413_page[] = | |
163 | static char ngx_http_error_413_page[] = | |
157 | 164 | "<html>" CRLF |
158 | 165 | "<head><title>413 Request Entity Too Large</title></head>" CRLF |
159 | 166 | "<body bgcolor=\"white\">" CRLF |
161 | 168 | ; |
162 | 169 | |
163 | 170 | |
164 | static char error_414_page[] = | |
171 | static char ngx_http_error_414_page[] = | |
165 | 172 | "<html>" CRLF |
166 | 173 | "<head><title>414 Request-URI Too Large</title></head>" CRLF |
167 | 174 | "<body bgcolor=\"white\">" CRLF |
169 | 176 | ; |
170 | 177 | |
171 | 178 | |
172 | static char error_415_page[] = | |
179 | static char ngx_http_error_415_page[] = | |
173 | 180 | "<html>" CRLF |
174 | 181 | "<head><title>415 Unsupported Media Type</title></head>" CRLF |
175 | 182 | "<body bgcolor=\"white\">" CRLF |
177 | 184 | ; |
178 | 185 | |
179 | 186 | |
180 | static char error_416_page[] = | |
187 | static char ngx_http_error_416_page[] = | |
181 | 188 | "<html>" CRLF |
182 | 189 | "<head><title>416 Requested Range Not Satisfiable</title></head>" CRLF |
183 | 190 | "<body bgcolor=\"white\">" CRLF |
185 | 192 | ; |
186 | 193 | |
187 | 194 | |
188 | static char error_495_page[] = | |
195 | static char ngx_http_error_495_page[] = | |
189 | 196 | "<html>" CRLF |
190 | 197 | "<head><title>400 The SSL certificate error</title></head>" |
191 | 198 | CRLF |
195 | 202 | ; |
196 | 203 | |
197 | 204 | |
198 | static char error_496_page[] = | |
205 | static char ngx_http_error_496_page[] = | |
199 | 206 | "<html>" CRLF |
200 | 207 | "<head><title>400 No required SSL certificate was sent</title></head>" |
201 | 208 | CRLF |
205 | 212 | ; |
206 | 213 | |
207 | 214 | |
208 | static char error_497_page[] = | |
215 | static char ngx_http_error_497_page[] = | |
209 | 216 | "<html>" CRLF |
210 | 217 | "<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>" |
211 | 218 | CRLF |
215 | 222 | ; |
216 | 223 | |
217 | 224 | |
218 | static char error_500_page[] = | |
225 | static char ngx_http_error_500_page[] = | |
219 | 226 | "<html>" CRLF |
220 | 227 | "<head><title>500 Internal Server Error</title></head>" CRLF |
221 | 228 | "<body bgcolor=\"white\">" CRLF |
223 | 230 | ; |
224 | 231 | |
225 | 232 | |
226 | static char error_501_page[] = | |
233 | static char ngx_http_error_501_page[] = | |
227 | 234 | "<html>" CRLF |
228 | 235 | "<head><title>501 Method Not Implemented</title></head>" CRLF |
229 | 236 | "<body bgcolor=\"white\">" CRLF |
231 | 238 | ; |
232 | 239 | |
233 | 240 | |
234 | static char error_502_page[] = | |
241 | static char ngx_http_error_502_page[] = | |
235 | 242 | "<html>" CRLF |
236 | 243 | "<head><title>502 Bad Gateway</title></head>" CRLF |
237 | 244 | "<body bgcolor=\"white\">" CRLF |
239 | 246 | ; |
240 | 247 | |
241 | 248 | |
242 | static char error_503_page[] = | |
249 | static char ngx_http_error_503_page[] = | |
243 | 250 | "<html>" CRLF |
244 | 251 | "<head><title>503 Service Temporarily Unavailable</title></head>" CRLF |
245 | 252 | "<body bgcolor=\"white\">" CRLF |
247 | 254 | ; |
248 | 255 | |
249 | 256 | |
250 | static char error_504_page[] = | |
257 | static char ngx_http_error_504_page[] = | |
251 | 258 | "<html>" CRLF |
252 | 259 | "<head><title>504 Gateway Time-out</title></head>" CRLF |
253 | 260 | "<body bgcolor=\"white\">" CRLF |
255 | 262 | ; |
256 | 263 | |
257 | 264 | |
258 | static char error_507_page[] = | |
265 | static char ngx_http_error_507_page[] = | |
259 | 266 | "<html>" CRLF |
260 | 267 | "<head><title>507 Insufficient Storage</title></head>" CRLF |
261 | 268 | "<body bgcolor=\"white\">" CRLF |
263 | 270 | ; |
264 | 271 | |
265 | 272 | |
266 | static ngx_str_t error_pages[] = { | |
267 | ||
268 | ngx_null_string, /* 201, 204 */ | |
273 | static ngx_str_t ngx_http_error_pages[] = { | |
274 | ||
275 | ngx_null_string, /* 201, 204 */ | |
269 | 276 | |
270 | 277 | #define NGX_HTTP_LEVEL_200 1 |
271 | 278 | |
272 | /* ngx_null_string, */ /* 300 */ | |
273 | ngx_string(error_301_page), | |
274 | ngx_string(error_302_page), | |
275 | ngx_null_string, /* 303 */ | |
279 | /* ngx_null_string, */ /* 300 */ | |
280 | ngx_string(ngx_http_error_301_page), | |
281 | ngx_string(ngx_http_error_302_page), | |
282 | ngx_null_string, /* 303 */ | |
276 | 283 | |
277 | 284 | #define NGX_HTTP_LEVEL_300 3 |
278 | 285 | |
279 | ngx_string(error_400_page), | |
280 | ngx_string(error_401_page), | |
281 | ngx_string(error_402_page), | |
282 | ngx_string(error_403_page), | |
283 | ngx_string(error_404_page), | |
284 | ngx_string(error_405_page), | |
285 | ngx_string(error_406_page), | |
286 | ngx_null_string, /* 407 */ | |
287 | ngx_string(error_408_page), | |
288 | ngx_string(error_409_page), | |
289 | ngx_string(error_410_page), | |
290 | ngx_string(error_411_page), | |
291 | ngx_string(error_412_page), | |
292 | ngx_string(error_413_page), | |
293 | ngx_string(error_414_page), | |
294 | ngx_string(error_415_page), | |
295 | ngx_string(error_416_page), | |
286 | ngx_string(ngx_http_error_400_page), | |
287 | ngx_string(ngx_http_error_401_page), | |
288 | ngx_string(ngx_http_error_402_page), | |
289 | ngx_string(ngx_http_error_403_page), | |
290 | ngx_string(ngx_http_error_404_page), | |
291 | ngx_string(ngx_http_error_405_page), | |
292 | ngx_string(ngx_http_error_406_page), | |
293 | ngx_null_string, /* 407 */ | |
294 | ngx_string(ngx_http_error_408_page), | |
295 | ngx_string(ngx_http_error_409_page), | |
296 | ngx_string(ngx_http_error_410_page), | |
297 | ngx_string(ngx_http_error_411_page), | |
298 | ngx_string(ngx_http_error_412_page), | |
299 | ngx_string(ngx_http_error_413_page), | |
300 | ngx_string(ngx_http_error_414_page), | |
301 | ngx_string(ngx_http_error_415_page), | |
302 | ngx_string(ngx_http_error_416_page), | |
296 | 303 | |
297 | 304 | #define NGX_HTTP_LEVEL_400 17 |
298 | 305 | |
299 | ngx_string(error_495_page), /* 495, https certificate error */ | |
300 | ngx_string(error_496_page), /* 496, https no certificate */ | |
301 | ngx_string(error_497_page), /* 497, http to https */ | |
302 | ngx_string(error_404_page), /* 498, invalid host name */ | |
303 | ngx_null_string, /* 499, client had closed connection */ | |
304 | ||
305 | ngx_string(error_500_page), | |
306 | ngx_string(error_501_page), | |
307 | ngx_string(error_502_page), | |
308 | ngx_string(error_503_page), | |
309 | ngx_string(error_504_page), | |
310 | ngx_null_string, /* 505 */ | |
311 | ngx_null_string, /* 506 */ | |
312 | ngx_string(error_507_page) | |
306 | ngx_string(ngx_http_error_495_page), /* 495, https certificate error */ | |
307 | ngx_string(ngx_http_error_496_page), /* 496, https no certificate */ | |
308 | ngx_string(ngx_http_error_497_page), /* 497, http to https */ | |
309 | ngx_string(ngx_http_error_404_page), /* 498, invalid host name */ | |
310 | ngx_null_string, /* 499, client has closed connection */ | |
311 | ||
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_null_string, /* 505 */ | |
318 | ngx_null_string, /* 506 */ | |
319 | ngx_string(ngx_http_error_507_page) | |
313 | 320 | }; |
314 | 321 | |
315 | 322 | |
319 | 326 | ngx_int_t |
320 | 327 | ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) |
321 | 328 | { |
322 | u_char *p; | |
323 | size_t msie_refresh; | |
324 | uintptr_t escape; | |
325 | 329 | ngx_int_t rc; |
326 | ngx_buf_t *b; | |
327 | ngx_str_t *uri, *location; | |
328 | ngx_uint_t i, n, err, msie_padding; | |
329 | ngx_chain_t *out, *cl; | |
330 | ngx_uint_t i, err; | |
330 | 331 | ngx_http_err_page_t *err_page; |
331 | 332 | ngx_http_core_loc_conf_t *clcf; |
332 | 333 | |
377 | 378 | err_page = clcf->error_pages->elts; |
378 | 379 | |
379 | 380 | for (i = 0; i < clcf->error_pages->nelts; i++) { |
380 | ||
381 | 381 | if (err_page[i].status == error) { |
382 | r->err_status = err_page[i].overwrite; | |
383 | ||
384 | r->method = NGX_HTTP_GET; | |
385 | r->method_name = ngx_http_get_name; | |
386 | ||
387 | uri = &err_page[i].uri; | |
388 | ||
389 | if (err_page[i].uri_lengths) { | |
390 | if (ngx_http_script_run(r, uri, | |
391 | err_page[i].uri_lengths->elts, 0, | |
392 | err_page[i].uri_values->elts) | |
393 | == NULL) | |
394 | { | |
395 | return NGX_ERROR; | |
396 | } | |
397 | ||
398 | if (r->zero_in_uri) { | |
399 | for (n = 0; n < uri->len; n++) { | |
400 | if (uri->data[n] == '\0') { | |
401 | goto zero; | |
402 | } | |
403 | } | |
404 | ||
405 | r->zero_in_uri = 0; | |
406 | } | |
407 | ||
408 | } else { | |
409 | r->zero_in_uri = 0; | |
410 | } | |
411 | ||
412 | zero: | |
413 | ||
414 | if (uri->data[0] == '/') { | |
415 | return ngx_http_internal_redirect(r, uri, NULL); | |
416 | } | |
417 | ||
418 | if (uri->data[0] == '@') { | |
419 | return ngx_http_named_location(r, uri); | |
420 | } | |
421 | ||
422 | r->headers_out.location = | |
423 | ngx_list_push(&r->headers_out.headers); | |
424 | ||
425 | if (r->headers_out.location) { | |
426 | error = NGX_HTTP_MOVED_TEMPORARILY; | |
427 | ||
428 | r->err_status = NGX_HTTP_MOVED_TEMPORARILY; | |
429 | ||
430 | r->headers_out.location->hash = 1; | |
431 | r->headers_out.location->key.len = sizeof("Location") - 1; | |
432 | r->headers_out.location->key.data = (u_char *) "Location"; | |
433 | r->headers_out.location->value = *uri; | |
434 | ||
435 | } else { | |
436 | return NGX_ERROR; | |
437 | } | |
382 | return ngx_http_send_error_page(r, &err_page[i]); | |
438 | 383 | } |
439 | 384 | } |
385 | } | |
386 | ||
387 | if (clcf->msie_refresh | |
388 | && r->headers_in.msie | |
389 | && (error == NGX_HTTP_MOVED_PERMANENTLY | |
390 | || error == NGX_HTTP_MOVED_TEMPORARILY)) | |
391 | { | |
392 | return ngx_http_send_refresh(r); | |
440 | 393 | } |
441 | 394 | |
442 | 395 | if (error == NGX_HTTP_CREATED) { |
467 | 420 | case NGX_HTTPS_CERT_ERROR: |
468 | 421 | case NGX_HTTPS_NO_CERT: |
469 | 422 | r->err_status = NGX_HTTP_BAD_REQUEST; |
470 | error = NGX_HTTP_BAD_REQUEST; | |
471 | 423 | break; |
472 | 424 | } |
473 | 425 | } |
474 | 426 | |
427 | return ngx_http_send_special_response(r, clcf, err); | |
428 | } | |
429 | ||
430 | ||
431 | static ngx_int_t | |
432 | ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) | |
433 | { | |
434 | u_char ch, *p, *last; | |
435 | ngx_str_t *uri, *args, u, a; | |
436 | ngx_table_elt_t *location; | |
437 | ngx_http_core_loc_conf_t *clcf; | |
438 | ||
439 | r->err_status = err_page->overwrite; | |
440 | ||
441 | r->method = NGX_HTTP_GET; | |
442 | r->method_name = ngx_http_get_name; | |
443 | ||
444 | r->zero_in_uri = 0; | |
445 | ||
446 | args = NULL; | |
447 | ||
448 | if (err_page->uri_lengths) { | |
449 | if (ngx_http_script_run(r, &u, err_page->uri_lengths->elts, 0, | |
450 | err_page->uri_values->elts) | |
451 | == NULL) | |
452 | { | |
453 | return NGX_ERROR; | |
454 | } | |
455 | ||
456 | p = u.data; | |
457 | uri = &u; | |
458 | ||
459 | if (*p == '/') { | |
460 | ||
461 | last = p + uri->len; | |
462 | ||
463 | while (p < last) { | |
464 | ||
465 | ch = *p++; | |
466 | ||
467 | if (ch == '?') { | |
468 | a.len = last - p; | |
469 | a.data = p; | |
470 | args = &a; | |
471 | ||
472 | u.len = p - 1 - u.data; | |
473 | ||
474 | while (p < last) { | |
475 | if (*p++ == '\0') { | |
476 | r->zero_in_uri = 1; | |
477 | break; | |
478 | } | |
479 | } | |
480 | ||
481 | break; | |
482 | } | |
483 | ||
484 | if (ch == '\0') { | |
485 | r->zero_in_uri = 1; | |
486 | continue; | |
487 | } | |
488 | } | |
489 | } | |
490 | ||
491 | } else { | |
492 | uri = &err_page->uri; | |
493 | } | |
494 | ||
495 | if (uri->data[0] == '/') { | |
496 | return ngx_http_internal_redirect(r, uri, args); | |
497 | } | |
498 | ||
499 | if (uri->data[0] == '@') { | |
500 | return ngx_http_named_location(r, uri); | |
501 | } | |
502 | ||
503 | location = ngx_list_push(&r->headers_out.headers); | |
504 | ||
505 | if (location == NULL) { | |
506 | return NGX_ERROR; | |
507 | } | |
508 | ||
509 | r->err_status = NGX_HTTP_MOVED_TEMPORARILY; | |
510 | ||
511 | location->hash = 1; | |
512 | location->key.len = sizeof("Location") - 1; | |
513 | location->key.data = (u_char *) "Location"; | |
514 | location->value = *uri; | |
515 | ||
516 | r->headers_out.location = location; | |
517 | ||
518 | clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
519 | ||
520 | if (clcf->msie_refresh && r->headers_in.msie) { | |
521 | return ngx_http_send_refresh(r); | |
522 | } | |
523 | ||
524 | return ngx_http_send_special_response(r, clcf, NGX_HTTP_MOVED_TEMPORARILY | |
525 | - NGX_HTTP_MOVED_PERMANENTLY | |
526 | + NGX_HTTP_LEVEL_200); | |
527 | } | |
528 | ||
529 | ||
530 | static ngx_int_t | |
531 | ngx_http_send_special_response(ngx_http_request_t *r, | |
532 | ngx_http_core_loc_conf_t *clcf, ngx_uint_t err) | |
533 | { | |
534 | u_char *tail; | |
535 | size_t len; | |
536 | ngx_int_t rc; | |
537 | ngx_buf_t *b; | |
538 | ngx_uint_t msie_padding; | |
539 | ngx_chain_t out[3]; | |
540 | ||
541 | if (clcf->server_tokens) { | |
542 | len = sizeof(ngx_http_error_full_tail) - 1; | |
543 | tail = ngx_http_error_full_tail; | |
544 | ||
545 | } else { | |
546 | len = sizeof(ngx_http_error_tail) - 1; | |
547 | tail = ngx_http_error_tail; | |
548 | } | |
549 | ||
475 | 550 | msie_padding = 0; |
476 | 551 | |
477 | 552 | if (!r->zero_body) { |
478 | if (error_pages[err].len) { | |
479 | r->headers_out.content_length_n = error_pages[err].len | |
480 | + (clcf->server_tokens ? sizeof(error_full_tail) - 1: | |
481 | sizeof(error_tail) - 1); | |
482 | ||
553 | if (ngx_http_error_pages[err].len) { | |
554 | r->headers_out.content_length_n = ngx_http_error_pages[err].len | |
555 | + len; | |
483 | 556 | if (clcf->msie_padding |
484 | 557 | && r->headers_in.msie |
485 | 558 | && r->http_version >= NGX_HTTP_VERSION_10 |
486 | && error >= NGX_HTTP_BAD_REQUEST | |
487 | && error != NGX_HTTP_REQUEST_URI_TOO_LARGE) | |
559 | && err >= NGX_HTTP_LEVEL_300) | |
488 | 560 | { |
489 | 561 | r->headers_out.content_length_n += |
490 | 562 | sizeof(ngx_http_msie_stub) - 1; |
491 | 563 | msie_padding = 1; |
492 | 564 | } |
493 | 565 | |
566 | r->headers_out.content_type_len = sizeof("text/html") - 1; | |
494 | 567 | r->headers_out.content_type.len = sizeof("text/html") - 1; |
495 | 568 | r->headers_out.content_type.data = (u_char *) "text/html"; |
496 | 569 | |
508 | 581 | r->headers_out.content_length = NULL; |
509 | 582 | } |
510 | 583 | |
511 | if (clcf->msie_refresh | |
512 | && r->headers_in.msie | |
513 | && (error == NGX_HTTP_MOVED_PERMANENTLY | |
514 | || error == NGX_HTTP_MOVED_TEMPORARILY)) | |
515 | { | |
516 | ||
517 | location = &r->headers_out.location->value; | |
518 | ||
519 | escape = 2 * ngx_escape_uri(NULL, location->data, location->len, | |
520 | NGX_ESCAPE_REFRESH); | |
521 | ||
522 | msie_refresh = sizeof(ngx_http_msie_refresh_head) - 1 | |
523 | + escape + location->len | |
524 | + sizeof(ngx_http_msie_refresh_tail) - 1; | |
525 | ||
526 | r->err_status = NGX_HTTP_OK; | |
527 | r->headers_out.content_type_len = sizeof("text/html") - 1; | |
528 | r->headers_out.content_length_n = msie_refresh; | |
529 | r->headers_out.location->hash = 0; | |
530 | r->headers_out.location = NULL; | |
531 | ||
532 | } else { | |
533 | location = NULL; | |
534 | escape = 0; | |
535 | msie_refresh = 0; | |
536 | } | |
537 | ||
538 | 584 | ngx_http_clear_accept_ranges(r); |
539 | 585 | ngx_http_clear_last_modified(r); |
540 | 586 | |
544 | 590 | return rc; |
545 | 591 | } |
546 | 592 | |
547 | ||
548 | if (msie_refresh == 0) { | |
549 | ||
550 | if (error_pages[err].len == 0) { | |
551 | return NGX_OK; | |
552 | } | |
553 | ||
593 | if (ngx_http_error_pages[err].len == 0) { | |
594 | return NGX_OK; | |
595 | } | |
596 | ||
597 | b = ngx_calloc_buf(r->pool); | |
598 | if (b == NULL) { | |
599 | return NGX_ERROR; | |
600 | } | |
601 | ||
602 | b->memory = 1; | |
603 | b->pos = ngx_http_error_pages[err].data; | |
604 | b->last = ngx_http_error_pages[err].data + ngx_http_error_pages[err].len; | |
605 | ||
606 | out[0].buf = b; | |
607 | out[0].next = &out[1]; | |
608 | ||
609 | b = ngx_calloc_buf(r->pool); | |
610 | if (b == NULL) { | |
611 | return NGX_ERROR; | |
612 | } | |
613 | ||
614 | b->memory = 1; | |
615 | ||
616 | b->pos = tail; | |
617 | b->last = tail + len; | |
618 | ||
619 | out[1].buf = b; | |
620 | out[1].next = NULL;; | |
621 | ||
622 | if (msie_padding) { | |
554 | 623 | b = ngx_calloc_buf(r->pool); |
555 | 624 | if (b == NULL) { |
556 | 625 | return NGX_ERROR; |
557 | 626 | } |
558 | 627 | |
559 | 628 | b->memory = 1; |
560 | b->pos = error_pages[err].data; | |
561 | b->last = error_pages[err].data + error_pages[err].len; | |
562 | ||
563 | cl = ngx_alloc_chain_link(r->pool); | |
564 | if (cl == NULL) { | |
565 | return NGX_ERROR; | |
566 | } | |
567 | ||
568 | cl->buf = b; | |
569 | out = cl; | |
570 | ||
571 | ||
572 | b = ngx_calloc_buf(r->pool); | |
573 | if (b == NULL) { | |
574 | return NGX_ERROR; | |
575 | } | |
576 | ||
577 | b->memory = 1; | |
578 | ||
579 | if (clcf->server_tokens) { | |
580 | b->pos = error_full_tail; | |
581 | b->last = error_full_tail + sizeof(error_full_tail) - 1; | |
582 | } else { | |
583 | b->pos = error_tail; | |
584 | b->last = error_tail + sizeof(error_tail) - 1; | |
585 | } | |
586 | ||
587 | cl->next = ngx_alloc_chain_link(r->pool); | |
588 | if (cl->next == NULL) { | |
589 | return NGX_ERROR; | |
590 | } | |
591 | ||
592 | cl = cl->next; | |
593 | cl->buf = b; | |
594 | ||
595 | if (msie_padding) { | |
596 | b = ngx_calloc_buf(r->pool); | |
597 | if (b == NULL) { | |
598 | return NGX_ERROR; | |
599 | } | |
600 | ||
601 | b->memory = 1; | |
602 | b->pos = ngx_http_msie_stub; | |
603 | b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1; | |
604 | ||
605 | cl->next = ngx_alloc_chain_link(r->pool); | |
606 | if (cl->next == NULL) { | |
607 | return NGX_ERROR; | |
608 | } | |
609 | ||
610 | cl = cl->next; | |
611 | cl->buf = b; | |
612 | } | |
613 | ||
614 | } else { | |
615 | b = ngx_create_temp_buf(r->pool, msie_refresh); | |
616 | if (b == NULL) { | |
617 | return NGX_ERROR; | |
618 | } | |
619 | ||
620 | p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head, | |
621 | sizeof(ngx_http_msie_refresh_head) - 1); | |
622 | ||
623 | if (escape == 0) { | |
624 | p = ngx_cpymem(p, location->data, location->len); | |
625 | ||
626 | } else { | |
627 | p = (u_char *) ngx_escape_uri(p, location->data, location->len, | |
628 | NGX_ESCAPE_REFRESH); | |
629 | } | |
630 | ||
631 | b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail, | |
632 | sizeof(ngx_http_msie_refresh_tail) - 1); | |
633 | ||
634 | cl = ngx_alloc_chain_link(r->pool); | |
635 | if (cl == NULL) { | |
636 | return NGX_ERROR; | |
637 | } | |
638 | ||
639 | cl->buf = b; | |
640 | out = cl; | |
629 | b->pos = ngx_http_msie_stub; | |
630 | b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1; | |
631 | ||
632 | out[1].next = &out[2]; | |
633 | out[2].buf = b; | |
634 | out[2].next = NULL;; | |
641 | 635 | } |
642 | 636 | |
643 | 637 | if (r == r->main) { |
646 | 640 | |
647 | 641 | b->last_in_chain = 1; |
648 | 642 | |
649 | cl->next = NULL; | |
650 | ||
651 | return ngx_http_output_filter(r, out); | |
643 | return ngx_http_output_filter(r, &out[0]); | |
652 | 644 | } |
645 | ||
646 | ||
647 | static ngx_int_t | |
648 | ngx_http_send_refresh(ngx_http_request_t *r) | |
649 | { | |
650 | u_char *p, *location; | |
651 | size_t len, size; | |
652 | uintptr_t escape; | |
653 | ngx_int_t rc; | |
654 | ngx_buf_t *b; | |
655 | ngx_chain_t out; | |
656 | ||
657 | len = r->headers_out.location->value.len; | |
658 | location = r->headers_out.location->value.data; | |
659 | ||
660 | escape = 2 * ngx_escape_uri(NULL, location, len, NGX_ESCAPE_REFRESH); | |
661 | ||
662 | size = sizeof(ngx_http_msie_refresh_head) - 1 | |
663 | + escape + len | |
664 | + sizeof(ngx_http_msie_refresh_tail) - 1; | |
665 | ||
666 | r->err_status = NGX_HTTP_OK; | |
667 | ||
668 | r->headers_out.content_type_len = sizeof("text/html") - 1; | |
669 | r->headers_out.content_type.len = sizeof("text/html") - 1; | |
670 | r->headers_out.content_type.data = (u_char *) "text/html"; | |
671 | ||
672 | r->headers_out.location->hash = 0; | |
673 | r->headers_out.location = NULL; | |
674 | ||
675 | r->headers_out.content_length_n = size; | |
676 | ||
677 | if (r->headers_out.content_length) { | |
678 | r->headers_out.content_length->hash = 0; | |
679 | r->headers_out.content_length = NULL; | |
680 | } | |
681 | ||
682 | ngx_http_clear_accept_ranges(r); | |
683 | ngx_http_clear_last_modified(r); | |
684 | ||
685 | rc = ngx_http_send_header(r); | |
686 | ||
687 | if (rc == NGX_ERROR || r->header_only) { | |
688 | return rc; | |
689 | } | |
690 | ||
691 | b = ngx_create_temp_buf(r->pool, size); | |
692 | if (b == NULL) { | |
693 | return NGX_ERROR; | |
694 | } | |
695 | ||
696 | p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head, | |
697 | sizeof(ngx_http_msie_refresh_head) - 1); | |
698 | ||
699 | if (escape == 0) { | |
700 | p = ngx_cpymem(p, location, len); | |
701 | ||
702 | } else { | |
703 | p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH); | |
704 | } | |
705 | ||
706 | b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail, | |
707 | sizeof(ngx_http_msie_refresh_tail) - 1); | |
708 | ||
709 | b->last_buf = 1; | |
710 | b->last_in_chain = 1; | |
711 | ||
712 | out.buf = b; | |
713 | out.next = NULL; | |
714 | ||
715 | return ngx_http_output_filter(r, &out); | |
716 | } |