Annotation of embedaddon/lighttpd/src/mod_status.c, revision 1.1.1.1
1.1 misho 1: #include "server.h"
2: #include "connections.h"
3: #include "response.h"
4: #include "connections.h"
5: #include "log.h"
6:
7: #include "plugin.h"
8:
9: #include "inet_ntop_cache.h"
10:
11: #include <sys/types.h>
12:
13: #include <fcntl.h>
14: #include <stdlib.h>
15: #include <string.h>
16: #include <unistd.h>
17: #include <errno.h>
18: #include <time.h>
19: #include <stdio.h>
20:
21: #include "version.h"
22:
23: typedef struct {
24: buffer *config_url;
25: buffer *status_url;
26: buffer *statistics_url;
27:
28: int sort;
29: } plugin_config;
30:
31: typedef struct {
32: PLUGIN_DATA;
33:
34: double traffic_out;
35: double requests;
36:
37: double mod_5s_traffic_out[5];
38: double mod_5s_requests[5];
39: size_t mod_5s_ndx;
40:
41: double rel_traffic_out;
42: double rel_requests;
43:
44: double abs_traffic_out;
45: double abs_requests;
46:
47: double bytes_written;
48:
49: buffer *module_list;
50:
51: plugin_config **config_storage;
52:
53: plugin_config conf;
54: } plugin_data;
55:
56: INIT_FUNC(mod_status_init) {
57: plugin_data *p;
58: size_t i;
59:
60: p = calloc(1, sizeof(*p));
61:
62: p->traffic_out = p->requests = 0;
63: p->rel_traffic_out = p->rel_requests = 0;
64: p->abs_traffic_out = p->abs_requests = 0;
65: p->bytes_written = 0;
66: p->module_list = buffer_init();
67:
68: for (i = 0; i < 5; i++) {
69: p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
70: }
71:
72: return p;
73: }
74:
75: FREE_FUNC(mod_status_free) {
76: plugin_data *p = p_d;
77:
78: UNUSED(srv);
79:
80: if (!p) return HANDLER_GO_ON;
81:
82: buffer_free(p->module_list);
83:
84: if (p->config_storage) {
85: size_t i;
86: for (i = 0; i < srv->config_context->used; i++) {
87: plugin_config *s = p->config_storage[i];
88:
89: buffer_free(s->status_url);
90: buffer_free(s->statistics_url);
91: buffer_free(s->config_url);
92:
93: free(s);
94: }
95: free(p->config_storage);
96: }
97:
98:
99: free(p);
100:
101: return HANDLER_GO_ON;
102: }
103:
104: SETDEFAULTS_FUNC(mod_status_set_defaults) {
105: plugin_data *p = p_d;
106: size_t i;
107:
108: config_values_t cv[] = {
109: { "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
110: { "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
111: { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
112: { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
113: { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
114: };
115:
116: if (!p) return HANDLER_ERROR;
117:
118: p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
119:
120: for (i = 0; i < srv->config_context->used; i++) {
121: plugin_config *s;
122:
123: s = calloc(1, sizeof(plugin_config));
124: s->config_url = buffer_init();
125: s->status_url = buffer_init();
126: s->sort = 1;
127: s->statistics_url = buffer_init();
128:
129: cv[0].destination = s->status_url;
130: cv[1].destination = s->config_url;
131: cv[2].destination = &(s->sort);
132: cv[3].destination = s->statistics_url;
133:
134: p->config_storage[i] = s;
135:
136: if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
137: return HANDLER_ERROR;
138: }
139: }
140:
141: return HANDLER_GO_ON;
142: }
143:
144:
145:
146: static int mod_status_row_append(buffer *b, const char *key, const char *value) {
147: buffer_append_string_len(b, CONST_STR_LEN(" <tr>\n"));
148: buffer_append_string_len(b, CONST_STR_LEN(" <td><b>"));
149: buffer_append_string(b, key);
150: buffer_append_string_len(b, CONST_STR_LEN("</b></td>\n"));
151: buffer_append_string_len(b, CONST_STR_LEN(" <td>"));
152: buffer_append_string(b, value);
153: buffer_append_string_len(b, CONST_STR_LEN("</td>\n"));
154: buffer_append_string_len(b, CONST_STR_LEN(" </tr>\n"));
155:
156: return 0;
157: }
158:
159: static int mod_status_header_append(buffer *b, const char *key) {
160: buffer_append_string_len(b, CONST_STR_LEN(" <tr>\n"));
161: buffer_append_string_len(b, CONST_STR_LEN(" <th colspan=\"2\">"));
162: buffer_append_string(b, key);
163: buffer_append_string_len(b, CONST_STR_LEN("</th>\n"));
164: buffer_append_string_len(b, CONST_STR_LEN(" </tr>\n"));
165:
166: return 0;
167: }
168:
169: static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
170: plugin_data *p = p_d;
171:
172: if (p->conf.sort) {
173: buffer_append_string_len(b, CONST_STR_LEN("<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">"));
174: buffer_append_string(b, key);
175: buffer_append_string_len(b, CONST_STR_LEN("<span class=\"sortarrow\">:</span></a></th>\n"));
176: } else {
177: buffer_append_string_len(b, CONST_STR_LEN("<th class=\"status\">"));
178: buffer_append_string(b, key);
179: buffer_append_string_len(b, CONST_STR_LEN("</th>\n"));
180: }
181:
182: return 0;
183: }
184:
185: static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
186: *multiplier = ' ';
187:
188: if (*avg > size) { *avg /= size; *multiplier = 'k'; }
189: if (*avg > size) { *avg /= size; *multiplier = 'M'; }
190: if (*avg > size) { *avg /= size; *multiplier = 'G'; }
191: if (*avg > size) { *avg /= size; *multiplier = 'T'; }
192: if (*avg > size) { *avg /= size; *multiplier = 'P'; }
193: if (*avg > size) { *avg /= size; *multiplier = 'E'; }
194: if (*avg > size) { *avg /= size; *multiplier = 'Z'; }
195: if (*avg > size) { *avg /= size; *multiplier = 'Y'; }
196:
197: return 0;
198: }
199:
200: static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) {
201: plugin_data *p = p_d;
202: buffer *b;
203: size_t j;
204: double avg;
205: char multiplier = '\0';
206: char buf[32];
207: time_t ts;
208:
209: int days, hours, mins, seconds;
210:
211: b = chunkqueue_get_append_buffer(con->write_queue);
212:
213: buffer_copy_string_len(b, CONST_STR_LEN(
214: "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
215: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
216: " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
217: "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
218: " <head>\n"
219: " <title>Status</title>\n"
220:
221: " <style type=\"text/css\">\n"
222: " table.status { border: black solid thin; }\n"
223: " td { white-space: nowrap; }\n"
224: " td.int { background-color: #f0f0f0; text-align: right }\n"
225: " td.string { background-color: #f0f0f0; text-align: left }\n"
226: " th.status { background-color: black; color: white; font-weight: bold; }\n"
227: " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
228: " span.sortarrow { color: white; text-decoration: none; }\n"
229: " </style>\n"));
230:
231: if (p->conf.sort) {
232: buffer_append_string_len(b, CONST_STR_LEN(
233: "<script type=\"text/javascript\">\n"
234: "// <!--\n"
235: "var sort_column;\n"
236: "var prev_span = null;\n"
237:
238: "function get_inner_text(el) {\n"
239: " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
240: " return el;\n"
241: " if(el.innerText)\n"
242: " return el.innerText;\n"
243: " else {\n"
244: " var str = \"\";\n"
245: " var cs = el.childNodes;\n"
246: " var l = cs.length;\n"
247: " for (i=0;i<l;i++) {\n"
248: " if (cs[i].nodeType==1) str += get_inner_text(cs[i]);\n"
249: " else if (cs[i].nodeType==3) str += cs[i].nodeValue;\n"
250: " }\n"
251: " }\n"
252: " return str;\n"
253: "}\n"
254:
255: "function sortfn(a,b) {\n"
256: " var at = get_inner_text(a.cells[sort_column]);\n"
257: " var bt = get_inner_text(b.cells[sort_column]);\n"
258: " if (a.cells[sort_column].className == 'int') {\n"
259: " return parseInt(at)-parseInt(bt);\n"
260: " } else {\n"
261: " aa = at.toLowerCase();\n"
262: " bb = bt.toLowerCase();\n"
263: " if (aa==bb) return 0;\n"
264: " else if (aa<bb) return -1;\n"
265: " else return 1;\n"
266: " }\n"
267: "}\n"
268:
269: "function resort(lnk) {\n"
270: " var span = lnk.childNodes[1];\n"
271: " var table = lnk.parentNode.parentNode.parentNode.parentNode;\n"
272: " var rows = new Array();\n"
273: " for (j=1;j<table.rows.length;j++)\n"
274: " rows[j-1] = table.rows[j];\n"
275: " sort_column = lnk.parentNode.cellIndex;\n"
276: " rows.sort(sortfn);\n"
277:
278: " if (prev_span != null) prev_span.innerHTML = '';\n"
279: " if (span.getAttribute('sortdir')=='down') {\n"
280: " span.innerHTML = '↑';\n"
281: " span.setAttribute('sortdir','up');\n"
282: " rows.reverse();\n"
283: " } else {\n"
284: " span.innerHTML = '↓';\n"
285: " span.setAttribute('sortdir','down');\n"
286: " }\n"
287: " for (i=0;i<rows.length;i++)\n"
288: " table.tBodies[0].appendChild(rows[i]);\n"
289: " prev_span = span;\n"
290: "}\n"
291: "// -->\n"
292: "</script>\n"));
293: }
294:
295: buffer_append_string_len(b, CONST_STR_LEN(
296: " </head>\n"
297: " <body>\n"));
298:
299:
300:
301: /* connection listing */
302: buffer_append_string_len(b, CONST_STR_LEN("<h1>Server-Status (" PACKAGE_NAME " " PACKAGE_VERSION ")</h1>"));
303:
304: buffer_append_string_len(b, CONST_STR_LEN("<table summary=\"status\" class=\"status\">"));
305: buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Hostname</td><td class=\"string\">"));
306: buffer_append_string_buffer(b, con->uri.authority);
307: buffer_append_string_len(b, CONST_STR_LEN(" ("));
308: buffer_append_string_buffer(b, con->server_name);
309: buffer_append_string_len(b, CONST_STR_LEN(")</td></tr>\n"));
310: buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Uptime</td><td class=\"string\">"));
311:
312: ts = srv->cur_ts - srv->startup_ts;
313:
314: days = ts / (60 * 60 * 24);
315: ts %= (60 * 60 * 24);
316:
317: hours = ts / (60 * 60);
318: ts %= (60 * 60);
319:
320: mins = ts / (60);
321: ts %= (60);
322:
323: seconds = ts;
324:
325: if (days) {
326: buffer_append_long(b, days);
327: buffer_append_string_len(b, CONST_STR_LEN(" days "));
328: }
329:
330: if (hours) {
331: buffer_append_long(b, hours);
332: buffer_append_string_len(b, CONST_STR_LEN(" hours "));
333: }
334:
335: if (mins) {
336: buffer_append_long(b, mins);
337: buffer_append_string_len(b, CONST_STR_LEN(" min "));
338: }
339:
340: buffer_append_long(b, seconds);
341: buffer_append_string_len(b, CONST_STR_LEN(" s"));
342:
343: buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
344: buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Started at</td><td class=\"string\">"));
345:
346: ts = srv->startup_ts;
347:
348: strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
349: buffer_append_string(b, buf);
350: buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
351:
352:
353: buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">absolute (since start)</th></tr>\n"));
354:
355: buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
356: avg = p->abs_requests;
357:
358: mod_status_get_multiplier(&avg, &multiplier, 1000);
359:
360: buffer_append_long(b, avg);
361: buffer_append_string_len(b, CONST_STR_LEN(" "));
362: if (multiplier) buffer_append_string_len(b, &multiplier, 1);
363: buffer_append_string_len(b, CONST_STR_LEN("req</td></tr>\n"));
364:
365: buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
366: avg = p->abs_traffic_out;
367:
368: mod_status_get_multiplier(&avg, &multiplier, 1024);
369:
370: sprintf(buf, "%.2f", avg);
371: buffer_append_string(b, buf);
372: buffer_append_string_len(b, CONST_STR_LEN(" "));
373: if (multiplier) buffer_append_string_len(b, &multiplier, 1);
374: buffer_append_string_len(b, CONST_STR_LEN("byte</td></tr>\n"));
375:
376:
377:
378: buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">average (since start)</th></tr>\n"));
379:
380: buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
381: avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
382:
383: mod_status_get_multiplier(&avg, &multiplier, 1000);
384:
385: buffer_append_long(b, avg);
386: buffer_append_string_len(b, CONST_STR_LEN(" "));
387: if (multiplier) buffer_append_string_len(b, &multiplier, 1);
388: buffer_append_string_len(b, CONST_STR_LEN("req/s</td></tr>\n"));
389:
390: buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
391: avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
392:
393: mod_status_get_multiplier(&avg, &multiplier, 1024);
394:
395: sprintf(buf, "%.2f", avg);
396: buffer_append_string(b, buf);
397: buffer_append_string_len(b, CONST_STR_LEN(" "));
398: if (multiplier) buffer_append_string_len(b, &multiplier, 1);
399: buffer_append_string_len(b, CONST_STR_LEN("byte/s</td></tr>\n"));
400:
401:
402:
403: buffer_append_string_len(b, CONST_STR_LEN("<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n"));
404: for (j = 0, avg = 0; j < 5; j++) {
405: avg += p->mod_5s_requests[j];
406: }
407:
408: avg /= 5;
409:
410: buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Requests</td><td class=\"string\">"));
411:
412: mod_status_get_multiplier(&avg, &multiplier, 1000);
413:
414: buffer_append_long(b, avg);
415: buffer_append_string_len(b, CONST_STR_LEN(" "));
416: if (multiplier) buffer_append_string_len(b, &multiplier, 1);
417:
418: buffer_append_string_len(b, CONST_STR_LEN("req/s</td></tr>\n"));
419:
420: for (j = 0, avg = 0; j < 5; j++) {
421: avg += p->mod_5s_traffic_out[j];
422: }
423:
424: avg /= 5;
425:
426: buffer_append_string_len(b, CONST_STR_LEN("<tr><td>Traffic</td><td class=\"string\">"));
427:
428: mod_status_get_multiplier(&avg, &multiplier, 1024);
429:
430: sprintf(buf, "%.2f", avg);
431: buffer_append_string(b, buf);
432: buffer_append_string_len(b, CONST_STR_LEN(" "));
433: if (multiplier) buffer_append_string_len(b, &multiplier, 1);
434: buffer_append_string_len(b, CONST_STR_LEN("byte/s</td></tr>\n"));
435:
436: buffer_append_string_len(b, CONST_STR_LEN("</table>\n"));
437:
438:
439: buffer_append_string_len(b, CONST_STR_LEN(
440: "<hr />\n<pre><b>legend</b>\n"
441: ". = connect, C = close, E = hard error, k = keep-alive\n"
442: "r = read, R = read-POST, W = write, h = handle-request\n"
443: "q = request-start, Q = request-end\n"
444: "s = response-start, S = response-end\n"));
445:
446: buffer_append_string_len(b, CONST_STR_LEN("<b>"));
447: buffer_append_long(b, srv->conns->used);
448: buffer_append_string_len(b, CONST_STR_LEN(" connections</b>\n"));
449:
450: for (j = 0; j < srv->conns->used; j++) {
451: connection *c = srv->conns->ptr[j];
452: const char *state;
453:
454: if (CON_STATE_READ == c->state && c->request.orig_uri->used > 0) {
455: state = "k";
456: } else {
457: state = connection_get_short_state(c->state);
458: }
459:
460: buffer_append_string_len(b, state, 1);
461:
462: if (((j + 1) % 50) == 0) {
463: buffer_append_string_len(b, CONST_STR_LEN("\n"));
464: }
465: }
466:
467: buffer_append_string_len(b, CONST_STR_LEN("\n</pre><hr />\n<h2>Connections</h2>\n"));
468:
469: buffer_append_string_len(b, CONST_STR_LEN("<table summary=\"status\" class=\"status\">\n"));
470: buffer_append_string_len(b, CONST_STR_LEN("<tr>"));
471: mod_status_header_append_sort(b, p_d, "Client IP");
472: mod_status_header_append_sort(b, p_d, "Read");
473: mod_status_header_append_sort(b, p_d, "Written");
474: mod_status_header_append_sort(b, p_d, "State");
475: mod_status_header_append_sort(b, p_d, "Time");
476: mod_status_header_append_sort(b, p_d, "Host");
477: mod_status_header_append_sort(b, p_d, "URI");
478: mod_status_header_append_sort(b, p_d, "File");
479: buffer_append_string_len(b, CONST_STR_LEN("</tr>\n"));
480:
481: for (j = 0; j < srv->conns->used; j++) {
482: connection *c = srv->conns->ptr[j];
483:
484: buffer_append_string_len(b, CONST_STR_LEN("<tr><td class=\"string\">"));
485:
486: buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
487:
488: buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
489:
490: if (c->request.content_length) {
491: buffer_append_long(b, c->request_content_queue->bytes_in);
492: buffer_append_string_len(b, CONST_STR_LEN("/"));
493: buffer_append_long(b, c->request.content_length);
494: } else {
495: buffer_append_string_len(b, CONST_STR_LEN("0/0"));
496: }
497:
498: buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
499:
500: buffer_append_off_t(b, chunkqueue_written(c->write_queue));
501: buffer_append_string_len(b, CONST_STR_LEN("/"));
502: buffer_append_off_t(b, chunkqueue_length(c->write_queue));
503:
504: buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
505:
506: if (CON_STATE_READ == c->state && c->request.orig_uri->used > 0) {
507: buffer_append_string_len(b, CONST_STR_LEN("keep-alive"));
508: } else {
509: buffer_append_string(b, connection_get_state(c->state));
510: }
511:
512: buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"int\">"));
513:
514: buffer_append_long(b, srv->cur_ts - c->request_start);
515:
516: buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
517:
518: if (buffer_is_empty(c->server_name)) {
519: buffer_append_string_buffer(b, c->uri.authority);
520: }
521: else {
522: buffer_append_string_buffer(b, c->server_name);
523: }
524:
525: buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
526:
527: if (!buffer_is_empty(c->uri.path)) {
528: buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
529: }
530:
531: if (!buffer_is_empty(c->uri.query)) {
532: buffer_append_string_len(b, CONST_STR_LEN("?"));
533: buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.query), ENCODING_HTML);
534: }
535:
536: if (!buffer_is_empty(c->request.orig_uri)) {
537: buffer_append_string_len(b, CONST_STR_LEN(" ("));
538: buffer_append_string_encoded(b, CONST_BUF_LEN(c->request.orig_uri), ENCODING_HTML);
539: buffer_append_string_len(b, CONST_STR_LEN(")"));
540: }
541: buffer_append_string_len(b, CONST_STR_LEN("</td><td class=\"string\">"));
542:
543: buffer_append_string_buffer(b, c->physical.path);
544:
545: buffer_append_string_len(b, CONST_STR_LEN("</td></tr>\n"));
546: }
547:
548:
549: buffer_append_string_len(b, CONST_STR_LEN(
550: "</table>\n"));
551:
552:
553: buffer_append_string_len(b, CONST_STR_LEN(
554: " </body>\n"
555: "</html>\n"
556: ));
557:
558: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
559:
560: return 0;
561: }
562:
563:
564: static handler_t mod_status_handle_server_status_text(server *srv, connection *con, void *p_d) {
565: plugin_data *p = p_d;
566: buffer *b;
567: double avg;
568: time_t ts;
569: char buf[32];
570: unsigned int k;
571: unsigned int l;
572:
573: b = chunkqueue_get_append_buffer(con->write_queue);
574:
575: /* output total number of requests */
576: buffer_append_string_len(b, CONST_STR_LEN("Total Accesses: "));
577: avg = p->abs_requests;
578: snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
579: buffer_append_string(b, buf);
580: buffer_append_string_len(b, CONST_STR_LEN("\n"));
581:
582: /* output total traffic out in kbytes */
583: buffer_append_string_len(b, CONST_STR_LEN("Total kBytes: "));
584: avg = p->abs_traffic_out / 1024;
585: snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
586: buffer_append_string(b, buf);
587: buffer_append_string_len(b, CONST_STR_LEN("\n"));
588:
589: /* output uptime */
590: buffer_append_string_len(b, CONST_STR_LEN("Uptime: "));
591: ts = srv->cur_ts - srv->startup_ts;
592: buffer_append_long(b, ts);
593: buffer_append_string_len(b, CONST_STR_LEN("\n"));
594:
595: /* output busy servers */
596: buffer_append_string_len(b, CONST_STR_LEN("BusyServers: "));
597: buffer_append_long(b, srv->conns->used);
598: buffer_append_string_len(b, CONST_STR_LEN("\n"));
599:
600: buffer_append_string_len(b, CONST_STR_LEN("IdleServers: "));
601: buffer_append_long(b, srv->conns->size - srv->conns->used);
602: buffer_append_string_len(b, CONST_STR_LEN("\n"));
603:
604: /* output scoreboard */
605: buffer_append_string_len(b, CONST_STR_LEN("Scoreboard: "));
606: for (k = 0; k < srv->conns->used; k++) {
607: connection *c = srv->conns->ptr[k];
608: const char *state = connection_get_short_state(c->state);
609: buffer_append_string_len(b, state, 1);
610: }
611: for (l = 0; l < srv->conns->size - srv->conns->used; l++) {
612: buffer_append_string_len(b, CONST_STR_LEN("_"));
613: }
614: buffer_append_string_len(b, CONST_STR_LEN("\n"));
615:
616: /* set text/plain output */
617:
618: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
619:
620: return 0;
621: }
622:
623: static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) {
624: buffer *b;
625: size_t i;
626: array *st = srv->status;
627: UNUSED(p_d);
628:
629: if (0 == st->used) {
630: /* we have nothing to send */
631: con->http_status = 204;
632: con->file_finished = 1;
633:
634: return HANDLER_FINISHED;
635: }
636:
637: b = chunkqueue_get_append_buffer(con->write_queue);
638:
639: for (i = 0; i < st->used; i++) {
640: size_t ndx = st->sorted[i];
641:
642: buffer_append_string_buffer(b, st->data[ndx]->key);
643: buffer_append_string_len(b, CONST_STR_LEN(": "));
644: buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
645: buffer_append_string_len(b, CONST_STR_LEN("\n"));
646: }
647:
648: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
649:
650: con->http_status = 200;
651: con->file_finished = 1;
652:
653: return HANDLER_FINISHED;
654: }
655:
656:
657: static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
658:
659: if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
660: mod_status_handle_server_status_text(srv, con, p_d);
661: } else {
662: mod_status_handle_server_status_html(srv, con, p_d);
663: }
664:
665: con->http_status = 200;
666: con->file_finished = 1;
667:
668: return HANDLER_FINISHED;
669: }
670:
671:
672: static handler_t mod_status_handle_server_config(server *srv, connection *con, void *p_d) {
673: plugin_data *p = p_d;
674: buffer *b, *m = p->module_list;
675: size_t i;
676:
677: struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
678: {
679: /* - epoll is most reliable
680: * - select works everywhere
681: */
682: #ifdef USE_LINUX_EPOLL
683: { FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
684: #endif
685: #ifdef USE_POLL
686: { FDEVENT_HANDLER_POLL, "poll" },
687: #endif
688: #ifdef USE_SELECT
689: { FDEVENT_HANDLER_SELECT, "select" },
690: #endif
691: #ifdef USE_LIBEV
692: { FDEVENT_HANDLER_LIBEV, "libev" },
693: #endif
694: #ifdef USE_SOLARIS_DEVPOLL
695: { FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
696: #endif
697: #ifdef USE_SOLARIS_PORT
698: { FDEVENT_HANDLER_SOLARIS_PORT, "solaris-eventports" },
699: #endif
700: #ifdef USE_FREEBSD_KQUEUE
701: { FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
702: #endif
703: { FDEVENT_HANDLER_UNSET, NULL }
704: };
705:
706: b = chunkqueue_get_append_buffer(con->write_queue);
707:
708: buffer_copy_string_len(b, CONST_STR_LEN(
709: "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
710: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
711: " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
712: "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
713: " <head>\n"
714: " <title>Status</title>\n"
715: " </head>\n"
716: " <body>\n"
717: " <h1>" PACKAGE_DESC "</h1>\n"
718: " <table summary=\"status\" border=\"1\">\n"));
719:
720: mod_status_header_append(b, "Server-Features");
721: #ifdef HAVE_PCRE_H
722: mod_status_row_append(b, "RegEx Conditionals", "enabled");
723: #else
724: mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
725: #endif
726: mod_status_header_append(b, "Network Engine");
727:
728: for (i = 0; event_handlers[i].name; i++) {
729: if (event_handlers[i].et == srv->event_handler) {
730: mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
731: break;
732: }
733: }
734:
735: mod_status_header_append(b, "Config-File-Settings");
736:
737: for (i = 0; i < srv->plugins.used; i++) {
738: plugin **ps = srv->plugins.ptr;
739:
740: plugin *pl = ps[i];
741:
742: if (i == 0) {
743: buffer_copy_string_buffer(m, pl->name);
744: } else {
745: buffer_append_string_len(m, CONST_STR_LEN("<br />"));
746: buffer_append_string_buffer(m, pl->name);
747: }
748: }
749:
750: mod_status_row_append(b, "Loaded Modules", m->ptr);
751:
752: buffer_append_string_len(b, CONST_STR_LEN(" </table>\n"));
753:
754: buffer_append_string_len(b, CONST_STR_LEN(
755: " </body>\n"
756: "</html>\n"
757: ));
758:
759: response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
760:
761: con->http_status = 200;
762: con->file_finished = 1;
763:
764: return HANDLER_FINISHED;
765: }
766:
767: #define PATCH(x) \
768: p->conf.x = s->x;
769: static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
770: size_t i, j;
771: plugin_config *s = p->config_storage[0];
772:
773: PATCH(status_url);
774: PATCH(config_url);
775: PATCH(sort);
776: PATCH(statistics_url);
777:
778: /* skip the first, the global context */
779: for (i = 1; i < srv->config_context->used; i++) {
780: data_config *dc = (data_config *)srv->config_context->data[i];
781: s = p->config_storage[i];
782:
783: /* condition didn't match */
784: if (!config_check_cond(srv, con, dc)) continue;
785:
786: /* merge config */
787: for (j = 0; j < dc->value->used; j++) {
788: data_unset *du = dc->value->data[j];
789:
790: if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
791: PATCH(status_url);
792: } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
793: PATCH(config_url);
794: } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
795: PATCH(sort);
796: } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
797: PATCH(statistics_url);
798: }
799: }
800: }
801:
802: return 0;
803: }
804:
805: static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
806: plugin_data *p = p_d;
807:
808: if (con->mode != DIRECT) return HANDLER_GO_ON;
809:
810: mod_status_patch_connection(srv, con, p);
811:
812: if (!buffer_is_empty(p->conf.status_url) &&
813: buffer_is_equal(p->conf.status_url, con->uri.path)) {
814: return mod_status_handle_server_status(srv, con, p_d);
815: } else if (!buffer_is_empty(p->conf.config_url) &&
816: buffer_is_equal(p->conf.config_url, con->uri.path)) {
817: return mod_status_handle_server_config(srv, con, p_d);
818: } else if (!buffer_is_empty(p->conf.statistics_url) &&
819: buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
820: return mod_status_handle_server_statistics(srv, con, p_d);
821: }
822:
823: return HANDLER_GO_ON;
824: }
825:
826: TRIGGER_FUNC(mod_status_trigger) {
827: plugin_data *p = p_d;
828: size_t i;
829:
830: /* check all connections */
831: for (i = 0; i < srv->conns->used; i++) {
832: connection *c = srv->conns->ptr[i];
833:
834: p->bytes_written += c->bytes_written_cur_second;
835: }
836:
837: /* a sliding average */
838: p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
839: p->mod_5s_requests [p->mod_5s_ndx] = p->requests;
840:
841: p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
842:
843: p->abs_traffic_out += p->bytes_written;
844: p->rel_traffic_out += p->bytes_written;
845:
846: p->bytes_written = 0;
847:
848: /* reset storage - second */
849: p->traffic_out = 0;
850: p->requests = 0;
851:
852: return HANDLER_GO_ON;
853: }
854:
855: REQUESTDONE_FUNC(mod_status_account) {
856: plugin_data *p = p_d;
857:
858: UNUSED(srv);
859:
860: p->requests++;
861: p->rel_requests++;
862: p->abs_requests++;
863:
864: p->bytes_written += con->bytes_written_cur_second;
865:
866: return HANDLER_GO_ON;
867: }
868:
869: int mod_status_plugin_init(plugin *p);
870: int mod_status_plugin_init(plugin *p) {
871: p->version = LIGHTTPD_VERSION_ID;
872: p->name = buffer_init_string("status");
873:
874: p->init = mod_status_init;
875: p->cleanup = mod_status_free;
876: p->set_defaults= mod_status_set_defaults;
877:
878: p->handle_uri_clean = mod_status_handler;
879: p->handle_trigger = mod_status_trigger;
880: p->handle_request_done = mod_status_account;
881:
882: p->data = NULL;
883:
884: return 0;
885: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>