diff --git a/README.md b/README.md
index 6f919b795..390edf89b 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,8 @@ lightweight, configurable, scalable and flexible way. It's easy to build and
cross-build via cmake and is suitable for tasks from embedded RTOS through mass
cloud serving.
-[50 minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples) for various scenarios, CC0-licensed (public domain) for cut-and-paste, allow you to get started quickly.
+[50 minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples) for
+various scenarios, CC0-licensed (public domain) for cut-and-paste, allow you to get started quickly.

@@ -19,38 +20,38 @@ News
- **lws threadpool** - lightweight pool of pthreads integrated to lws wsi, with all
synchronization to event loop handled internally, queue for excess tasks
- [threadpool docs](https://libwebsockets.org/git/libwebsockets/tree/lib/misc/threadpool)
- [threadpool minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/ws-server/minimal-ws-server-threadpool)
+ [threadpool docs](https://libwebsockets.org/git/libwebsockets/tree/lib/misc/threadpool),
+ [threadpool minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/ws-server/minimal-ws-server-threadpool),
Cmake config: `-DLWS_WITH_THREADPOOL=1`
- **libdbus support** integrated on lws event loop
- [lws dbus docs](https://libwebsockets.org/git/libwebsockets/tree/lib/roles/dbus)
- [lws dbus client minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/dbus-client)
- [lws dbus server minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/dbus-server)
+ [lws dbus docs](https://libwebsockets.org/git/libwebsockets/tree/lib/roles/dbus),
+ [lws dbus client minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/dbus-client),
+ [lws dbus server minimal examples](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/dbus-server),
Cmake config: `-DLWS_ROLE_DBUS=1`
- **lws allocated chunks (lwsac)** - helpers for optimized mass allocation of small
objects inside a few larger malloc chunks... if you need to allocate a lot of
inter-related structs for a limited time, this removes per-struct allocation
library overhead completely and removes the need for any destruction handling
- [lwsac docs](https://libwebsockets.org/git/libwebsockets/tree/lib/misc/lwsac)
- [lwsac minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-lwsac)
+ [lwsac docs](https://libwebsockets.org/git/libwebsockets/tree/lib/misc/lwsac),
+ [lwsac minimal example](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-lwsac),
Cmake Config: `-DLWS_WITH_LWSAC=1`
- **lws tokenizer** - helper api for robustly tokenizing your own strings without
allocating or adding complexity. Configurable by flags for common delimiter
sets and comma-separated-lists in the tokenizer. Detects and reports syntax
errors.
- [lws_tokenize docs](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-tokenize.h)
+ [lws_tokenize docs](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-tokenize.h),
[lws_tokenize minimal example / api test](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-lws_tokenize)
- **lws full-text search** - optimized trie generation, serialization,
autocomplete suggestion generation and instant global search support extensible
to huge corpuses of UTF-8 text while remaining super lightweight on resources.
- [full-text search docs](https://libwebsockets.org/git/libwebsockets/tree/lib/misc/fts)
- [full-text search minimal example / api test](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-fts)
- [demo](https://libwebsockets.org/ftsdemo/)
- [demo sources](https://libwebsockets.org/git/libwebsockets/tree/plugins/protocol_fulltext_demo.c)
+ [full-text search docs](https://libwebsockets.org/git/libwebsockets/tree/lib/misc/fts),
+ [full-text search minimal example / api test](https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/api-tests/api-test-fts),
+ [demo](https://libwebsockets.org/ftsdemo/),
+ [demo sources](https://libwebsockets.org/git/libwebsockets/tree/plugins/protocol_fulltext_demo.c),
Cmake config: `-DLWS_WITH_FTS=1 -DLWS_WITH_LWSAC=1`
- **gzip + brotli http server-side compression** - h1 and h2 detection of client support
@@ -62,7 +63,7 @@ News
- **managed disk cache** - API for managing a directory containing cached files
with hashed names, and automatic deletion of LRU files once the cache is
above a given limit.
- [lws diskcache docs](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-diskcache.h)
+ [lws diskcache docs](https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-diskcache.h),
Cmake config: `-DLWS_WITH_DISKCACHE=1`
- **http reverse proxy** - lws mounts support proxying h1 or h2 requests to
@@ -70,11 +71,18 @@ News
type architectures where parts of the common URL space are actually handled
by external processes which may be remote or on the same machine.
[lws gitohashi serving](https://libwebsockets.org/git/) is handled this way.
- [unix domain sockets reverse proxy docs](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.unix-domain-reverse-proxy.md)
- CMake config: `-DLWS_WITH_HTTP_PROXY=1`
+ [unix domain sockets reverse proxy docs](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.unix-domain-reverse-proxy.md),
+ CMake config: `-DLWS_WITH_HTTP_PROXY=1` and `-DLWS_UNIX_SOCK=1` for Unix Domain Sockets
+
+ - **update minimal examples for strict Content Security Policy** the minimal
+ examples now show the best practices around Content Security Policy and
+ disabling inline Javascript. Updated examples that are served with the
+ recommended security restrictions show a new "Strict Content Security Policy"
+ graphic. [Read how to upgrade your applications to use a strict CSP](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.content-security-policy.md).
- **release policy docs** - unsure what branch, version or tag to use, or how
to follow master cleanly? [Read the release policy docs](https://libwebsockets.org/git/libwebsockets/tree/READMEs/README.release-policy.md)
+ which explain how and why lws is developed, released and maintained.
## v3.0.1 released
diff --git a/READMEs/README.content-security-policy.md b/READMEs/README.content-security-policy.md
index 4514a67d6..0fe0cc209 100644
--- a/READMEs/README.content-security-policy.md
+++ b/READMEs/README.content-security-policy.md
@@ -85,7 +85,8 @@ completely rejected by the browser.
Inline `onclick()` etc are kinds of inline scripting and are banned.
Modern browsers have offered a different system called ["EventListener" for
-a while](https://developer.mozilla.org/en-US/docs/Web/API/EventListener) which allows binding of events to DOM elements in JS.
+a while](https://developer.mozilla.org/en-US/docs/Web/API/EventListener)
+which allows binding of events to DOM elements in JS.
A bunch of different named events are possible to listen on, commonly the
`.js` file will ask for one or both of
diff --git a/READMEs/README.unix-domain-reverse-proxy.md b/READMEs/README.unix-domain-reverse-proxy.md
index ef61968d3..bca4f7520 100644
--- a/READMEs/README.unix-domain-reverse-proxy.md
+++ b/READMEs/README.unix-domain-reverse-proxy.md
@@ -7,7 +7,9 @@ lws is able to use a mount to place reverse proxies into the URL space.
These are particularly useful when using Unix Domain Sockets, basically
files in the server filesystem, to communicate between lws and a separate
server process and integrate the result into a coherent URL namespace on
-the lws side.
+the lws side. It's also possible to proxy using tcp sockets.
+
+
This has the advantage that the actual web server that forwards the
data from the unix socket owner is in a different process than the server
diff --git a/changelog b/changelog
index e3ce5f2ce..42b8fd2c0 100644
--- a/changelog
+++ b/changelog
@@ -12,6 +12,11 @@ v3.1.0
- CHANGE: CMAKE:
- LWS_WITH_HTTP2: now defaults ON
+ - CHANGE: Minimal examples updated to use Content Security Policy best
+ practices, using
+ `LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE` vhost
+ option flag and disabling of inline style and scripts.
+
- NEW: CMAKE
- LWS_FOR_GITOHASHI: sets various cmake options suitable for gitohashi
- LWS_WITH_ASAN: for Linux, enable build with ASAN
diff --git a/doc-assets/http-proxy-overview.svg b/doc-assets/http-proxy-overview.svg
new file mode 100644
index 000000000..fbfcf0cfc
--- /dev/null
+++ b/doc-assets/http-proxy-overview.svg
@@ -0,0 +1,84 @@
+
+
diff --git a/include/libwebsockets/lws-context-vhost.h b/include/libwebsockets/lws-context-vhost.h
index 10627a2cb..c6ab222a2 100644
--- a/include/libwebsockets/lws-context-vhost.h
+++ b/include/libwebsockets/lws-context-vhost.h
@@ -145,6 +145,20 @@ enum lws_context_options {
* allow lax hostname mappings like localhost / 127.0.0.1, and CNAME
* mappings like www.mysite.com / mysite.com
*/
+ LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE = (1 << 28),
+ /**< (VH) Send lws default HTTP headers recommended by Mozilla Observatory
+ * for security. This is a helper option that sends canned headers on each
+ * http response enabling a VERY strict Content Security Policy. The policy
+ * is so strict, for example it won't let the page run its own inline JS nor
+ * show images or take CSS from a different server. In many cases your JS only
+ * comes from your server as do the image sources and CSS, so that is what you
+ * want... attackers hoping to inject JS into your DOM are completely out of
+ * luck since even if they succeed, it will be rejected for execution by the
+ * browser according to the strict CSP. In other cases you have to deviate from
+ * the complete strictness, in which case don't use this flag: use the .headers
+ * member in the vhost init described in struct lws_context_creation_info
+ * instead to send the adapted headers yourself.
+ */
/****** add new things just above ---^ ******/
};
diff --git a/include/libwebsockets/lws-http.h b/include/libwebsockets/lws-http.h
index 97a2c712c..9319ac98f 100644
--- a/include/libwebsockets/lws-http.h
+++ b/include/libwebsockets/lws-http.h
@@ -21,6 +21,9 @@
* included from libwebsockets.h
*/
+/* minimal space for typical headers and CSP stuff */
+
+#define LWS_RECOMMENDED_MIN_HEADER_SPACE 2048
/*! \defgroup http HTTP
diff --git a/lib/roles/h2/ops-h2.c b/lib/roles/h2/ops-h2.c
index 76d5a62b7..ea3f69d45 100644
--- a/lib/roles/h2/ops-h2.c
+++ b/lib/roles/h2/ops-h2.c
@@ -739,11 +739,10 @@ rops_callback_on_writable_h2(struct lws *wsi)
/* for network action, act only on the network wsi */
- wsi = network_wsi;
if (already
#if !defined(LWS_NO_CLIENT)
- && !wsi->client_h2_alpn
- && !wsi->client_h2_substream
+ && !network_wsi->client_h2_alpn
+ && !network_wsi->client_h2_substream
#endif
)
return 1;
diff --git a/lib/roles/http/header.c b/lib/roles/http/header.c
index 0a7d92e04..2fbed12ce 100644
--- a/lib/roles/http/header.c
+++ b/lib/roles/http/header.c
@@ -242,6 +242,26 @@ static const char * const err500[] = {
"HTTP Version Not Supported"
};
+/* security best practices from Mozilla Observatory */
+
+static const
+struct lws_protocol_vhost_options pvo_hsbph[] = {{
+ NULL, NULL, "referrer-policy:", "no-referrer"
+}, {
+ &pvo_hsbph[0], NULL, "x-frame-options:", "deny"
+}, {
+ &pvo_hsbph[1], NULL, "x-xss-protection:", "1; mode=block"
+}, {
+ &pvo_hsbph[2], NULL, "x-content-type-options:", "nosniff"
+}, {
+ &pvo_hsbph[3], NULL, "content-security-policy:",
+ "default-src 'none'; img-src 'self' data: ; "
+ "script-src 'self'; font-src 'self'; "
+ "style-src 'self'; connect-src 'self'; "
+ "frame-ancestors 'none'; base-uri 'none';"
+ "form-action 'self';"
+}};
+
int
lws_add_http_header_status(struct lws *wsi, unsigned int _code,
unsigned char **p, unsigned char *end)
@@ -306,6 +326,20 @@ lws_add_http_header_status(struct lws *wsi, unsigned int _code,
headers = headers->next;
}
+ if (wsi->vhost->options &
+ LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE) {
+ headers = &pvo_hsbph[LWS_ARRAY_SIZE(pvo_hsbph) - 1];
+ while (headers) {
+ if (lws_add_http_header_by_name(wsi,
+ (const unsigned char *)headers->name,
+ (unsigned char *)headers->value,
+ (int)strlen(headers->value), p, end))
+ return 1;
+
+ headers = headers->next;
+ }
+ }
+
if (wsi->context->server_string &&
!(_code & LWSAHH_FLAG_NO_SERVER_NAME))
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
diff --git a/minimal-examples/client-server/minimal-ws-proxy/minimal-ws-proxy.c b/minimal-examples/client-server/minimal-ws-proxy/minimal-ws-proxy.c
index 6c9eaab85..f7c25fc38 100644
--- a/minimal-examples/client-server/minimal-ws-proxy/minimal-ws-proxy.c
+++ b/minimal-examples/client-server/minimal-ws-proxy/minimal-ws-proxy.c
@@ -78,7 +78,8 @@ int main(int argc, const char **argv)
lwsl_user("LWS minimal ws proxy | visit http://localhost:7681\n");
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
- info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
+ info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
+ LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
info.port = 7681;
info.mounts = &mount;
info.protocols = protocols;
diff --git a/minimal-examples/client-server/minimal-ws-proxy/mount-origin/example.js b/minimal-examples/client-server/minimal-ws-proxy/mount-origin/example.js
new file mode 100644
index 000000000..a25a3cd44
--- /dev/null
+++ b/minimal-examples/client-server/minimal-ws-proxy/mount-origin/example.js
@@ -0,0 +1,70 @@
+var head = 0, tail = 0, ring = new Array();
+
+function get_appropriate_ws_url(extra_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] + "/" + extra_url;
+}
+
+function new_ws(urlpath, protocol)
+{
+ if (typeof MozWebSocket != "undefined")
+ return new MozWebSocket(urlpath, protocol);
+
+ return new WebSocket(urlpath, protocol);
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+
+ ws = new_ws(get_appropriate_ws_url(""), "lws-minimal-proxy");
+ try {
+ ws.onopen = function() {
+ document.getElementById("r").disabled = 0;
+ };
+
+ ws.onmessage =function got_packet(msg) {
+ var n, s = "";
+
+ ring[head] = msg.data + "\n";
+ head = (head + 1) % 20;
+ if (tail === head)
+ tail = (tail + 1) % 20;
+
+ n = tail;
+ do {
+ s = s + ring[n];
+ n = (n + 1) % 20;
+ } while (n !== head);
+
+ document.getElementById("r").value = s;
+ document.getElementById("r").scrollTop =
+ document.getElementById("r").scrollHeight;
+ };
+
+ ws.onclose = function(){
+ document.getElementById("r").disabled = 1;
+ };
+ } catch(exception) {
+ alert("
+
+
+
-
-
+
+
+
Hello from the minimal http Server Side Events example.
This is a static page served from ./mount-origin/index.html.
It connects back to the server at /sse/sourcename using EventSource()
- and displays the perioding incoming event data below.
+ and displays the periodic incoming event data below.
+
+
+
-
-
-
+
+
+
LWS bulk transfer example.
A large ws message is sent to all browsers open on this page.
The browser js echoes the large ws message back to the server.
@@ -11,81 +14,6 @@
Ws closed
-
-
-
-
-
-
diff --git a/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/libwebsockets.org-logo.png b/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/libwebsockets.org-logo.png
deleted file mode 100644
index 2060a10c9..000000000
Binary files a/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/libwebsockets.org-logo.png and /dev/null differ
diff --git a/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/libwebsockets.org-logo.svg b/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/libwebsockets.org-logo.svg
new file mode 100644
index 000000000..7baea649f
--- /dev/null
+++ b/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/libwebsockets.org-logo.svg
@@ -0,0 +1,120 @@
+
+
diff --git a/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/strict-csp.svg b/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/strict-csp.svg
new file mode 100644
index 000000000..cd128f1d2
--- /dev/null
+++ b/minimal-examples/ws-server/minimal-ws-server-pmd-bulk/mount-origin/strict-csp.svg
@@ -0,0 +1,53 @@
+
+
diff --git a/minimal-examples/ws-server/minimal-ws-server-pmd/minimal-ws-server-pmd.c b/minimal-examples/ws-server/minimal-ws-server-pmd/minimal-ws-server-pmd.c
index 25cded376..40e3b85cf 100644
--- a/minimal-examples/ws-server/minimal-ws-server-pmd/minimal-ws-server-pmd.c
+++ b/minimal-examples/ws-server/minimal-ws-server-pmd/minimal-ws-server-pmd.c
@@ -90,6 +90,8 @@ int main(int argc, const char **argv)
info.mounts = &mount;
info.protocols = protocols;
info.extensions = extensions;
+ info.options =
+ LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
context = lws_create_context(&info);
if (!context) {
diff --git a/minimal-examples/ws-server/minimal-ws-server-pmd/mount-origin/example.js b/minimal-examples/ws-server/minimal-ws-server-pmd/mount-origin/example.js
new file mode 100644
index 000000000..4760a20f8
--- /dev/null
+++ b/minimal-examples/ws-server/minimal-ws-server-pmd/mount-origin/example.js
@@ -0,0 +1,71 @@
+
+function get_appropriate_ws_url(extra_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] + "/" + extra_url;
+}
+
+function new_ws(urlpath, protocol)
+{
+ if (typeof MozWebSocket != "undefined")
+ return new MozWebSocket(urlpath, protocol);
+
+ return new WebSocket(urlpath, protocol);
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+
+ ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
+ try {
+ ws.onopen = function() {
+ document.getElementById("m").disabled = 0;
+ document.getElementById("b").disabled = 0;
+ document.getElementById("status").textContent = "ws open "+ ws.extensions;
+ };
+
+ ws.onmessage =function got_packet(msg) {
+ document.getElementById("r").value =
+ document.getElementById("r").value + msg.data + "\n";
+ document.getElementById("r").scrollTop =
+ document.getElementById("r").scrollHeight;
+ };
+
+ ws.onclose = function(){
+ document.getElementById("m").disabled = 1;
+ document.getElementById("b").disabled = 1;
+ document.getElementById("status").textContent = "ws closed";
+ };
+ } catch(exception) {
+ alert("
+
+
+
-
-
+
+
+
Minimal ws server threadpool example.
8 x ws connections are opened back to the example server.
There are three threads in the pool to service them, the
@@ -12,86 +16,4 @@
-
-
-
-
diff --git a/minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/libwebsockets.org-logo.png b/minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/libwebsockets.org-logo.png
deleted file mode 100644
index 2060a10c9..000000000
Binary files a/minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/libwebsockets.org-logo.png and /dev/null differ
diff --git a/minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/libwebsockets.org-logo.svg b/minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/libwebsockets.org-logo.svg
new file mode 100644
index 000000000..7baea649f
--- /dev/null
+++ b/minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/libwebsockets.org-logo.svg
@@ -0,0 +1,120 @@
+
+
diff --git a/minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/strict-csp.svg b/minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/strict-csp.svg
new file mode 100644
index 000000000..cd128f1d2
--- /dev/null
+++ b/minimal-examples/ws-server/minimal-ws-server-threadpool/mount-origin/strict-csp.svg
@@ -0,0 +1,53 @@
+
+
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads/minimal-ws-server.c b/minimal-examples/ws-server/minimal-ws-server-threads/minimal-ws-server.c
index 1632626a4..0f2e9fa6a 100644
--- a/minimal-examples/ws-server/minimal-ws-server-threads/minimal-ws-server.c
+++ b/minimal-examples/ws-server/minimal-ws-server-threads/minimal-ws-server.c
@@ -108,6 +108,8 @@ int main(int argc, const char **argv)
info.mounts = &mount;
info.protocols = protocols;
info.pvo = &pvo; /* per-vhost options */
+ info.options =
+ LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
context = lws_create_context(&info);
if (!context) {
diff --git a/minimal-examples/ws-server/minimal-ws-server-threads/mount-origin/example.js b/minimal-examples/ws-server/minimal-ws-server-threads/mount-origin/example.js
new file mode 100644
index 000000000..a6ff6630f
--- /dev/null
+++ b/minimal-examples/ws-server/minimal-ws-server-threads/mount-origin/example.js
@@ -0,0 +1,71 @@
+var head = 0, tail = 0, ring = new Array();
+
+function get_appropriate_ws_url(extra_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] + "/" + extra_url;
+}
+
+function new_ws(urlpath, protocol)
+{
+ if (typeof MozWebSocket != "undefined")
+ return new MozWebSocket(urlpath, protocol);
+
+ return new WebSocket(urlpath, protocol);
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+
+ ws = new_ws(get_appropriate_ws_url(""), "lws-minimal");
+ try {
+ ws.onopen = function() {
+ document.getElementById("r").disabled = 0;
+ };
+
+ ws.onmessage =function got_packet(msg) {
+ var n, s = "";
+
+ ring[head] = msg.data + "\n";
+ head = (head + 1) % 50;
+ if (tail === head)
+ tail = (tail + 1) % 50;
+
+ n = tail;
+ do {
+ s = s + ring[n];
+ n = (n + 1) % 50;
+ } while (n !== head);
+
+ document.getElementById("r").value = s;
+ document.getElementById("r").scrollTop =
+ document.getElementById("r").scrollHeight;
+ };
+
+ ws.onclose = function(){
+ document.getElementById("r").disabled = 1;
+ };
+ } catch(exception) {
+ alert("