522 lines
20 KiB
HTML
522 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
|
|
|
|
<link rel="shortcut icon" href="../img/favicon.ico">
|
|
<title>Ws - IXWebSocket</title>
|
|
<link href="../css/bootstrap-custom.min.css" rel="stylesheet">
|
|
<link href="../css/font-awesome.min.css" rel="stylesheet">
|
|
<link href="../css/base.css" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css">
|
|
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
|
<!--[if lt IE 9]>
|
|
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
|
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
|
|
<![endif]-->
|
|
|
|
<script src="../js/jquery-1.10.2.min.js" defer></script>
|
|
<script src="../js/bootstrap-3.0.3.min.js" defer></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
|
|
<script>hljs.initHighlightingOnLoad();</script>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
|
|
<div class="container">
|
|
|
|
<!-- Collapsed navigation -->
|
|
<div class="navbar-header">
|
|
<!-- Expander button -->
|
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
|
<span class="sr-only">Toggle navigation</span>
|
|
<span class="icon-bar"></span>
|
|
<span class="icon-bar"></span>
|
|
<span class="icon-bar"></span>
|
|
</button>
|
|
<a class="navbar-brand" href="..">IXWebSocket</a>
|
|
</div>
|
|
|
|
<!-- Expanded navigation -->
|
|
<div class="navbar-collapse collapse">
|
|
<!-- Main navigation -->
|
|
<ul class="nav navbar-nav">
|
|
<li >
|
|
<a href="..">Home</a>
|
|
</li>
|
|
<li >
|
|
<a href="../CHANGELOG/">Changelog</a>
|
|
</li>
|
|
<li >
|
|
<a href="../build/">Build</a>
|
|
</li>
|
|
<li >
|
|
<a href="../cobra/">Cobra</a>
|
|
</li>
|
|
<li >
|
|
<a href="../design/">Design</a>
|
|
</li>
|
|
<li >
|
|
<a href="../usage/">Examples</a>
|
|
</li>
|
|
<li class="active">
|
|
<a href="./">Ws</a>
|
|
</li>
|
|
</ul>
|
|
|
|
<ul class="nav navbar-nav navbar-right">
|
|
<li>
|
|
<a href="#" data-toggle="modal" data-target="#mkdocs_search_modal">
|
|
<i class="fa fa-search"></i> Search
|
|
</a>
|
|
</li>
|
|
<li >
|
|
<a rel="next" href="../usage/">
|
|
<i class="fa fa-arrow-left"></i> Previous
|
|
</a>
|
|
</li>
|
|
<li class="disabled">
|
|
<a rel="prev" >
|
|
Next <i class="fa fa-arrow-right"></i>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container">
|
|
<div class="col-md-3"><div class="bs-sidebar hidden-print affix well" role="complementary">
|
|
<ul class="nav bs-sidenav">
|
|
<li class="main active"><a href="#general">General</a></li>
|
|
<li class="main "><a href="#curl">curl</a></li>
|
|
<li class="main "><a href="#connect">connect</a></li>
|
|
<li class="main "><a href="#websocket-proxy">Websocket proxy</a></li>
|
|
<li class="main "><a href="#file-transfer">File transfer</a></li>
|
|
<li class="main "><a href="#http-client">HTTP Client</a></li>
|
|
<li class="main "><a href="#cobra-client-and-server">Cobra client and server</a></li>
|
|
</ul>
|
|
</div></div>
|
|
<div class="col-md-9" role="main">
|
|
|
|
<h2 id="general">General</h2>
|
|
<p>ws is a command line tool that should exercise most of the IXWebSocket code, and provide example code.</p>
|
|
<pre><code>ws is a websocket tool
|
|
Usage: ws [OPTIONS] SUBCOMMAND
|
|
|
|
Options:
|
|
-h,--help Print this help message and exit
|
|
|
|
Subcommands:
|
|
send Send a file
|
|
receive Receive a file
|
|
transfer Broadcasting server
|
|
connect Connect to a remote server
|
|
chat Group chat
|
|
echo_server Echo server
|
|
broadcast_server Broadcasting server
|
|
ping Ping pong
|
|
curl HTTP Client
|
|
redis_publish Redis publisher
|
|
redis_subscribe Redis subscriber
|
|
cobra_subscribe Cobra subscriber
|
|
cobra_publish Cobra publisher
|
|
cobra_to_statsd Cobra to statsd
|
|
cobra_to_sentry Cobra to sentry
|
|
snake Snake server
|
|
httpd HTTP server
|
|
</code></pre>
|
|
|
|
<h2 id="curl">curl</h2>
|
|
<p>The curl subcommand try to be compatible with the curl syntax, to fetch http pages.</p>
|
|
<p>Making a HEAD request with the -I parameter.</p>
|
|
<pre><code>$ ws curl -I https://www.google.com/
|
|
|
|
Accept-Ranges: none
|
|
Alt-Svc: quic=":443"; ma=2592000; v="46,43",h3-Q048=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000
|
|
Cache-Control: private, max-age=0
|
|
Content-Type: text/html; charset=ISO-8859-1
|
|
Date: Tue, 08 Oct 2019 21:36:57 GMT
|
|
Expires: -1
|
|
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
|
|
Server: gws
|
|
Set-Cookie: NID=188=ASwfz8GrXQrHCLqAz-AndLOMLcz0rC9yecnf3h0yXZxRL3rTufTU_GDDwERp7qQL7LZ_EB8gCRyPXGERyOSAgaqgnrkoTmvWrwFemRLMaOZ896GrHobi5fV7VLklnSG2w48Gj8xMlwxfP7Z-bX-xR9UZxep1tHM6UmFQdD_GkBE; expires=Wed, 08-Apr-2020 21:36:57 GMT; path=/; domain=.google.com; HttpOnly
|
|
Transfer-Encoding: chunked
|
|
Vary: Accept-Encoding
|
|
X-Frame-Options: SAMEORIGIN
|
|
X-XSS-Protection: 0
|
|
Upload size: 143
|
|
Download size: 0
|
|
Status: 200
|
|
</code></pre>
|
|
|
|
<p>Making a POST request with the -F parameter.</p>
|
|
<pre><code>$ ws curl -F foo=bar https://httpbin.org/post
|
|
foo: bar
|
|
Downloaded 438 bytes out of 438
|
|
Access-Control-Allow-Credentials: true
|
|
Access-Control-Allow-Origin: *
|
|
Connection: keep-alive
|
|
Content-Encoding:
|
|
Content-Length: 438
|
|
Content-Type: application/json
|
|
Date: Tue, 08 Oct 2019 21:47:54 GMT
|
|
Referrer-Policy: no-referrer-when-downgrade
|
|
Server: nginx
|
|
X-Content-Type-Options: nosniff
|
|
X-Frame-Options: DENY
|
|
X-XSS-Protection: 1; mode=block
|
|
Upload size: 219
|
|
Download size: 438
|
|
Status: 200
|
|
payload: {
|
|
"args": {},
|
|
"data": "",
|
|
"files": {},
|
|
"form": {
|
|
"foo": "bar"
|
|
},
|
|
"headers": {
|
|
"Accept": "*/*",
|
|
"Content-Length": "7",
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
"Host": "httpbin.org",
|
|
"User-Agent": "ixwebsocket/7.0.0 macos ssl/OpenSSL OpenSSL 1.0.2q 20 Nov 2018 zlib 1.2.11"
|
|
},
|
|
"json": null,
|
|
"origin": "155.94.127.118, 155.94.127.118",
|
|
"url": "https://httpbin.org/post"
|
|
}
|
|
</code></pre>
|
|
|
|
<p>Passing in a custom header with -H.</p>
|
|
<pre><code>$ ws curl -F foo=bar -H 'my_custom_header: baz' https://httpbin.org/post
|
|
my_custom_header: baz
|
|
foo: bar
|
|
Downloaded 470 bytes out of 470
|
|
Access-Control-Allow-Credentials: true
|
|
Access-Control-Allow-Origin: *
|
|
Connection: keep-alive
|
|
Content-Encoding:
|
|
Content-Length: 470
|
|
Content-Type: application/json
|
|
Date: Tue, 08 Oct 2019 21:50:25 GMT
|
|
Referrer-Policy: no-referrer-when-downgrade
|
|
Server: nginx
|
|
X-Content-Type-Options: nosniff
|
|
X-Frame-Options: DENY
|
|
X-XSS-Protection: 1; mode=block
|
|
Upload size: 243
|
|
Download size: 470
|
|
Status: 200
|
|
payload: {
|
|
"args": {},
|
|
"data": "",
|
|
"files": {},
|
|
"form": {
|
|
"foo": "bar"
|
|
},
|
|
"headers": {
|
|
"Accept": "*/*",
|
|
"Content-Length": "7",
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
"Host": "httpbin.org",
|
|
"My-Custom-Header": "baz",
|
|
"User-Agent": "ixwebsocket/7.0.0 macos ssl/OpenSSL OpenSSL 1.0.2q 20 Nov 2018 zlib 1.2.11"
|
|
},
|
|
"json": null,
|
|
"origin": "155.94.127.118, 155.94.127.118",
|
|
"url": "https://httpbin.org/post"
|
|
}
|
|
</code></pre>
|
|
|
|
<h2 id="connect">connect</h2>
|
|
<p>The connect command connects to a websocket endpoint, and starts an interactive prompt. Line editing, such as using the direction keys to fetch the last thing you tried to type) is provided. That command is pretty useful to try to send random data to an endpoint and verify that the service handles it with grace (such as sending invalid json).</p>
|
|
<pre><code>ws connect wss://echo.websocket.org
|
|
Type Ctrl-D to exit prompt...
|
|
Connecting to url: wss://echo.websocket.org
|
|
> ws_connect: connected
|
|
Uri: /
|
|
Handshake Headers:
|
|
Connection: Upgrade
|
|
Date: Tue, 08 Oct 2019 21:38:44 GMT
|
|
Sec-WebSocket-Accept: 2j6LBScZveqrMx1W/GJkCWvZo3M=
|
|
sec-websocket-extensions:
|
|
Server: Kaazing Gateway
|
|
Upgrade: websocket
|
|
Received ping
|
|
Received ping
|
|
Received ping
|
|
Hello world !
|
|
> Received 13 bytes
|
|
ws_connect: received message: Hello world !
|
|
> Hello world !
|
|
> Received 13 bytes
|
|
ws_connect: received message: Hello world !
|
|
</code></pre>
|
|
|
|
<pre><code>ws connect 'ws://jeanserge.com/v2?appkey=_pubsub'
|
|
Type Ctrl-D to exit prompt...
|
|
Connecting to url: ws://jeanserge.com/v2?appkey=_pubsub
|
|
> ws_connect: connected
|
|
Uri: /v2?appkey=_pubsub
|
|
Handshake Headers:
|
|
Connection: Upgrade
|
|
Date: Tue, 08 Oct 2019 21:45:28 GMT
|
|
Sec-WebSocket-Accept: LYHmjh9Gsu/Yw7aumQqyPObOEV4=
|
|
Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
|
|
Server: Python/3.7 websockets/8.0.2
|
|
Upgrade: websocket
|
|
bababababababab
|
|
> ws_connect: connection closed: code 1000 reason
|
|
|
|
ws_connect: connected
|
|
Uri: /v2?appkey=_pubsub
|
|
Handshake Headers:
|
|
Connection: Upgrade
|
|
Date: Tue, 08 Oct 2019 21:45:44 GMT
|
|
Sec-WebSocket-Accept: I1rqxdLgTU+opPi5/zKPBTuXdLw=
|
|
Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
|
|
Server: Python/3.7 websockets/8.0.2
|
|
Upgrade: websocket
|
|
</code></pre>
|
|
|
|
<h2 id="websocket-proxy">Websocket proxy</h2>
|
|
<pre><code>ws proxy_server --remote_host ws://127.0.0.1:9000 -v
|
|
Listening on 127.0.0.1:8008
|
|
</code></pre>
|
|
|
|
<p>If you connect to ws://127.0.0.1:8008, the proxy will connect to ws://127.0.0.1:9000 and pass all traffic to this server.</p>
|
|
<h2 id="file-transfer">File transfer</h2>
|
|
<pre><code># Start transfer server, which is just a broadcast server at this point
|
|
ws transfer # running on port 8080.
|
|
|
|
# Start receiver first
|
|
ws receive ws://localhost:8080
|
|
|
|
# Then send a file. File will be received and written to disk by the receiver process
|
|
ws send ws://localhost:8080 /file/to/path
|
|
</code></pre>
|
|
|
|
<h2 id="http-client">HTTP Client</h2>
|
|
<pre><code>$ ws curl --help
|
|
HTTP Client
|
|
Usage: ws curl [OPTIONS] url
|
|
|
|
Positionals:
|
|
url TEXT REQUIRED Connection url
|
|
|
|
Options:
|
|
-h,--help Print this help message and exit
|
|
-d TEXT Form data
|
|
-F TEXT Form data
|
|
-H TEXT Header
|
|
--output TEXT Output file
|
|
-I Send a HEAD request
|
|
-L Follow redirects
|
|
--max-redirects INT Max Redirects
|
|
-v Verbose
|
|
-O Save output to disk
|
|
--compress Enable gzip compression
|
|
--connect-timeout INT Connection timeout
|
|
--transfer-timeout INT Transfer timeout
|
|
</code></pre>
|
|
|
|
<h2 id="cobra-client-and-server">Cobra client and server</h2>
|
|
<p><a href="https://github.com/machinezone/cobra">cobra</a> is a real time messenging server. ws has several sub-command to interact with cobra. There is also a minimal cobra compatible server named snake available.</p>
|
|
<p>Below are examples on running a snake server and clients with TLS enabled (the server only works with the OpenSSL backend for now).</p>
|
|
<p>First, generate certificates.</p>
|
|
<pre><code>$ cd /path/to/IXWebSocket
|
|
$ cd ixsnake/ixsnake
|
|
$ bash ../../ws/generate_certs.sh
|
|
Generating RSA private key, 2048 bit long modulus
|
|
.....+++
|
|
.................+++
|
|
e is 65537 (0x10001)
|
|
generated ./.certs/trusted-ca-key.pem
|
|
generated ./.certs/trusted-ca-crt.pem
|
|
Generating RSA private key, 2048 bit long modulus
|
|
..+++
|
|
.......................................+++
|
|
e is 65537 (0x10001)
|
|
generated ./.certs/trusted-server-key.pem
|
|
Signature ok
|
|
subject=/O=machinezone/O=IXWebSocket/CN=trusted-server
|
|
Getting CA Private Key
|
|
generated ./.certs/trusted-server-crt.pem
|
|
Generating RSA private key, 2048 bit long modulus
|
|
...................................+++
|
|
..................................................+++
|
|
e is 65537 (0x10001)
|
|
generated ./.certs/trusted-client-key.pem
|
|
Signature ok
|
|
subject=/O=machinezone/O=IXWebSocket/CN=trusted-client
|
|
Getting CA Private Key
|
|
generated ./.certs/trusted-client-crt.pem
|
|
Generating RSA private key, 2048 bit long modulus
|
|
..............+++
|
|
.......................................+++
|
|
e is 65537 (0x10001)
|
|
generated ./.certs/untrusted-ca-key.pem
|
|
generated ./.certs/untrusted-ca-crt.pem
|
|
Generating RSA private key, 2048 bit long modulus
|
|
..........+++
|
|
................................................+++
|
|
e is 65537 (0x10001)
|
|
generated ./.certs/untrusted-client-key.pem
|
|
Signature ok
|
|
subject=/O=machinezone/O=IXWebSocket/CN=untrusted-client
|
|
Getting CA Private Key
|
|
generated ./.certs/untrusted-client-crt.pem
|
|
Generating RSA private key, 2048 bit long modulus
|
|
.....................................................................................+++
|
|
...........+++
|
|
e is 65537 (0x10001)
|
|
generated ./.certs/selfsigned-client-key.pem
|
|
Signature ok
|
|
subject=/O=machinezone/O=IXWebSocket/CN=selfsigned-client
|
|
Getting Private key
|
|
generated ./.certs/selfsigned-client-crt.pem
|
|
</code></pre>
|
|
|
|
<p>Now run the snake server.</p>
|
|
<pre><code>$ export certs=.certs
|
|
$ ws snake --tls --port 8765 --cert-file ${certs}/trusted-server-crt.pem --key-file ${certs}/trusted-server-key.pem --ca-file ${certs}/trusted-ca-crt.pem
|
|
{
|
|
"apps": {
|
|
"FC2F10139A2BAc53BB72D9db967b024f": {
|
|
"roles": {
|
|
"_sub": {
|
|
"secret": "66B1dA3ED5fA074EB5AE84Dd8CE3b5ba"
|
|
},
|
|
"_pub": {
|
|
"secret": "1c04DB8fFe76A4EeFE3E318C72d771db"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
redis host: 127.0.0.1
|
|
redis password:
|
|
redis port: 6379
|
|
</code></pre>
|
|
|
|
<p>As a new connection comes in, such output should be printed</p>
|
|
<pre><code>[2019-12-19 20:27:19.724] [info] New connection
|
|
id: 0
|
|
Uri: /v2?appkey=_health
|
|
Headers:
|
|
Connection: Upgrade
|
|
Host: 127.0.0.1:8765
|
|
Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
|
|
Sec-WebSocket-Key: d747B0fE61Db73f7Eh47c0==
|
|
Sec-WebSocket-Protocol: json
|
|
Sec-WebSocket-Version: 13
|
|
Upgrade: websocket
|
|
User-Agent: ixwebsocket/7.5.8 macos ssl/OpenSSL OpenSSL 1.0.2q 20 Nov 2018 zlib 1.2.11
|
|
</code></pre>
|
|
|
|
<p>To connect and publish a message, do:</p>
|
|
<pre><code>$ export certs=.certs
|
|
$ cd /path/to/ws/folder
|
|
$ ls cobraMetricsSample.json
|
|
cobraMetricsSample.json
|
|
$ ws cobra_publish --endpoint wss://127.0.0.1:8765 --appkey FC2F10139A2BAc53BB72D9db967b024f --rolename _pub --rolesecret 1c04DB8fFe76A4EeFE3E318C72d771db --channel foo --cert-file ${certs}/trusted-client-crt.pem --key-file ${certs}/trusted-client-key.pem --ca-file ${certs}/trusted-ca-crt.pem cobraMetricsSample.json
|
|
[2019-12-19 20:46:42.656] [info] Publisher connected
|
|
[2019-12-19 20:46:42.657] [info] Connection: Upgrade
|
|
[2019-12-19 20:46:42.657] [info] Sec-WebSocket-Accept: rs99IFThoBrhSg+k8G4ixH9yaq4=
|
|
[2019-12-19 20:46:42.657] [info] Sec-WebSocket-Extensions: permessage-deflate; server_max_window_bits=15; client_max_window_bits=15
|
|
[2019-12-19 20:46:42.657] [info] Server: ixwebsocket/7.5.8 macos ssl/OpenSSL OpenSSL 1.0.2q 20 Nov 2018 zlib 1.2.11
|
|
[2019-12-19 20:46:42.657] [info] Upgrade: websocket
|
|
[2019-12-19 20:46:42.658] [info] Publisher authenticated
|
|
[2019-12-19 20:46:42.658] [info] Published msg 3
|
|
[2019-12-19 20:46:42.659] [info] Published message id 3 acked
|
|
</code></pre>
|
|
|
|
<p>To use OpenSSL on macOS, compile with <code>make ws_openssl</code>. First you will have to install OpenSSL libraries, which can be done with Homebrew.</p></div>
|
|
</div>
|
|
|
|
<footer class="col-md-12">
|
|
<hr>
|
|
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
|
|
</footer>
|
|
<script>
|
|
var base_url = "..",
|
|
shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
|
|
</script>
|
|
<script src="../js/base.js" defer></script>
|
|
<script src="../search/main.js" defer></script>
|
|
|
|
<div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="Search Modal" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
|
<h4 class="modal-title" id="exampleModalLabel">Search</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>
|
|
From here you can search these documents. Enter
|
|
your search terms below.
|
|
</p>
|
|
<form role="form">
|
|
<div class="form-group">
|
|
<input type="text" class="form-control" placeholder="Search..." id="mkdocs-search-query" title="Type search term here">
|
|
</div>
|
|
</form>
|
|
<div id="mkdocs-search-results"></div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="Keyboard Shortcuts Modal" aria-hidden="true">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
|
<h4 class="modal-title" id="exampleModalLabel">Keyboard Shortcuts</h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th style="width: 20%;">Keys</th>
|
|
<th>Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td class="help shortcut"><kbd>?</kbd></td>
|
|
<td>Open this help</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="next shortcut"><kbd>n</kbd></td>
|
|
<td>Next page</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="prev shortcut"><kbd>p</kbd></td>
|
|
<td>Previous page</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="search shortcut"><kbd>s</kbd></td>
|
|
<td>Search</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="modal-footer">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</body>
|
|
</html>
|