1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_router.h>
8 #include <nxt_http.h>
9 
10 
11 static void nxt_http_request_send_error_body(nxt_task_t *task, void *r,
12     void *data);
13 
14 
15 static const nxt_http_request_state_t  nxt_http_request_send_error_body_state;
16 
17 
18 static const char  error[] =
19     "<!DOCTYPE html>"
20     "<title>Error %03d</title>"
21     "<p>Error %03d.\r\n";
22 
23 /* Two %03d (4 chars) patterns are replaced by status code (3 chars). */
24 #define NXT_HTTP_ERROR_LEN  (nxt_length(error) - 2)
25 
26 
27 void
nxt_http_request_error(nxt_task_t * task,nxt_http_request_t * r,nxt_http_status_t status)28 nxt_http_request_error(nxt_task_t *task, nxt_http_request_t *r,
29     nxt_http_status_t status)
30 {
31     nxt_http_field_t  *content_type;
32 
33     nxt_debug(task, "http request error: %d", status);
34 
35     if (r->header_sent || r->error) {
36         goto fail;
37     }
38 
39     r->error = (status == NXT_HTTP_INTERNAL_SERVER_ERROR);
40 
41     r->status = status;
42 
43     r->resp.fields = nxt_list_create(r->mem_pool, 8, sizeof(nxt_http_field_t));
44     if (nxt_slow_path(r->resp.fields == NULL)) {
45         goto fail;
46     }
47 
48     content_type = nxt_list_zero_add(r->resp.fields);
49     if (nxt_slow_path(content_type == NULL)) {
50         goto fail;
51     }
52 
53     nxt_http_field_set(content_type, "Content-Type", "text/html");
54 
55     r->resp.content_length = NULL;
56     r->resp.content_length_n = NXT_HTTP_ERROR_LEN;
57 
58     r->state = &nxt_http_request_send_error_body_state;
59 
60     nxt_http_request_header_send(task, r,
61                                  nxt_http_request_send_error_body, NULL);
62     return;
63 
64 fail:
65 
66     nxt_http_request_error_handler(task, r, r->proto.any);
67 }
68 
69 
70 static const nxt_http_request_state_t  nxt_http_request_send_error_body_state
71     nxt_aligned(64) =
72 {
73     .error_handler = nxt_http_request_error_handler,
74 };
75 
76 
77 static void
nxt_http_request_send_error_body(nxt_task_t * task,void * obj,void * data)78 nxt_http_request_send_error_body(nxt_task_t *task, void *obj, void *data)
79 {
80     nxt_buf_t           *out;
81     nxt_http_request_t  *r;
82 
83     r = obj;
84 
85     nxt_debug(task, "http request send error body");
86 
87     out = nxt_http_buf_mem(task, r, NXT_HTTP_ERROR_LEN);
88     if (nxt_slow_path(out == NULL)) {
89         goto fail;
90     }
91 
92     out->mem.free = nxt_sprintf(out->mem.pos, out->mem.end, error,
93                                 r->status, r->status);
94 
95     out->next = nxt_http_buf_last(r);
96 
97     nxt_http_request_send(task, r, out);
98 
99     return;
100 
101 fail:
102 
103     nxt_http_request_error_handler(task, r, r->proto.any);
104 }
105