1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
13 static ngx_int_t ngx_http_stub_status_handler(ngx_http_request_t *r);
14 static ngx_int_t ngx_http_stub_status_variable(ngx_http_request_t *r,
15     ngx_http_variable_value_t *v, uintptr_t data);
16 static ngx_int_t ngx_http_stub_status_add_variables(ngx_conf_t *cf);
17 static char *ngx_http_set_stub_status(ngx_conf_t *cf, ngx_command_t *cmd,
18     void *conf);
19 
20 
21 static ngx_command_t  ngx_http_status_commands[] = {
22 
23     { ngx_string("stub_status"),
24       NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1,
25       ngx_http_set_stub_status,
26       0,
27       0,
28       NULL },
29 
30       ngx_null_command
31 };
32 
33 
34 static ngx_http_module_t  ngx_http_stub_status_module_ctx = {
35     ngx_http_stub_status_add_variables,    /* preconfiguration */
36     NULL,                                  /* postconfiguration */
37 
38     NULL,                                  /* create main configuration */
39     NULL,                                  /* init main configuration */
40 
41     NULL,                                  /* create server configuration */
42     NULL,                                  /* merge server configuration */
43 
44     NULL,                                  /* create location configuration */
45     NULL                                   /* merge location configuration */
46 };
47 
48 
49 ngx_module_t  ngx_http_stub_status_module = {
50     NGX_MODULE_V1,
51     &ngx_http_stub_status_module_ctx,      /* module context */
52     ngx_http_status_commands,              /* module directives */
53     NGX_HTTP_MODULE,                       /* module type */
54     NULL,                                  /* init master */
55     NULL,                                  /* init module */
56     NULL,                                  /* init process */
57     NULL,                                  /* init thread */
58     NULL,                                  /* exit thread */
59     NULL,                                  /* exit process */
60     NULL,                                  /* exit master */
61     NGX_MODULE_V1_PADDING
62 };
63 
64 
65 static ngx_http_variable_t  ngx_http_stub_status_vars[] = {
66 
67     { ngx_string("connections_active"), NULL, ngx_http_stub_status_variable,
68       0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
69 
70     { ngx_string("connections_reading"), NULL, ngx_http_stub_status_variable,
71       1, NGX_HTTP_VAR_NOCACHEABLE, 0 },
72 
73     { ngx_string("connections_writing"), NULL, ngx_http_stub_status_variable,
74       2, NGX_HTTP_VAR_NOCACHEABLE, 0 },
75 
76     { ngx_string("connections_waiting"), NULL, ngx_http_stub_status_variable,
77       3, NGX_HTTP_VAR_NOCACHEABLE, 0 },
78 
79       ngx_http_null_variable
80 };
81 
82 
83 static ngx_int_t
ngx_http_stub_status_handler(ngx_http_request_t * r)84 ngx_http_stub_status_handler(ngx_http_request_t *r)
85 {
86     size_t             size;
87     ngx_int_t          rc;
88     ngx_buf_t         *b;
89     ngx_chain_t        out;
90     ngx_atomic_int_t   ap, hn, ac, rq, rd, wr, wa;
91 
92     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
93         return NGX_HTTP_NOT_ALLOWED;
94     }
95 
96     rc = ngx_http_discard_request_body(r);
97 
98     if (rc != NGX_OK) {
99         return rc;
100     }
101 
102     r->headers_out.content_type_len = sizeof("text/plain") - 1;
103     ngx_str_set(&r->headers_out.content_type, "text/plain");
104     r->headers_out.content_type_lowcase = NULL;
105 
106     if (r->method == NGX_HTTP_HEAD) {
107         r->headers_out.status = NGX_HTTP_OK;
108 
109         rc = ngx_http_send_header(r);
110 
111         if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
112             return rc;
113         }
114     }
115 
116     size = sizeof("Active connections:  \n") + NGX_ATOMIC_T_LEN
117            + sizeof("server accepts handled requests\n") - 1
118            + 6 + 3 * NGX_ATOMIC_T_LEN
119            + sizeof("Reading:  Writing:  Waiting:  \n") + 3 * NGX_ATOMIC_T_LEN;
120 
121     b = ngx_create_temp_buf(r->pool, size);
122     if (b == NULL) {
123         return NGX_HTTP_INTERNAL_SERVER_ERROR;
124     }
125 
126     out.buf = b;
127     out.next = NULL;
128 
129     ap = *ngx_stat_accepted;
130     hn = *ngx_stat_handled;
131     ac = *ngx_stat_active;
132     rq = *ngx_stat_requests;
133     rd = *ngx_stat_reading;
134     wr = *ngx_stat_writing;
135     wa = *ngx_stat_waiting;
136 
137     b->last = ngx_sprintf(b->last, "Active connections: %uA \n", ac);
138 
139     b->last = ngx_cpymem(b->last, "server accepts handled requests\n",
140                          sizeof("server accepts handled requests\n") - 1);
141 
142     b->last = ngx_sprintf(b->last, " %uA %uA %uA \n", ap, hn, rq);
143 
144     b->last = ngx_sprintf(b->last, "Reading: %uA Writing: %uA Waiting: %uA \n",
145                           rd, wr, wa);
146 
147     r->headers_out.status = NGX_HTTP_OK;
148     r->headers_out.content_length_n = b->last - b->pos;
149 
150     b->last_buf = (r == r->main) ? 1 : 0;
151     b->last_in_chain = 1;
152 
153     rc = ngx_http_send_header(r);
154 
155     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
156         return rc;
157     }
158 
159     return ngx_http_output_filter(r, &out);
160 }
161 
162 
163 static ngx_int_t
ngx_http_stub_status_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)164 ngx_http_stub_status_variable(ngx_http_request_t *r,
165     ngx_http_variable_value_t *v, uintptr_t data)
166 {
167     u_char            *p;
168     ngx_atomic_int_t   value;
169 
170     p = ngx_pnalloc(r->pool, NGX_ATOMIC_T_LEN);
171     if (p == NULL) {
172         return NGX_ERROR;
173     }
174 
175     switch (data) {
176     case 0:
177         value = *ngx_stat_active;
178         break;
179 
180     case 1:
181         value = *ngx_stat_reading;
182         break;
183 
184     case 2:
185         value = *ngx_stat_writing;
186         break;
187 
188     case 3:
189         value = *ngx_stat_waiting;
190         break;
191 
192     /* suppress warning */
193     default:
194         value = 0;
195         break;
196     }
197 
198     v->len = ngx_sprintf(p, "%uA", value) - p;
199     v->valid = 1;
200     v->no_cacheable = 0;
201     v->not_found = 0;
202     v->data = p;
203 
204     return NGX_OK;
205 }
206 
207 
208 static ngx_int_t
ngx_http_stub_status_add_variables(ngx_conf_t * cf)209 ngx_http_stub_status_add_variables(ngx_conf_t *cf)
210 {
211     ngx_http_variable_t  *var, *v;
212 
213     for (v = ngx_http_stub_status_vars; v->name.len; v++) {
214         var = ngx_http_add_variable(cf, &v->name, v->flags);
215         if (var == NULL) {
216             return NGX_ERROR;
217         }
218 
219         var->get_handler = v->get_handler;
220         var->data = v->data;
221     }
222 
223     return NGX_OK;
224 }
225 
226 
227 static char *
ngx_http_set_stub_status(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)228 ngx_http_set_stub_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
229 {
230     ngx_http_core_loc_conf_t  *clcf;
231 
232     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
233     clcf->handler = ngx_http_stub_status_handler;
234 
235     return NGX_CONF_OK;
236 }
237