diff --git a/CMakeLists.txt b/CMakeLists.txt index 346940280339f52009b5d0082b2406670b00c64d..661260125c87f4522c81a9a5e9a8b19e926d4bbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,13 +95,14 @@ option(LWS_WITH_HTTP_PROXY "Support for rewriting HTTP proxying" OFF) option(LWS_WITH_LWSWS "Libwebsockets Webserver" OFF) option(LWS_WITH_PLUGINS "Support plugins for protocols and extensions" OFF) option(LWS_WITH_ACCESS_LOG "Support generating Apache-compatible access logs" OFF) - +option(LWS_WITH_SERVER_STATUS "Support json + jscript server monitoring" OFF) if (LWS_WITH_LWSWS) message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV") set(LWS_WITH_PLUGINS 1) set(LWS_WITH_LIBUV 1) set(LWS_WITH_ACCESS_LOG 1) + set(LWS_WITH_SERVER_STATUS 1) endif() if (LWS_WITH_PLUGINS AND NOT LWS_WITH_LIBUV) @@ -1199,6 +1200,10 @@ if (NOT LWS_WITHOUT_TESTAPPS) "plugins/protocol_lws_mirror.c") create_plugin(protocol_lws_status "plugins/protocol_lws_status.c") +if (LWS_WITH_SERVER_STATUS) + create_plugin(protocol_lws_server_status + "plugins/protocol_lws_server_status.c") +endif() endif(LWS_WITH_PLUGINS AND LWS_WITH_SHARED) # @@ -1399,6 +1404,11 @@ if (LWS_WITH_PLUGINS) PERMISSIONS OWNER_WRITE OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE OWNER_READ GROUP_READ WORLD_READ DESTINATION share/libwebsockets-test-server/plugins COMPONENT plugins) +if (LWS_WITH_SERVER_STATUS) + install(FILES plugins/server-status.html + DESTINATION share/libwebsockets-test-server/server-status + COMPONENT examples) +endif() endif() # Install the LibwebsocketsConfig.cmake and LibwebsocketsConfigVersion.cmake @@ -1466,6 +1476,7 @@ message(" LWS_WITH_HTTP_PROXY = ${LWS_WITH_HTTP_PROXY}") message(" LIBHUBBUB_LIBRARIES = ${LIBHUBBUB_LIBRARIES}") message(" PLUGINS = ${PLUGINS_LIST}") message(" LWS_WITH_ACCESS_LOG = ${LWS_WITH_ACCESS_LOG}") +message(" LWS_WITH_SERVER_STATUS = ${LWS_WITH_SERVER_STATUS}") message("---------------------------------------------------------------------") # These will be available to parent projects including libwebsockets using add_subdirectory() diff --git a/README.lwsws.md b/README.lwsws.md index 6b821271ea80f0f67142e8b67c0eecad99e32d77..15a8bd31914cfb69bcae8c8fac1fbe177fe01394 100644 --- a/README.lwsws.md +++ b/README.lwsws.md @@ -153,6 +153,11 @@ Vhosts can select which plugins they want to offer and give them per-vhost setti ``` +The "x":"y" parameters like "status":"ok" are made available to the protocol during its per-vhost +LWS_CALLBACK_PROTOCOL_INIT (@in is a pointer to a linked list of struct lws_protocol_vhost_options +containing the name and value pointers). + + Other vhost options ------------------- @@ -265,3 +270,28 @@ dumb increment, mirror and status protocol plugins are provided as examples. +lws-server-status plugin +------------------------ + +One provided protocol can be used to monitor the server status. + +Enable the protocol like this on a vhost's ws-protocols section + + "lws-server-status": { + "status": "ok", + "update-ms": "5000" + } + +"update-ms" is used to control how often updated JSON is sent on a ws link. + +And map the provided HTML into the vhost in the mounts section + + { + "mountpoint": "/server-status", + "origin": "file:///usr/local/share/libwebsockets-test-server/server-status", + "default": "server-status.html" + } + +You might choose to put it on its own vhost which has "interface": "lo", so it's not +externally visible. + diff --git a/lib/context.c b/lib/context.c index e746e8cbd08b93f2d883b154fe877fe922ca2313..8ee5ffa75b2b301b2c694040566283f1fceefbba 100644 --- a/lib/context.c +++ b/lib/context.c @@ -440,7 +440,6 @@ lws_create_context(struct lws_context_creation_info *info) struct rlimit rt; #endif - lwsl_notice("Initial logging level %d\n", log_level); lwsl_notice("Libwebsockets version: %s\n", library_version); #if LWS_POSIX @@ -471,6 +470,8 @@ lws_create_context(struct lws_context_creation_info *info) lwsl_err("No memory for websocket context\n"); return NULL; } + + context->time_up = time(NULL); #ifndef LWS_NO_DAEMONIZE if (pid_daemon) { context->started_with_parent = pid_daemon; diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 22368a22af05ebffa0a85ae87f1336fb78dec76a..58d0006401cf11234435bcd55fb088d79beaca41 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -2234,6 +2234,8 @@ lws_access_log(struct lws *wsi) } #endif +#ifdef LWS_WITH_SERVER_STATUS + LWS_EXTERN int lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len) { @@ -2254,10 +2256,15 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len) buf += snprintf(buf, end - buf, "{\n \"name\":\"%s\",\n" " \"port\":\"%d\",\n" - " \"use-ssl\":\"%d\",\n" + " \"use_ssl\":\"%d\",\n" " \"sts\":\"%d\",\n" " \"rx\":\"%lu\",\n" - " \"tx\":\"%lu\",\n", + " \"tx\":\"%lu\",\n" + " \"conn\":\"%lu\",\n" + " \"trans\":\"%lu\",\n" + " \"ws_upg\":\"%lu\",\n" + " \"http2_upg\":\"%lu\"" + , vh->name, vh->listen_port, #ifdef LWS_OPENSSL_SUPPORT vh->use_ssl, @@ -2265,7 +2272,8 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len) 0, #endif !!(vh->options & LWS_SERVER_OPTION_STS), - vh->rx, vh->tx + vh->rx, vh->tx, vh->conn, vh->trans, vh->ws_upgrades, + vh->http2_upgrades ); if (vh->mount_list) { @@ -2277,7 +2285,7 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len) buf += snprintf(buf, end - buf, ","); buf += snprintf(buf, end - buf, "\n {\n \"mountpoint\":\"%s\",\n" - " \"origin\":\"%s%s\"" + " \"origin\":\"%s%s\"\n" , m->mountpoint, prots[m->origin_protocol], @@ -2316,3 +2324,34 @@ lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len) return buf - orig; } + + +LWS_EXTERN LWS_VISIBLE int +lws_json_dump_context(const struct lws_context *context, char *buf, int len) +{ + char *orig = buf, *end = buf + len - 1, first = 1; + struct lws_vhost *vh = context->vhost_list; + time_t t = time(NULL); + + buf += snprintf(buf, end - buf, "{ " + "\"uptime\":\"%ld\",\n" + "\"wsi_alive\":\"%d\",\n" + "\"vhosts\":[\n ", + (unsigned long)(t - context->time_up), + context->count_wsi_allocated); + + while (vh) { + if (!first) + if(buf != end) + *buf++ = ','; + buf += lws_json_dump_vhost(vh, buf, end - buf); + first = 0; + vh = vh->vhost_next; + } + + buf += snprintf(buf, end - buf, "]}\n "); + + return buf - orig; +} + +#endif diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 0f6687dd93ce43f4cf67f70e8c10f4fd9ebc945c..60bbe4f291a8d454378024fc02c6d5af5b1618df 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -1566,6 +1566,9 @@ lws_write_http_mount(struct lws_http_mount *next, struct lws_http_mount **res, LWS_EXTERN int lws_json_dump_vhost(const struct lws_vhost *vh, char *buf, int len); +LWS_EXTERN int +lws_json_dump_context(const struct lws_context *context, char *buf, int len); + LWS_VISIBLE LWS_EXTERN void lws_set_log_level(int level, void (*log_emit_function)(int level, const char *line)); diff --git a/lib/output.c b/lib/output.c index c3fc2c84e0a2a43f39fe1d0a556b839adb780013..451ca0df86801470b9e6a6a11757138d3e788780 100644 --- a/lib/output.c +++ b/lib/output.c @@ -251,6 +251,8 @@ LWS_VISIBLE int lws_write(struct lws *wsi, unsigned char *buf, size_t len, #ifdef LWS_WITH_ACCESS_LOG wsi->access_log.sent += len; #endif + if (wsi->vhost) + wsi->vhost->tx += len; if (wsi->state == LWSS_ESTABLISHED && wsi->u.ws.tx_draining_ext) { /* remove us from the list */ @@ -634,8 +636,11 @@ lws_ssl_capable_read_no_ssl(struct lws *wsi, unsigned char *buf, int len) int n; n = recv(wsi->sock, (char *)buf, len, 0); - if (n > 0) + if (n > 0) { + if (wsi->vhost) + wsi->vhost->rx += n; return n; + } #if LWS_POSIX if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK || diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index f91a5c132e847a11c398d11f2de19046ad818863..60c038ca46bde293f2206f5b12afef8bfd7fd9d7 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -668,7 +668,7 @@ struct lws_vhost { #ifndef LWS_NO_EXTENSIONS const struct lws_extension *extensions; #endif - unsigned long rx, tx; + unsigned long rx, tx, conn, trans, ws_upgrades, http2_upgrades; int listen_port; unsigned int http_proxy_port; @@ -698,6 +698,7 @@ struct lws_vhost { struct lws_context { time_t last_timeout_check_s; + time_t time_up; struct lws_plat_file_ops fops; struct lws_context_per_thread pt[LWS_MAX_SMP]; #ifdef _WIN32 @@ -1255,6 +1256,7 @@ struct lws { unsigned int socket_is_permanently_unusable:1; unsigned int rxflow_change_to:2; unsigned int more_rx_waiting:1; /* has to live here since ah may stick to end */ + unsigned int conn_stat_done:1; #ifdef LWS_WITH_ACCESS_LOG unsigned int access_log_pending:1; #endif diff --git a/lib/server.c b/lib/server.c index 761590803304959d17d85361421150c1e914ed3e..41e6339a17891c9b09192257076f8f66f7ecaae4 100644 --- a/lib/server.c +++ b/lib/server.c @@ -700,6 +700,23 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len) lwsl_debug("%s: wsi->more_rx_waiting=%d\n", __func__, wsi->more_rx_waiting); + /* select vhost */ + + if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { + struct lws_vhost *vhost = lws_select_vhost( + context, wsi->vhost->listen_port, + lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)); + + if (vhost) + wsi->vhost = vhost; + } + + wsi->vhost->trans++; + if (!wsi->conn_stat_done) { + wsi->vhost->conn++; + wsi->conn_stat_done = 1; + } + wsi->mode = LWSCM_PRE_WS_SERVING_ACCEPT; lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); @@ -708,12 +725,14 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len) if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) { if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE), "websocket")) { + wsi->vhost->ws_upgrades++; lwsl_info("Upgrade to ws\n"); goto upgrade_ws; } #ifdef LWS_USE_HTTP2 if (!strcasecmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE), "h2c")) { + wsi->vhost->http2_upgrades++; lwsl_info("Upgrade to h2c\n"); goto upgrade_h2c; } @@ -728,17 +747,6 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len) lwsl_info("No upgrade\n"); ah = wsi->u.hdr.ah; - /* select vhost */ - - if (lws_hdr_total_length(wsi, WSI_TOKEN_HOST)) { - struct lws_vhost *vhost = lws_select_vhost( - context, wsi->vhost->listen_port, - lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST)); - - if (vhost) - wsi->vhost = vhost; - } - lws_union_transition(wsi, LWSCM_HTTP_SERVING_ACCEPTED); wsi->state = LWSS_HTTP; wsi->u.http.fd = LWS_INVALID_FILE; diff --git a/lws_config.h.in b/lws_config.h.in index a9298ff4dda5d53da1d10e36be9e40f0247777ec..87a0c6d2af352cfc39e8834e78a692696c01a9e2 100644 --- a/lws_config.h.in +++ b/lws_config.h.in @@ -94,6 +94,7 @@ /* Http access log support */ #cmakedefine LWS_WITH_ACCESS_LOG +#cmakedefine LWS_WITH_SERVER_STATUS /* Maximum supported service threads */ #define LWS_MAX_SMP ${LWS_MAX_SMP} diff --git a/plugins/protocol_dumb_increment.c b/plugins/protocol_dumb_increment.c index fd4eb299cfa64cefe7fea85aadb1a076fbb080a8..5c1a343d98e75fd1ba0b5818a2a6d6598e5adf63 100644 --- a/plugins/protocol_dumb_increment.c +++ b/plugins/protocol_dumb_increment.c @@ -59,7 +59,6 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: - lwsl_notice("%s: pvo %p\n", __func__, in); vhd = lws_protocol_vh_priv_zalloc(lws_vhost_get(wsi), lws_protocol_get(wsi), sizeof(struct per_vhost_data__dumb_increment)); @@ -73,6 +72,8 @@ callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_PROTOCOL_DESTROY: + if (!vhd) + break; uv_timer_stop(&vhd->timeout_watcher); break; diff --git a/plugins/protocol_lws_mirror.c b/plugins/protocol_lws_mirror.c index 05614db9ade8194257eff53a5df26fe7658166d1..4b9319c4e5557772d1a195e64decd8db728998d3 100644 --- a/plugins/protocol_lws_mirror.c +++ b/plugins/protocol_lws_mirror.c @@ -66,6 +66,8 @@ callback_lws_mirror(struct lws *wsi, enum lws_callback_reasons reason, break; case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */ + if (!v) + break; lwsl_info("%s: mirror protocol cleaning up %p\n", __func__, v); for (n = 0; n < ARRAY_SIZE(v->ringbuffer); n++) if (v->ringbuffer[n].payload) { diff --git a/plugins/protocol_lws_server_status.c b/plugins/protocol_lws_server_status.c new file mode 100644 index 0000000000000000000000000000000000000000..588ada555ca6ac113754110c5c825c5c6e1db35b --- /dev/null +++ b/plugins/protocol_lws_server_status.c @@ -0,0 +1,147 @@ +/* + * libwebsockets-test-server - libwebsockets test implementation + * + * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com> + * + * This file is made available under the Creative Commons CC0 1.0 + * Universal Public Domain Dedication. + * + * The person who associated a work with this deed has dedicated + * the work to the public domain by waiving all of his or her rights + * to the work worldwide under copyright law, including all related + * and neighboring rights, to the extent allowed by law. You can copy, + * modify, distribute and perform the work, even for commercial purposes, + * all without asking permission. + * + * The test apps are intended to be adapted for use in your code, which + * may be proprietary. So unlike the library itself, they are licensed + * Public Domain. + */ +#include "../lib/libwebsockets.h" +#include <string.h> + +#define LWS_SS_VERSIONS 3 + +struct lws_ss_dumps { + char buf[32768]; + int length; +}; + +static struct lws_ss_dumps d[LWS_SS_VERSIONS]; +static int last_dump; +static uv_timer_t timeout_watcher; +static struct lws_context *context; +static int tow_flag; + +struct per_session_data__server_status { + int ver; + int pos; +}; + +static const struct lws_protocols protocols[]; + +static void +uv_timeout_cb_server_status(uv_timer_t *w +#if UV_VERSION_MAJOR == 0 + , int status +#endif +) +{ + int n; + + last_dump = (last_dump + 1) % LWS_SS_VERSIONS; + n = lws_json_dump_context(context, d[last_dump].buf + LWS_PRE, + sizeof(d[0].buf) - LWS_PRE); + d[last_dump].length = n; + + lws_callback_on_writable_all_protocol(context, &protocols[0]); +} + +static int +callback_lws_server_status(struct lws *wsi, enum lws_callback_reasons reason, + void *user, void *in, size_t len) +{ + struct lws_protocol_vhost_options *pvo = + (struct lws_protocol_vhost_options *)in; + int m, period = 1000; + + switch (reason) { + + case LWS_CALLBACK_ESTABLISHED: + lwsl_info("%s: LWS_CALLBACK_ESTABLISHED\n", __func__); + lws_callback_on_writable(wsi); + break; + + case LWS_CALLBACK_PROTOCOL_INIT: /* per vhost */ + if (tow_flag) + break; + while (pvo) { + if (!strcmp(pvo->name, "update-ms")) + period = atoi(pvo->value); + pvo = pvo->next; + } + context = lws_get_context(wsi); + uv_timer_init(lws_uv_getloop(context, 0), &timeout_watcher); + uv_timer_start(&timeout_watcher, + uv_timeout_cb_server_status, 2000, period); + tow_flag = 1; + break; + + case LWS_CALLBACK_PROTOCOL_DESTROY: /* per vhost */ + if (!tow_flag) + break; + uv_timer_stop(&timeout_watcher); + tow_flag = 0; + break; + + case LWS_CALLBACK_SERVER_WRITEABLE: + m = lws_write(wsi, (unsigned char *) + d[last_dump].buf + LWS_PRE, d[last_dump].length, + LWS_WRITE_TEXT); + if (m < 0) + return -1; + break; + + case LWS_CALLBACK_RECEIVE: + break; + + default: + break; + } + + return 0; +} + +static const struct lws_protocols protocols[] = { + { + "lws-server-status", + callback_lws_server_status, + sizeof(struct per_session_data__server_status), + 1024, + }, +}; + +LWS_VISIBLE int +init_protocol_lws_server_status(struct lws_context *context, + struct lws_plugin_capability *c) +{ + if (c->api_magic != LWS_PLUGIN_API_MAGIC) { + lwsl_err("Plugin API %d, library API %d", + LWS_PLUGIN_API_MAGIC, c->api_magic); + return 1; + } + + c->protocols = protocols; + c->count_protocols = ARRAY_SIZE(protocols); + c->extensions = NULL; + c->count_extensions = 0; + + return 0; +} + +LWS_VISIBLE int +destroy_protocol_lws_server_status(struct lws_context *context) +{ + return 0; +} + diff --git a/plugins/protocol_lws_status.c b/plugins/protocol_lws_status.c index 76d2563e6d693221bb5c010494a62a647ce51969..38281b7682b0cc33dbbfd84106fc00df2f61f991 100644 --- a/plugins/protocol_lws_status.c +++ b/plugins/protocol_lws_status.c @@ -102,8 +102,7 @@ callback_lws_status(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__lws_status *pss = - (struct per_session_data__lws_status *)user, - **pp; + (struct per_session_data__lws_status *)user, **pp; char name[128], rip[128]; int m; diff --git a/plugins/server-status.html b/plugins/server-status.html new file mode 100644 index 0000000000000000000000000000000000000000..0ecebb4b17fa23876ae425a05773a6b8c6d9946e --- /dev/null +++ b/plugins/server-status.html @@ -0,0 +1,219 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset=utf-8 http-equiv="Content-Language" content="en"/> + <title>LWS Server Status</title> +<style type="text/css"> + span.title { font-size:18pt; font: Arial; font-weight:normal; + text-align:center; color:#000000; } + span.mount { font-size:10pt; font: Arial; font-weight:normal; + text-align:center; color:#000000; } + .browser { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#ffff00; vertical-align:middle; text-align:center; background:#d0b070; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px;} + .group2 { vertical-align:middle; + text-align:center; + background:#f0f0e0; + padding:12px; + -webkit-border-radius:10px; + -moz-border-radius:10px; + border-radius:10px; } + .explain { vertical-align:middle; + text-align:center; + background:#f0f0c0; padding:12px; + -webkit-border-radius:10px; + -moz-border-radius:10px; + border-radius:10px; + color:#404000; } + td.wsstatus { vertical-align:middle; width:200px; height:50px; + text-align:center; + background:#f0f0c0; padding:6px; + -webkit-border-radius:8px; + -moz-border-radius:8px; + border-radius:8px; + color:#404000; } + td.l { vertical-align:middle; + text-align:center; + background:#d0d0b0; + padding:3px; + -webkit-border-radius:3px; + -moz-border-radius:3px; + border-radius:3px; } + td.c { vertical-align:middle; + text-align:center; + background:#c0c0a0; + padding:3px; + -webkit-border-radius:3px; + -moz-border-radius:3px; + border-radius:3px; } + td.t { vertical-align:middle; + text-align:center; + background:#e0e0c0; + padding:3px; + -webkit-border-radius:3px; + -moz-border-radius:3px; + border-radius:3px; } + .content { vertical-align:top; text-align:center; background:#fffff0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; } + .canvas { vertical-align:top; text-align:center; background:#efefd0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; } +.tabs { + position: relative; + min-height: 750px; /* This part sucks */ + clear: both; + margin: 25px 0; +} +.tab { + float: left; +} +.tab label { + background: #eee; + padding: 10px; + border: 1px solid #ccc; + margin-left: -1px; + position: relative; + left: 1px; +} +.tab [type=radio] { + display: none; +} +.content { + position: absolute; + top: 28px; + left: 0; + background: white; + right: 0; + bottom: 0; + padding: 20px; + border: 1px solid #ccc; +} +[type=radio]:checked ~ label { + background: white; + border-bottom: 1px solid white; + z-index: 2; +} +[type=radio]:checked ~ label ~ .content { + z-index: 1; +} +</style> +</head> + +<body> +<header></header> +<article> + +<table><tr><td align=center> +<div id="conninfo">...</div> +</td></tr> + + +</table> + +</article> + +<script> + +/* + * We display untrusted stuff in html context... reject anything + * that has HTML stuff in it + */ + +function san(s) +{ + if (s.search("<") != -1) + return "invalid string"; + + return s; +} + + var pos = 0; + +function get_appropriate_ws_url() +{ + var pcol; + var u = document.URL; + + /* + * We open the websocket encrypted if this page came on an + * https:// url itself, otherwise unencrypted + */ + + if (u.substring(0, 5) == "https") { + pcol = "wss://"; + u = u.substr(8); + } else { + pcol = "ws://"; + if (u.substring(0, 4) == "http") + u = u.substr(7); + } + + u = u.split('/'); + + /* + "/xxx" bit is for IE10 workaround */ + + return pcol + u[0] + "/xxx"; +} + + + var socket_status, jso, s; + + if (typeof MozWebSocket != "undefined") { + socket_status = new MozWebSocket(get_appropriate_ws_url(), + "lws-server-status"); + } else { + socket_status = new WebSocket(get_appropriate_ws_url(), + "lws-server-status"); + } + + + try { + socket_status.onopen = function() { + } + + socket_status.onmessage =function got_packet(msg) { + document.getElementById("conninfo").innerHTML = "<pre>"+msg.data+"</pre>"; + jso = JSON.parse(msg.data); + + s="<table><tr><td class=\"c\">" + + "Context</td><td>Uptime: " + san(jso.uptime) + "<br>" + + "Current wsi alive: " + san(jso.wsi_alive) + + "</td></tr>"; + var n; + for (n = 0; n < jso.vhosts.length; n++) { + s = s + "<tr><td class=\"l\">vhost " + (n + 1) + + "</td><td><b>" + san(jso.vhosts[n].name) + ":" + + san(jso.vhosts[n].port) + + "</b><br>" + + "ssl " + san(jso.vhosts[n].use_ssl) + ", " + + "sts " + san(jso.vhosts[n].sts) + "<br>" + + "rx " + san(jso.vhosts[n].rx) + ", " + + "tx " + san(jso.vhosts[n].tx) + "<br>" + + "total connections " + san(jso.vhosts[n].conn) + ", " + + "total http transactions " + san(jso.vhosts[n].trans) + "<br>" + + "Upgrades to ws " + san(jso.vhosts[n].ws_upg) + ", " + + "to http2 " + san(jso.vhosts[n].http2_upg) + "<br>" + + "<table><tr><td class=t colspan=2>Mounts</td></tr>"; + + var m; + for (m = 0; m < jso.vhosts[n].mounts.length; m++) { + s = s + "<tr><td>"; + s = s + san(jso.vhosts[n].mounts[m].mountpoint) + + "</td><td>" + + san(jso.vhosts[n].mounts[m].origin); + s = s + "</td></tr>" + } + s = s + "</table>"; + s = s + "</td></tr>"; + } + s = s + "</table>"; + + document.getElementById("conninfo").innerHTML = s; + } + + socket_status.onclose = function(){ + document.getElementById("s_statustd").style.backgroundColor = "#ff4040"; + document.getElementById("s_status").textContent = " websocket connection CLOSED "; + } + } catch(exception) { + alert('<p>Error' + exception); + } +</script> + +</body> +</html>