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 = '&uarr;';\n"
                    281:                                           "  span.setAttribute('sortdir','up');\n"
                    282:                                           "  rows.reverse();\n"
                    283:                                           " } else {\n"
                    284:                                           "  span.innerHTML = '&darr;';\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>