Annotation of embedaddon/lighttpd/src/mod_status.c, revision 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>