Full Code of vi/websocat for AI

master 29c8c54d6f27 cached
60 files
559.8 KB
153.7k tokens
588 symbols
1 requests
Download .txt
Showing preview only (582K chars total). Download the full file or copy to clipboard to get everything.
Repository: vi/websocat
Branch: master
Commit: 29c8c54d6f27
Files: 60
Total size: 559.8 KB

Directory structure:
gitextract_scxsgr_6/

├── .dockerignore
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yaml
│       └── container-image-buildah.yml
├── .gitignore
├── 1234.pkcs12
├── CHANGELOG.md
├── Cargo.lock.legacy
├── Cargo.toml
├── Dockerfile
├── Dockerfile.debian
├── LICENSE
├── README.md
├── doc.md
├── misc/
│   └── prebuilt_release_settings.sh
├── moreexamples.md
├── src/
│   ├── all_peers.rs
│   ├── broadcast_reuse_peer.rs
│   ├── crypto_peer.rs
│   ├── file_peer.rs
│   ├── foreachmsg_peer.rs
│   ├── help.rs
│   ├── http_peer.rs
│   ├── http_serve.rs
│   ├── jsonrpc_peer.rs
│   ├── lengthprefixed_peer.rs
│   ├── lib.rs
│   ├── line_peer.rs
│   ├── lints.rs
│   ├── main.rs
│   ├── mirror_peer.rs
│   ├── my_copy.rs
│   ├── net_peer.rs
│   ├── options.rs
│   ├── primitive_reuse_peer.rs
│   ├── process_peer.rs
│   ├── prometheus_peer.rs
│   ├── readdebt.rs
│   ├── reconnect_peer.rs
│   ├── sessionserve.rs
│   ├── socks5_peer.rs
│   ├── specifier.rs
│   ├── specparse.rs
│   ├── ssl_peer.rs
│   ├── stdio_peer.rs
│   ├── stdio_threaded_peer.rs
│   ├── timestamp_peer.rs
│   ├── trivial_peer.rs
│   ├── unix_peer.rs
│   ├── unix_seqpacket_peer.rs
│   ├── util.rs
│   ├── windows_np_peer.rs
│   ├── ws_client_peer.rs
│   ├── ws_lowlevel_peer.rs
│   ├── ws_peer.rs
│   └── ws_server_peer.rs
├── test.pkcs12
├── test.sh
├── test_help.sh
└── tests/
    └── test.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
target


================================================
FILE: .github/dependabot.yml
================================================
# see https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:

  # Maintain dependencies for GitHub Actions
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
      day: friday

  # Maintain dependencies for Bundler
  - package-ecosystem: "cargo"
    directory: "/"
    schedule:
      interval: "weekly"
      day: wednesday


================================================
FILE: .github/workflows/ci.yaml
================================================
name: CI

on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

env:
  CARGO_TERM_COLOR: always

jobs:
  clippy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: dtolnay/rust-toolchain@stable
    - name: Run clippy
      run: cargo clippy

  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: dtolnay/rust-toolchain@stable
    - name: Build
      run: cargo build --verbose
    - name: Run tests
      run: cargo test --verbose


================================================
FILE: .github/workflows/container-image-buildah.yml
================================================
name: Container Image

on:
  workflow_dispatch:
    inputs:
      platforms:
        description: "comma-separated list of platforms to build for, e.g. linux/amd64,linux/arm64,linux/s390x,linux/ppc64le,linux/riscv64 (leave empty for defaults)"
        default: ''
      custom_tag:
        description: optional custom tag on remote repo you want image to be tagged with
        default: scratch
  workflow_call:
    inputs:
      platforms:
        required: false
        default: ''
        type: string
      custom_tag:
        required: false
        default: ''
        type: string
  #schedule:
  #  # every Wednesday morning
  #  - cron: 7 7 * * 3
  push:
    branches: [ master ]
    tags:
      - '*'           # Push events to every tag not containing /
  #pull_request:
  #  types: [opened, reopened, synchronize]

concurrency:
  group: ci-container-build-${{ github.ref }}-1
  cancel-in-progress: true

env:
  # Use docker.io for Docker Hub if empty
  REGISTRY: ghcr.io
  # github.repository as <account>/<repo>
  IMAGE_NAME: ${{ github.repository }}

# Sets permissions of the GITHUB_TOKEN to allow deployment to ghcr.io
permissions:
  contents: read
  packages: write
  id-token: write

jobs:
  buildah:
    strategy:
      matrix:
        include:
          - architecture: amd64
            runner: ubuntu-latest
          - architecture: arm64
            runner: ubuntu-24.04-arm
    runs-on: ${{ matrix.runner }}
    steps:
      - name: Sanitize Platforms
        id: platforms
        run: |
          platforms="${{ inputs.platforms == '' && 'linux/amd64,linux/arm64' || inputs.platforms }}"
          if [ "${{ matrix.architecture }}" = "arm64" ]; then
            platforms="linux/arm64"
          else
            platforms="$( sed -e 's#linux/arm64,##g' -e 's#,linux/arm64##g' -e 's#linux/arm64##g' <<< $platforms)"
            archs="$( sed -e 's#linux/##g' <<< $platforms )"
            echo "archs=$archs" >> $GITHUB_OUTPUT
          fi
          echo "platforms=$platforms" >> $GITHUB_OUTPUT

      - name: Install Podman on ubuntu-24.04-arm
        if: matrix.architecture == 'arm64'
        run: |
          sudo apt-get update
          sudo apt-get install -y podman
          echo -e "[registries.search]\nregistries = ['docker.io']" | sudo tee /etc/containers/registries.conf

      # Allow multi-target builds
      - name: Set up QEMU
        if: matrix.architecture == 'amd64'
        uses: docker/setup-qemu-action@v3
        with:
          platforms: ${{ steps.platforms.outputs.archs }}
      # Login against a Docker registry except on PR
      # https://github.com/docker/login-action
      - name: Log into registry ${{ env.REGISTRY }}
        if: github.event_name != 'pull_request'
        uses: redhat-actions/podman-login@v1
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      # Extract metadata (tags, labels) for Docker
      # https://github.com/docker/metadata-action
      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.architecture }}
          tags: |
            type=schedule
            type=raw,value=latest,enable=${{ github.ref_name == 'master' }}
            ${{ github.ref_name == 'master' && 'type=raw,value=nightly' }}
            type=ref,event=branch,enable=${{ github.ref_name != 'master' && inputs.custom_tag == '' }}
            ${{ inputs.custom_tag }}
            type=ref,event=tag
            type=ref,event=pr

      # https://github.com/actions/checkout
      - uses: actions/checkout@v4

      - name: Build image
        id: build-image
        uses: redhat-actions/buildah-build@v2
        with:
          tags: ${{ steps.meta.outputs.tags }}
          platforms: ${{ steps.platforms.outputs.platforms }}
          labels: ${{ steps.meta.outputs.labels }}
          layers: false
          oci: true
          tls-verify: true
          extra-args: |
            --squash
            --jobs=3
          containerfiles: |
            Dockerfile

      - name: Echo Outputs
        run: |
          echo "Image: ${{ steps.build-image.outputs.image }}"
          echo "Tags: ${{ steps.build-image.outputs.tags }}"
          echo "Tagged Image: ${{ steps.build-image.outputs.image-with-tag }}"

      - name: Check images created
        run: buildah images

      - name: Smoke test the images
        run: |
          set -ex
          # accessing a mapped port from a container did not work so lets
          # create a pod where both - server and client have same localhost
          podman pod create > podid
          platforms="${{ steps.platforms.outputs.platforms }}"

          test_tag () {
            podman run -d --pod-id-file=podid --name=listener -u 14:0 "${{ steps.build-image.outputs.image-with-tag }}$1" -s 0.0.0.0:1234
            sleep 3
            podman logs listener
            podman run --pod-id-file=podid --rm -i "${{ steps.build-image.outputs.image-with-tag }}$1" ws://127.0.0.1:1234/ <<< "Test Message $1"
            echo Expecting "\"Test Message $1\"" in listener log..
            podman logs listener | tee /dev/stderr | grep -q "Test Message $1"
            podman rm -f listener
          }

          if [ x$( sed -E -e 's#[^/]##g' <<< $platforms ) != "x/" ]; then
            # if we are here, user has selected more than one build platform
            arch_tags=$( tr ',' ' ' <<< $platforms | tr -d '/' )
            # removed slashes to produce "linuxamd64 linuxs390x linuxppc64le"
            for tag in $arch_tags; do test_tag -$tag; done
          else
            # if we are here, user has selected a single build platform
            test_tag
          fi

      - name: Push To Container Registry
        id: push-to-container-registry
        uses: redhat-actions/push-to-registry@v2
        if: github.event_name != 'pull_request'
        with:
          tags: ${{ steps.build-image.outputs.tags }}

      - name: Print image url
        run: echo "Image pushed to ${{ steps.push-to-container-registry.outputs.registry-paths }}"

  merge-archs:
    runs-on: ubuntu-latest
    needs: buildah
    steps:
      - name: Log into registry ${{ env.REGISTRY }}
        if: github.event_name != 'pull_request'
        uses: redhat-actions/podman-login@v1
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=schedule
            type=raw,value=latest,enable=${{ github.ref_name == 'master' }}
            ${{ github.ref_name == 'master' && 'type=raw,value=nightly' }}
            type=ref,event=branch,enable=${{ github.ref_name != 'master' && inputs.custom_tag == '' }}
            ${{ inputs.custom_tag }}
            type=ref,event=tag
            type=ref,event=pr

      - name: Create and push manifest
        run: |
          set -x

          img="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}"
          podman manifest create $img

          archs="amd64 arm64"
          for arch in $archs; do
            podman manifest add $img "${img}-${arch}:latest"
          done

          tags="${{ steps.meta.outputs.tags }}"
          for tag in $tags; do
            podman tag $img $tag
            podman manifest push --all $tag
          done


================================================
FILE: .gitignore
================================================
target


================================================
FILE: CHANGELOG.md
================================================
<a name="v1.14.0"></a>
# [Sunset (v1.14.0)](https://github.com/vi/websocat/releases/tag/v1.14.0) - 12 Nov 2024

* Attempt to priorize ping requests and replies over normal traffic
* More options to supply password for basic auth: `--basic-auth-file` and `WEBSOCAT_BASIC_AUTH`
* `drop_on_backpressure:` overlay
* `--ua` shortcut for `-H User-Agent:`
* SOCKS5 authentication

<a name="v1.13.0"></a>
# [Happy eyeballs (v1.13.0)](https://github.com/vi/websocat/releases/tag/v1.13.0) - 31 Mar 2024

* `waitfordata:` overlay to delay connection initiation until first data is attempted to be written to it
* Dockerfile updates
* `lengthprefixed:` overlay - alternative to base64 mode
* Fix for #23 - "happy eyeballs" for ws:// and wss:// URLs.

<a name="v1.12.0"></a>
# [Maintainance release (v1.12.0)](https://github.com/vi/websocat/releases/tag/v1.12.0) - 17 Sep 2023

* Option to stop sending or replying to WebSocket pings after specified amount of sent or received pings (for testing idling disconnection behaviour of counterparts).
* `--exec-exit-on-disconnect`
* Print `Location:` header value in error message when facing a redirect instead of a WebSocket connection.
* Other minor fixes

[Changes][v1.12.0]


<a name="v1.11.0"></a>
# [Still keeping v1 afloat instead of concentrating on v3 (v1.11.0)](https://github.com/vi/websocat/releases/tag/v1.11.0) - 24 Sep 2022

* `--preamble` (`-p`) options to prepend static text to Websocat sessions. For use to authenticate and subscribe to something over WebSocket. Note that specifying passwords on command line may be insecure. Also command line handling around `-p` is finicky. There is also `--preamble-reverse` (`-P`) option to prepend similar chunk in the reverse direction.
* `--compress-{zlib,deflate,gzip}` and respective `--uncompress-...` options to modify binary WebSocket messages going to/from a WebSocket. Note that it is not related to [permessage-deflate](https://www.rfc-editor.org/rfc/rfc7692.html), which does similar thing, but on lower level.
* `exit_on_specific_byte:` overlay to trigger exit when specific byte is encountered. For interactive tty usage.
* `--client-pkcs12-der` to specify client identity certificate for connecting to `wss://` or `ssl:` that requires mutual authentication.
* `openssl-probe` is now active by default on Linux, to support for overriding CA lists using environment variables.
* Incoming WebSocket frames and message are now limited by default, to prevent memory stuffing denial of service. But the default limit is big (100 megabytes). Use `--max-ws-frame-length` and `--max-ws-message-length` options to override.
* `Cargo.lock` is now oriented for building with modern Rust compiler. There is `Cargo.lock.legacy` with dependencies manually locked to versions that support Rust 1.46.0.

[Changes][v1.11.0]

<a name="v1.10.0"></a>
# [Some fixes, some features. (v1.10.0)](https://github.com/vi/websocat/releases/tag/v1.10.0) - 17 May 2022

* Add `--close-status-code` and ` --close-reason`
* Fix `--queue-len` option that took no effect
* Fix racing to connect to multiple resolved addresses in `tcp:` specifier (i.e. "happy eyeballs") - now it skips errors if there is a working connection. This does not fix `ws://localhost` unfortunately.
* `crypto:` overlay and associated options
* `prometheus:` overlay and associated options
* `random:` specifier

[Changes][v1.10.0]

<a name="v1.9.0"></a>
# [Supposedly without yanked crates (v1.9.0)](https://github.com/vi/websocat/releases/tag/v1.9.0) - 30 Oct 2021

* `ssl` Cargo feature is now enabled by default
* `vendored_openssl` Cargo feature is now not enabled by default
* `--stdout-announce-listening-ports` option to print message when server port is ready to accept clients.
* `--no-close` option now also affects Websocket server mode, not just client
* `timestamp:` overlay to mangle message, prepending current timestamp as text
* `--print-ping-rtts` option
* Updated deps for [#138](https://github.com/vi/websocat/issues/138) (not checked whether all yanks are resolved although).

[Changes][v1.9.0]

<a name="v1.8.0"></a>
# [Fix some bugs (v1.8.0)](https://github.com/vi/websocat/releases/tag/v1.8.0) - 15 Apr 2021

* `--accept-from-fd` option for better systemd intergration
* `exec:`/`cmd:`/`sh-c:` specifiers now don't terminate process prematurely
* `--foreachmsg-wait-read` for better `foreachmsg:` overlay behaviour. Now `foreachmsg:exec:./myscript` is more meaningul.
* ` --basic-auth` option to insert basic authentication header more easily
* Websocket close message is now logged in debug mode

[Changes][v1.8.0]

<a name="v1.7.0"></a>
# [Default threaded stdio, `log:` filter (v1.7.0)](https://github.com/vi/websocat/releases/tag/v1.7.0) - 22 Feb 2021

* Websocat now does not set terminal to nonblocking mode if isatty by default. This should help with [#76](https://github.com/vi/websocat/issues/76).
* New overlay `log:` that prints bytes as they travel though Websocat, for debugging.

[Changes][v1.7.0]

<a name="v1.6.0"></a>
# [A heartbeat release (v1.6.0)](https://github.com/vi/websocat/releases/tag/v1.6.0) - 08 Jul 2020

* UDP multicast options
* `foreachmsg:` overlay - run specifier (i.e. connect somewhere or execute a program) on each WebSocket message instead of on each WebSocket connection.
* Various minor options like `--max-messages` or zero-length message handling.
* Low-level Websocket features: `--just-generate-key` and `--just-generate-accept` options which help generating HTTP headers for WebSockets. `ws-lowlevel-server:` and `ws-lowlevel-client:` overlays to use expose WebSocket's data encoder/decoder without HTTP part.
* Basic `http://` client with arbitrary method, uri and so on.
* Delay for `autoreconnect:` overlay
* More pre-built release assets
* Base64 mode for binary WebSocket messages
* Prefixes for text and binary WebSocket messages, allowing to discriminate incoming binary and text WebSocket messages and intermix outgoing binary and text WebSocket messages.
* Sort-of-unfinished `http-post-sse:` specifier allowing to use HTTP server-sent events (in one direction) and POST request bodies (in the other direction) instead of (or in addition to) a WebSocket and to bridge them together. This mode is not tested properly although.

[Changes][v1.6.0]

<a name="v1.5.0"></a>
# [Client basic auth, header-to-env (v1.5.0)](https://github.com/vi/websocat/releases/tag/v1.5.0) - 18 Aug 2019

* Using client URI's like `websocat ws://user:password@host/` now adds basic authentication HTTP header to request
* New command-line option: `--header-to-env`
* Minor dependencies update
* Built with newer Rust on newer Debian

[Changes][v1.5.0]

<a name="v1.4.0"></a>
# [WebSocket ping and Sec-WebSocket-Protocol improvements (v1.4.0)](https://github.com/vi/websocat/releases/tag/v1.4.0) - 21 Mar 2019

* New options: `--server-protocol`, `--ping-timeout`, `--ping-interval`, `--server-header`
* Fixed replying to WebSocket pings
* Fixed replying to requests with `Sec-WebSocket-Protocol`.

[Changes][v1.4.0]

<a name="v1.3.0"></a>
# [tokio, conncap, pkcs12-passwd, typos (v1.3.0)](https://github.com/vi/websocat/releases/tag/v1.3.0) - 06 Mar 2019

[Changes][v1.3.0]

<a name="v1.2.0"></a>
# [-k (--insecure), native-tls (v1.2.0)](https://github.com/vi/websocat/releases/tag/v1.2.0) - 01 Nov 2018

[Changes][v1.2.0]

<a name="v1.1.0"></a>
# [More features (v1.1.0)](https://github.com/vi/websocat/releases/tag/v1.1.0) - 30 Aug 2018

* Static files aside from the websocket for easy prototyping
* SOCKS5 proxy client
* wss:// listener
* Setting environment variables for `exec:`
* Sending SIGHUP signal to child process on client disconnect
* `--jsonrpc` mode

[Changes][v1.1.0]

<a name="v1.1-pre"></a>
# [Preview of 1.1 (v1.1-pre)](https://github.com/vi/websocat/releases/tag/v1.1-pre) - 13 Jul 2018

* --set-environment option and --static-file

[Changes][v1.1-pre]


<a name="v1.0.0"></a>
# [The release. Finally. (v1.0.0)](https://github.com/vi/websocat/releases/tag/v1.0.0) - 04 Jul 2018

[Changes][v1.0.0]


<a name="v1.0.0-beta"></a>
# [Refactor and more features (v1.0.0-beta)](https://github.com/vi/websocat/releases/tag/v1.0.0-beta) - 20 Jun 2018

[Changes][v1.0.0-beta]

<a name="v1.0.0-alpha"></a>
# [Async alpha (v1.0.0-alpha)](https://github.com/vi/websocat/releases/tag/v1.0.0-alpha) - 10 May 2018

[Changes][v1.0.0-alpha]

<a name="v0.5.1-alpha"></a>
# [Async preview (v0.5.1-alpha)](https://github.com/vi/websocat/releases/tag/v0.5.1-alpha) - 14 Mar 2018

[Changes][v0.5.1-alpha]

<a name="v0.4.0"></a>
# [Forked rust-websocket (v0.4.0)](https://github.com/vi/websocat/releases/tag/v0.4.0) - 18 Jan 2017

[Changes][v0.4.0]

<a name="v0.3.0"></a>
# [More features (v0.3.0)](https://github.com/vi/websocat/releases/tag/v0.3.0) - 22 Dec 2016

- Unix sockets
- Executing programs and command lines
- Unidirectional mode
- Text mode (don't rely on it)

[Changes][v0.3.0]

<a name="v0.2.0"></a>
# [First actual release (v0.2.0)](https://github.com/vi/websocat/releases/tag/v0.2.0) - 24 Nov 2016

[Changes][v0.2.0]


[v1.12.0]: https://github.com/vi/websocat/compare/v1.11.0...v1.12.0
[v1.11.0]: https://github.com/vi/websocat/compare/v1.10.0...v1.11.0
[v1.10.0]: https://github.com/vi/websocat/compare/v3.0.0-prealpha0...v1.10.0
[v1.9.0]: https://github.com/vi/websocat/compare/v1.8.0...v1.9.0
[v1.8.0]: https://github.com/vi/websocat/compare/v1.7.0...v1.8.0
[v1.7.0]: https://github.com/vi/websocat/compare/v1.6.0...v1.7.0
[v1.6.0]: https://github.com/vi/websocat/compare/v2.0.0-alpha0...v1.6.0
[v1.5.0]: https://github.com/vi/websocat/compare/v1.4.0...v1.5.0
[v1.4.0]: https://github.com/vi/websocat/compare/v1.3.0...v1.4.0
[v1.3.0]: https://github.com/vi/websocat/compare/v1.2.0...v1.3.0
[v1.2.0]: https://github.com/vi/websocat/compare/v1.1.0...v1.2.0
[v1.1.0]: https://github.com/vi/websocat/compare/v1.1-pre...v1.1.0
[v1.1-pre]: https://github.com/vi/websocat/compare/v1.0.0...v1.1-pre
[v1.0.0]: https://github.com/vi/websocat/compare/v1.0.0-beta...v1.0.0
[v1.0.0-beta]: https://github.com/vi/websocat/compare/v1.0.0-alpha...v1.0.0-beta
[v1.0.0-alpha]: https://github.com/vi/websocat/compare/v0.5.1-alpha...v1.0.0-alpha
[v0.5.1-alpha]: https://github.com/vi/websocat/compare/v0.4.0...v0.5.1-alpha
[v0.4.0]: https://github.com/vi/websocat/compare/v0.3.0...v0.4.0
[v0.3.0]: https://github.com/vi/websocat/compare/v0.2.0...v0.3.0
[v0.2.0]: https://github.com/vi/websocat/tree/v0.2.0

<!-- Generated by https://github.com/rhysd/changelog-from-release v3.7.1 -->


================================================
FILE: Cargo.lock.legacy
================================================
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"

[[package]]
name = "aead"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
dependencies = [
 "generic-array 0.14.5",
]

[[package]]
name = "anymap"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"

[[package]]
name = "argon2"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db4ce4441f99dbd377ca8a8f57b698c44d0d6e712d8329b5040da5a64aa1ce73"
dependencies = [
 "base64ct",
 "blake2",
 "password-hash",
]

[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
 "hermit-abi",
 "libc",
 "winapi 0.3.9",
]

[[package]]
name = "autocfg"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
dependencies = [
 "autocfg 1.1.0",
]

[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"

[[package]]
name = "base64"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
dependencies = [
 "byteorder",
 "safemem",
]

[[package]]
name = "base64"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
dependencies = [
 "byteorder",
]

[[package]]
name = "base64ct"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851"

[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"

[[package]]
name = "blake2"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9cf849ee05b2ee5fba5e36f97ff8ec2533916700fc0758d40d92136a42f3388"
dependencies = [
 "digest 0.10.3",
]

[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
 "block-padding",
 "byte-tools",
 "byteorder",
 "generic-array 0.12.4",
]

[[package]]
name = "block-buffer"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
dependencies = [
 "generic-array 0.14.5",
]

[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
 "byte-tools",
]

[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"

[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"

[[package]]
name = "bytes"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
dependencies = [
 "byteorder",
 "iovec",
]

[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"

[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"

[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"

[[package]]
name = "chacha20"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c80e5460aa66fe3b91d40bcbdab953a597b60053e34d684ac6903f863b680a6"
dependencies = [
 "cfg-if 1.0.0",
 "cipher",
 "cpufeatures",
 "zeroize",
]

[[package]]
name = "chacha20poly1305"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a18446b09be63d457bbec447509e85f662f32952b035ce892290396bc0b0cff5"
dependencies = [
 "aead",
 "chacha20",
 "cipher",
 "poly1305",
 "zeroize",
]

[[package]]
name = "cipher"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [
 "generic-array 0.14.5",
]

[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
 "bitflags",
 "textwrap",
 "unicode-width",
]

[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
 "bitflags",
]

[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
 "core-foundation-sys",
 "libc",
]

[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"

[[package]]
name = "cpufeatures"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b"
dependencies = [
 "libc",
]

[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
 "cfg-if 1.0.0",
]

[[package]]
name = "crossbeam-deque"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed"
dependencies = [
 "crossbeam-epoch",
 "crossbeam-utils 0.7.2",
 "maybe-uninit",
]

[[package]]
name = "crossbeam-epoch"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
dependencies = [
 "autocfg 1.1.0",
 "cfg-if 0.1.10",
 "crossbeam-utils 0.7.2",
 "lazy_static",
 "maybe-uninit",
 "memoffset",
 "scopeguard",
]

[[package]]
name = "crossbeam-queue"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
dependencies = [
 "crossbeam-utils 0.6.6",
]

[[package]]
name = "crossbeam-queue"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
dependencies = [
 "cfg-if 0.1.10",
 "crossbeam-utils 0.7.2",
 "maybe-uninit",
]

[[package]]
name = "crossbeam-utils"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
dependencies = [
 "cfg-if 0.1.10",
 "lazy_static",
]

[[package]]
name = "crossbeam-utils"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
 "autocfg 1.1.0",
 "cfg-if 0.1.10",
 "lazy_static",
]

[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
 "generic-array 0.14.5",
 "typenum",
]

[[package]]
name = "derivative"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c6d883546668a3e2011b6a716a7330b82eabb0151b138217f632c8243e17135"
dependencies = [
 "proc-macro2 0.4.30",
 "quote 0.6.13",
 "syn 0.15.44",
]

[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
 "generic-array 0.12.4",
]

[[package]]
name = "digest"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
dependencies = [
 "block-buffer 0.10.2",
 "crypto-common",
 "subtle",
]

[[package]]
name = "env_logger"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
dependencies = [
 "log 0.4.17",
]

[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"

[[package]]
name = "fastrand"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
dependencies = [
 "instant",
]

[[package]]
name = "flate2"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
dependencies = [
 "crc32fast",
 "miniz_oxide",
]

[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"

[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
 "foreign-types-shared",
]

[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"

[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"

[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
dependencies = [
 "bitflags",
 "fuchsia-zircon-sys",
]

[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"

[[package]]
name = "futures"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"

[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
 "typenum",
]

[[package]]
name = "generic-array"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
dependencies = [
 "typenum",
 "version_check 0.9.4",
]

[[package]]
name = "getrandom"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
 "cfg-if 1.0.0",
 "libc",
 "wasi 0.11.0+wasi-snapshot-preview1",
]

[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
 "unicode-segmentation",
]

[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
 "libc",
]

[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"

[[package]]
name = "http"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0"
dependencies = [
 "bytes",
 "fnv",
 "itoa",
]

[[package]]
name = "http-bytes"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3332986b24440d485a8c31e5a823c098f9c1616e7c60945e09dbc6c8d45bed55"
dependencies = [
 "base64 0.10.1",
 "bytes",
 "http",
 "httparse",
 "percent-encoding",
]

[[package]]
name = "httparse"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c"

[[package]]
name = "hyper"
version = "0.10.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273"
dependencies = [
 "base64 0.9.3",
 "httparse",
 "language-tags",
 "log 0.3.9",
 "mime",
 "num_cpus",
 "time",
 "traitobject",
 "typeable",
 "unicase",
 "url",
]

[[package]]
name = "idna"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
dependencies = [
 "matches",
 "unicode-bidi",
 "unicode-normalization",
]

[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
 "cfg-if 1.0.0",
]

[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
dependencies = [
 "libc",
]

[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"

[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
dependencies = [
 "winapi 0.2.8",
 "winapi-build",
]

[[package]]
name = "language-tags"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"

[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

[[package]]
name = "libc"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"

[[package]]
name = "lock_api"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75"
dependencies = [
 "scopeguard",
]

[[package]]
name = "lock_api"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
dependencies = [
 "autocfg 1.1.0",
 "scopeguard",
]

[[package]]
name = "log"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
dependencies = [
 "log 0.4.17",
]

[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
 "cfg-if 1.0.0",
]

[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"

[[package]]
name = "maybe-uninit"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"

[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"

[[package]]
name = "memoffset"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
dependencies = [
 "autocfg 1.1.0",
]

[[package]]
name = "mime"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
dependencies = [
 "log 0.3.9",
]

[[package]]
name = "miniz_oxide"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
dependencies = [
 "adler",
]

[[package]]
name = "mio"
version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
dependencies = [
 "cfg-if 0.1.10",
 "fuchsia-zircon",
 "fuchsia-zircon-sys",
 "iovec",
 "kernel32-sys",
 "libc",
 "log 0.4.17",
 "miow 0.2.2",
 "net2",
 "slab",
 "winapi 0.2.8",
]

[[package]]
name = "mio-named-pipes"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0840c1c50fd55e521b247f949c241c9997709f23bd7f023b9762cd561e935656"
dependencies = [
 "log 0.4.17",
 "mio",
 "miow 0.3.7",
 "winapi 0.3.9",
]

[[package]]
name = "mio-uds"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0"
dependencies = [
 "iovec",
 "libc",
 "mio",
]

[[package]]
name = "miow"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
dependencies = [
 "kernel32-sys",
 "net2",
 "winapi 0.2.8",
 "ws2_32-sys",
]

[[package]]
name = "miow"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
 "winapi 0.3.9",
]

[[package]]
name = "native-tls"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d"
dependencies = [
 "lazy_static",
 "libc",
 "log 0.4.17",
 "openssl",
 "openssl-probe",
 "openssl-sys",
 "schannel",
 "security-framework",
 "security-framework-sys",
 "tempfile",
]

[[package]]
name = "net2"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
dependencies = [
 "cfg-if 0.1.10",
 "libc",
 "winapi 0.3.9",
]

[[package]]
name = "num_cpus"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
 "hermit-abi",
 "libc",
]

[[package]]
name = "once_cell"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"

[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"

[[package]]
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"

[[package]]
name = "openssl"
version = "0.10.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95"
dependencies = [
 "bitflags",
 "cfg-if 1.0.0",
 "foreign-types",
 "libc",
 "once_cell",
 "openssl-sys",
]

[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"

[[package]]
name = "openssl-src"
version = "111.22.0+1.1.1q"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853"
dependencies = [
 "cc",
]

[[package]]
name = "openssl-sys"
version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [
 "autocfg 1.1.0",
 "cc",
 "libc",
 "openssl-src",
 "pkg-config",
 "vcpkg",
]

[[package]]
name = "parking_lot"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
dependencies = [
 "lock_api 0.3.4",
 "parking_lot_core 0.6.2",
 "rustc_version",
]

[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
 "lock_api 0.4.7",
 "parking_lot_core 0.9.3",
]

[[package]]
name = "parking_lot_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
dependencies = [
 "cfg-if 0.1.10",
 "cloudabi",
 "libc",
 "redox_syscall 0.1.57",
 "rustc_version",
 "smallvec 0.6.14",
 "winapi 0.3.9",
]

[[package]]
name = "parking_lot_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
dependencies = [
 "cfg-if 1.0.0",
 "libc",
 "redox_syscall 0.2.16",
 "smallvec 1.9.0",
 "windows-sys",
]

[[package]]
name = "password-hash"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
dependencies = [
 "base64ct",
 "rand_core 0.6.3",
 "subtle",
]

[[package]]
name = "percent-encoding"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"

[[package]]
name = "pkg-config"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"

[[package]]
name = "poly1305"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "048aeb476be11a4b6ca432ca569e375810de9294ae78f4774e78ea98a9246ede"
dependencies = [
 "cpufeatures",
 "opaque-debug 0.3.0",
 "universal-hash",
]

[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"

[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
dependencies = [
 "unicode-xid",
]

[[package]]
name = "proc-macro2"
version = "1.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b"
dependencies = [
 "unicode-ident",
]

[[package]]
name = "prometheus"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cface98dfa6d645ea4c789839f176e4b072265d085bfcc48eaa8d137f58d3c39"
dependencies = [
 "cfg-if 1.0.0",
 "fnv",
 "lazy_static",
 "memchr",
 "parking_lot 0.12.1",
 "thiserror",
]

[[package]]
name = "prometheus-metric-storage"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3282447ea0b07baa9011e45de96794c5963db0162c1001d2867750715d63ff14"
dependencies = [
 "lazy_static",
 "prometheus",
 "prometheus-metric-storage-derive",
]

[[package]]
name = "prometheus-metric-storage-derive"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "239221aa10cd35277c58b8f6509280b2613321760b49584d7a7351a6aacb6963"
dependencies = [
 "proc-macro2 1.0.42",
 "quote 1.0.20",
 "syn 1.0.98",
]

[[package]]
name = "quote"
version = "0.6.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
 "proc-macro2 0.4.30",
]

[[package]]
name = "quote"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
dependencies = [
 "proc-macro2 1.0.42",
]

[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
 "autocfg 0.1.8",
 "libc",
 "rand_chacha 0.1.1",
 "rand_core 0.4.2",
 "rand_hc",
 "rand_isaac",
 "rand_jitter",
 "rand_os",
 "rand_pcg",
 "rand_xorshift",
 "winapi 0.3.9",
]

[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
 "libc",
 "rand_chacha 0.3.1",
 "rand_core 0.6.3",
]

[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
 "autocfg 0.1.8",
 "rand_core 0.3.1",
]

[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
 "ppv-lite86",
 "rand_core 0.6.3",
]

[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
 "rand_core 0.4.2",
]

[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"

[[package]]
name = "rand_core"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
dependencies = [
 "getrandom",
]

[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
 "rand_core 0.3.1",
]

[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
 "rand_core 0.3.1",
]

[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
 "libc",
 "rand_core 0.4.2",
 "winapi 0.3.9",
]

[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
 "cloudabi",
 "fuchsia-cprng",
 "libc",
 "rand_core 0.4.2",
 "rdrand",
 "winapi 0.3.9",
]

[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
 "autocfg 0.1.8",
 "rand_core 0.4.2",
]

[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
 "rand_core 0.3.1",
]

[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
 "rand_core 0.3.1",
]

[[package]]
name = "readwrite"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73891b98dabbe836d23a094941e6ec891bc4880e771faea98813f2ff27ede473"
dependencies = [
 "futures",
 "tokio-io",
]

[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"

[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
 "bitflags",
]

[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
 "winapi 0.3.9",
]

[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
 "semver",
]

[[package]]
name = "safemem"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"

[[package]]
name = "schannel"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
dependencies = [
 "lazy_static",
 "windows-sys",
]

[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"

[[package]]
name = "security-framework"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc"
dependencies = [
 "bitflags",
 "core-foundation",
 "core-foundation-sys",
 "libc",
 "security-framework-sys",
]

[[package]]
name = "security-framework-sys"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
dependencies = [
 "core-foundation-sys",
 "libc",
]

[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
 "semver-parser",
]

[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"

[[package]]
name = "sha-1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [
 "block-buffer 0.7.3",
 "digest 0.8.1",
 "fake-simd",
 "opaque-debug 0.2.3",
]

[[package]]
name = "signal-hook-registry"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [
 "libc",
]

[[package]]
name = "slab"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
dependencies = [
 "autocfg 1.1.0",
]

[[package]]
name = "slab_typesafe"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e1a2062526abda41283046a3149dc589cb760c8c6672dd88e209f7fba0c0c1"
dependencies = [
 "slab",
]

[[package]]
name = "smallvec"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0"
dependencies = [
 "maybe-uninit",
]

[[package]]
name = "smallvec"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"

[[package]]
name = "smart-default"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e5c02ddada494809d36623d38050f3bd63446750abd21e7e13c01aa3a79b69"
dependencies = [
 "proc-macro2 0.4.30",
 "quote 0.6.13",
 "syn 0.15.44",
]

[[package]]
name = "structopt"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff"
dependencies = [
 "clap",
 "structopt-derive",
]

[[package]]
name = "structopt-derive"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f"
dependencies = [
 "heck",
 "proc-macro2 0.4.30",
 "quote 0.6.13",
 "syn 0.15.44",
]

[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"

[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
dependencies = [
 "proc-macro2 0.4.30",
 "quote 0.6.13",
 "unicode-xid",
]

[[package]]
name = "syn"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
dependencies = [
 "proc-macro2 1.0.42",
 "quote 1.0.20",
 "unicode-ident",
]

[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
 "cfg-if 1.0.0",
 "fastrand",
 "libc",
 "redox_syscall 0.2.16",
 "remove_dir_all",
 "winapi 0.3.9",
]

[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
 "unicode-width",
]

[[package]]
name = "thiserror"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
dependencies = [
 "thiserror-impl",
]

[[package]]
name = "thiserror-impl"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
dependencies = [
 "proc-macro2 1.0.42",
 "quote 1.0.20",
 "syn 1.0.98",
]

[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
 "libc",
 "wasi 0.10.0+wasi-snapshot-preview1",
 "winapi 0.3.9",
]

[[package]]
name = "tinyvec"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
 "tinyvec_macros",
]

[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"

[[package]]
name = "tk-listen"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5462b0f968c0457efe38fcd2df7e487096b992419e4f5337b06775a614bbda4b"
dependencies = [
 "futures",
 "log 0.4.17",
 "tokio",
 "tokio-io",
]

[[package]]
name = "tokio"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6"
dependencies = [
 "bytes",
 "futures",
 "mio",
 "num_cpus",
 "tokio-codec",
 "tokio-current-thread",
 "tokio-executor",
 "tokio-fs",
 "tokio-io",
 "tokio-reactor",
 "tokio-sync",
 "tokio-tcp",
 "tokio-threadpool",
 "tokio-timer",
 "tokio-udp",
 "tokio-uds",
]

[[package]]
name = "tokio-codec"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b"
dependencies = [
 "bytes",
 "futures",
 "tokio-io",
]

[[package]]
name = "tokio-current-thread"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e"
dependencies = [
 "futures",
 "tokio-executor",
]

[[package]]
name = "tokio-executor"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671"
dependencies = [
 "crossbeam-utils 0.7.2",
 "futures",
]

[[package]]
name = "tokio-file-unix"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7742e2a421379472607d46e2641e66ee2d135f5274d12ad0aba1c1fbbcea2e8c"
dependencies = [
 "bytes",
 "libc",
 "mio",
 "tokio-io",
 "tokio-reactor",
]

[[package]]
name = "tokio-fs"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4"
dependencies = [
 "futures",
 "tokio-io",
 "tokio-threadpool",
]

[[package]]
name = "tokio-io"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674"
dependencies = [
 "bytes",
 "futures",
 "log 0.4.17",
]

[[package]]
name = "tokio-named-pipes"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d282d483052288b2308ba5ee795f5673b159c9bdf63c385a05609da782a5eae"
dependencies = [
 "bytes",
 "futures",
 "mio",
 "mio-named-pipes",
 "tokio",
]

[[package]]
name = "tokio-process"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "382d90f43fa31caebe5d3bc6cfd854963394fff3b8cb59d5146607aaae7e7e43"
dependencies = [
 "crossbeam-queue 0.1.2",
 "futures",
 "lazy_static",
 "libc",
 "log 0.4.17",
 "mio",
 "mio-named-pipes",
 "tokio-io",
 "tokio-reactor",
 "tokio-signal",
 "winapi 0.3.9",
]

[[package]]
name = "tokio-reactor"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351"
dependencies = [
 "crossbeam-utils 0.7.2",
 "futures",
 "lazy_static",
 "log 0.4.17",
 "mio",
 "num_cpus",
 "parking_lot 0.9.0",
 "slab",
 "tokio-executor",
 "tokio-io",
 "tokio-sync",
]

[[package]]
name = "tokio-signal"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0c34c6e548f101053321cba3da7cbb87a610b85555884c41b07da2eb91aff12"
dependencies = [
 "futures",
 "libc",
 "mio",
 "mio-uds",
 "signal-hook-registry",
 "tokio-executor",
 "tokio-io",
 "tokio-reactor",
 "winapi 0.3.9",
]

[[package]]
name = "tokio-stdin-stdout"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc480d205310fa52f8ea65e7f9443568b6b342f326e86431d2aeb176d720c17"
dependencies = [
 "futures",
 "tokio-io",
]

[[package]]
name = "tokio-sync"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee"
dependencies = [
 "fnv",
 "futures",
]

[[package]]
name = "tokio-tcp"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72"
dependencies = [
 "bytes",
 "futures",
 "iovec",
 "mio",
 "tokio-io",
 "tokio-reactor",
]

[[package]]
name = "tokio-threadpool"
version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89"
dependencies = [
 "crossbeam-deque",
 "crossbeam-queue 0.2.3",
 "crossbeam-utils 0.7.2",
 "futures",
 "lazy_static",
 "log 0.4.17",
 "num_cpus",
 "slab",
 "tokio-executor",
]

[[package]]
name = "tokio-timer"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296"
dependencies = [
 "crossbeam-utils 0.7.2",
 "futures",
 "slab",
 "tokio-executor",
]

[[package]]
name = "tokio-tls"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c"
dependencies = [
 "futures",
 "native-tls",
 "tokio-io",
]

[[package]]
name = "tokio-udp"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82"
dependencies = [
 "bytes",
 "futures",
 "log 0.4.17",
 "mio",
 "tokio-codec",
 "tokio-io",
 "tokio-reactor",
]

[[package]]
name = "tokio-uds"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0"
dependencies = [
 "bytes",
 "futures",
 "iovec",
 "libc",
 "log 0.4.17",
 "mio",
 "mio-uds",
 "tokio-codec",
 "tokio-io",
 "tokio-reactor",
]

[[package]]
name = "traitobject"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"

[[package]]
name = "typeable"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"

[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"

[[package]]
name = "unicase"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
dependencies = [
 "version_check 0.1.5",
]

[[package]]
name = "unicode-bidi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"

[[package]]
name = "unicode-ident"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"

[[package]]
name = "unicode-normalization"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
dependencies = [
 "tinyvec",
]

[[package]]
name = "unicode-segmentation"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"

[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"

[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"

[[package]]
name = "universal-hash"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
dependencies = [
 "generic-array 0.14.5",
 "subtle",
]

[[package]]
name = "url"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
dependencies = [
 "idna",
 "matches",
 "percent-encoding",
]

[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"

[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"

[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"

[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"

[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

[[package]]
name = "websocat"
version = "1.11.0"
dependencies = [
 "anymap",
 "argon2",
 "atty",
 "base64 0.10.1",
 "chacha20poly1305",
 "derivative",
 "env_logger",
 "flate2",
 "futures",
 "hex",
 "http-bytes",
 "hyper",
 "libc",
 "log 0.4.17",
 "native-tls",
 "net2",
 "openssl-probe",
 "openssl-sys",
 "prometheus",
 "prometheus-metric-storage",
 "rand 0.8.5",
 "readwrite",
 "slab_typesafe",
 "smart-default",
 "structopt",
 "structopt-derive",
 "tempfile",
 "tk-listen",
 "tokio",
 "tokio-codec",
 "tokio-current-thread",
 "tokio-file-unix",
 "tokio-io",
 "tokio-named-pipes",
 "tokio-process",
 "tokio-reactor",
 "tokio-signal",
 "tokio-stdin-stdout",
 "tokio-tcp",
 "tokio-timer",
 "tokio-tls",
 "tokio-udp",
 "tokio-uds",
 "url",
 "websocket",
 "websocket-base",
]

[[package]]
name = "websocket"
version = "0.26.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92aacab060eea423e4036820ddd28f3f9003b2c4d8048cbda985e5a14e18038d"
dependencies = [
 "bytes",
 "futures",
 "hyper",
 "native-tls",
 "rand 0.6.5",
 "tokio-codec",
 "tokio-io",
 "tokio-reactor",
 "tokio-tcp",
 "tokio-tls",
 "unicase",
 "url",
 "websocket-base",
]

[[package]]
name = "websocket-base"
version = "0.26.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49aec794b07318993d1db16156d5a9c750120597a5ee40c6b928d416186cb138"
dependencies = [
 "base64 0.10.1",
 "bitflags",
 "byteorder",
 "bytes",
 "futures",
 "native-tls",
 "rand 0.6.5",
 "sha-1",
 "tokio-codec",
 "tokio-io",
 "tokio-tcp",
 "tokio-tls",
]

[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"

[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
 "winapi-i686-pc-windows-gnu",
 "winapi-x86_64-pc-windows-gnu",
]

[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"

[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

[[package]]
name = "windows-sys"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
 "windows_aarch64_msvc",
 "windows_i686_gnu",
 "windows_i686_msvc",
 "windows_x86_64_gnu",
 "windows_x86_64_msvc",
]

[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"

[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"

[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"

[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"

[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"

[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
dependencies = [
 "winapi 0.2.8",
 "winapi-build",
]

[[package]]
name = "zeroize"
version = "1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f"


================================================
FILE: Cargo.toml
================================================
[package]
name = "websocat"
version = "1.14.1"
authors = ["Vitaly \"_Vi\" Shukela <vi0oss@gmail.com>"]
license = "MIT"
repository = "https://github.com/vi/websocat"
description = "Command-line client for web sockets, like netcat/curl/socat for ws://."
keywords = ["WebSocket", "socat", "rfc6455", "netcat", "cli"]
include = ["src","Cargo.toml","LICENSE","README.md"]
readme = "README.md"
edition = "2018"
#msrv = "1.48.0"

[package.metadata.deb]
section = "utility"
extended-description = """\
A tool allows you to interconnect two specifiers, like in socat, \
but with Websocket and some other additional functions."""
features = ["ssl", "workaround1", "seqpacket", "unix_stdio"]
#depends = "$auto"
depends = "libssl1.1, libc6 (>= 2.19), libgcc1 (>= 1:4.9.0)"


[dependencies]
websocket = { version="0.27.1", default-features = false, features=["async"] }
websocket-base = { version="0.26.5", default-features = false, features=["async"] }
http-bytes = {version = "0.1.0"}
env_logger = { version = "0.6.0", default-features = false }
log = {version="0.4.1", default-features = false, features=["release_max_level_debug"]}
futures = {version = "0.1.17" }
tokio-io = "0.1.5"
tokio-stdin-stdout = "0.1.5"
structopt = { version = "=0.2.16", default-features = false }
structopt-derive = { version = "=0.2.16", default-features = false }
tokio-process = { version = "0.2.3", optional = true }
slab_typesafe = "0.1"
hyper="0.10.13"
url="1.7.1"
openssl-probe = { version = "0.1.2", optional = true }
smart-default = "0.3.0"
tokio-tls = {version = "0.2.0", optional = true}
native-tls = {version = "0.2.1", optional = true}
readwrite = {version = "0.1.1", optional = true, features = ["tokio"]}
derivative="1.0.0"
tokio-codec = "0.1.1"
tokio-tcp = "0.1.2"
tokio-udp = "0.1.3"
tokio-reactor = "0.1.7"
tokio = "0.1.11"
tokio-current-thread = "0.1.4"
tk-listen = "0.2.1"
tokio-timer = "0.2.0"
tempfile = "3.0.8"
net2 = "0.2.33"
anymap = "0.12.1"
base64 = "0.10"
atty = "0.2.14"
#anymap = { path = "/mnt/src/git/anymap"}
hex = "0.4.2"
chacha20poly1305 = {version="0.9.0",optional=true}
rand = { version = "0.8.4", optional = false }
argon2 = { version = "0.4.0", optional = true }
prometheus = { version = "0.13.0", optional = true, default-features = false }
prometheus-metric-storage = { version = "0.5.0", optional = true }
flate2 = {version = "1", optional = true}

# Rust 1.30.1 compat:
#cfg-if="=0.1.9"
#unicode-width="=0.1.5"
#tokio-reactor = "=0.1.9"
#cc="=1.0.41"


[target.'cfg(unix)'.dependencies]
tokio-file-unix = "0.5.1"
tokio-signal = { version = "0.2.7", optional = true }
tokio-uds = "0.2.3"
libc = { version = "0.2" }

[target.'cfg(windows)'.dependencies]
tokio-named-pipes = {version="0.1.0", optional=true}

[features]
default = ["signal_handler", "tokio-process", "unix_stdio", "windows_named_pipes", "ssl", "compression"]
unix_stdio = []
ssl = ["websocket/async-ssl", "tokio-tls", "native-tls", "readwrite", "openssl-sys"]
signal_handler = ["tokio-signal"]
workaround1=[]
seqpacket=[]
windows_named_pipes=["tokio-named-pipes"]
vendored_openssl = ["openssl-sys/vendored"]
crypto_peer = ["chacha20poly1305","argon2"]
prometheus_peer=["prometheus","prometheus-metric-storage"]
compression=["flate2"]

[target.'arm-linux-androideabi'.dependencies]
openssl-sys = { version="0.9", features=[], optional=true }


#[patch."crates-io"]
#"tokio-process:0.1.6" = {path="/mnt/src/git/tokio-process"}
#"tokio-core:0.1.17" = {path="/mnt/src/git/tokio-core"}
#"websocket" = {path="/home/vi/src/rust-websocket"}
#"websocket-base" = {path="/home/vi/src/rust-websocket/websocket-base"}




================================================
FILE: Dockerfile
================================================
# Build stage
FROM rust:1.87.0-alpine3.20 AS cargo-build

RUN apk add --no-cache musl-dev pkgconfig openssl-dev

WORKDIR /src/websocat
ENV RUSTFLAGS='-Ctarget-feature=-crt-static'

COPY Cargo.toml Cargo.toml
ARG CARGO_OPTS="--features=workaround1,seqpacket,prometheus_peer,prometheus/process,crypto_peer"

RUN mkdir src/ &&\
    echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs && \
    cargo build --release $CARGO_OPTS && \
    rm -f target/release/deps/websocat*

COPY src src
RUN cargo build --release $CARGO_OPTS && \
    strip target/release/websocat

# Final stage
FROM alpine:3.20

RUN apk add --no-cache libgcc

WORKDIR /
COPY --from=cargo-build /src/websocat/target/release/websocat /usr/local/bin/

ENTRYPOINT ["/usr/local/bin/websocat"]


================================================
FILE: Dockerfile.debian
================================================
# Build stage
FROM rust:1.87.0-bookworm AS cargo-build

RUN apt-get update
RUN apt-get install -y libgcc-12-dev libc6-dev pkg-config libssl-dev

WORKDIR /src/websocat
ENV RUSTFLAGS='-Ctarget-feature=-crt-static'

COPY Cargo.toml Cargo.toml
# ARG CARGO_OPTS="--features=workaround1,seqpacket,prometheus_peer,prometheus/process,crypto_peer"
ARG CARGO_OPTS="--features=ssl,workaround1,seqpacket,unix_stdio,prometheus_peer,prometheus/process,crypto_peer"

RUN mkdir src/ &&\
    echo "fn main() {println!(\"if you see this, the build broke\")}" > src/main.rs && \
    cargo build --release $CARGO_OPTS && \
    rm -f target/release/deps/websocat*

COPY src src
RUN cargo build --release $CARGO_OPTS && \
    strip target/release/websocat

# Final stage
FROM debian:bookworm

RUN apt-get update
RUN apt-get install -y libssl3
RUN apt-get clean && \
    rm -rf /var/lib/apt/lists/*

WORKDIR /
COPY --from=cargo-build /src/websocat/target/release/websocat /usr/local/bin/

ENTRYPOINT ["/usr/local/bin/websocat"]


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2016 Vitaly Shukela

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# websocat
Netcat, curl and socat for [WebSockets](https://en.wikipedia.org/wiki/WebSocket).

[![Gitter](https://badges.gitter.im/websocat.svg)](https://gitter.im/websocat/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge)
[![image-build](https://github.com/vi/websocat/actions/workflows/container-image-buildah.yml/badge.svg)](https://github.com/vi/websocat/pkgs/container/websocat)

## Examples

### Connect to public echo server (Ctrl+d to quit)

```
$ websocat ws://ws.vi-server.org/mirror
123
123
ABC
ABC

$ docker run --rm -ti ghcr.io/vi/websocat:nightly wss://ws.vi-server.org/mirror
123
123
ABC
ABC
```

### Serve and connect

```
A$ websocat -s 1234
Listening on ws://127.0.0.1:1234/
ABC
123

B$ websocat ws://127.0.0.1:1234/
ABC
123
```

### Open a tab in Chromium using remote debugging.

```
$ chromium --remote-debugging-port=9222&
$ curl -sg http://127.0.0.1:9222/json/new | grep webSocketDebuggerUrl | cut -d'"' -f4 | head -1
ws://127.0.0.1:9222/devtools/page/A331E56CCB8615EB4FCB720425A82259
$ echo 'Page.navigate {"url":"https://example.com"}' | websocat -n1 --jsonrpc --jsonrpc-omit-jsonrpc ws://127.0.0.1:9222/devtools/page/A331E56CCB8615EB4FCB720425A82259
{"id":2,"result":{"frameId":"A331E56CCB8615EB4FCB720425A82259","loaderId":"EF5AAD19F2F8BB27FAF55F94FFB27DF9"}}
```


### Proxy TCP connections to WebSocket connections and back.

```
$ websocat --oneshot -b ws-l:127.0.0.1:1234 tcp:127.0.0.1:22&
$ websocat --oneshot -b tcp-l:127.0.0.1:1236 ws://127.0.0.1:1234/&
$ nc 127.0.0.1 1236
SSH-2.0-OpenSSH_7.4p1 Debian-10+deb9u3
qwertyu
Protocol mismatch.
```


### Broadcast all messages between connected WebSocket clients

```
A$ websocat -t ws-l:127.0.0.1:1234 broadcast:mirror:
B$ websocat ws://127.0.0.1:1234
C$ websocat ws://127.0.0.1:1234
```

(if you like this one, you may actually want https://github.com/vi/wsbroad/ instead)

See [moreexamples.md](./moreexamples.md) for further examples.

## Features

* Connecting to and serving WebSockets from command line.
* Executing external program and making it communicate to WebSocket using stdin/stdout.
* Text and binary modes, converting between lines (or null-terminated records) and messages.
* Inetd mode, UNIX sockets (including abstract namespaced on Linux).
* Integration with Nginx using TCP or UNIX sockets.
* Directly using unauthenticated SOCKS5 servers for connecting to WebSockets and listening WebSocket connection.
* Auto-reconnect and connection-reuse modes.
* Linux, Windows and Mac support, with [pre-built executables][releases].
* Low-level WebSocket clients and servers with overridable underlying transport connection, e.g. calling external program to serve as a transport for websocat (for SSL, proxying, etc.).

[releases]:https://github.com/vi/websocat/releases

# Installation

There are multiple options for installing WebSocat. From easy to hard:

## FreeBSD

`pkg install websocat`

## Debian / Ubuntu
* Download a pre-build executable from [GitHub releases][releases].
* Websocat is not yet officially packaged for Debian. Some older versions of Websocat may also have Debian package files available on Github releases.

## macOS

[Homebrew](https://brew.sh): `brew install websocat`

[MacPorts](https://www.macports.org): `sudo port install websocat`

## From source
* Install the [Rust toolchain](https://rustup.rs/) and do `cargo install websocat`. If something fails with a `-sys` crate, try with `--no-default-features`;
* Build Websocat from source code (see below), then move `target/release/websocat` somewhere to the PATH.

## Pre-built binaries
Pre-built binaries for Linux (usual and musl), Windows, OS X and Android are available on the [releases page](https://github.com/vi/websocat/releases).


Building from source code
---

1. Install the [Rust toolchain](https://rustup.rs/). Note that Websocat v1 (i.e. the current stable version) may fail to support too new Rust due to its old dependencies which can be broken by e.g. [this](https://github.com/rust-lang/rust/pull/78802).
2. `cargo build --release`.
3. Find the executable somewhere under `target/`, e.g. in `target/release/websocat`.

### Rust versions


|Websocat versions|Minimal Rust version|Maximal Rust version|
|----|----|----|
| 4.0.0-alpha1 | 1.84 | ?   |
| 1.12+     | ?    | ?          |
| 1.9 - 1.11| 1.46 | maybe 1.63 |
| 1.6 - 1.8 | 1.34 | maybe 1.63  |
| 1.3 - 1.5 | 1.31 | 1.47? |
| 1.2       | 1.28 | 1.47? |
| 1.0-1.1   | 1.23 | 1.47? |
| 1.2       | ?    | ?     |

Note that building with legacy Rust version (e.g. 1.46) may require manually copying `Cargo.lock.legacy` to `Cargo.lock` prior to the building.

Early non-async versions of Websocat should be buildable by even older rustc.  

Note that old versions of Websocat may misbehave if built by Rust 1.48 or later due to https://github.com/rust-lang/rust/pull/71274/.

It may be not a good idea to build v1.x line of Websocat with Rust 1.64 due to [IP address representation refactor]. It may expose previously hidden undefined behaviour in legacy dependencies. (In practice, it seems to just work though - but a lot of time passed since I checked Websocat properly and in detail).

[ipaddr]:https://github.com/rust-lang/rust/pull/78802


SSL on Android
---

websocat's `wss://` may fail on Android. As a workaround, download certificate bundle, for example, from https://curl.haxx.se/ca/cacert.pem and specify it explicitly:

    SSL_CERT_FILE=cacert.pem /data/local/tmp/websocat wss://echo.websocket.org

Or just use `--insecure` option.

Documentation
---

Basic usage examples are provided at the top of this README and in `--help` message. More tricks are described in [moreexamples.md](./moreexamples.md).

There is a [list of all address types and overlays](doc.md).

<details><summary>`websocat --help=long` output</summary>

```
websocat 1.13.0
Vitaly "_Vi" Shukela <vi0oss@gmail.com>
Command-line client for web sockets, like netcat/curl/socat for ws://.

USAGE:
    websocat ws://URL | wss://URL               (simple client)
    websocat -s port                            (simple server)
    websocat [FLAGS] [OPTIONS] <addr1> <addr2>  (advanced mode)

FLAGS:
        --stdout-announce-listening-ports        [A] Print a line to stdout for each port being listened
        --async-stdio
            [A] On UNIX, set stdin and stdout to nonblocking mode instead of spawning a thread. This should improve
            performance, but may break other programs running on the same console.
        --compress-deflate
            [A] Compress data coming to a WebSocket using deflate method. Affects only binary WebSocket messages.

        --compress-gzip
            [A] Compress data coming to a WebSocket using gzip method. Affects only binary WebSocket messages.

        --compress-zlib
            [A] Compress data coming to a WebSocket using zlib method. Affects only binary WebSocket messages.

        --crypto-reverse
            [A] Swap encryption and decryption operations in `crypto:` specifier - encrypt on read, decrypto on write.

        --dump-spec                              [A] Instead of running, dump the specifiers representation to stdout
    -e, --set-environment
            Set WEBSOCAT_* environment variables when doing exec:/cmd:/sh-c:
            Currently it's WEBSOCAT_URI and WEBSOCAT_CLIENT for
            request URI and client address (if TCP)
            Beware of ShellShock or similar security problems.
    -E, --exit-on-eof                            Close a data transfer direction if the other one reached EOF
        --foreachmsg-wait-read                   [A] Wait for reading to finish before closing foreachmsg:'s peer
        --jsonrpc
            Format messages you type as JSON RPC 2.0 method calls. First word becomes method name, the rest becomes
            parameters, possibly automatically wrapped in [].
        --jsonrpc-omit-jsonrpc                   [A] Omit `jsonrpc` field when using `--jsonrpc`, e.g. for Chromium
        --just-generate-key                      [A] Just a Sec-WebSocket-Key value without running main Websocat
        --lengthprefixed-little-endian
            [A] Use little-endian framing headers instead of big-endian for `lengthprefixed:` overlay.

        --lengthprefixed-skip-read-direction
            [A] Only affect one direction of the `lengthprefixed:` overlay, bypass tranformation for the other one.

        --lengthprefixed-skip-write-direction
            [A] Only affect one direction of the `lengthprefixed:` overlay, bypass tranformation for the other one.

        --linemode-strip-newlines
            [A] Don't include trailing \n or \r\n coming from streams in WebSocket messages

    -0, --null-terminated                        Use \0 instead of \n for linemode
        --no-line                                [A] Don't automatically insert line-to-message transformation
        --no-exit-on-zeromsg
            [A] Don't exit when encountered a zero message. Zero messages are used internally in Websocat, so it may
            fail to close connection at all.
        --no-fixups
            [A] Don't perform automatic command-line fixups. May destabilize websocat operation. Use --dump-spec without
            --no-fixups to discover what is being inserted automatically and read the full manual about Websocat
            internal workings.
        --no-async-stdio                         [A] Inhibit using stdin/stdout in a nonblocking way if it is not a tty
    -1, --one-message                            Send and/or receive only one message. Use with --no-close and/or -u/-U.
        --oneshot                                Serve only once. Not to be confused with -1 (--one-message)
        --print-ping-rtts
            Print measured round-trip-time to stderr after each received WebSocket pong.

        --exec-exit-on-disconnect
            [A] Make exec: or sh-c: or cmd: immediately exit when connection is closed, don't wait for termination.

        --exec-sighup-on-stdin-close
            [A] Make exec: or sh-c: or cmd: send SIGHUP on UNIX when input is closed.

        --exec-sighup-on-zero-msg
            [A] Make exec: or sh-c: or cmd: send SIGHUP on UNIX when facing incoming zero-length message.

    -q                                           Suppress all diagnostic messages, except of startup errors
        --reuser-send-zero-msg-on-disconnect
            [A] Make reuse-raw: send a zero-length message to the peer when some clients disconnects.

    -s, --server-mode                            Simple server mode: specify TCP port or addr:port as single argument
    -S, --strict
            strict line/message mode: drop too long messages instead of splitting them, drop incomplete lines.

        --timestamp-monotonic                    [A] Use monotonic clock for `timestamp:` overlay
    -k, --insecure                               Accept invalid certificates and hostnames while connecting to TLS
        --udp-broadcast                          [A] Set SO_BROADCAST
        --udp-multicast-loop                     [A] Set IP[V6]_MULTICAST_LOOP
        --udp-oneshot                            [A] udp-listen: replies only one packet per client
        --udp-reuseaddr
            [A] Set SO_REUSEADDR for UDP socket. Listening TCP sockets are always reuseaddr.

        --uncompress-deflate
            [A] Uncompress data coming from a WebSocket using deflate method. Affects only binary WebSocket messages.

        --uncompress-gzip
            [A] Uncompress data coming from a WebSocket using deflate method. Affects only binary WebSocket messages.

        --uncompress-zlib
            [A] Uncompress data coming from a WebSocket using deflate method. Affects only binary WebSocket messages.

    -u, --unidirectional                         Inhibit copying data in one direction
    -U, --unidirectional-reverse
            Inhibit copying data in the other direction (or maybe in both directions if combined with -u)

        --accept-from-fd
            [A] Do not call `socket(2)` in UNIX socket listener peer, start with `accept(2)` using specified file
            descriptor number as argument instead of filename
        --unlink                                 [A] Unlink listening UNIX socket before binding to it
    -V, --version                                Prints version information
    -v                                           Increase verbosity level to info or further
    -b, --binary                                 Send message to WebSockets as binary messages
    -n, --no-close                               Don't send Close message to websocket on EOF
        --websocket-ignore-zeromsg
            [A] Silently drop incoming zero-length WebSocket messages. They may cause connection close due to usage of
            zero-len message as EOF flag inside Websocat.
    -t, --text                                   Send message to WebSockets as text messages
        --base64
            Encode incoming binary WebSocket messages in one-line Base64 If `--binary-prefix` (see `--help=full`) is
            set, outgoing WebSocket messages that start with the prefix are decoded from base64 prior to sending.
        --base64-text
            [A] Encode incoming text WebSocket messages in one-line Base64. I don't know whether it can be ever useful,
            but it's for symmetry with `--base64`.

OPTIONS:
        --socks5 <auto_socks5>
            Use specified address:port as a SOCKS5 proxy. Note that proxy authentication is not supported yet. Example:
            --socks5 127.0.0.1:9050
        --autoreconnect-delay-millis <autoreconnect_delay_millis>
            [A] Delay before reconnect attempt for `autoreconnect:` overlay. [default: 20]

        --basic-auth <basic_auth>
            Add `Authorization: Basic` HTTP request header with this base64-encoded parameter

        --queue-len <broadcast_queue_len>
            [A] Number of pending queued messages for broadcast reuser [default: 16]

    -B, --buffer-size <buffer_size>                                  Maximum message size, in bytes [default: 65536]
        --byte-to-exit-on <byte_to_exit_on>
            [A] Override the byte which byte_to_exit_on: overlay looks for [default: 28]

        --client-pkcs12-der <client_pkcs12_der>                      [A] Client identity TLS certificate
        --client-pkcs12-passwd <client_pkcs12_passwd>
            [A] Password for --client-pkcs12-der pkcs12 archive. Required on Mac.

        --close-reason <close_reason>
            Close connection with a reason message. This option only takes effect if --close-status-code option is
            provided as well.
        --close-status-code <close_status_code>                      Close connection with a status code.
        --crypto-key <crypto_key>
            [A] Specify encryption/decryption key for `crypto:` specifier. Requires `base64:`, `file:` or `pwd:` prefix.

    -H, --header <custom_headers>...
            Add custom HTTP header to websocket client request. Separate header name and value with a colon and
            optionally a single space. Can be used multiple times. Note that single -H may eat multiple further
            arguments, leading to confusing errors. Specify headers at the end or with equal sign like -H='X: y'.
        --server-header <custom_reply_headers>...
            Add custom HTTP header to websocket upgrade reply. Separate header name and value with a colon and
            optionally a single space. Can be used multiple times. Note that single -H may eat multiple further
            arguments, leading to confusing errors.
        --exec-args <exec_args>...
            [A] Arguments for the `exec:` specifier. Must be the last option, everything after it gets into the exec
            args list.
        --header-to-env <headers_to_env>...
            Forward specified incoming request header to H_* environment variable for `exec:`-like specifiers.

    -h, --help <help>
            See the help.
            --help=short is the list of easy options and address types
            --help=long lists all options and types (see [A] markers)
            --help=doc also shows longer description and examples.
        --inhibit-pongs <inhibit_pongs>
            [A] Stop replying to incoming WebSocket pings after specified number of replies

        --just-generate-accept <just_generate_accept>
            [A] Just a Sec-WebSocket-Accept value based on supplied Sec-WebSocket-Key value without running main
            Websocat
        --lengthprefixed-nbytes <lengthprefixed_header_bytes>
            [A] Use this number of length header bytes for `lengthprefixed:` overlay. [default: 4]

        --max-messages <max_messages>
            Maximum number of messages to copy in one direction.

        --max-messages-rev <max_messages_rev>
            Maximum number of messages to copy in the other direction.

        --conncap <max_parallel_conns>
            Maximum number of simultaneous connections for listening mode

        --max-sent-pings <max_sent_pings>
            [A] Stop sending pings after this number of sent pings

        --max-ws-frame-length <max_ws_frame_length>
            [A] Maximum size of incoming WebSocket frames, to prevent memory overflow [default: 104857600]

        --max-ws-message-length <max_ws_message_length>
            [A] Maximum size of incoming WebSocket messages (sans of one data frame), to prevent memory overflow
            [default: 209715200]
        --origin <origin>                                            Add Origin HTTP header to websocket client request
        --pkcs12-der <pkcs12_der>
            Pkcs12 archive needed to accept SSL connections, certificate and key.
            A command to output it: openssl pkcs12 -export -out output.pkcs12 -inkey key.pem -in cert.pem
            Use with -s (--server-mode) option or with manually specified TLS overlays.
            See moreexamples.md for more info.
        --pkcs12-passwd <pkcs12_passwd>
            Password for --pkcs12-der pkcs12 archive. Required on Mac.

    -p, --preamble <preamble>...
            Prepend copied data with a specified string. Can be specified multiple times.

    -P, --preamble-reverse <preamble_reverse>...
            Prepend copied data with a specified string (reverse direction). Can be specified multiple times.

        --prometheus <prometheus>
            Expose Prometheus metrics on specified IP address and port in addition to running usual Websocat session

        --request-header <request_headers>...
            [A] Specify HTTP request headers for `http-request:` specifier.

    -X, --request-method <request_method>                            [A] Method to use for `http-request:` specifier
        --request-uri <request_uri>                                  [A] URI to use for `http-request:` specifier
        --restrict-uri <restrict_uri>
            When serving a websocket, only accept the given URI, like `/ws`
            This liberates other URIs for things like serving static files or proxying.
    -F, --static-file <serve_static_files>...
            Serve a named static file for non-websocket connections.
            Argument syntax: <URI>:<Content-Type>:<file-path>
            Argument example: /index.html:text/html:index.html
            Directories are not and will not be supported for security reasons.
            Can be specified multiple times. Recommended to specify them at the end or with equal sign like `-F=...`,
            otherwise this option may eat positional arguments
        --socks5-bind-script <socks5_bind_script>
            [A] Execute specified script in `socks5-bind:` mode when remote port number becomes known.

        --socks5-destination <socks_destination>
            [A] Examples: 1.2.3.4:5678  2600:::80  hostname:5678

        --tls-domain <tls_domain>
            [A] Specify domain for SNI or certificate verification when using tls-connect: overlay

        --udp-multicast <udp_join_multicast_addr>...
            [A] Issue IP[V6]_ADD_MEMBERSHIP for specified multicast address. Can be specified multiple times.

        --udp-multicast-iface-v4 <udp_join_multicast_iface_v4>...
            [A] IPv4 address of multicast network interface. Has to be either not specified or specified the same number
            of times as multicast IPv4 addresses. Order matters.
        --udp-multicast-iface-v6 <udp_join_multicast_iface_v6>...
            [A] Index of network interface for IPv6 multicast. Has to be either not specified or specified the same
            number of times as multicast IPv6 addresses. Order matters.
        --udp-ttl <udp_ttl>                                          [A] Set IP_TTL, also IP_MULTICAST_TTL if applicable
        --protocol <websocket_protocol>
            Specify this Sec-WebSocket-Protocol: header when connecting

        --server-protocol <websocket_reply_protocol>
            Force this Sec-WebSocket-Protocol: header when accepting a connection

        --websocket-version <websocket_version>                      Override the Sec-WebSocket-Version value
        --binary-prefix <ws_binary_prefix>
            [A] Prepend specified text to each received WebSocket binary message. Also strip this prefix from outgoing
            messages, explicitly marking them as binary even if `--text` is specified
        --ws-c-uri <ws_c_uri>
            [A] URI to use for ws-c: overlay [default: ws://0.0.0.0/]

        --ping-interval <ws_ping_interval>                           Send WebSocket pings each this number of seconds
        --ping-timeout <ws_ping_timeout>
            Drop WebSocket connection if Pong message not received for this number of seconds

        --text-prefix <ws_text_prefix>
            [A] Prepend specified text to each received WebSocket text message. Also strip this prefix from outgoing
            messages, explicitly marking them as text even if `--binary` is specified

ARGS:
    <addr1>    In simple mode, WebSocket URL to connect. In advanced mode first address (there are many kinds of
               addresses) to use. See --help=types for info about address types. If this is an address for
               listening, it will try serving multiple connections.
    <addr2>    In advanced mode, second address to connect. If this is an address for listening, it will accept only
               one connection.


Basic examples:
  Command-line websocket client:
    websocat ws://ws.vi-server.org/mirror/
    
  WebSocket server
    websocat -s 8080
    
  WebSocket-to-TCP proxy:
    websocat --binary ws-l:127.0.0.1:8080 tcp:127.0.0.1:5678
    

Full list of address types:
	ws://           	Insecure (ws://) WebSocket client. Argument is host and URL.
	wss://          	Secure (wss://) WebSocket client. Argument is host and URL.
	ws-listen:      	WebSocket server. Argument is host and port to listen.
	inetd-ws:       	WebSocket inetd server. [A]
	l-ws-unix:      	WebSocket UNIX socket-based server. [A]
	l-ws-abstract:  	WebSocket abstract-namespaced UNIX socket server. [A]
	ws-lowlevel-client:	[A] Low-level HTTP-independent WebSocket client connection without associated HTTP upgrade.
	ws-lowlevel-server:	[A] Low-level HTTP-independent WebSocket server connection without associated HTTP upgrade.
	wss-listen:     	Listen for secure WebSocket connections on a TCP port
	http:           	[A] Issue HTTP request, receive a 1xx or 2xx reply, then pass
	asyncstdio:     	[A] Set stdin and stdout to nonblocking mode, then use it as a communication counterpart. UNIX-only.
	inetd:          	Like `asyncstdio:`, but intended for inetd(8) usage. [A]
	tcp:            	Connect to specified TCP host and port. Argument is a socket address.
	tcp-listen:     	Listen TCP port on specified address.
	ssl-listen:     	Listen for SSL connections on a TCP port
	sh-c:           	Start specified command line using `sh -c` (even on Windows)
	cmd:            	Start specified command line using `sh -c` or `cmd /C` (depending on platform)
	exec:           	Execute a program directly (without a subshell), providing array of arguments on Unix [A]
	readfile:       	Synchronously read a file. Argument is a file path.
	writefile:      	Synchronously truncate and write a file.
	appendfile:     	Synchronously append a file.
	udp:            	Send and receive packets to specified UDP socket, from random UDP port  
	udp-listen:     	Bind an UDP socket to specified host:port, receive packet
	open-async:     	Open file for read and write and use it like a socket. [A]
	open-fd:        	Use specified file descriptor like a socket. [A]
	threadedstdio:  	[A] Stdin/stdout, spawning a thread (threaded version).
	-               	Read input from console, print to console. Uses threaded implementation even on UNIX unless requested by `--async-stdio` CLI option.
	unix:           	Connect to UNIX socket. Argument is filesystem path. [A]
	unix-listen:    	Listen for connections on a specified UNIX socket [A]
	unix-dgram:     	Send packets to one path, receive from the other. [A]
	abstract:       	Connect to UNIX abstract-namespaced socket. Argument is some string used as address. [A]
	abstract-listen:	Listen for connections on a specified abstract UNIX socket [A]
	abstract-dgram: 	Send packets to one address, receive from the other. [A]
	mirror:         	Simply copy output to input. No arguments needed.
	literalreply:   	Reply with a specified string for each input packet.
	clogged:        	Do nothing. Don't read or write any bytes. Keep connections in "hung" state. [A]
	literal:        	Output a string, discard input.
	assert:         	Check the input.  [A]
	assert2:        	Check the input. [A]
	seqpacket:      	Connect to AF_UNIX SOCK_SEQPACKET socket. Argument is a filesystem path. [A]
	seqpacket-listen:	Listen for connections on a specified AF_UNIX SOCK_SEQPACKET socket [A]
	random:         	Generate random bytes when being read from, discard written bytes.
Full list of overlays:
	ws-upgrade:     	WebSocket upgrader / raw server. Specify your own protocol instead of usual TCP. [A]
	http-request:   	[A] Issue HTTP request, receive a 1xx or 2xx reply, then pass
	http-post-sse:  	[A] Accept HTTP/1 request. Then, if it is GET,
	ssl-connect:    	Overlay to add TLS encryption atop of existing connection [A]
	ssl-accept:     	Accept an TLS connection using arbitrary backing stream. [A]
	reuse-raw:      	Reuse subspecifier for serving multiple clients: unpredictable mode. [A]
	broadcast:      	Reuse this connection for serving multiple clients, sending replies to all clients.
	autoreconnect:  	Re-establish underlying connection on any error or EOF
	ws-c:           	Low-level WebSocket connector. Argument is a some another address. [A]
	msg2line:       	Line filter: Turns messages from packet stream into lines of byte stream. [A]
	line2msg:       	Line filter: turn lines from byte stream into messages as delimited by '\\n' or '\\0' [A]
	lengthprefixed: 	Turn stream of bytes to/from data packets with length-prefixed framing.  [A]
	foreachmsg:     	Execute something for each incoming message.
	log:            	Log each buffer as it pass though the underlying connector.
	jsonrpc:        	[A] Turns messages like `abc 1,2` into `{"jsonrpc":"2.0","id":412, "method":"abc", "params":[1,2]}`.
	timestamp:      	[A] Prepend timestamp to each incoming message.
	socks5-connect: 	SOCKS5 proxy client (raw) [A]
	socks5-bind:    	SOCKS5 proxy client (raw, bind command) [A]
	crypto:         	[A] Encrypts written messages and decrypts (and verifies) read messages with a static key, using ChaCha20-Poly1305 algorithm.
	prometheus:     	[A] Account connections, messages, bytes and other data and expose Prometheus metrics on a separate port.
	exit_on_specific_byte:	[A] Turn specific byte into a EOF, allowing user to escape interactive Websocat session
	waitfordata:    	Wait for some data to pending being written before starting connecting. [A]
```
</details>


Some notes
---

* IPv6 is supported, surround your IP in square brackets or use it as is, depending on context.
* Web socket usage is not obligatory, you can use any specs on both sides.
* Typically one line in binary stream correspond to one WebSocket text message. This is adjustable with options.

Limitations
---

* It only connects (or serves) HTTP/1. [RFC 8441](https://www.rfc-editor.org/rfc/rfc8441) or [RFC 9220](https://www.rfc-editor.org/rfc/rfc9220.html) are not currently supported.
* It is not convenient when text and binary WebSocket messages are mixed. This affects `mirror:` specifier, making it a bit different from ws://echo.websocket.org. There are `--binary-prefix`, `--text-prefix` and `--base64` options to handle mixture of binary and text.
* Current version of Websocat don't receive notification about closed sockets. This makes serving without `-E` or `-u` options or in backpressure scenarios prone to socket leak.
* Readline is not integrated. Users are advices to wrap websocat using [`rlwrap`](https://linux.die.net/man/1/rlwrap) tool for more convenient CLI.
* Build process of current version of Websocat is not properly automated and is fragile.
* Main version (v1) is based on obsolete dependency versions that trigger security warnings and may become tricky to build. There is [new version (v4)](https://github.com/vi/websocat/tree/websocat4), but is not yet considered stable and [has many missing features](https://github.com/vi/websocat/issues/276).

Bindings
---

* Node.js: [`seamapi/node-websocat`](https://github.com/seamapi/node-websocat)

See also
---

* [wstunnel](https://github.com/erebe/wstunnel)
* [wscat](https://github.com/websockets/wscat)
* [websocketd](https://github.com/joewalnes/websocketd)
* [wsd](https://github.com/alexanderGugel/wsd)


================================================
FILE: doc.md
================================================

# Websocat Reference (in progress)

Websocat has many command-line options and special format for positional arguments.

There are three main modes of websocat invocation:

* Simple client mode: `websocat wss://your.server/url`
* Simple server mode: `websocat -s 127.0.0.1:8080`
* Advanced [socat][1]-like mode: `websocat -t ws-l:127.0.0.1:8080 mirror:`

Ultimately in any of those modes websocat creates two connections and exchanges data between them.
If one of the connections is bytestream-oriented (for example the terminal stdin/stdout or a TCP connection), but the other is message-oriented (for example, a WebSocket or UDP) then websocat operates in lines: each line correspond to a message. Details of this are configurable by various options.

`ws-l:` or `mirror:` above are examples of address types. With the exception of special cases like WebSocket URL `ws://1.2.3.4/` or stdio `-`, websocat's positional argument is defined by this rule:

```
<specifier> ::= ( <overlay> ":" )* <addrtype> ":" [address]
```

Some address types may be "aliases" to other address types or combinations of overlays and address types.

[1]:http://www.dest-unreach.org/socat/doc/socat.html

# `--help=long`

"Advanced" options and flags are denoted by `[A]` marker.


```

websocat 1.14.0
Vitaly "_Vi" Shukela <vi0oss@gmail.com>
Command-line client for web sockets, like netcat/curl/socat for ws://.

USAGE:
    websocat ws://URL | wss://URL               (simple client)
    websocat -s port                            (simple server)
    websocat [FLAGS] [OPTIONS] <addr1> <addr2>  (advanced mode)

FLAGS:
        --stdout-announce-listening-ports        [A] Print a line to stdout for each port being listened
        --async-stdio
            [A] On UNIX, set stdin and stdout to nonblocking mode instead of spawning a thread. This should improve
            performance, but may break other programs running on the same console.
        --compress-deflate
            [A] Compress data coming to a WebSocket using deflate method. Affects only binary WebSocket messages.

        --compress-gzip
            [A] Compress data coming to a WebSocket using gzip method. Affects only binary WebSocket messages.

        --compress-zlib
            [A] Compress data coming to a WebSocket using zlib method. Affects only binary WebSocket messages.

        --crypto-reverse
            [A] Swap encryption and decryption operations in `crypto:` specifier - encrypt on read, decrypto on write.

        --dump-spec                              [A] Instead of running, dump the specifiers representation to stdout
    -e, --set-environment
            Set WEBSOCAT_* environment variables when doing exec:/cmd:/sh-c:
            Currently it's WEBSOCAT_URI and WEBSOCAT_CLIENT for
            request URI and client address (if TCP)
            Beware of ShellShock or similar security problems.
    -E, --exit-on-eof                            Close a data transfer direction if the other one reached EOF
        --foreachmsg-wait-read                   [A] Wait for reading to finish before closing foreachmsg:'s peer
        --jsonrpc
            Format messages you type as JSON RPC 2.0 method calls. First word becomes method name, the rest becomes
            parameters, possibly automatically wrapped in [].
        --jsonrpc-omit-jsonrpc                   [A] Omit `jsonrpc` field when using `--jsonrpc`, e.g. for Chromium
        --just-generate-key                      [A] Just a Sec-WebSocket-Key value without running main Websocat
        --lengthprefixed-little-endian
            [A] Use little-endian framing headers instead of big-endian for `lengthprefixed:` overlay.

        --lengthprefixed-skip-read-direction
            [A] Only affect one direction of the `lengthprefixed:` overlay, bypass tranformation for the other one.

        --lengthprefixed-skip-write-direction
            [A] Only affect one direction of the `lengthprefixed:` overlay, bypass tranformation for the other one.

        --linemode-strip-newlines
            [A] Don't include trailing \n or \r\n coming from streams in WebSocket messages

    -0, --null-terminated                        Use \0 instead of \n for linemode
        --no-line                                [A] Don't automatically insert line-to-message transformation
        --no-exit-on-zeromsg
            [A] Don't exit when encountered a zero message. Zero messages are used internally in Websocat, so it may
            fail to close connection at all.
        --no-fixups
            [A] Don't perform automatic command-line fixups. May destabilize websocat operation. Use --dump-spec without
            --no-fixups to discover what is being inserted automatically and read the full manual about Websocat
            internal workings.
        --no-async-stdio                         [A] Inhibit using stdin/stdout in a nonblocking way if it is not a tty
    -1, --one-message                            Send and/or receive only one message. Use with --no-close and/or -u/-U.
        --oneshot                                Serve only once. Not to be confused with -1 (--one-message)
        --print-ping-rtts
            Print measured round-trip-time to stderr after each received WebSocket pong.

        --exec-exit-on-disconnect
            [A] Make exec: or sh-c: or cmd: immediately exit when connection is closed, don't wait for termination.

        --exec-sighup-on-stdin-close
            [A] Make exec: or sh-c: or cmd: send SIGHUP on UNIX when input is closed.

        --exec-sighup-on-zero-msg
            [A] Make exec: or sh-c: or cmd: send SIGHUP on UNIX when facing incoming zero-length message.

    -q                                           Suppress all diagnostic messages, except of startup errors
        --reuser-send-zero-msg-on-disconnect
            [A] Make reuse-raw: send a zero-length message to the peer when some clients disconnects.

    -s, --server-mode                            Simple server mode: specify TCP port or addr:port as single argument
    -S, --strict
            strict line/message mode: drop too long messages instead of splitting them, drop incomplete lines.

        --timestamp-monotonic                    [A] Use monotonic clock for `timestamp:` overlay
    -k, --insecure                               Accept invalid certificates and hostnames while connecting to TLS
        --udp-broadcast                          [A] Set SO_BROADCAST
        --udp-multicast-loop                     [A] Set IP[V6]_MULTICAST_LOOP
        --udp-oneshot                            [A] udp-listen: replies only one packet per client
        --udp-reuseaddr
            [A] Set SO_REUSEADDR for UDP socket. Listening TCP sockets are always reuseaddr.

        --uncompress-deflate
            [A] Uncompress data coming from a WebSocket using deflate method. Affects only binary WebSocket messages.

        --uncompress-gzip
            [A] Uncompress data coming from a WebSocket using deflate method. Affects only binary WebSocket messages.

        --uncompress-zlib
            [A] Uncompress data coming from a WebSocket using deflate method. Affects only binary WebSocket messages.

    -u, --unidirectional                         Inhibit copying data in one direction
    -U, --unidirectional-reverse
            Inhibit copying data in the other direction (or maybe in both directions if combined with -u)

        --accept-from-fd
            [A] Do not call `socket(2)` in UNIX socket listener peer, start with `accept(2)` using specified file
            descriptor number as argument instead of filename
        --unlink                                 [A] Unlink listening UNIX socket before binding to it
    -V, --version                                Prints version information
    -v                                           Increase verbosity level to info or further
    -b, --binary                                 Send message to WebSockets as binary messages
    -n, --no-close                               Don't send Close message to websocket on EOF
        --websocket-ignore-zeromsg
            [A] Silently drop incoming zero-length WebSocket messages. They may cause connection close due to usage of
            zero-len message as EOF flag inside Websocat.
    -t, --text                                   Send message to WebSockets as text messages
        --base64
            Encode incoming binary WebSocket messages in one-line Base64 If `--binary-prefix` (see `--help=full`) is
            set, outgoing WebSocket messages that start with the prefix are decoded from base64 prior to sending.
        --base64-text
            [A] Encode incoming text WebSocket messages in one-line Base64. I don't know whether it can be ever useful,
            but it's for symmetry with `--base64`.

OPTIONS:
        --socks5 <auto_socks5>
            Use specified address:port as a SOCKS5 proxy. Example: --socks5 127.0.0.1:9050

        --autoreconnect-delay-millis <autoreconnect_delay_millis>
            [A] Delay before reconnect attempt for `autoreconnect:` overlay. [default: 20]

        --basic-auth <basic_auth>
            Add `Authorization: Basic` HTTP request header with this base64-encoded parameter. Also available as
            `WEBSOCAT_BASIC_AUTH` environment variable
        --basic-auth-file <basic_auth_file>
            Add `Authorization: Basic` HTTP request header base64-encoded content of the specified file

        --queue-len <broadcast_queue_len>
            [A] Number of pending queued messages for broadcast reuser [default: 16]

    -B, --buffer-size <buffer_size>                                  Maximum message size, in bytes [default: 65536]
        --byte-to-exit-on <byte_to_exit_on>
            [A] Override the byte which byte_to_exit_on: overlay looks for [default: 28]

        --client-pkcs12-der <client_pkcs12_der>                      [A] Client identity TLS certificate
        --client-pkcs12-passwd <client_pkcs12_passwd>
            [A] Password for --client-pkcs12-der pkcs12 archive. Required on Mac.

        --close-reason <close_reason>
            Close connection with a reason message. This option only takes effect if --close-status-code option is
            provided as well.
        --close-status-code <close_status_code>                      Close connection with a status code.
        --crypto-key <crypto_key>
            [A] Specify encryption/decryption key for `crypto:` specifier. Requires `base64:`, `file:` or `pwd:` prefix.

    -H, --header <custom_headers>...
            Add custom HTTP header to websocket client request. Separate header name and value with a colon and
            optionally a single space. Can be used multiple times. Note that single -H may eat multiple further
            arguments, leading to confusing errors. Specify headers at the end or with equal sign like -H='X: y'.
        --server-header <custom_reply_headers>...
            Add custom HTTP header to websocket upgrade reply. Separate header name and value with a colon and
            optionally a single space. Can be used multiple times. Note that single -H may eat multiple further
            arguments, leading to confusing errors.
        --exec-args <exec_args>...
            [A] Arguments for the `exec:` specifier. Must be the last option, everything after it gets into the exec
            args list.
        --header-to-env <headers_to_env>...
            Forward specified incoming request header to H_* environment variable for `exec:`-like specifiers.

    -h, --help <help>
            See the help.
            --help=short is the list of easy options and address types
            --help=long lists all options and types (see [A] markers)
            --help=doc also shows longer description and examples.
        --inhibit-pongs <inhibit_pongs>
            [A] Stop replying to incoming WebSocket pings after specified number of replies

        --just-generate-accept <just_generate_accept>
            [A] Just a Sec-WebSocket-Accept value based on supplied Sec-WebSocket-Key value without running main
            Websocat
        --lengthprefixed-nbytes <lengthprefixed_header_bytes>
            [A] Use this number of length header bytes for `lengthprefixed:` overlay. [default: 4]

        --max-messages <max_messages>
            Maximum number of messages to copy in one direction.

        --max-messages-rev <max_messages_rev>
            Maximum number of messages to copy in the other direction.

        --conncap <max_parallel_conns>
            Maximum number of simultaneous connections for listening mode

        --max-sent-pings <max_sent_pings>
            [A] Stop sending pings after this number of sent pings

        --max-ws-frame-length <max_ws_frame_length>
            [A] Maximum size of incoming WebSocket frames, to prevent memory overflow [default: 104857600]

        --max-ws-message-length <max_ws_message_length>
            [A] Maximum size of incoming WebSocket messages (sans of one data frame), to prevent memory overflow
            [default: 209715200]
        --origin <origin>                                            Add Origin HTTP header to websocket client request
        --pkcs12-der <pkcs12_der>
            Pkcs12 archive needed to accept SSL connections, certificate and key.
            A command to output it: openssl pkcs12 -export -out output.pkcs12 -inkey key.pem -in cert.pem
            Use with -s (--server-mode) option or with manually specified TLS overlays.
            See moreexamples.md for more info.
        --pkcs12-passwd <pkcs12_passwd>
            Password for --pkcs12-der pkcs12 archive. Required on Mac.

    -p, --preamble <preamble>...
            Prepend copied data with a specified string. Can be specified multiple times.

    -P, --preamble-reverse <preamble_reverse>...
            Prepend copied data with a specified string (reverse direction). Can be specified multiple times.

        --prometheus <prometheus>
            Expose Prometheus metrics on specified IP address and port in addition to running usual Websocat session

        --request-header <request_headers>...
            [A] Specify HTTP request headers for `http-request:` specifier.

    -X, --request-method <request_method>                            [A] Method to use for `http-request:` specifier
        --request-uri <request_uri>                                  [A] URI to use for `http-request:` specifier
        --restrict-uri <restrict_uri>
            When serving a websocket, only accept the given URI, like `/ws`
            This liberates other URIs for things like serving static files or proxying.
    -F, --static-file <serve_static_files>...
            Serve a named static file for non-websocket connections.
            Argument syntax: <URI>:<Content-Type>:<file-path>
            Argument example: /index.html:text/html:index.html
            Directories are not and will not be supported for security reasons.
            Can be specified multiple times. Recommended to specify them at the end or with equal sign like `-F=...`,
            otherwise this option may eat positional arguments
        --socks5-bind-script <socks5_bind_script>
            [A] Execute specified script in `socks5-bind:` mode when remote port number becomes known.

        --socks5-user-pass <socks5_user_pass>
            [A] Specify username:password for SOCKS5 proxy. If not specified, the default is to use no authentication.

        --socks5-destination <socks_destination>
            [A] Examples: 1.2.3.4:5678  2600:::80  hostname:5678

        --tls-domain <tls_domain>
            [A] Specify domain for SNI or certificate verification when using tls-connect: overlay

        --udp-multicast <udp_join_multicast_addr>...
            [A] Issue IP[V6]_ADD_MEMBERSHIP for specified multicast address. Can be specified multiple times.

        --udp-multicast-iface-v4 <udp_join_multicast_iface_v4>...
            [A] IPv4 address of multicast network interface. Has to be either not specified or specified the same number
            of times as multicast IPv4 addresses. Order matters.
        --udp-multicast-iface-v6 <udp_join_multicast_iface_v6>...
            [A] Index of network interface for IPv6 multicast. Has to be either not specified or specified the same
            number of times as multicast IPv6 addresses. Order matters.
        --udp-ttl <udp_ttl>                                          [A] Set IP_TTL, also IP_MULTICAST_TTL if applicable
        --ua <useragent>
            Set `User-Agent` request header to this value. Similar to setting it with `-H`.

        --protocol <websocket_protocol>
            Specify this Sec-WebSocket-Protocol: header when connecting

        --server-protocol <websocket_reply_protocol>
            Force this Sec-WebSocket-Protocol: header when accepting a connection

        --websocket-version <websocket_version>                      Override the Sec-WebSocket-Version value
        --binary-prefix <ws_binary_prefix>
            [A] Prepend specified text to each received WebSocket binary message. Also strip this prefix from outgoing
            messages, explicitly marking them as binary even if `--text` is specified
        --ws-c-uri <ws_c_uri>
            [A] URI to use for ws-c: overlay [default: ws://0.0.0.0/]

        --ping-interval <ws_ping_interval>                           Send WebSocket pings each this number of seconds
        --ping-timeout <ws_ping_timeout>
            Drop WebSocket connection if Pong message not received for this number of seconds

        --text-prefix <ws_text_prefix>
            [A] Prepend specified text to each received WebSocket text message. Also strip this prefix from outgoing
            messages, explicitly marking them as text even if `--binary` is specified

ARGS:
    <addr1>    In simple mode, WebSocket URL to connect. In advanced mode first address (there are many kinds of
               addresses) to use. See --help=types for info about address types. If this is an address for
               listening, it will try serving multiple connections.
    <addr2>    In advanced mode, second address to connect. If this is an address for listening, it will accept only
               one connection.


Basic examples:
  Command-line websocket client:
    websocat ws://ws.vi-server.org/mirror/
    
  WebSocket server
    websocat -s 8080
    
  WebSocket-to-TCP proxy:
    websocat --binary ws-l:127.0.0.1:8080 tcp:127.0.0.1:5678
    

```

# Full list of address types

"Advanced" address types are denoted by `[A]` marker.


### `ws://`

Internal name for --dump-spec: WsClient


Insecure (ws://) WebSocket client. Argument is host and URL.

Example: connect to public WebSocket loopback and copy binary chunks from stdin to the websocket.

    websocat - ws://echo.websocket.org/


### `wss://`

Internal name for --dump-spec: WsClientSecure


Secure (wss://) WebSocket client. Argument is host and URL.

Example: forward TCP port 4554 to a websocket

    websocat tcp-l:127.0.0.1:4554 wss://127.0.0.1/some_websocket

### `ws-listen:`

Aliases: `ws-l:`, `l-ws:`, `listen-ws:`  
Internal name for --dump-spec: WsTcpServer


WebSocket server. Argument is host and port to listen.

Example: Dump all incoming websocket data to console

    websocat ws-l:127.0.0.1:8808 -

Example: the same, but more verbose:

    websocat ws-l:tcp-l:127.0.0.1:8808 reuse:-


### `inetd-ws:`

Aliases: `ws-inetd:`  
Internal name for --dump-spec: WsInetdServer


WebSocket inetd server. [A]

TODO: transfer the example here


### `l-ws-unix:`

Internal name for --dump-spec: WsUnixServer


WebSocket UNIX socket-based server. [A]


### `l-ws-abstract:`

Internal name for --dump-spec: WsAbstractUnixServer


WebSocket abstract-namespaced UNIX socket server. [A]


### `ws-lowlevel-client:`

Aliases: `ws-ll-client:`, `ws-ll-c:`  
Internal name for --dump-spec: WsLlClient


[A] Low-level HTTP-independent WebSocket client connection without associated HTTP upgrade.

Example: TODO


### `ws-lowlevel-server:`

Aliases: `ws-ll-server:`, `ws-ll-s:`  
Internal name for --dump-spec: WsLlServer


[A] Low-level HTTP-independent WebSocket server connection without associated HTTP upgrade.

Example: TODO


### `wss-listen:`

Aliases: `wss-l:`, `l-wss:`, `wss-listen:`  
Internal name for --dump-spec: WssListen


Listen for secure WebSocket connections on a TCP port

Example: wss:// echo server + client for testing

    websocat -E -t --pkcs12-der=q.pkcs12 wss-listen:127.0.0.1:1234 mirror:
    websocat --ws-c-uri=wss://localhost/ -t - ws-c:cmd:'socat - ssl:127.0.0.1:1234,verify=0'

See [moreexamples.md](./moreexamples.md) for info about generation of `q.pkcs12`.


### `http:`

Internal name for --dump-spec: Http


[A] Issue HTTP request, receive a 1xx or 2xx reply, then pass
the torch to outer peer, if any - highlevel version.

Content you write becomes body, content you read is body that server has sent.

URI is specified inline.

Example:

    websocat  -b - http://example.com < /dev/null


### `asyncstdio:`

Internal name for --dump-spec: AsyncStdio


[A] Set stdin and stdout to nonblocking mode, then use it as a communication counterpart. UNIX-only.
May cause problems with programs running at the same terminal. This specifier backs the `--async-stdio` CLI option. 

Typically this specifier can be specified only one time.
    
Example: simulate `cat(1)`. This is an exception from "only one time" rule above:

    websocat - -

Example: SSH transport

    ssh -c ProxyCommand='websocat asyncstdio: ws://myserver/mywebsocket' user@myserver


### `inetd:`

Internal name for --dump-spec: Inetd


Like `asyncstdio:`, but intended for inetd(8) usage. [A]

Automatically enables `-q` (`--quiet`) mode.

`inetd-ws:` - is of `ws-l:inetd:`

Example of inetd.conf line that makes it listen for websocket
connections on port 1234 and redirect the data to local SSH server.

    1234 stream tcp nowait myuser  /opt/websocat websocat inetd-ws: tcp:127.0.0.1:22


### `tcp:`

Aliases: `tcp-connect:`, `connect-tcp:`, `tcp-c:`, `c-tcp:`  
Internal name for --dump-spec: TcpConnect


Connect to specified TCP host and port. Argument is a socket address.

Example: simulate netcat netcat

    websocat - tcp:127.0.0.1:22

Example: redirect websocket connections to local SSH server over IPv6

    websocat ws-l:0.0.0.0:8084 tcp:[::1]:22


### `tcp-listen:`

Aliases: `listen-tcp:`, `tcp-l:`, `l-tcp:`  
Internal name for --dump-spec: TcpListen


Listen TCP port on specified address.
    
Example: echo server

    websocat tcp-l:0.0.0.0:1441 mirror:
    
Example: redirect TCP to a websocket

    websocat tcp-l:0.0.0.0:8088 ws://echo.websocket.org


### `ssl-listen:`

Aliases: `ssl-l:`, `tls-l:`, `tls-listen:`, `l-ssl:`, `listen-ssl:`, `listen-tls:`, `listen-tls:`  
Internal name for --dump-spec: TlsListen


Listen for SSL connections on a TCP port

Example: Non-websocket SSL echo server

    websocat -E -b --pkcs12-der=q.pkcs12 ssl-listen:127.0.0.1:1234 mirror:
    socat - ssl:127.0.0.1:1234,verify=0


### `sh-c:`

Internal name for --dump-spec: ShC


Start specified command line using `sh -c` (even on Windows)
  
Example: serve a counter

    websocat -U ws-l:127.0.0.1:8008 sh-c:'for i in 0 1 2 3 4 5 6 7 8 9 10; do echo $i; sleep 1; done'
  
Example: unauthenticated shell

    websocat --exit-on-eof ws-l:127.0.0.1:5667 sh-c:'bash -i 2>&1'


### `cmd:`

Internal name for --dump-spec: Cmd


Start specified command line using `sh -c` or `cmd /C` (depending on platform)

Otherwise should be the the same as `sh-c:` (see examples from there).


### `exec:`

Internal name for --dump-spec: Exec


Execute a program directly (without a subshell), providing array of arguments on Unix [A]

Example: Serve current date

  websocat -U ws-l:127.0.0.1:5667 exec:date
  
Example: pinger

  websocat -U ws-l:127.0.0.1:5667 exec:ping --exec-args 127.0.0.1 -c 1
  


### `readfile:`

Internal name for --dump-spec: ReadFile


Synchronously read a file. Argument is a file path.

Blocking on operations with the file pauses the whole process

Example: Serve the file once per connection, ignore all replies.

    websocat ws-l:127.0.0.1:8000 readfile:hello.json



### `writefile:`

Internal name for --dump-spec: WriteFile



Synchronously truncate and write a file.

Blocking on operations with the file pauses the whole process

Example:

    websocat ws-l:127.0.0.1:8000 writefile:data.txt



### `appendfile:`

Internal name for --dump-spec: AppendFile



Synchronously append a file.

Blocking on operations with the file pauses the whole process

Example: Logging all incoming data from WebSocket clients to one file

    websocat -u ws-l:127.0.0.1:8000 reuse:appendfile:log.txt


### `udp:`

Aliases: `udp-connect:`, `connect-udp:`, `udp-c:`, `c-udp:`  
Internal name for --dump-spec: UdpConnect


Send and receive packets to specified UDP socket, from random UDP port  


### `udp-listen:`

Aliases: `listen-udp:`, `udp-l:`, `l-udp:`  
Internal name for --dump-spec: UdpListen


Bind an UDP socket to specified host:port, receive packet
from any remote UDP socket, send replies to recently observed
remote UDP socket.

Note that it is not a multiconnect specifier like e.g. `tcp-listen`:
entire lifecycle of the UDP socket is the same connection.

File a feature request on Github if you want proper DNS-like request-reply UDP mode here.


### `open-async:`

Internal name for --dump-spec: OpenAsync


Open file for read and write and use it like a socket. [A]
Not for regular files, see readfile/writefile instead.
  
Example: Serve big blobs of random data to clients

    websocat -U ws-l:127.0.0.1:8088 open-async:/dev/urandom



### `open-fd:`

Internal name for --dump-spec: OpenFdAsync


Use specified file descriptor like a socket. [A]

Example: Serve random data to clients v2

    websocat -U ws-l:127.0.0.1:8088 reuse:open-fd:55   55< /dev/urandom


### `threadedstdio:`

Internal name for --dump-spec: ThreadedStdio


[A] Stdin/stdout, spawning a thread (threaded version).

Like `-`, but forces threaded mode instead of async mode

Use when standard input is not `epoll(7)`-able or you want to avoid setting it to nonblocking mode.


### `-`

Aliases: `stdio:`  
Internal name for --dump-spec: Stdio


Read input from console, print to console. Uses threaded implementation even on UNIX unless requested by `--async-stdio` CLI option.

Typically this specifier can be specified only one time.
    
Example: simulate `cat(1)`. This is an exception from "only one time" rule above:

    websocat - -

Example: SSH transport

    ssh -c ProxyCommand='websocat - ws://myserver/mywebsocket' user@myserver


### `unix:`

Aliases: `unix-connect:`, `connect-unix:`, `unix-c:`, `c-unix:`  
Internal name for --dump-spec: UnixConnect


Connect to UNIX socket. Argument is filesystem path. [A]

Example: forward connections from websockets to a UNIX stream socket

    websocat ws-l:127.0.0.1:8088 unix:the_socket


### `unix-listen:`

Aliases: `listen-unix:`, `unix-l:`, `l-unix:`  
Internal name for --dump-spec: UnixListen


Listen for connections on a specified UNIX socket [A]

Example: forward connections from a UNIX socket to a WebSocket

    websocat --unlink unix-l:the_socket ws://127.0.0.1:8089

Example: Accept forwarded WebSocket connections from Nginx

    umask 0000
    websocat --unlink -b -E ws-u:unix-l:/tmp/wstest tcp:[::]:22

Nginx config:

    location /ws {
        proxy_read_timeout 7d;
        proxy_send_timeout 7d;
        #proxy_pass http://localhost:3012;
        proxy_pass http://unix:/tmp/wstest;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection \"upgrade\";
    }

This configuration allows to make Nginx responsible for
SSL and also it can choose which connections to forward
to websocat based on URLs.

Obviously, Nginx can also redirect to TCP-listening
websocat just as well - UNIX sockets are not a requirement for this feature.

See `moreexamples.md` for SystemD usage (untested).

TODO: --chmod option?


### `unix-dgram:`

Internal name for --dump-spec: UnixDgram


Send packets to one path, receive from the other. [A]
A socket for sending must be already opened.

I don't know if this mode has any use, it is here just for completeness.

Example:

    socat unix-recv:./sender -&
    websocat - unix-dgram:./receiver:./sender


### `abstract:`

Aliases: `abstract-connect:`, `connect-abstract:`, `abstract-c:`, `c-abstract:`  
Internal name for --dump-spec: AbstractConnect


Connect to UNIX abstract-namespaced socket. Argument is some string used as address. [A]

Too long addresses may be silently chopped off.

Example: forward connections from websockets to an abstract stream socket

    websocat ws-l:127.0.0.1:8088 abstract:the_socket

Note that abstract-namespaced Linux sockets may not be normally supported by Rust,
so non-prebuilt versions may have problems with them.


### `abstract-listen:`

Aliases: `listen-abstract:`, `abstract-l:`, `l-abstract:`  
Internal name for --dump-spec: AbstractListen


Listen for connections on a specified abstract UNIX socket [A]

Example: forward connections from an abstract UNIX socket to a WebSocket

    websocat abstract-l:the_socket ws://127.0.0.1:8089

Note that abstract-namespaced Linux sockets may not be normally supported by Rust,
so non-prebuilt versions may have problems with them.


### `abstract-dgram:`

Internal name for --dump-spec: AbstractDgram


Send packets to one address, receive from the other. [A]
A socket for sending must be already opened.

I don't know if this mode has any use, it is here just for completeness.

Example (untested):

    websocat - abstract-dgram:receiver_addr:sender_addr

Note that abstract-namespaced Linux sockets may not be normally supported by Rust,
so non-prebuilt versions may have problems with them. In particular, this mode
may fail to work without `workaround1` Cargo feature.


### `mirror:`

Internal name for --dump-spec: Mirror


Simply copy output to input. No arguments needed.

Example: emulate echo.websocket.org

    websocat -t ws-l:127.0.0.1:1234 mirror:


### `literalreply:`

Internal name for --dump-spec: LiteralReply


Reply with a specified string for each input packet.

Example:

    websocat ws-l:0.0.0.0:1234 literalreply:'{"status":"OK"}'


### `clogged:`

Internal name for --dump-spec: Clogged


Do nothing. Don't read or write any bytes. Keep connections in "hung" state. [A]


### `literal:`

Internal name for --dump-spec: Literal


Output a string, discard input.

Example:

    websocat ws-l:127.0.0.1:8080 literal:'{ "hello":"world"} '


### `assert:`

Internal name for --dump-spec: Assert


Check the input.  [A]

Read entire input and panic the program if the input is not equal
to the specified string. Used in tests.


### `assert2:`

Internal name for --dump-spec: Assert2


Check the input. [A]

Read entire input and emit an error if the input is not equal
to the specified string.


### `seqpacket:`

Aliases: `seqpacket-connect:`, `connect-seqpacket:`, `seqpacket-c:`, `c-seqpacket:`  
Internal name for --dump-spec: SeqpacketConnect


Connect to AF_UNIX SOCK_SEQPACKET socket. Argument is a filesystem path. [A]

Start the path with `@` character to make it connect to abstract-namespaced socket instead.

Too long paths are silently truncated.

Example: forward connections from websockets to a UNIX seqpacket abstract socket

    websocat ws-l:127.0.0.1:1234 seqpacket:@test


### `seqpacket-listen:`

Aliases: `listen-seqpacket:`, `seqpacket-l:`, `l-seqpacket:`  
Internal name for --dump-spec: SeqpacketListen


Listen for connections on a specified AF_UNIX SOCK_SEQPACKET socket [A]

Start the path with `@` character to make it connect to abstract-namespaced socket instead.

Too long (>=108 bytes) paths are silently truncated.

Example: forward connections from a UNIX seqpacket socket to a WebSocket

    websocat --unlink seqpacket-l:the_socket ws://127.0.0.1:8089


### `random:`

Internal name for --dump-spec: Random


Generate random bytes when being read from, discard written bytes.

    websocat -b random: ws://127.0.0.1/flood





# Full list of overlays

"Advanced" overlays denoted by `[A]` marker.


### `ws-upgrade:`

Aliases: `upgrade-ws:`, `ws-u:`, `u-ws:`  
Internal name for --dump-spec: WsServer


WebSocket upgrader / raw server. Specify your own protocol instead of usual TCP. [A]

All other WebSocket server modes actually use this overlay under the hood.

Example: serve incoming connection from socat

    socat tcp-l:1234,fork,reuseaddr exec:'websocat -t ws-u\:stdio\: mirror\:'


### `http-request:`

Internal name for --dump-spec: HttpRequest


[A] Issue HTTP request, receive a 1xx or 2xx reply, then pass
the torch to outer peer, if any - lowlevel version.

Content you write becomes body, content you read is body that server has sent.

URI is specified using a separate command-line parameter

Example:

    websocat -Ub - http-request:tcp:example.com:80 --request-uri=http://example.com/ --request-header 'Connection: close'


### `http-post-sse:`

Internal name for --dump-spec: HttpPostSse


[A] Accept HTTP/1 request. Then, if it is GET,
unidirectionally return incoming messages as server-sent events (SSE).

If it is POST then, also unidirectionally, write body upstream.

Example - turn SSE+POST pair into a client WebSocket connection:

    websocat -E -t http-post-sse:tcp-l:127.0.0.1:8080 reuse:ws://127.0.0.1:80/websock

`curl -dQQQ http://127.0.0.1:8080/` would send into it and 
`curl -N http://127.0.0.1:8080/` would recv from it.


### `ssl-connect:`

Aliases: `ssl-c:`, `ssl:`, `tls:`, `tls-connect:`, `tls-c:`, `c-ssl:`, `connect-ssl:`, `c-tls:`, `connect-tls:`  
Internal name for --dump-spec: TlsConnect


Overlay to add TLS encryption atop of existing connection [A]

Example: manually connect to a secure websocket

    websocat -t - ws-c:tls-c:tcp:174.129.224.73:1080 --ws-c-uri ws://echo.websocket.org --tls-domain echo.websocket.org

For a user-friendly solution, see --socks5 command-line option


### `ssl-accept:`

Aliases: `ssl-a:`, `tls-a:`, `tls-accept:`, `a-ssl:`, `accept-ssl:`, `accept-tls:`, `accept-tls:`  
Internal name for --dump-spec: TlsAccept


Accept an TLS connection using arbitrary backing stream. [A]

Example: The same as in TlsListenClass's example, but with manual acceptor

    websocat -E -b --pkcs12-der=q.pkcs12 tls-a:tcp-l:127.0.0.1:1234 mirror:


### `reuse-raw:`

Aliases: `raw-reuse:`  
Internal name for --dump-spec: Reuser


Reuse subspecifier for serving multiple clients: unpredictable mode. [A]

Better used with --unidirectional, otherwise replies get directed to
random connected client.

Example: Forward multiple parallel WebSocket connections to a single persistent TCP connection

    websocat -u ws-l:0.0.0.0:8800 reuse:tcp:127.0.0.1:4567

Example (unreliable): don't disconnect SSH when websocket reconnects

    websocat ws-l:[::]:8088 reuse:tcp:127.0.0.1:22


### `broadcast:`

Aliases: `reuse:`, `reuse-broadcast:`, `broadcast-reuse:`  
Internal name for --dump-spec: BroadcastReuser


Reuse this connection for serving multiple clients, sending replies to all clients.

Messages from any connected client get directed to inner connection,
replies from the inner connection get duplicated across all connected
clients (and are dropped if there are none).

If WebSocket client is too slow for accepting incoming data,
messages get accumulated up to the configurable --broadcast-buffer, then dropped.

Example: Simple data exchange between connected WebSocket clients

    websocat -E ws-l:0.0.0.0:8800 reuse-broadcast:mirror:


### `autoreconnect:`

Internal name for --dump-spec: AutoReconnect


Re-establish underlying connection on any error or EOF

Example: keep connecting to the port or spin 100% CPU trying if it is closed.

    websocat - autoreconnect:tcp:127.0.0.1:5445
    
Example: keep remote logging connection open (or flood the host if port is closed):

    websocat -u ws-l:0.0.0.0:8080 reuse:autoreconnect:tcp:192.168.0.3:1025
  
TODO: implement delays between reconnect attempts


### `ws-c:`

Aliases: `c-ws:`, `ws-connect:`, `connect-ws:`  
Internal name for --dump-spec: WsConnect


Low-level WebSocket connector. Argument is a some another address. [A]

URL and Host: header being sent are independent from the underlying connection.

Example: connect to echo server in more explicit way

    websocat --ws-c-uri=ws://echo.websocket.org/ - ws-c:tcp:174.129.224.73:80

Example: connect to echo server, observing WebSocket TCP packet exchange

    websocat --ws-c-uri=ws://echo.websocket.org/ - ws-c:cmd:"socat -v -x - tcp:174.129.224.73:80"



### `msg2line:`

Internal name for --dump-spec: Message2Line


Line filter: Turns messages from packet stream into lines of byte stream. [A]

Ensure each message (a chunk from one read call from underlying connection)
contains no inner newlines (or zero bytes) and terminates with one newline.

Reverse of the `line2msg:`.

Unless --null-terminated, replaces both newlines (\x0A) and carriage returns (\x0D) with spaces (\x20) for each read.

Does not affect writing at all. Use this specifier on both ends to get bi-directional behaviour.

Automatically inserted by --line option on top of the stack containing a websocket.

Example: TODO


### `line2msg:`

Internal name for --dump-spec: Line2Message


Line filter: turn lines from byte stream into messages as delimited by '\\n' or '\\0' [A]

Ensure that each message (a successful read call) is obtained from a line [A]
coming from underlying specifier, buffering up or splitting content as needed.

Reverse of the `msg2line:`.

Does not affect writing at all. Use this specifier on both ends to get bi-directional behaviour.

Automatically inserted by --line option at the top of the stack opposite to websocket-containing stack.

Example: TODO


### `lengthprefixed:`

Internal name for --dump-spec: LengthPrefixed


Turn stream of bytes to/from data packets with length-prefixed framing.  [A]

You can choose the number of header bytes (1 to 8) and endianness. Default is 4 bytes big endian.

This affects both reading and writing - attach this overlay to stream specifier to turn it into a packet-orineted specifier.

Mind the buffer size (-B). All packets should fit in there.

Examples:

    websocat -u -b udp-l:127.0.0.1:1234 lengthprefixed:writefile:test.dat

    websocat -u -b lengthprefixed:readfile:test.dat udp:127.0.0.1:1235

This would save incoming UDP packets to a file, then replay the datagrams back to UDP socket

    websocat -b lengthprefixed:- ws://127.0.0.1:1234/ --binary-prefix=B --text-prefix=T

This allows to mix and match text and binary WebSocket messages to and from stdio without the base64 overhead.


### `foreachmsg:`

Internal name for --dump-spec: Foreachmsg


Execute something for each incoming message.

Somewhat the reverse of the `autoreconnect:`.

Example:

    websocat -t -u ws://server/listen_for_updates foreachmsg:writefile:status.txt

This keeps only recent incoming message in file and discards earlier messages.


### `log:`

Internal name for --dump-spec: Log


Log each buffer as it pass though the underlying connector.

If you increase the logging level, you will also see hex buffers.

Example: view WebSocket handshake and traffic on the way to echo.websocket.org

    websocat -t - ws-c:log:tcp:127.0.0.1:1080 --ws-c-uri ws://echo.websocket.org



### `jsonrpc:`

Internal name for --dump-spec: JsonRpc


[A] Turns messages like `abc 1,2` into `{"jsonrpc":"2.0","id":412, "method":"abc", "params":[1,2]}`.

For simpler manual testing of websocket-based JSON-RPC services

Example: TODO


### `timestamp:`

Internal name for --dump-spec: Timestamp


[A] Prepend timestamp to each incoming message.

Example: TODO


### `socks5-connect:`

Internal name for --dump-spec: SocksProxy


SOCKS5 proxy client (raw) [A]

Example: connect to a websocket using local `ssh -D` proxy

    websocat -t - ws-c:socks5-connect:tcp:127.0.0.1:1080 --socks5-destination echo.websocket.org:80 --ws-c-uri ws://echo.websocket.org

For a user-friendly solution, see --socks5 command-line option


### `socks5-bind:`

Internal name for --dump-spec: SocksBind


SOCKS5 proxy client (raw, bind command) [A]

Example: bind to a websocket using some remote SOCKS server

    websocat -v -t ws-u:socks5-bind:tcp:132.148.129.183:14124 - --socks5-destination 255.255.255.255:65535

Note that port is typically unpredictable. Use --socks5-bind-script option to know the port.
See an example in moreexamples.md for more thorough example.


### `crypto:`

Internal name for --dump-spec: Crypto


[A] Encrypts written messages and decrypts (and verifies) read messages with a static key, using ChaCha20-Poly1305 algorithm.

Do not not use in stream mode - packet boundaries are significant.

Note that attacker may duplicate, drop or reorder messages, including between different Websocat sessions with the same key.

Each encrypted message is 12 bytes bigger than original message.

Associated --crypto-key option accepts the following prefixes:

- `file:` prefix means that Websocat should read 32-byte file and use it as a key.
- `base64:` prefix means the rest of the value is base64-encoded 32-byte buffer
- `pwd:` means Websocat should use argon2 derivation from the specified password as a key

Use `--crypto-reverse` option to swap encryption and decryption.

Note that `crypto:` specifier is absent in usual Websocat builds.
You may need to build Websocat from source code with `--features=crypto_peer` for it to be available.


### `prometheus:`

Aliases: `metrics:`  
Internal name for --dump-spec: Prometheus


[A] Account connections, messages, bytes and other data and expose Prometheus metrics on a separate port.

Not included by default, build a crate with `--features=prometheus_peer` to have it.
You can also use `--features=prometheus_peer,prometheus/process` to have additional metrics.


### `exit_on_specific_byte:`

Internal name for --dump-spec: ExitOnSpecificByte


[A] Turn specific byte into a EOF, allowing user to escape interactive Websocat session
when terminal is set to raw mode. Works only bytes read from the overlay, not on the written bytes.

Default byte is 1C which is typically triggered by Ctrl+\.

Example: `(stty raw -echo; websocat -b exit_on_specific_byte:stdio tcp:127.0.0.1:23; stty sane)`



### `drop_on_backpressure:`

Internal name for --dump-spec: DropOnBackpressure


[A] Prevent writing from ever blocking, drop writes instead.

Does not affect reading part.
when terminal is set to raw mode. Works only bytes read from the overlay, not on the written bytes.

Default byte is 1C which is typically triggered by Ctrl+\.

Example (attachable log observer):

    some_program | websocat -b -u asyncstdio: drop_on_backpressure:autoreconnect:ws-l:127.0.0.1:1234



### `waitfordata:`

Aliases: `wait-for-data:`  
Internal name for --dump-spec: WaitForData


Wait for some data to pending being written before starting connecting. [A]

Example: Connect to the TCP server on the left side immediately, but connect to
the TCP server on the right side only after some data gets written by the first connection


    websocat -b tcp:127.0.0.1:1234 waitfordata:tcp:127.0.0.1:1235

Example: Connect to first WebSocket server, wait for some incoming WebSocket message, then
connect to the second WebSocket server and start exchanging text and binary WebSocket messages
between them.

    websocat -b --binary-prefix=b --text-prefix=t ws://127.0.0.1:1234 waitfordata:ws://127.0.0.1:1235/



  
### Address types or specifiers to be implemented later:

`sctp:`, `speedlimit:`, `quic:`

### Final example

Final example just for fun: wacky mode

    websocat ws-c:ws-l:ws-c:- tcp:127.0.0.1:5678
    
Connect to a websocket using stdin/stdout as a transport,
then accept a websocket connection over the previous websocket used as a transport,
then connect to a websocket using previous step as a transport,
then forward resulting connection to the TCP port.

(Exercise to the reader: manage to make it actually connect to 5678).



================================================
FILE: misc/prebuilt_release_settings.sh
================================================
targetsettings() {
  EXTRA_CARGO_FLAGS="--features=vendored_openssl,openssl-probe"
  case "$1" in
     i686-unknown-linux-musl)
          EXTRA_CARGO_FLAGS="--no-default-features --features=signal_handler,tokio-process,unix_stdio,compression"
     ;;
     arm-unknown-linux-musleabi)
          EXTRA_CARGO_FLAGS="--no-default-features --features=signal_handler,tokio-process,unix_stdio,compression"
     ;;
     loongarch64-unknown-linux-musl)
          EXTRA_CARGO_FLAGS="--no-default-features --features=signal_handler,tokio-process,unix_stdio,compression"
     ;;
     riscv64gc-unknown-linux-musl)
          EXTRA_CARGO_FLAGS="--no-default-features --features=signal_handler,tokio-process,unix_stdio,compression"
     ;;
     wasm32-wasip1)
          SKIP=1
     ;;
  esac
}


================================================
FILE: moreexamples.md
================================================
More examples to avoid bloating up README or specifier-specific docs.


# SSL (TLS) and wss://

## Connecting to wss:// without checking certificate

Websocat has `-k` option to turn off checking of SSL certificate. As alternative (or when using older versions of Websocat) you can use external programs to provide SSL for websocat.
With `socat`:

```
$ websocat -t --ws-c-uri=wss://echo.websocket.org/ - ws-c:cmd:'socat - ssl:echo.websocket.org:443,verify=0'
sadf
sadf
dsafdsaf
dsafdsaf
```

With `openssl s_client`, also showing the log output:

```
$ websocat -v -t --ws-c-uri=wss://echo.websocket.org/ - ws-c:cmd:'openssl s_client -connect echo.websocket.org:443 -quiet' 
 INFO 2018-08-30T15:45:31Z: websocat::lints: Auto-inserting the line mode
 INFO 2018-08-30T15:45:31Z: websocat::sessionserve: Serving Line2Message(Stdio) to Message2Line(WsConnect(Cmd("openssl s_client -connect echo.websocket.org:443 -quiet"))) with Options { websocket_text_mode: true, websocket_protocol: None, udp_oneshot_mode: false, unidirectional: false, unidirectional_reverse: false, exit_on_eof: false, oneshot: false, unlink_unix_socket: false, exec_args: [], ws_c_uri: "wss://echo.websocket.org/", linemode_strip_newlines: false, linemode_strict: false, origin: None, custom_headers: [], websocket_version: None, websocket_dont_close: false, one_message: false, no_auto_linemode: false, buffer_size: 65536, broadcast_queue_len: 16, read_debt_handling: Warn, linemode_zero_terminated: false, restrict_uri: None, serve_static_files: [], exec_set_env: false, reuser_send_zero_msg_on_disconnect: false, process_zero_sighup: false, process_exit_sighup: false, socks_destination: None, auto_socks5: None, socks5_bind_script: None, tls_domain: None }
 INFO 2018-08-30T15:45:31Z: websocat::stdio_peer: get_stdio_peer (async)
 INFO 2018-08-30T15:45:31Z: websocat::stdio_peer: Setting stdin to nonblocking mode
 INFO 2018-08-30T15:45:31Z: websocat::stdio_peer: Installing signal handler
 INFO 2018-08-30T15:45:31Z: websocat::ws_client_peer: get_ws_client_peer_wrapped
depth=2 C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", CN = Go Daddy Root Certificate Authority - G2
verify return:1
depth=1 C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certs.godaddy.com/repository/, CN = Go Daddy Secure Certificate Authority - G2
verify return:1
depth=0 OU = Domain Control Validated, CN = *.websocket.org
verify return:1
 INFO 2018-08-30T15:45:31Z: websocat::ws_client_peer: Connected to ws
123
123
qwer
qwer
 INFO 2018-08-30T15:45:35Z: websocat::sessionserve: Forward finished
 INFO 2018-08-30T15:45:35Z: websocat::sessionserve: Forward shutdown finished
 INFO 2018-08-30T15:45:35Z: websocat::sessionserve: Reverse finished
 INFO 2018-08-30T15:45:35Z: websocat::sessionserve: Reverse shutdown finished
 INFO 2018-08-30T15:45:35Z: websocat::sessionserve: Finished
 INFO 2018-08-30T15:45:35Z: websocat::stdio_peer: Restoring blocking status for stdin
 INFO 2018-08-30T15:45:35Z: websocat::stdio_peer: Restoring blocking status for stdin
```

This approach can also be used in Websocat builds that do not support SSL.

## Listening wss:// for development purposes

```
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Generating a 4096 bit RSA private key
..........++
.........................++
writing new private key to 'key.pem'
Enter PEM pass phrase:1234
Verifying - Enter PEM pass phrase:1234
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:

$ openssl pkcs12 -export -out q.pkcs12 -inkey key.pem -in cert.pem
Enter pass phrase for key.pem:1234
Enter Export Password:<empty>
Verifying - Enter Export Password:<empty>

$ websocat --pkcs12-der=q.pkcs12 -s 1234
Listening on wss://127.0.0.1:1234/
```

There is a pre-generated certificate `test.pkcs12` included in Git.

Workaround method for creating a `wss://` server:

```
socat openssl-listen:1234,cert=cert.pem,key=key.pem,verify=0,fork,reuseaddr system:"websocat -t inetd-ws\\: open-fd\\:2"
```

# Proxy servers

## Connect to a WebSocket using a SOCKS5 proxy

There is internal SOCKS5 client now, but sometimes external client is better:

    websocat -v -t - --ws-c-uri=ws://echo.websocket.org ws-c:cmd:'SOCKS5_PASSWORD=a connect-proxy -S a@127.0.0.1:9050 echo.websocket.org 80'

## Connect to a WebSocket using HTTP proxy

    websocat -v -t - --ws-c-uri=ws://echo.websocket.org ws-c:cmd:'connect-proxy -H 127.0.0.1:9051 echo.websocket.org 80'


## Listen WebSocket on SOCKS5 server side and connect to it

```
cat > port_obtained << \EOF
#!/bin/sh
echo Remote port opened: $1
websocat -t -1 literal:"Roundtrip using SOCKS server" ws://132.148.129.183:$1/
EOF

chmod +x port_obtained

websocat -E -t ws-u:socks5-bind:tcp:132.148.129.183:14124 - --socks5-destination 255.255.255.255:65535 --socks5-bind-script ./port_obtained
Remote port opened: 53467
Roundtrip using SOCKS server

websocat -v -E -t ws-u:socks5-bind:tcp:132.148.129.183:14124 - --socks5-destination 255.255.255.255:65535 --socks5-bind-script ./port_obtained 
 INFO 2018-08-29T22:04:42Z: websocat::lints: Auto-inserting the line mode
 INFO 2018-08-29T22:04:42Z: websocat::sessionserve: Serving Message2Line(WsServer(SocksBind(TcpConnect(V4(132.148.129.183:14124))))) to Line2Message(Stdio) with Options { websocket_text_mode: true, websocket_protocol: None, udp_oneshot_mode: false, unidirectional: false, unidirectional_reverse: false, exit_on_eof: true, oneshot: false, unlink_unix_socket: false, exec_args: [], ws_c_uri: "ws://0.0.0.0/", linemode_strip_newlines: false, linemode_strict: false, origin: None, custom_headers: [], websocket_version: None, websocket_dont_close: false, one_message: false, no_auto_linemode: false, buffer_size: 65536, broadcast_queue_len: 16, read_debt_handling: Warn, linemode_zero_terminated: false, restrict_uri: None, serve_static_files: [], exec_set_env: false, reuser_send_zero_msg_on_disconnect: false, process_zero_sighup: false, process_exit_sighup: false, socks_destination: Some(SocksSocketAddr { host: Ip(V4(255.255.255.255)), port: 65535 }), auto_socks5: None, socks5_bind_script: Some("./port_obtained") }
 INFO 2018-08-29T22:04:43Z: websocat::net_peer: Connected to TCP
 INFO 2018-08-29T22:04:46Z: websocat::proxy_peer: SOCKS5 connect/bind: SocksSocketAddr { host: Ip(V4(0.0.0.0)), port: 34020 }
Remote port opened: 34020
 INFO 2018-08-29T22:04:46Z: websocat::proxy_peer: SOCKS5 remote connected: SocksSocketAddr { host: Ip(V4(104.131.203.210)), port: 58836 }
 INFO 2018-08-29T22:04:47Z: websocat::ws_server_peer: Incoming connection to websocket: /
 INFO 2018-08-29T22:04:47Z: websocat::ws_server_peer: Upgraded
 INFO 2018-08-29T22:04:47Z: websocat::stdio_peer: get_stdio_peer (async)
 INFO 2018-08-29T22:04:47Z: websocat::stdio_peer: Setting stdin to nonblocking mode
 INFO 2018-08-29T22:04:47Z: websocat::stdio_peer: Installing signal handler
Roundtrip using SOCKS server
 INFO 2018-08-29T22:04:47Z: websocat::sessionserve: Forward finished
 INFO 2018-08-29T22:04:47Z: websocat::sessionserve: Forward shutdown finished
 INFO 2018-08-29T22:04:47Z: websocat::sessionserve: One of directions finished
 INFO 2018-08-29T22:04:47Z: websocat::stdio_peer: Restoring blocking status for stdin
 INFO 2018-08-29T22:04:47Z: websocat::stdio_peer: Restoring blocking status for stdin
```

# Persistent client connection

Suppose there is WebSocket server which replies exactly one WebSocket text message for each received WebSocket request.

You want to have a persistent WebSocket client connection to that server and issue multiple requests from a script.

You can do something like this:

```
$ websocat -t -E tcp-l:127.0.0.1:1234  reuse-raw:ws://echo.websocket.org --max-messages-rev 1&
[1] 864

$ WS_PID=$!

$ echo 'Hello 1' | nc 127.0.0.1 1234
Hello 1

$ echo 'World 2' | nc 127.0.0.1 1234
World 2

$ kill $WS_PID
```

This scheme is unfortunately unreliable: if client is disconnected before it can receive a message,
the message can get delivered to next connected client.


# Configuring Nginx to forward Websocket connections

Usual `proxy_pass` is not enough.

You need something like this:

```
location /mywebsocket {
    proxy_read_timeout 1d;
    proxy_send_timeout 1d;
    proxy_pass http://localhost:8123;
    #proxy_pass http://unix:/tmp/unixsocket_websocat;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}
```

# Debugging connection issues by dumping traffic.

If you want to log information that is passing though Websocat to console, you can use `log:` filter (overlay).

This allows inspecting traffic at various levels. For Websocat versions earlier than 1.7, you can use `ws-c:cmd:` trick instead.

Example sessions:

## At message level

```
$ websocat  -t - --ws-c-uri=wss://echo.websocket.org log:ws-c:ssl:tcp:echo.websocket.org:443
[WARN  websocat::ssl_peer] Connected to TLS without proper verification of certificate. Use --tls-domain option.
asdf
WRITE 5 "asdf\n"
READ 5 "asdf\n"
asdf
12345
WRITE 6 "12345\n"
READ 6 "12345\n"
12345
```

## At HTTP and Websocket protocol level

```
$ websocat  -t - --ws-c-uri=wss://echo.websocket.org ws-c:log:ssl:tcp:echo.websocket.org:443
[WARN  websocat::ssl_peer] Connected to TLS without proper verification of certificate. Use --tls-domain option.
WRITE 157 "GET / HTTP/1.1\r\nHost: echo.websocket.org\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: lnQ/ReYmkEBvBVajdASTHg==\r\n\r\n"
READ 201 "HTTP/1.1 101 Web Socket Protocol Handshake\r\nConnection: Upgrade\r\nDate: Sun, 21 Feb 2021 20:59:59 GMT\r\nSec-WebSocket-Accept: uZ5OAMgIFtQE5WRsqRRlA+DM0UI=\r\nServer: Kaazing Gateway\r\nUpgrade: websocket\r\n\r\n"
ABCDE
WRITE 12 "\x81\x86\xd6\xa90\x97\x97\xebs\xd3\x93\xa3"
READ 8 "\x81\x06ABCDE\n"
ABCDE
56789
WRITE 12 "\x81\x86\x8aH\xe8b\xbf~\xdfZ\xb3B"
READ 8 "\x81\x0656789\n"
56789
WRITE 6 "\x88\x80u\xbfoz"
READ 2 "\x88\x00"
```

## At TCP stream level

```
$ websocat  -t - --ws-c-uri=wss://echo.websocket.org --tls-domain=echo.websocket.org ws-c:ssl:log:tcp:echo.websocket.org:443
WRITE 517 "\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03\x0e(r\xec\xbbXr\xacb\xe2\x0b+\x0f\xdc\xfa\x17\xb7R`\x1e\xda\xb42e\xd7\xf2\xdd\xd24O;\xd9 Y\t2\xe9kI\xa5I\xd4\xee)p6\xd6\xbf\x8dE:`\xe8]\x7fVN\x9e\x10\xe4\x7f8\xa2:\x98\x00>\x13\x02\x13\x03\x13\x01\xc0,\xc00\x00\x9f\xcc\xa9\xcc\xa8\xcc\xaa\xc0+\xc0/\x00\x9e\xc0$\xc0(\x00k\xc0#\xc0\'\x00g\xc0\n\xc0\x14\x009\xc0\t\xc0\x13\x003\x00\x9d\x00\x9c\x00=\x00<\x005\x00/\x00\xff\x01\x00\x01u\x00\x00\x00\x17\x00\x15\x00\x00\x12echo.websocket.org\x00\x0b\x00\x04\x03\x00\x01\x02\x00\n\x00\x0c\x00\n\x00\x1d\x00\x17\x00\x1e\x00\x19\x00\x18\x00#\x00\x00\x00\x16\x00\x00\x00\x17\x00\x00\x00\r\x000\x00.\x04\x03\x05\x03\x06\x03\x08\x07\x08\x08\x08\t\x08\n\x08\x0b\x08\x04\x08\x05\x08\x06\x04\x01\x05\x01\x06\x01\x03\x03\x02\x03\x03\x01\x02\x01\x03\x02\x02\x02\x04\x02\x05\x02\x06\x02\x00+\x00\t\x08\x03\x04\x03\x03\x03\x02\x03\x01\x00-\x00\x02\x01\x01\x003\x00&\x00$\x00\x1d\x00 \xa0t\xa8\x9d\xd8t\x06E\x94\xba+\xa7\xcf\x90**W\x8dS\xd1\xf4\xd4\xf7\x06\xda\xa4B\x9e\xeb\xa4\xf3\x10\x00\x15\x00\xc1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
READ 5 "\x16\x03\x03\n\x00"
READ 2560 "\x02\x00\x00M\x03\x03`2\xca\x95\x17H\xaa\x9f\x7fz[O>\x0e\xc8x\xd9\x8d\xe71\xac\xffJ\xb8\xd8\x8d\xe4LB2\xee\x80 `2\xca\x95\x93;2\xdc\x04@;T\xc23Ei\x8ax\xfa\xb8y\x12\'\x05(\xce8|^Fv\x97\x00/\x00\x00\x05\xff\x01\x00\x01\x00\x0b\x00\t\xa7\x00\t\xa4\x00\x0550\x82\x0510\x82\x04\x19\xa0\x03\x02\x01\x02\x02\x12\x04\x00\xd5\xa4Naq\xe3S\xeb\xc7\xc8\x82\xb3g\xc5\xdeq0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00021\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x160\x14\x06\x03U\x04\n\x13\rLet\'s Encrypt1\x0b0\t\x06\x03U\x04\x03\x13\x02R30\x1e\x17\r210104172430Z\x17\r210404172430Z0\x181\x160\x14\x06\x03U\x04\x03\x13\rwebsocket.org0\x82\x01\"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xa56O\xbfj\xb6\'\x8a<#\xcf\xce=\x1d\xb4\x1d\x0fI\xffW\\\xd9\xdb\xack\xd3\xed;<?\xb9K\xfcf;\xec\x98-\r\xa0KG\xd5\xec\x9c\xdeIY\x89\x97\x83\xfc\xc7A7\x89\xa9\xf41\x0b\xe6g3\n\xb9nH\x87c\xe3K\x88\xae\x88\x97\x93#\x9d\x19f\x8b\xbf\xe6\xb7\x9d\x87\xc9\xee\x94\x94\xaflz\xeb_P\x1eG\xeb\x88Q\n\x9f\x95VnR1\xed\x1a/\xee\xe5\x87\x1a\xec\x9c\xcd\xff!\x04\xb8\x8c\x9b\x9c&]\xb8\xe4=\xb1\xad\xb0R\x83~\xa9,\xb4ct\x17\xb6\x9f\x82\xda\xf6\xae&\xed\xdf\xfe\x91\x851\x91\xafG8\x14R\xf2\xf8e9\xd8\x0bTsc\xa6\x98\x9dBi%\xfd\xaa\xa7\"\x17{=\x90a\x12os\x8c|\x94M\xeeD\xc7v\xb6\x04\xa1\xd6\xda\x9d_\xb1\xd0\xb5\xb1;\x08\xd72\x89+\xa9W\xd7\x9e\xf0\x86D\xe8\xbf\x81\x0b\xf7\xa9nca|\xd4SK}\x02\xdf7\xa7\xa3\xd5MD\x80b\x19\xa5\xb2(\x9c*\x87\xe0\x9b\x9b\xf6\xe3\x02\x03\x01\x00\x01\xa3\x82\x02Y0\x82\x02U0\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x05\xa00\x1d\x06\x03U\x1d%\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x020\x0c\x06\x03U\x1d\x13\x01\x01\xff\x04\x020\x000\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14\x04c\xfdH\xa3m\xbf\x01B%\x98\x95\x9cP\xb6\x10\x96\xc6i\x1c0\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14\x14.\xb3\x17\xb7XV\xcb\xaeP\t@\xe6\x1f\xaf\x9d\x8b\x14\xc2\xc60U\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04I0G0!\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x15http://r3.o.lencr.org0\"\x06\x08+\x06\x01\x05\x05\x070\x02\x86\x16http://r3.i.lencr.org/0)\x06\x03U\x1d\x11\x04\"0 \x82\x0f*.websocket.org\x82\rwebsocket.org0L\x06\x03U\x1d \x04E0C0\x08\x06\x06g\x81\x0c\x01\x02\x0107\x06\x0b+\x06\x01\x04\x01\x82\xdf\x13\x01\x01\x010(0&\x06\x08+\x06\x01\x05\x05\x07\x02\x01\x16\x1ahttp://cps.letsencrypt.org0\x82\x01\x04\x06\n+\x06\x01\x04\x01\xd6y\x02\x04\x02\x04\x81\xf5\x04\x81\xf2\x00\xf0\x00v\x00\x94 \xbc\x1e\x8e\xd5\x8dl\x88s\x1f\x82\x8b\",\r\xd1\xdaM^lO\x94=a\xdbN/XM\xa2\xc2\x00\x00\x01v\xce\xa4\xb7\xce\x00\x00\x04\x03\x00G0E\x02!\x00\x9df\x0b\xa0\xc2?\x02\x0c;V1\x04B\xf8\xbc\x80\xf3ToUi\x98i\xfb\x08\xb1\x1d2\xed\xd7\n=\x02 b 2b\x8d\x1b\xac2\xf5-:\xad\x8f\r\xaa\xc7\xccR\xc3\xba\xd5kz#g.\x85c\xb2\xf1\x9b\x86\x00v\x00\xf6\\\x94/\xd1w0\"\x14T\x18\x080\x94V\x8e\xe3M\x13\x193\xbf\xdf\x0c/ \x0b\xccN\xf1d\xe3\x00\x00\x01v\xce\xa4\xb7\xc8\x00\x00\x04\x03\x00G0E\x02 o\xb2V\x9fH\xf6\xfe\x88\x08diV\x9d\x91\x06Gj\x02\xad(\xaa\x1f\xfa\xdd\x13\xe6\xe2Z\r\x8fD\xae\x02!\x00\x88\xf3\xfd\xd6\x04\xef\x03\"\x8c=\xb3dI\x19\xdd\xa8\xf2P\xca#*\t\xdb\x95B9\xee\xd6\x8a\xc1\t[0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00W\xde]\xac\xc8;=\xc1\xf7\x84#\x08\\!W\xe6\xe6O\x9a\x81\x86\xefRg~\xff\xc1\xf5\x04q\x89\xb1\x96\xc9c\t%l\xc0\xe9\xee\xaba\x84o\xc2u<o\xaf(\xad:\x14\x94:\x97\x89\x12?\x9f\x80n\x11\xa87\x9e\xdbw\xf8\xde\xde\x9c\x1e\xc3\xe3\xdb\xa3.!R\xa2\x8eM\xb2z\xbc\xb8\xc9\x04\x9b\xc8Q\xff\x8e\xea\x8c\x813\x9e\xc8WOP\xdc\x9e\xbe5P\xc8\xdeq\xdf\xc9\x0ek\xa9\x8f\xfc\xff\xee\xd5\xcf\x95U\xd0\x0f\x1a]\xa2\xb0(y\xaa\xb0(&N^~\xd8\x7f`\'\x85\xeff\xc1\xce\x9f1\xaf\xe1U\xe3\x89t\x14VE\xa3\xf1]\xa7\xf9K\xbeV\x99\xbb\x1c\xc4\xe2|\xf5Pg\x14\xde\xf7\xeb\"Z(\xa1D=#1\xcc\x1f\xa9\xad=\xbe\xb2\x01j\x02\xc9\xd0\x96\n3\xb9(b>\xc4?7\x8d)\x1bOf\xf4\xfd\xefw\xdb\xbb\xf6\x9cN\xf4-\x1a.8Th\xa0q\xfe\xf5\xb0\xcf\x9f/\x14\xb4\xbb \xb8\xfd\xd24Yg?}\xd5L\xde\x07\x00\x04i0\x82\x04e0\x82\x03M\xa0\x03\x02\x01\x02\x02\x10@\x01u\x04\x83\x14\xa4\xc8!\x8c\x84\xa9\x0c\x16\xcd\xdf0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x000?1$0\"\x06\x03U\x04\n\x13\x1bDigital Signature Trust Co.1\x170\x15\x06\x03U\x04\x03\x13\x0eDST Root CA X30\x1e\x17\r201007192140Z\x17\r210929192140Z021\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x160\x14\x06\x03U\x04\n\x13\rLet\'s Encrypt1\x0b0\t\x06\x03U\x04\x03\x13\x02R30\x82\x01\"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xbb\x02\x15(\xcc\xf6\xa0\x94\xd3\x0f\x12\xec\x8dU\x92\xc3\xf8\x82\xf1\x99\xa6zB\x88\xa7]&\xaa\xb5+\xb9\xc5L\xb1\xaf\x8ek\xf9u\xc8\xa3\xd7\x0fG\x94\x14U5W\x8c\x9e\xa8\xa29\x19\xf5\x82<B\xa9Nn\xf5;\xc3.\xdb\x8d\xc0\xb0\\\xf3Y8\xe7\xed\xcfi\xf0Z\x0b\x1b\xbe\xc0\x94$%\x87\xfa7q\xb3\x13\xe7\x1c\xac\xe1\x9b\xef\xdb\xe4;ERE\x96\xa9\xc1S\xce4\xc8R\xee\xb5\xae\xed\x8f\xde`p\xe2\xa5T\xab\xb6m\x0e\x97\xa5@4k+\xd3\xbcf\xebf4|\xfak\x8b\x8fW)\x99\xf80\x17]\xbaro\xfb\x81\xc5\xad\xd2\x86X=\x17\xc7\xe7\t\xbb\xf1+\xf7\x86\xdc\xc1\xdaq]\xd4F\xe3\xcc\xad%\xc1\x88\xbc`guf\xb3\xf1\x18\xf7\xa2\\\xe6S\xff:\x88\xb6G\xa5\xff\x13\x18\xea\x98\tw?\x9dS\xf9\xcf\x01\xe5\xf5\xa6p\x17\x14\xafc\xa4\xff\x99\xb3\x93\x9d\xdcS\xa7\x06\xfeH\x85\x1d\xa1i\xae%u\xbb\x13\xccR\x03\xf5\xedQ\xa1\x8b\xdb\x15\x02\x03\x01\x00\x01\xa3\x82\x01h0\x82\x01d0\x12\x06\x03U\x1d\x13\x01\x01\xff\x04\x080\x06\x01\x01\xff\x02\x01\x000\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01\x860K\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04?0=0;\x06\x08+\x06\x01\x05\x05\x070\x02\x86/http://apps.identrust.com/roots/dstrootcax3.p7c0\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14\xc4\xa7\xb1\xa4{,q\xfa\xdb\xe1K\x90u\xff\xc4\x15`\x85\x89\x100T\x06\x03U\x1d \x04M0K0\x08\x06\x06g\x81\x0c\x01\x02\x010?\x06\x0b+\x06\x01\x04\x01\x82\xdf\x13\x01\x01\x01000.\x06\x08+\x06\x01\x05\x05\x07\x02\x01\x16\"http://cps.root-x1.letsencrypt.org0<\x06\x03U\x1d\x1f\x0450301\xa0/\xa0-\x86+http://crl.identrust.com/DSTROOTCAX3CRL.crl0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14\x14.\xb3\x17\xb7XV\xcb\xaeP\t@\xe6\x1f\xaf\x9d\x8b\x14\xc2\xc60\x1d\x06\x03U\x1d%\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x020\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\xd9L\xe0\xc9\xf5\x84\x8871\xdb\xbb\x13\xe2\xb3\xfc\x8bkb\x12lX\xb7I~<\x02\xb7\xa8\x1f(a\xeb\xce\xe0.s\xefI\x07z5\x84\x1f\x1d\xadh\xf0\xd8\xfeV\x81/m\x7fX\xa6n56\x10\x1cs\xc3\xe5\xbdm^\x01\xd7nr\xfb*\xa0\xb8\xd3Wd\xe5[\xc2i\xd4\xd0\xb2\xf7|K\xc3\x17\x8e\x88rs\xdc\xfd\xfcm\xbd\xe3\xc9\x0b\x8ea:\x16X}t6+U\x80=\xc7c\xbe\x84C\xc69\xa1\x0ekW\x9e?)\xc1\x80\xf6\xb2\xbdG\xcb\xaa0l\xb72\xe1YT\x0b\x18\t\x17^cl\xfb\x96g<\x1cs\x0c\x93\x8b\xc6\x11v$\x86\xde@\x07\x07\xe4}-f\xb5%\xa3\x96X\xc8\xea\x80\xee\xcfi;\x96\xfc\xe6\x8d\xc03\xf3\x89\xf8)-\x14\x14-~\xf0ap\x95]\xf7\x0b\xe5\xc0\xfb$\xfa\xec\x8e\xcba\xc8\xeecq(\xa8,\x05;w\xef\x9b^\x03d\xf0Q\xd1\xe4\x85S\\\xb0\x02\x97\xd4~\xc64\xd2\xce\x10\x00\xe4\xb1\xdf:\xc2\xea\x17\xbe\x0e\x00\x00\x00"
WRITE 342 "\x16\x03\x03\x01\x06\x10\x00\x01\x02\x01\x00s\xaa\x90\xf7\x88\xba\xdcI\xe0\x81\xcb\xf4\x93\x1cbt#+^\x13?N\xc2\x18\xaf\xab\xb7\xc7\xf5\xc6\x8e\xcaD\xf9U\xaak\x96E\xa6\xeeH&F\x0f\x12\x03\xcf)}\xb8\xbc\x9e\xe2j\x98\xaa\x1b\"L&D\xac\xef\x7fe\x0fu\xf1B\xf1\x8b>0P\xd067\xdfBM\xf0\xd7r\x13`\x8e\x88=\xd0\x9a\xf8\xfe\x0c\x01~\xb8\x87I\xa5\xcc\x15s\x95\"\xa1\xdb>3m4\x92j&\xa6_r\x96\xa0v\xfa\x12\x14WH\xfd\xa6\xa5\x8dY\xfa\xd6(\xa3\xafT\x18\xca8\xb8E\xc2a\xb7l\x1e\xd75\x80_\xb3\x14}S\xa2\x1d\x98\xc4y\x80W\xf6\xb3&\xdf9\x84O9~\xbfd\xd2\xd7/\xb7U\xe1~\xcb6\x8a\xf2\x07\x07\xc1\xb3\xf1L\x14\xa3\x0c\xb2\xf0(\x99\xa3;\xff[\x1d\xa3p\xe2\xe9\x9cZ5\xaa\xe3\xf0\xa4\xb28\xac\x82e\xb9\x82\xfcz\xbf0\x1f\xce\x9f\x9d\xcb\x94\x7f\xc7\xb8\x8fH$\xdcj+\xfe\xb7z\x9b\xe0\xf0\xd4\xdct\xa7\xe7W\x92A\xa1e8\xc7\x14\x03\x03\x00\x01\x01\x16\x03\x03\x00@\xbb\x00\xba\x14\xcc\xa1\xa2@w mP=\xd3T\xaf\"\xe6M!\xa8\xe8A\xbb[\xafx\xbeDU}\xe1/\x8b\x0e\x8b\x8a\xe6\x82\x06\xe5bHy\xbcq{ \xdb\xb3o\xae\xb1\x03\x9e\xa6\xcf\x19\xee\xf9\x9b\xb3@0"
READ 5 "\x14\x03\x03\x00\x01"
READ 1 "\x01"
READ 5 "\x16\x03\x03\x00@"
READ 64 "\\0\xa6\xfb\x9fcks\xe2o\xd7L\xc2\xf7@\x0f\xaf\xc8\xb3\xd9F\xb0\x1b\xa3\xe7\xc6\xfb\xb4\x12\xf1\xac8\x9d0\x89\x96\x89H\xde\xda\n\xaaN\x90@\xa9<#\xe9_\xa1\xcex\x11\xe2\x0f\x87\x1c\x87 \xbf\'9\xa4"
WRITE 213 "\x17\x03\x03\x00\xd0\x8b\xf1G\xdcB\x83\xbf\x0f\xb0\xf4\x97YXk\xe7ow\xd3\x81\x89\xa0\xa1\x8bG\x99\xeb\xe3\xfa\xda\xd4QW=\x1d\x06\xadn#)L\x08\xa6\x10\xa4\x03O\xdf\xd5\xe2a\xda\xce\x9b\xe9f\xdf\xf4\x14UzW\xd8\xc8\x1c\xa2\xbf\x00\xc5\x9c}\x7fW;\x9b\xe8\x9f\xb0\xaa\x8c\xd0\xf9\xe0\xf7\xf4\"\xb6\xb0\nY\xff\x05\x0bz\xbc\x9c\x81\xd0\xf5\xee\x0bK\xd4Q\xd5l\x81E\xfb\xdcW\x12\xe4\xaa\xe7\xaf\x1c\x7f.\xb1\xd78\x11\xe6\xfd\xb6\xb9\xc5\xd1\xec\x83\xe5\x16\xb2P\xbd\x97\xb5E\x95\'\xf2\xf8B\xee\x01S\xf61&@-\xa0\x95e,H\x07\xb1\x9c\xba`\xd9\xf3\x9b\xe8\xba\x8c\xaaqt_\xe2t&f\xd3\xba\xc3W\xcc\xb7;\xa7\xc9A\x16\x11$e\xfd\x1e\x8eKF\x0cO+\x84\x1e\xc7\x85\x1b\xf2\"Pou\xda"
READ 5 "\x17\x03\x03\x00\xf0"
READ 240 "3\x14\xe7g\x12\xc2I4\x96\x8f\r$\xb4\xa2(\xf2b\xf5]\x82\xa77\x88wJy\x84\xf4\x8e\xaf\xa6\x04\x8d\xed\x7f\xd6q\x80o\'0\x1e\x85\xa1\xf8\x9buk\xc2\x9bx>\xb4S\xe3\xa4\xa2\x88\x8a\xff\xac\x06\x81\xc4\x98g,\xb2\xa9\'\xe2C=\x90\x9b\xc4\xd4\x7f\xa3\xcffneE\xee\x86\xae\xd3\x17\xf3 (\xb7\xf8W\xcd(\x16\x82s2\xe7\x03y81\xe0r\xa0C\x82\xedK\x93u\x87x,\xf3\xca\xc7\x84\xa1\xf5x \x06Q5\xe7\x00%\xb4\x84\xfaw\x1f^R\xc9o\xb4\x96\xf0\xa7\x01\xc5h\x04.\xc8Q\xcfw\t\x8e\xa8\xf9\x98\x9a~q\xb9/\x9f.u\x023Q8\x95\x8b\x7f~\xccx\xa9_,\xc7*<.\x0e\'jH\x05\x8b\xe8\xc2\xee\xd8\xa4\x12\xe1\xb6\xd7FL\xe7\r\xc1\x07*\xcb+\xf0\xc2Pq\xed7\t\x1e\xa4,\x05\xd0\x0e\xba\xf1ABtL*\xba\xbb\xe7~\x1e\xefO\x85\xbd\xe6\x84S"
qwert
WRITE 69 "\x17\x03\x03\x00@\n\x8c\\\xa8b\xae\x05N\xb9O\x81\xaej\x9eM\xf7$\xf9\x8f\xc8\xefz!\x89.\xfe\x19\x12`\xbf{fJS\xd5\x15\x84\x0e\xa5\xf7\"4\xa1\xda[\x95\xe2#&\xe8\xd3\x96\xb8]\xa4+~\xb2Cc\xfc6\xb2|"
READ 5 "\x17\x03\x03\x000"
READ 48 "\xb8uj&\xda\xed\xf9\xbc\xbfn\x9eS`\xa3\x10q\x10[\x05}\xef\xd6\xbf\t\xea\x14f\xf9c\xe6$\xd1R:\xdc\xcc\x88[\x97\xca\x12\x9f\xc1pk\x0e\xf6o"
qwert
zxcvbn
WRITE 69 "\x17\x03\x03\x00@\xe5\xf4\x99xS\xf6\xad\xf4\x89?\xbd\x99=`a\xab\x8e\xed\xd83\xa9-\xabU{\xfa~\xd9h\xf8\x1a\xfaS\xfdD-\xc4\x84=:\xae;\x0b\xccRHT\xef\x04E\x927\xbf~\x0e:\xb0\x16\x01\xf5\xd1\x0f\x1e\xc9"
READ 5 "\x17\x03\x03\x000"
READ 48 "\xa4\x9b=\x85\xe3\x8c\x0c-*\x08(Qu\xd8\x93\xbde,c\x1a\x9c\"\xc9o\xa7\xb5\xe9eH6\xa1\xed\xb9\xcb+\x13>nu^\x1c\x9d\x1b2\xc0\x98\x1d("
zxcvbn
WRITE 53 "\x17\x03\x03\x000\x17\x19\xf4>\xddSG8\xdd\xcd\x00\xf2\xf58\x15n\xbaY\xbaU\xf0H\x8b\t}\xa5\xaa\xfbXy\xc7f\xc2r\x9e\x94dO\xdc\xaf\xad\xcc\xcd\x16\x87\xdd\x19\xb9"
READ 5 "\x17\x03\x03\x000"
READ 48 "j#\x9d\x17B\x89\xee\x92\x90\xcaH6\xf7PQe|p\xed\xf8,=\x0f+\x8a\x10)\xcf\x06\xb1\x06\xde\x9eA>B\xb7g\xde\xce\xcc\xfd\x88\x1c\xf1-\x96\x00"
```

# listening websockets from systemd

Systemd units for WebSocket-to-localhost-SSH redirector.

## `Accept=yes` mode

Each client connection gets separate Websocat process.

`/etc/systemd/system/qqq.socket`

```
[Unit]
Description="websocat"

[Socket]
ListenStream=/run/qqq.socket
#ListenStream=127.0.0.1:1234 # also works for TCP
Accept=yes

[Install]
WantedBy=sockets.target
```

`/etc/systemd/system/qqq@.service` (note the important `@` character).

```
[Unit]
Description="websocat"
Requires=qqq.socket

[Service]
Type=simple
ExecStart=/opt/websocat -E -b ws-inetd: tcp:127.0.0.1:22
StandardInput=socket
NonBlocking=true

[Install]
WantedBy=multi-user.target
```

## `Accept=no` mode

Websocat is socket-activated by systemd and keeps on listening for more connections

Requires new enough Websocat version with `--accept-from-fd` option.

`/etc/systemd/system/qqq.socket`

```
[Unit]
Description="websocat"

[Socket]
ListenStream=/run/qqq.socket
# does _not_ work with TCP socket currently
Accept=no

[Install]
WantedBy=sockets.target
```


`/etc/systemd/system/qqq.service` (note the absence of  `@`).

```
[Unit]
Description="websocat"
Requires=qqq.socket

[Service]
ExecStart=/opt/websocat -E -b --accept-from-fd l-ws-unix:3 tcp:127.0.0.1:22

[Install]
WantedBy=multi-user.target
```

with `SocketUser=www-data` it can be combined with Nginx setup above.

Example SSH client command: `ssh root@localhost -o 'ProxyCommand=/opt/websocat -E -b - ws-c:unix:/run/qqq.socket'`


# Specifying distinct host names for resolving IP address, `Host: ` header and TLS.

Example command line:

    websocat -t - --ws-c-uri=wss://domain-for-host-header/ ws-c:tls:tcp:domain-or-ip-address-for-resolving:443 --tls-domain domain-for-checking-certificate

Or without TLS:

    websocat -t - --ws-c-uri=wss://domain-for-host-header/ ws-c:tcp:domain-or-ip-address-for-resolving:80


================================================
FILE: src/all_peers.rs
================================================
// This is an X-Macro.
#[macro_export]
macro_rules! list_of_all_specifier_classes {
    ($your_macro:ident) => {
        $your_macro!($crate::ws_client_peer::WsClientClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ws_client_peer::WsClientSecureClass);
        $your_macro!($crate::ws_server_peer::WsTcpServerClass);
        $your_macro!($crate::ws_server_peer::WsInetdServerClass);
        $your_macro!($crate::ws_server_peer::WsUnixServerClass);
        $your_macro!($crate::ws_server_peer::WsAbstractUnixServerClass);
        $your_macro!($crate::ws_server_peer::WsServerClass);
        $your_macro!($crate::ws_lowlevel_peer::WsLlClientClass);
        $your_macro!($crate::ws_lowlevel_peer::WsLlServerClass);

        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::WssListenClass);

        $your_macro!($crate::http_peer::HttpRequestClass);
        $your_macro!($crate::http_peer::HttpClass);
        $your_macro!($crate::http_peer::HttpPostSseClass);
        

        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::AsyncStdioClass);
        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::InetdClass);
        #[cfg(not(all(unix, feature = "unix_stdio")))]
        $your_macro!($crate::stdio_threaded_peer::InetdClass);

        $your_macro!($crate::net_peer::TcpConnectClass);
        $your_macro!($crate::net_peer::TcpListenClass);

        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::TlsConnectClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::TlsAcceptClass);
        #[cfg(feature = "ssl")]
        $your_macro!($crate::ssl_peer::TlsListenClass);

        #[cfg(feature = "tokio-process")]
        $your_macro!($crate::process_peer::ShCClass);
        #[cfg(feature = "tokio-process")]
        $your_macro!($crate::process_peer::CmdClass);
        #[cfg(feature = "tokio-process")]
        $your_macro!($crate::process_peer::ExecClass);

        $your_macro!($crate::file_peer::ReadFileClass);
        $your_macro!($crate::file_peer::WriteFileClass);
        $your_macro!($crate::file_peer::AppendFileClass);

        $your_macro!($crate::primitive_reuse_peer::ReuserClass);
        $your_macro!($crate::broadcast_reuse_peer::BroadcastReuserClass);
        $your_macro!($crate::reconnect_peer::AutoReconnectClass);

        $your_macro!($crate::ws_client_peer::WsConnectClass);

        $your_macro!($crate::net_peer::UdpConnectClass);
        $your_macro!($crate::net_peer::UdpListenClass);

        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::OpenAsyncClass);
        #[cfg(all(unix, feature = "unix_stdio"))]
        $your_macro!($crate::stdio_peer::OpenFdAsyncClass);

        $your_macro!($crate::stdio_threaded_peer::ThreadedStdioClass);
        $your_macro!($crate::stdio_threaded_peer::StdioClass);

        #[cfg(unix)]
        $your_macro!($crate::unix_peer::UnixConnectClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::UnixListenClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::UnixDgramClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::AbstractConnectClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::AbstractListenClass);
        #[cfg(unix)]
        $your_macro!($crate::unix_peer::AbstractDgramClass);

        #[cfg(all(windows,feature = "windows_named_pipes"))]
        $your_macro!($crate::windows_np_peer::NamedPipeConnectClass);

        $your_macro!($crate::line_peer::Message2LineClass);
        $your_macro!($crate::line_peer::Line2MessageClass);
        $your_macro!($crate::lengthprefixed_peer::LengthPrefixedClass);
        $your_macro!($crate::foreachmsg_peer::ForeachmsgClass);
        $your_macro!($crate::mirror_peer::MirrorClass);
        $your_macro!($crate::mirror_peer::LiteralReplyClass);
        $your_macro!($crate::trivial_peer::CloggedClass);
        $your_macro!($crate::trivial_peer::LiteralClass);
        $your_macro!($crate::trivial_peer::AssertClass);
        $your_macro!($crate::trivial_peer::Assert2Class);

        $your_macro!($crate::trivial_peer::LogClass);

        #[cfg(all(target_os = "linux", feature = "seqpacket"))]
        $your_macro!($crate::unix_peer::unix_seqpacket_peer::SeqpacketConnectClass);
        #[cfg(all(target_os = "linux", feature = "seqpacket"))]
        $your_macro!($crate::unix_peer::unix_seqpacket_peer::SeqpacketListenClass);

        $your_macro!($crate::jsonrpc_peer::JsonRpcClass);
        $your_macro!($crate::timestamp_peer::TimestampClass);

        $your_macro!($crate::socks5_peer::SocksProxyClass);
        $your_macro!($crate::socks5_peer::SocksBindClass);

        #[cfg(feature = "crypto_peer")]
        $your_macro!($crate::crypto_peer::CryptoClass);

        $your_macro!($crate::trivial_peer::RandomClass);

        #[cfg(feature = "prometheus_peer")]
        $your_macro!($crate::prometheus_peer::PrometheusClass);

        $your_macro!($crate::trivial_peer::ExitOnSpecificByteClass);
        $your_macro!($crate::trivial_peer::DropOnBackpressureClass);

        $your_macro!($crate::reconnect_peer::WaitForDataClass);
    };
}


================================================
FILE: src/broadcast_reuse_peer.rs
================================================
extern crate futures;
extern crate tokio_io;

use futures::future::ok;
use std::cell::RefCell;
use std::rc::Rc;

use super::{brokenpipe, simple_err, wouldblock, BoxedNewPeerFuture, Peer};

use std::io::{Error as IoError, Read, Write};
use tokio_io::{AsyncRead, AsyncWrite};

use super::{once, ConstructParams, PeerConstructor, Specifier};
use futures::Async;
use futures::AsyncSink;
use futures::Future;
use futures::Sink;
use futures::Stream;
use crate::spawn_hack;
use std::ops::DerefMut;

use futures::unsync::mpsc;

declare_slab_token!(BroadcastClientIndex);
use slab_typesafe::Slab;

#[derive(Debug)]
pub struct BroadcastReuser(pub Rc<dyn Specifier>);
impl Specifier for BroadcastReuser {
    fn construct(&self, p: ConstructParams) -> PeerConstructor {
        let mut reuser = p.global(GlobalState::default).clone();
        let bs = p.program_options.buffer_size;
        let ql = p.program_options.broadcast_queue_len;
        let l2r = p.left_to_right.clone();
        let inner = || self.0.construct(p).get_only_first_conn(l2r);
        once(connection_reuser(&mut reuser, inner, bs, ql))
    }
    specifier_boilerplate!(singleconnect has_subspec globalstate);
    self_0_is_subspecifier!(...);
}

specifier_class!(
    name = BroadcastReuserClass,
    target = BroadcastReuser,
    prefixes = [
        "broadcast:",
        "reuse:",
        "reuse-broadcast:",
        "broadcast-reuse:"
    ],
    arg_handling = subspec,
    overlay = true,
    MessageBoundaryStatusDependsOnInnerType,
    SingleConnect,
    help = r#"
Reuse this connection for serving multiple clients, sending replies to all clients.

Messages from any connected client get directed to inner connection,
replies from the inner connection get duplicated across all connected
clients (and are dropped if there are none).

If WebSocket client is too slow for accepting incoming data,
messages get accumulated up to the configurable --broadcast-buffer, then dropped.

Example: Simple data exchange between connected WebSocket clients

    websocat -E ws-l:0.0.0.0:8800 reuse-broadcast:mirror:
"#
);

type SailingBuffer = Rc<Vec<u8>>;
type Clients = Slab<BroadcastClientIndex, mpsc::Sender<SailingBuffer>>;

pub struct Broadcaster {
    inner_peer: Peer,
    clients: Clients,
}
pub type HBroadCaster = Rc<RefCell<Option<Broadcaster>>>;

pub type GlobalState = HBroadCaster;

struct PeerHandleW(HBroadCaster);
struct PeerHandleR(
    HBroadCaster,
    mpsc::Receiver<SailingBuffer>,
    BroadcastClientIndex,
);
struct InnerPeerReader(HBroadCaster, Vec<u8>);

impl Future for InnerPeerReader {
    type Item = ();
    type Error = ();
    fn poll(&mut self) -> futures::Poll<(), ()> {
        loop {
            let mut meb = self.0.borrow_mut();
            let me = meb.as_mut().expect("Assertion failed 16293");
            match me.inner_peer.0.read(&mut self.1[..]) {
                Ok(0) => {
                    info!("Underlying peer finished");
                    return Ok(futures::Async::Ready(()));
                }
                Ok(n) => {
                    if me.clients.is_empty() {
                        info!("Dropping broadcast due to no clients being connected");
                        continue;
                    };
                    let sb = Rc::new(self.1[0..n].to_vec());
                    for (_, client) in me.clients.iter_mut() {
                        match client.start_send(sb.clone()) {
                            Ok(AsyncSink::Ready) => match client.poll_complete() {
                                Ok(Async::Ready(())) => {}
                                Ok(Async::NotReady) => {
                                    warn!("A client's sink is NotReady for poll_complete");
                                }
                                Err(e) => {
                                    warn!("A client's sink is in error state: {}", e);
                                }
                            },
                            Ok(AsyncSink::NotReady(_)) => {
                                warn!("A client's sink is NotReady for start_send");
                            }
                            Err(e) => {
                                warn!("A client's sink is in error state: {}", e);
                            }
                        };
                    }
                }
                Err(e) => {
                    if e.kind() == ::std::io::ErrorKind::WouldBlock {
                        return Ok(Async::NotReady);
                    }
                    error!("Inner peer read failed: {}", e);
                    return Err(());
                }
            }
        }
    }
}

impl Drop for PeerHandleR {
    fn drop(&mut self) {
        self.0
            .borrow_mut()
            .as_mut()
            .expect("Assertion failed 16292")
            .clients
            .remove(self.2);
    }
}

impl Read for PeerHandleR {
    fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {
        loop {
            return match self.1.poll() {
                Ok(Async::Ready(Some(v))) => {
                    if v.len() > b.len() {
                        error!("Too big message dropped");
                        continue;
                    }
                    b[0..(v.len())].copy_from_slice(&v[..]);
                    Ok(v.len())
                }
                Ok(Async::Ready(None)) => brokenpipe(),
                Ok(Async::NotReady) => wouldblock(),
                Err(()) => Err(simple_err("Something unexpected".into())),
            };
        }

        /*if let &mut Some(ref mut x) = self.0.borrow_mut().deref_mut() {
            x.inner_peer.0.read(b) // To be changed
        } else {
            unreachable!()
        }*/
    }
}
impl AsyncRead for PeerHandleR {}

impl Write for PeerHandleW {
    fn write(&mut self, b: &[u8]) -> Result<usize, IoError> {
        if let Some(ref mut x) = *self.0.borrow_mut().deref_mut() {
            x.inner_peer.1.write(b)
        } else {
            unreachable!()
        }
    }
    fn flush(&mut self) -> Result<(), IoError> {
        if let Some(ref mut x) = *self.0.borrow_mut().deref_mut() {
            x.inner_peer.1.flush()
        } else {
            unreachable!()
        }
    }
}
impl AsyncWrite for PeerHandleW {
    fn shutdown(&mut self) -> futures::Poll<(), IoError> {
        if let Some(ref mut _x) = *self.0.borrow_mut().deref_mut() {
            // Ignore shutdown attempts
            Ok(futures::Async::Ready(()))
        //_x.1.shutdown()
        } else {
            unreachable!()
        }
    }
}

fn makeclient(ps: HBroadCaster, queue_len: usize) -> Peer {
    let (send, recv) = mpsc::channel(queue_len);
    let k = ps
        .borrow_mut()
        .as_mut()
        .expect("Assertion failed 16291")
        .clients
        .insert(send);
    let ph1 = PeerHandleR(ps.clone(), recv, k);
    let ph2 = PeerHandleW(ps);
    Peer::new(ph1, ph2, None /* TODO */)
}

pub fn connection_reuser<F: FnOnce() -> BoxedNewPeerFuture>(
    s: &mut GlobalState,
    inner_peer: F,
    buffer_size: usize,
    queue_len: usize,
) -> BoxedNewPeerFuture {
    let need_init = s.borrow().is_none();

    let rc = s.clone();
    if need_init {
        info!("Initializing");
        Box::new(inner_peer().and_then(move |inner| {
            {
                let mut b = rc.borrow_mut();
                let x: &mut Option<Broadcaster> = b.deref_mut();
                *x = Some(Broadcaster {
                    inner_peer: inner,
                    clients: Clients::new(),
                });
                spawn_hack(InnerPeerReader(rc.clone(), vec![0; buffer_size]));
            }

            let ps: HBroadCaster = rc.clone();
            ok(makeclient(ps, queue_len))
        })) as BoxedNewPeerFuture
    } else {
        info!("Reusing");
        let ps: HBroadCaster = rc.clone();
        Box::new(ok(makeclient(ps, queue_len))) as BoxedNewPeerFuture
    }
}


================================================
FILE: src/crypto_peer.rs
================================================
use argon2::Argon2;
use futures::Async;
use futures::future::ok;

use std::rc::Rc;

use super::{BoxedNewPeerFuture, Peer};
use super::{ConstructParams, PeerConstructor, Specifier};

use std::io::{Read, Write};
use tokio_io::{AsyncRead, AsyncWrite};

use std::io::Error as IoError;

use chacha20poly1305::ChaCha20Poly1305;
use chacha20poly1305::Nonce;
use chacha20poly1305::aead::NewAead;
use chacha20poly1305::aead::Aead;
use rand::RngCore;

#[derive(Debug)]
pub struct Crypto<T: Specifier>(pub T);
impl<T: Specifier> Specifier for Crypto<T> {
    fn construct(&self, cp: ConstructParams) -> PeerConstructor {
        let inner = self.0.construct(cp.clone());
        let mut key = [0u8; 32];
        if let Some(k) = cp.program_options.crypto_key {
            key = k;
        } else {
            log::error!("You are using `crypto:` without `--crypto-key`. This uses a hard coded key and is insecure.")
        }
        inner.map(move |p, _| crypto_peer(p, key, cp.program_options.crypto_reverse))
    }
    specifier_boilerplate!(noglobalstate has_subspec);
    self_0_is_subspecifier!(proxy_is_multiconnect);
}
specifier_class!(
    name = CryptoClass,
    target = Crypto,
    prefixes = ["crypto:"],
    arg_handling = subspec,
    overlay = true,
    MessageOriented,
    MulticonnectnessDependsOnInnerType,
    help = r#"
[A] Encrypts written messages and decrypts (and verifies) read messages with a static key, using ChaCha20-Poly1305 algorithm.

Do not not use in stream mode - packet boundaries are significant.

Note that attacker may duplicate, drop or reorder messages, including between different Websocat sessions with the same key.

Each encrypted message is 12 bytes bigger than original message.

Associated --crypto-key option accepts the following prefixes:

- `file:` prefix means that Websocat should read 32-byte file and use it as a key.
- `base64:` prefix means the rest of the value is base64-encoded 32-byte buffer
- `pwd:` means Websocat should use argon2 derivation from the specified password as a key

Use `--crypto-reverse` option to swap encryption and decryption.

Note that `crypto:` specifier is absent in usual Websocat builds.
You may need to build Websocat from source code with `--features=crypto_peer` for it to be available.
"#
);

#[derive(Clone, Copy)]
enum Mode {
    Encrypt,
    Decrypt,
}

pub fn crypto_peer(inner_peer: Peer, key: [u8; 32], reverse: bool) -> BoxedNewPeerFuture {
    let (mode_r, mode_w) = if reverse {
        (Mode::Encrypt, Mode::Decrypt)
    } else {
        (Mode::Decrypt, Mode::Encrypt)
    };
    let crypto = ChaCha20Poly1305::new(chacha20poly1305::Key::from_slice(&key));
    let filtered_r = CryptoWrapperR(inner_peer.0, crypto.clone(), mode_r);
    let filtered_w = CryptoWrapperW(inner_peer.1, crypto, mode_w);
    let thepeer = Peer::new(filtered_r, filtered_w, inner_peer.2);
    Box::new(ok(thepeer)) as BoxedNewPeerFuture
}
struct CryptoWrapperR(Box<dyn AsyncRead>, ChaCha20Poly1305, Mode);

impl Read for CryptoWrapperR {
    fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {
        let mut l = b.len();

        assert!(l > 12);

        if matches!(self.2, Mode::Encrypt) {
            l -= 12;
        }

        let n = match self.0.read(&mut b[..l]) {
            Ok(x) => x,
            Err(e) => return Err(e),
        };

        if n == 0 { return Ok(0) }

        let data = process_data(&b[..n], &self.1, self.2)?;

        let m = data.len();
        b[..m].copy_from_slice(&data[..m]);

        Ok(m)
    }
}
impl AsyncRead for CryptoWrapperR {}

struct CryptoWrapperW(Box<dyn AsyncWrite>, ChaCha20Poly1305, Mode);

impl Write for CryptoWrapperW {
    fn write(&mut self, b: &[u8]) -> Result<usize, IoError> {
        let l = b.len();

        let data = process_data(b, &self.1, self.2)?;

        let n = match self.0.write(&data[..]) {
            Ok(x) => x,
            Err(e) => return Err(e),
        };

        if n != data.len() {
            log::error!("Short write when using `crypto:` specifier");
        }

        Ok(l)
    }

    fn flush(&mut self) -> std::io::Result<()> {
        self.0.flush()
    }
}
impl AsyncWrite for CryptoWrapperW {
    fn shutdown(&mut self) -> std::result::Result<Async<()>, std::io::Error> {
        self.0.shutdown()
    }
}

fn process_data(buf: &[u8], crypto: &ChaCha20Poly1305, mode: Mode) -> Result<Vec<u8>, IoError>  {
    let l = buf.len();
    match mode {
        Mode::Encrypt => {
            let mut nonce = [0u8; 12];
            rand::thread_rng().fill_bytes(&mut nonce[..]);
            let mut data: Vec<u8> = crypto
                .encrypt(Nonce::from_slice(&nonce), &buf[..])
                .unwrap();
            data.extend_from_slice(&nonce[..]);
            Ok(data)
        }
        Mode::Decrypt => {
            if l < 12 {
                log::error!("Insufficient packet length for `crypto:` specifier's decryption");
                return Err(std::io::ErrorKind::Other.into()); 
            }
            let mut nonce = [0u8; 12];
            nonce.copy_from_slice(&buf[l-12..l]);
            match crypto.decrypt(Nonce::from_slice(&nonce), &buf[..(l-12)]) {
                Ok(x) => Ok(x),
                Err(_) => {
                    log::error!("crypto: decryption failed");
                    return Err(std::io::ErrorKind::Other.into())
                }
            }
        }
    }
}

pub fn interpret_opt(x: &str) -> crate::Result<[u8; 32]> {
    let mut key = [0u8; 32];
    if x.starts_with("base64:") {
        let mut buf = Vec::with_capacity(32);
        base64::decode_config_buf(&x[7..], base64::STANDARD, &mut buf)?;
        if buf.len() != 32 {
            log::error!("Expected 32 bytes, got {} bytes", buf.len());
            return Err("Non 32-byte buffer specified".into());
        }
        key.copy_from_slice(&buf[..]);

    } else if x.starts_with("file:") {
        let buf = std::fs::read(&x[5..])?;
        if buf.len() != 32 {
            log::error!("Expected 32 bytes, got {} bytes", buf.len());
            return Err("Non 32-byte buffer specified".into());
        }
        key.copy_from_slice(&buf[..])
    } else if x.starts_with("pwd:") {
        let argon2 = Argon2::default();
        const SALT : &'static [u8] = &[0x81, 0x65, 0x0c, 0xc7, 0x09, 0x76, 0xc1, 0x12, 0x6b, 0x5b, 0x5f, 0x04,
        0x08, 0x61, 0xf6, 0x1b, 0xd6, 0xab, 0x88, 0xa2, 0xee, 0x67, 0x47, 0xc1,
        0xbe, 0x12, 0xd7, 0xd7, 0x2d, 0xb8, 0x39, 0xcf];
        argon2.hash_password_into(x[4..].as_bytes(),SALT,&mut key[..]).unwrap();
    } else {
        return Err("--crypto-key's value must start with `base64:`, `file:` or `pwd:`".into());
    }
    Ok(key)
}


================================================
FILE: src/file_peer.rs
================================================
use futures;
use futures::Async;
use std;
use std::io::Result as IoResult;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use tokio_io::{AsyncRead, AsyncWrite};

use std::fs::{File, OpenOptions};
use std::rc::Rc;

use super::{BoxedNewPeerFuture, Peer, Result};

use super::{once, ConstructParams, PeerConstructor, Specifier};

#[derive(Clone, Debug)]
pub struct ReadFile(pub PathBuf);
impl Specifier for ReadFile {
    fn construct(&self, _: ConstructParams) -> PeerConstructor {
        fn gp(p: &Path) -> Result<Peer> {
            let f = File::open(p)?;
            Ok(Peer::new(ReadFileWrapper(f), super::trivial_peer::DevNull, None))
        }
        once(Box::new(futures::future::result(gp(&self.0))) as BoxedNewPeerFuture)
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec);
}
specifier_class!(
    name = ReadFileClass,
    target = ReadFile,
    prefixes = ["readfile:"],
    arg_handling = into,
    overlay = false,
    StreamOriented,
    SingleConnect,
    help = r#"
Synchronously read a file. Argument is a file path.

Blocking on operations with the file pauses the whole process

Example: Serve the file once per connection, ignore all replies.

    websocat ws-l:127.0.0.1:8000 readfile:hello.json

"#
);

#[derive(Clone, Debug)]
pub struct WriteFile(pub PathBuf);
impl Specifier for WriteFile {
    fn construct(&self, _: ConstructParams) -> PeerConstructor {
     
Download .txt
gitextract_scxsgr_6/

├── .dockerignore
├── .github/
│   ├── dependabot.yml
│   └── workflows/
│       ├── ci.yaml
│       └── container-image-buildah.yml
├── .gitignore
├── 1234.pkcs12
├── CHANGELOG.md
├── Cargo.lock.legacy
├── Cargo.toml
├── Dockerfile
├── Dockerfile.debian
├── LICENSE
├── README.md
├── doc.md
├── misc/
│   └── prebuilt_release_settings.sh
├── moreexamples.md
├── src/
│   ├── all_peers.rs
│   ├── broadcast_reuse_peer.rs
│   ├── crypto_peer.rs
│   ├── file_peer.rs
│   ├── foreachmsg_peer.rs
│   ├── help.rs
│   ├── http_peer.rs
│   ├── http_serve.rs
│   ├── jsonrpc_peer.rs
│   ├── lengthprefixed_peer.rs
│   ├── lib.rs
│   ├── line_peer.rs
│   ├── lints.rs
│   ├── main.rs
│   ├── mirror_peer.rs
│   ├── my_copy.rs
│   ├── net_peer.rs
│   ├── options.rs
│   ├── primitive_reuse_peer.rs
│   ├── process_peer.rs
│   ├── prometheus_peer.rs
│   ├── readdebt.rs
│   ├── reconnect_peer.rs
│   ├── sessionserve.rs
│   ├── socks5_peer.rs
│   ├── specifier.rs
│   ├── specparse.rs
│   ├── ssl_peer.rs
│   ├── stdio_peer.rs
│   ├── stdio_threaded_peer.rs
│   ├── timestamp_peer.rs
│   ├── trivial_peer.rs
│   ├── unix_peer.rs
│   ├── unix_seqpacket_peer.rs
│   ├── util.rs
│   ├── windows_np_peer.rs
│   ├── ws_client_peer.rs
│   ├── ws_lowlevel_peer.rs
│   ├── ws_peer.rs
│   └── ws_server_peer.rs
├── test.pkcs12
├── test.sh
├── test_help.sh
└── tests/
    └── test.rs
Download .txt
SYMBOL INDEX (588 symbols across 40 files)

FILE: src/broadcast_reuse_peer.rs
  type BroadcastReuser (line 28) | pub struct BroadcastReuser(pub Rc<dyn Specifier>);
  method construct (line 30) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type SailingBuffer (line 71) | type SailingBuffer = Rc<Vec<u8>>;
  type Clients (line 72) | type Clients = Slab<BroadcastClientIndex, mpsc::Sender<SailingBuffer>>;
  type Broadcaster (line 74) | pub struct Broadcaster {
  type HBroadCaster (line 78) | pub type HBroadCaster = Rc<RefCell<Option<Broadcaster>>>;
  type GlobalState (line 80) | pub type GlobalState = HBroadCaster;
  type PeerHandleW (line 82) | struct PeerHandleW(HBroadCaster);
  type PeerHandleR (line 83) | struct PeerHandleR(
  type InnerPeerReader (line 88) | struct InnerPeerReader(HBroadCaster, Vec<u8>);
  type Item (line 91) | type Item = ();
  type Error (line 92) | type Error = ();
  method poll (line 93) | fn poll(&mut self) -> futures::Poll<(), ()> {
  method drop (line 141) | fn drop(&mut self) {
  method read (line 152) | fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {
  method write (line 179) | fn write(&mut self, b: &[u8]) -> Result<usize, IoError> {
  method flush (line 186) | fn flush(&mut self) -> Result<(), IoError> {
  method shutdown (line 195) | fn shutdown(&mut self) -> futures::Poll<(), IoError> {
  function makeclient (line 206) | fn makeclient(ps: HBroadCaster, queue_len: usize) -> Peer {
  function connection_reuser (line 219) | pub fn connection_reuser<F: FnOnce() -> BoxedNewPeerFuture>(

FILE: src/crypto_peer.rs
  type Crypto (line 22) | pub struct Crypto<T: Specifier>(pub T);
  method construct (line 24) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type Mode (line 68) | enum Mode {
  function crypto_peer (line 73) | pub fn crypto_peer(inner_peer: Peer, key: [u8; 32], reverse: bool) -> Bo...
  type CryptoWrapperR (line 85) | struct CryptoWrapperR(Box<dyn AsyncRead>, ChaCha20Poly1305, Mode);
  method read (line 88) | fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {
  type CryptoWrapperW (line 114) | struct CryptoWrapperW(Box<dyn AsyncWrite>, ChaCha20Poly1305, Mode);
  method write (line 117) | fn write(&mut self, b: &[u8]) -> Result<usize, IoError> {
  method flush (line 134) | fn flush(&mut self) -> std::io::Result<()> {
  method shutdown (line 139) | fn shutdown(&mut self) -> std::result::Result<Async<()>, std::io::Error> {
  function process_data (line 144) | fn process_data(buf: &[u8], crypto: &ChaCha20Poly1305, mode: Mode) -> Re...
  function interpret_opt (line 174) | pub fn interpret_opt(x: &str) -> crate::Result<[u8; 32]> {

FILE: src/file_peer.rs
  type ReadFile (line 17) | pub struct ReadFile(pub PathBuf);
  method construct (line 19) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type WriteFile (line 49) | pub struct WriteFile(pub PathBuf);
  method construct (line 51) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type AppendFile (line 82) | pub struct AppendFile(pub PathBuf);
  method construct (line 84) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type ReadFileWrapper (line 113) | pub struct ReadFileWrapper(pub File);
  method read (line 117) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  type WriteFileWrapper (line 122) | struct WriteFileWrapper(File);
  method shutdown (line 125) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 130) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 133) | fn flush(&mut self) -> IoResult<()> {

FILE: src/foreachmsg_peer.rs
  type Foreachmsg (line 17) | pub struct Foreachmsg(pub Rc<dyn Specifier>);
  method construct (line 19) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type State2 (line 47) | struct State2 {
  type Phase (line 52) | enum Phase {
  type State (line 60) | struct State {
    method poll (line 80) | fn poll(&mut self) -> Poll<&mut Peer, Box<dyn (::std::error::Error)>> {
    method reconnect (line 147) | fn reconnect(&mut self) {
  type PeerHandle (line 132) | struct PeerHandle(Rc<RefCell<State>>);
  method read (line 158) | fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {
  method write (line 220) | fn write(&mut self, b: &[u8]) -> Result<usize, IoError> {
  method flush (line 354) | fn flush(&mut self) -> Result<(), IoError> {
  method shutdown (line 360) | fn shutdown(&mut self) -> futures::Poll<(), IoError> {
  function foreachmsg_peer (line 366) | pub fn foreachmsg_peer(s: Rc<dyn Specifier>, cp: ConstructParams) -> Box...

FILE: src/help.rs
  function spechelp (line 3) | fn spechelp(sc: &dyn SpecifierClass, overlays: bool, advanced: bool) {
  function shorthelp (line 27) | pub fn shorthelp() {
  function longhelp (line 99) | pub fn longhelp() {
  function specdoc (line 124) | fn specdoc(sc: &dyn SpecifierClass, overlays: bool) {
  function dochelp (line 157) | pub fn dochelp() {

FILE: src/http_peer.rs
  type HttpRequest (line 27) | pub struct HttpRequest<T: Specifier>(pub T);
  method construct (line 29) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type Http (line 73) | pub struct Http<T: Specifier>(pub T, pub Uri);
  method construct (line 75) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type HttpHeaderEndDetectionState (line 142) | enum HttpHeaderEndDetectionState {
  type WaitForHttpHead (line 150) | struct WaitForHttpHead<R : AsyncRead>
  type WaitForHttpHeadResult (line 158) | struct WaitForHttpHeadResult {
  function new (line 165) | pub fn new(r:R) -> WaitForHttpHead<R> {
  type Item (line 176) | type Item = (WaitForHttpHeadResult, R);
  type Error (line 177) | type Error = Box<dyn std::error::Error>;
  method poll (line 179) | fn poll(&mut self) -> ::futures::Poll<Self::Item, Self::Error> {
  function http_request_peer (line 231) | pub fn http_request_peer(
  type HttpPostSse (line 291) | pub struct HttpPostSse<T: Specifier>(pub T);
  method construct (line 293) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type ModeOfOperation (line 326) | enum ModeOfOperation {
  function http_response_post_sse_peer (line 331) | pub fn http_response_post_sse_peer(
  type SseState (line 450) | enum SseState {
  type SseStream (line 457) | struct SseStream<W : Write>
  function new (line 465) | pub fn new(w: W) -> Self {
  method shutdown (line 475) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 481) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  method flush (line 544) | fn flush(&mut self) -> std::io::Result<()> {
  function test_basic_sse_stream (line 550) | fn test_basic_sse_stream() {

FILE: src/http_serve.rs
  constant BAD_REQUEST (line 17) | const BAD_REQUEST :&[u8] = b"HTTP/1.1 400 Bad Request\r\nServer: websoca...
  constant NOT_FOUND (line 19) | const NOT_FOUND: &[u8] = b"HTTP/1.1 404 Not Found\r\nServer: websocat\r\...
  constant NOT_FOUND2 (line 21) | const NOT_FOUND2: &[u8] = b"HTTP/1.1 500 Not Found\r\nServer: websocat\r...
  constant BAD_METHOD (line 23) | const BAD_METHOD :&[u8] = b"HTTP/1.1 400 Bad Request\r\nServer: websocat...
  constant BAD_URI_FORMAT (line 25) | const BAD_URI_FORMAT :&[u8] = b"HTTP/1.1 400 Bad Request\r\nServer: webs...
  function get_static_file_reply (line 27) | pub fn get_static_file_reply(len: Option<u64>, ct: &str) -> Vec<u8> {
  function http_serve (line 42) | pub fn http_serve(

FILE: src/jsonrpc_peer.rs
  type JsonRpc (line 14) | pub struct JsonRpc<T: Specifier>(pub T);
  method construct (line 16) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  function jsonrpc_peer (line 40) | pub fn jsonrpc_peer(inner_peer: Peer, omit_jsonrpc: bool) -> BoxedNewPee...
  type JsonRpcWrapper (line 45) | struct JsonRpcWrapper(Box<dyn AsyncRead>, u64, bool);
  method read (line 48) | fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {

FILE: src/lengthprefixed_peer.rs
  type LengthPrefixed (line 16) | pub struct LengthPrefixed<T: Specifier>(pub T);
  method construct (line 18) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  function lengthprefixed_peer (line 64) | pub fn lengthprefixed_peer(
  type Lengthprefixed2PacketWrapper (line 106) | struct Lengthprefixed2PacketWrapper {
  method read (line 116) | fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
  type Packet2LengthPrefixedWrapper (line 177) | struct Packet2LengthPrefixedWrapper {
  method write (line 188) | fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
  method flush (line 223) | fn flush(&mut self) -> std::io::Result<()> {
  method shutdown (line 229) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {

FILE: src/lib.rs
  type Result (line 52) | type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
  type WebsocatConfiguration1 (line 55) | pub struct WebsocatConfiguration1 {
    method parse1 (line 64) | pub fn parse1(self) -> Result<WebsocatConfiguration2> {
  type WebsocatConfiguration2 (line 80) | pub struct WebsocatConfiguration2 {
    method parse2 (line 87) | pub fn parse2(self) -> Result<WebsocatConfiguration3> {
  type WebsocatConfiguration3 (line 98) | pub struct WebsocatConfiguration3 {
    method serve (line 105) | pub fn serve<OE>(self, onerror: std::rc::Rc<OE>) -> impl Future<Item =...
  type ProgramState (line 117) | pub struct ProgramState(
  type LeftSpecToRightSpec (line 124) | pub struct LeftSpecToRightSpec {
  type L2rWriter (line 133) | pub type L2rWriter = Rc<RefCell<LeftSpecToRightSpec>>;
  type L2rReader (line 134) | pub type L2rReader = Rc<LeftSpecToRightSpec>;
  type L2rUser (line 137) | pub enum L2rUser {
  type HupToken (line 143) | pub type HupToken = Box<dyn Future<Item=(), Error=Box<dyn std::error::Er...
  type Peer (line 145) | pub struct Peer(Box<dyn AsyncRead>, Box<dyn AsyncWrite>, Option<HupToken>);
  type BoxedNewPeerFuture (line 147) | pub type BoxedNewPeerFuture = Box<dyn Future<Item = Peer, Error = Box<dy...
  type BoxedNewPeerStream (line 148) | pub type BoxedNewPeerStream = Box<dyn Stream<Item = Peer, Error = Box<dy...
  type PeerOverlay (line 210) | pub type PeerOverlay = Rc<dyn Fn(Peer, L2rUser) -> BoxedNewPeerFuture>;
  type PeerConstructor (line 212) | pub enum PeerConstructor {
  function spawn_hack (line 221) | pub fn spawn_hack<T>(f: T)
  type Transfer (line 237) | pub struct Transfer {
  type Session (line 241) | pub struct Session {

FILE: src/line_peer.rs
  type Message2Line (line 14) | pub struct Message2Line<T: Specifier>(pub T);
  method construct (line 16) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type Line2Message (line 51) | pub struct Line2Message<T: Specifier>(pub T);
  method construct (line 53) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  function packet2line_peer (line 87) | pub fn packet2line_peer(inner_peer: Peer, null_terminated: bool) -> Boxe...
  type Packet2LineWrapper (line 92) | struct Packet2LineWrapper(Box<dyn AsyncRead>, bool);
  method read (line 95) | fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {
  function line2packet_peer (line 140) | pub fn line2packet_peer(
  type Line2PacketWrapper (line 158) | struct Line2PacketWrapper {
    method deliver_the_line (line 170) | fn deliver_the_line(&mut self, buf: &mut [u8], mut n: usize) -> Option...
  method read (line 204) | fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {

FILE: src/lints.rs
  type StdioUsageStatus (line 17) | pub enum StdioUsageStatus {
  type ClassExt (line 28) | trait ClassExt {
    method is_stdio (line 29) | fn is_stdio(&self) -> bool;
    method is_reuser (line 30) | fn is_reuser(&self) -> bool;
    method is_stdio (line 37) | fn is_stdio(&self) -> bool {
    method is_reuser (line 44) | fn is_reuser(&self) -> bool {
  type OnWarning (line 33) | pub type OnWarning = Box<dyn for<'a> Fn(&'a str) + 'static>;
  type SpecifierStackExt (line 52) | pub trait SpecifierStackExt {
    method stdio_usage_status (line 53) | fn stdio_usage_status(&self) -> StdioUsageStatus;
    method reuser_count (line 54) | fn reuser_count(&self) -> usize;
    method contains (line 55) | fn contains(&self, t: &'static str) -> bool;
    method is_multiconnect (line 56) | fn is_multiconnect(&self) -> bool;
    method is_stream_oriented (line 57) | fn is_stream_oriented(&self) -> bool;
    method autotoreconn_misuse (line 58) | fn autotoreconn_misuse(&self)  -> bool;
    method insert_line_class_in_proper_place (line 59) | fn insert_line_class_in_proper_place(&mut self, x: Rc<dyn SpecifierCla...
    method stdio_usage_status (line 62) | fn stdio_usage_status(&self) -> StdioUsageStatus {
    method reuser_count (line 80) | fn reuser_count(&self) -> usize {
    method contains (line 89) | fn contains(&self, t: &'static str) -> bool {
    method autotoreconn_misuse (line 97) | fn autotoreconn_misuse(&self)  -> bool {
    method is_multiconnect (line 111) | fn is_multiconnect(&self) -> bool {
    method is_stream_oriented (line 127) | fn is_stream_oriented(&self) -> bool {
    method insert_line_class_in_proper_place (line 143) | fn insert_line_class_in_proper_place(&mut self, x: Rc<dyn SpecifierCla...
  method inetd_mode (line 158) | pub fn inetd_mode(&self) -> bool {
  method websocket_used (line 164) | pub fn websocket_used(&self) -> bool {
  method exec_used (line 174) | pub fn exec_used(&self) -> bool {
  method contains_class (line 181) | pub fn contains_class(&self, x: &'static str) -> bool {
  method get_exec_parameter (line 185) | pub fn get_exec_parameter(&self) -> Option<&str> {
  method l_stdio (line 195) | fn l_stdio(&mut self, multiconnect: bool, reuser_has_been_inserted: &mut...
  method l_reuser (line 240) | fn l_reuser(&mut self, reuser_has_been_inserted: bool) -> Result<()> {
  method l_linemode (line 250) | fn l_linemode(&mut self) -> Result<()> {
  method l_listener_on_the_right (line 277) | fn l_listener_on_the_right(&mut self, on_warning: &OnWarning) -> Result<...
  method l_reuser_for_append (line 283) | fn l_reuser_for_append(&mut self, multiconnect: bool) -> Result<()> {
  method l_exec (line 296) | fn l_exec(&mut self, on_warning: &OnWarning) -> Result<()> {
  method l_uri_staticfiles (line 309) | fn l_uri_staticfiles(&mut self, on_warning: &OnWarning) -> Result<()> {
  method l_environ (line 337) | fn l_environ(&mut self, on_warning: &OnWarning) -> Result<()> {
  method l_closebug (line 353) | fn l_closebug(&mut self, on_warning: &OnWarning) -> Result<()> {
  method l_socks5_c (line 369) | fn l_socks5_c(
  method l_socks5 (line 439) | fn l_socks5(&mut self, on_warning: &OnWarning) -> Result<()> {
  method l_ssl (line 488) | fn l_ssl(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method l_ping (line 514) | fn l_ping(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method l_proto (line 541) | fn l_proto(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method l_eeof_unidir (line 562) | fn l_eeof_unidir(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method l_udp (line 572) | fn l_udp(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method l_crypto (line 599) | fn l_crypto(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method l_prometheus (line 608) | fn l_prometheus(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method l_sizelimits (line 619) | fn l_sizelimits(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method l_compress (line 625) | fn l_compress(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method l_autoreconn_reuse (line 650) | fn l_autoreconn_reuse(&mut self, _on_warning: &OnWarning) -> Result<()> {
  method lint_and_fixup (line 657) | pub fn lint_and_fixup(&mut self, on_warning: OnWarning) -> Result<()> {

FILE: src/main.rs
  type Result (line 39) | type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
  type Opt (line 59) | struct Opt {
  function interpret_custom_header (line 650) | fn interpret_custom_header(x: &str) -> Result<(String, Vec<u8>)> {
  function interpret_custom_header2 (line 665) | fn interpret_custom_header2(x: &str) -> Result<(http::header::HeaderName...
  function interpret_static_file (line 683) | fn interpret_static_file(x: &str) -> Result<StaticFile> {
  function interpret_socks_destination (line 706) | fn interpret_socks_destination(x: &str) -> Result<SocksSocketAddr> {
  function setup_env_logger (line 740) | pub fn setup_env_logger(ll: u8) -> Result<(), Box<dyn (::std::error::Err...
  function run (line 767) | fn run() -> Result<()> {
  function main (line 1127) | fn main() {

FILE: src/mirror_peer.rs
  type Mirror (line 22) | pub struct Mirror;
  method construct (line 24) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type LiteralReply (line 48) | pub struct LiteralReply(pub Vec<u8>);
    method fmt (line 56) | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), ...
  method construct (line 50) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type MirrorWrite (line 77) | struct MirrorWrite(mpsc::Sender<Vec<u8>>);
  type MirrorRead (line 78) | struct MirrorRead {
  function get_mirror_peer (line 83) | pub fn get_mirror_peer(debt_handling: DebtHandling) -> BoxedNewPeerFuture {
  function get_literal_reply_peer (line 93) | pub fn get_literal_reply_peer(content: Vec<u8>) -> BoxedNewPeerFuture {
  method read (line 108) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  method shutdown (line 128) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 134) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 141) | fn flush(&mut self) -> IoResult<()> {
  method drop (line 150) | fn drop(&mut self) {
  type LiteralReplyHandle (line 157) | struct LiteralReplyHandle(mpsc::Sender<()>);
  type LiteralReplyRead (line 158) | struct LiteralReplyRead {
  method shutdown (line 165) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 171) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 177) | fn flush(&mut self) -> IoResult<()> {
  method read (line 186) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...

FILE: src/my_copy.rs
  type CopyOptions (line 8) | pub struct CopyOptions {
  type Copy (line 25) | pub struct Copy<R, W> {
  function copy (line 54) | pub fn copy<R, W>(reader: R, writer: W, opts: CopyOptions, preamble: Vec...
  type Item (line 81) | type Item = (u64, R, W);
  type Error (line 82) | type Error = io::Error;
  method poll (line 84) | fn poll(&mut self) -> Poll<(u64, R, W), io::Error> {

FILE: src/net_peer.rs
  type TcpConnect (line 24) | pub struct TcpConnect(pub Vec<SocketAddr>);
  method construct (line 26) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type TcpListen (line 54) | pub struct TcpListen(pub SocketAddr);
  method construct (line 56) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type UdpConnect (line 83) | pub struct UdpConnect(pub SocketAddr);
  method construct (line 85) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type UdpListen (line 104) | pub struct UdpListen(pub SocketAddr);
  method construct (line 106) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type MyTcpStream (line 160) | struct MyTcpStream(Rc<TcpStream>, bool);
  method read (line 163) | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
  method write (line 169) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 173) | fn flush(&mut self) -> IoResult<()> {
  method shutdown (line 181) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method drop (line 188) | fn drop(&mut self) {
  function tcp_race (line 196) | pub fn tcp_race(addrs: &[SocketAddr]) -> Box<dyn Future<Item = TcpStream...
  function tcp_connect_peer (line 233) | pub fn tcp_connect_peer(addrs: &[SocketAddr]) -> BoxedNewPeerFuture {
  function tcp_listen_peer (line 252) | pub fn tcp_listen_peer(addr: &SocketAddr, l2r: L2rUser, announce: bool) ...
  type UdpPeerState (line 290) | enum UdpPeerState {
  type UdpPeer (line 296) | struct UdpPeer {
  type UdpPeerHandle (line 303) | struct UdpPeerHandle(Rc<RefCell<UdpPeer>>);
  function get_zero_address (line 305) | fn get_zero_address(addr: &SocketAddr) -> SocketAddr {
  function apply_udp_options (line 314) | fn apply_udp_options(s: &UdpSocket, opts:&Rc<Options>) -> IoResult<()> {
  function get_udp (line 366) | pub fn get_udp(addr: &SocketAddr, opts: &Rc<Options>) -> IoResult<UdpSoc...
  function udp_connect_peer (line 379) | pub fn udp_connect_peer(addr: &SocketAddr, opts: &Rc<Options>) -> BoxedN...
  function udp_listen_peer (line 400) | pub fn udp_listen_peer(addr: &SocketAddr, opts: &Rc<Options>) -> BoxedNe...
  method read (line 422) | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
  method write (line 458) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 481) | fn flush(&mut self) -> IoResult<()> {
  method shutdown (line 489) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  type UndeprecateNonpollSendRecv (line 495) | trait UndeprecateNonpollSendRecv {
    method recv2 (line 496) | fn recv2(&mut self, buf: &mut [u8]) -> std::io::Result<usize>;
    method recv_from2 (line 497) | fn recv_from2(&mut self, buf: &mut [u8]) -> std::io::Result<(usize, So...
    method send2 (line 498) | fn send2(&mut self, buf: &[u8]) -> std::io::Result<usize>;
    method send_to2 (line 499) | fn send_to2(&mut self, buf: &[u8], target: &SocketAddr) -> std::io::Re...
    method recv2 (line 503) | fn recv2(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
    method recv_from2 (line 510) | fn recv_from2(&mut self, buf: &mut [u8]) -> std::io::Result<(usize, So...
    method send2 (line 517) | fn send2(&mut self, buf: &[u8]) -> std::io::Result<usize> {
    method send_to2 (line 524) | fn send_to2(&mut self, buf: &[u8], target: &SocketAddr) -> std::io::Re...

FILE: src/options.rs
  type StaticFile (line 9) | pub struct StaticFile {
  type Options (line 20) | pub struct Options {

FILE: src/primitive_reuse_peer.rs
  type Reuser (line 18) | pub struct Reuser(pub Rc<dyn Specifier>);
  method construct (line 20) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type PeerSlot (line 60) | type PeerSlot = Rc<RefCell<Option<Peer>>>;
  type GlobalState (line 63) | pub struct GlobalState(PeerSlot);
  type PeerHandle (line 66) | struct PeerHandle(PeerSlot, bool);
  method read (line 69) | fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {
  method write (line 80) | fn write(&mut self, b: &[u8]) -> Result<usize, IoError> {
  method flush (line 87) | fn flush(&mut self) -> Result<(), IoError> {
  method shutdown (line 96) | fn shutdown(&mut self) -> futures::Poll<(), IoError> {
  function connection_reuser (line 110) | pub fn connection_reuser<F: FnOnce() -> BoxedNewPeerFuture>(

FILE: src/process_peer.rs
  function needenv (line 22) | fn needenv(p: &ConstructParams) -> Option<&LeftSpecToRightSpec> {
  type Cmd (line 30) | pub struct Cmd(pub String);
  method construct (line 32) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type ShC (line 74) | pub struct ShC(pub String);
  method construct (line 76) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type Exec (line 115) | pub struct Exec(pub String);
  method construct (line 117) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  function process_connect_peer (line 156) | fn process_connect_peer(
  type ForgetfulProcess (line 187) | struct ForgetfulProcess {
  type ProcessPeer (line 192) | struct ProcessPeer {
  method read (line 199) | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
  method write (line 213) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 237) | fn flush(&mut self) -> IoResult<()> {
  method shutdown (line 253) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method drop (line 281) | fn drop(&mut self) {

FILE: src/prometheus_peer.rs
  type GlobalStats (line 24) | pub struct GlobalStats {
  type HGlobalStats (line 102) | pub type HGlobalStats = Rc<GlobalStats>;
  type GlobalState (line 104) | pub type GlobalState = (HGlobalStats, Rc<RefCell<Option<prometheus::Hist...
  type Droppie (line 106) | struct Droppie {
    method new (line 116) | fn new(handle: HGlobalStats) -> Droppie {
  method drop (line 130) | fn drop(&mut self) {
  function new_global_stats (line 145) | pub fn new_global_stats() -> GlobalState {
  function serve (line 149) | pub fn serve(psa: SocketAddr) -> crate::Result<()> {
  type Prometheus (line 170) | pub struct Prometheus<T: Specifier>(pub T);
  method construct (line 172) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  function prometheus_peer (line 197) | pub fn prometheus_peer(inner_peer: Peer, stats: GlobalState) -> BoxedNew...
  type StatsWrapperR (line 210) | struct StatsWrapperR(Box<dyn AsyncRead>, Rc<Droppie>);
  method read (line 213) | fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {
  type StatsWrapperW (line 238) | struct StatsWrapperW(Box<dyn AsyncWrite>, Rc<Droppie>);
  method write (line 241) | fn write(&mut self, b: &[u8]) -> Result<usize, IoError> {
  method flush (line 265) | fn flush(&mut self) -> std::io::Result<()> {
  method shutdown (line 270) | fn shutdown(&mut self) -> std::result::Result<Async<()>, std::io::Error> {

FILE: src/readdebt.rs
  type DebtHandling (line 4) | pub enum DebtHandling {
  type ZeroMessagesHandling (line 10) | pub enum ZeroMessagesHandling {
  type ProcessMessageResult (line 15) | pub enum ProcessMessageResult {
  type ReadDebt (line 21) | pub struct ReadDebt(pub Option<Vec<u8>>, pub DebtHandling, pub ZeroMessa...
    method process_message (line 23) | pub fn process_message(&mut self, buf: &mut [u8], buf_in: &[u8]) -> Pr...
    method check_debt (line 57) | pub fn check_debt(

FILE: src/reconnect_peer.rs
  type AutoReconnect (line 20) | pub struct AutoReconnect(pub Rc<dyn Specifier>);
  method construct (line 22) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type State2 (line 52) | struct State2 {
  type State (line 56) | struct State {
    method poll (line 74) | fn poll(&mut self) -> Poll<&mut Peer, Box<dyn (::std::error::Error)>> {
    method reconnect (line 166) | fn reconnect(&mut self) {
  type PeerHandle (line 151) | struct PeerHandle(Rc<RefCell<State>>);
  method read (line 217) | fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {
  method write (line 225) | fn write(&mut self, b: &[u8]) -> Result<usize, IoError> {
  method flush (line 230) | fn flush(&mut self) -> Result<(), IoError> {
  method shutdown (line 236) | fn shutdown(&mut self) -> futures::Poll<(), IoError> {
  function autoreconnector (line 243) | pub fn autoreconnector(s: Rc<dyn Specifier>, cp: ConstructParams) -> Box...
  function waitfordata (line 263) | pub fn waitfordata(s: Rc<dyn Specifier>, cp: ConstructParams) -> BoxedNe...
  type WaitForData (line 284) | pub struct WaitForData(pub Rc<dyn Specifier>);
  method construct (line 286) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {

FILE: src/sessionserve.rs
  method run (line 13) | pub fn run(self) -> Box<dyn Future<Item = (), Error = Box<dyn std::error...
  method new (line 87) | pub fn new(peer1: Peer, peer2: Peer, opts: Rc<Options>) -> Self {
  function l2r_new (line 104) | fn l2r_new() -> L2rWriter {
  function serve (line 108) | pub fn serve<OE>(
  function serve_impl (line 121) | fn serve_impl<OE>(

FILE: src/socks5_peer.rs
  type SocksHostAddr (line 16) | pub enum SocksHostAddr {
  type SocksSocketAddr (line 22) | pub struct SocksSocketAddr {
  type SocksProxy (line 28) | pub struct SocksProxy<T: Specifier>(pub T);
  method construct (line 30) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type SocksBind (line 59) | pub struct SocksBind<T: Specifier>(pub T);
  method construct (line 61) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type RSRRet (line 98) | type RSRRet =
  function read_socks_reply (line 100) | fn read_socks_reply(p: Peer) -> RSRRet {
  function socks5_peer (line 195) | pub fn socks5_peer(
  function authenticate_no_auth (line 280) | fn authenticate_no_auth(
  function authenticate_username_password (line 287) | fn authenticate_username_password(
  function build_socks5_request (line 331) | fn build_socks5_request(

FILE: src/specifier.rs
  type ClassMessageBoundaryStatus (line 7) | pub enum ClassMessageBoundaryStatus {
  type ClassMulticonnectStatus (line 13) | pub enum ClassMulticonnectStatus {
  type SpecifierClass (line 22) | pub trait SpecifierClass: std::fmt::Debug {
    method get_name (line 24) | fn get_name(&self) -> &'static str;
    method get_prefixes (line 26) | fn get_prefixes(&self) -> Vec<&'static str>;
    method help (line 28) | fn help(&self) -> &'static str;
    method construct (line 31) | fn construct(&self, arg: &str) -> Result<Rc<dyn Specifier>>;
    method construct_overlay (line 33) | fn construct_overlay(&self, inner: Rc<dyn Specifier>) -> Result<Rc<dyn...
    method is_overlay (line 35) | fn is_overlay(&self) -> bool;
    method message_boundary_status (line 37) | fn message_boundary_status(&self) -> ClassMessageBoundaryStatus;
    method multiconnect_status (line 39) | fn multiconnect_status(&self) -> ClassMulticonnectStatus;
    method alias_info (line 41) | fn alias_info(&self) -> Option<&'static str>;
  type SpecifierNode (line 170) | pub struct SpecifierNode {
  type SpecifierStack (line 176) | pub struct SpecifierStack {
  type ConstructParams (line 183) | pub struct ConstructParams {
    method reset_l2r (line 192) | pub fn reset_l2r(&mut self) {
    method reply (line 205) | pub fn reply(&self) -> Self {
    method deep_clone (line 217) | pub fn deep_clone(&self) -> Self {
    method global (line 234) | pub fn global<T:std::any::Any, F>(&self, def:F) -> std::cell::RefMut<T>
  type Specifier (line 249) | pub trait Specifier: std::fmt::Debug {
    method construct (line 251) | fn construct(&self, p: ConstructParams) -> PeerConstructor;
    method is_multiconnect (line 254) | fn is_multiconnect(&self) -> bool;
    method uses_global_state (line 255) | fn uses_global_state(&self) -> bool;
    method construct (line 259) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
    method is_multiconnect (line 263) | fn is_multiconnect(&self) -> bool {
    method uses_global_state (line 266) | fn uses_global_state(&self) -> bool {

FILE: src/specparse.rs
  function spec (line 6) | pub fn spec(s: &str) -> Result<Rc<dyn Specifier>> {
  function some_checks (line 10) | fn some_checks(s: &str) -> Result<()> {
  type Err (line 63) | type Err = Box<dyn (::std::error::Error)>;
  method from_str (line 65) | fn from_str(s: &str) -> Result<SpecifierStack> {
  function from_stack (line 124) | pub fn from_stack(st: &SpecifierStack) -> Result<Rc<dyn Specifier>> {

FILE: src/ssl_peer.rs
  function interpret_pkcs12 (line 17) | pub fn interpret_pkcs12(x: &OsStr) -> ::std::result::Result<Vec<u8>, OsS...
  type TlsConnect (line 35) | pub struct TlsConnect<T: Specifier>(pub T);
  method construct (line 37) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type TlsAccept (line 73) | pub struct TlsAccept<T: Specifier>(pub T);
  method construct (line 75) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  function ssl_connect (line 149) | pub fn ssl_connect(
  function ssl_accept (line 216) | pub fn ssl_accept(inner_peer: Peer, _l2r: L2rUser, progopt: Rc<Options>)...

FILE: src/stdio_peer.rs
  type AsyncStdio (line 28) | pub struct AsyncStdio;
  method construct (line 30) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type OpenAsync (line 85) | pub struct OpenAsync(pub PathBuf);
  method construct (line 87) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type OpenFdAsync (line 113) | pub struct OpenFdAsync(pub i32);
  method construct (line 115) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  function get_stdio_peer_impl (line 138) | fn get_stdio_peer_impl(s: &mut GlobalState) -> Result<Peer> {
  function get_stdio_peer (line 175) | pub fn get_stdio_peer(s: &mut GlobalState) -> BoxedNewPeerFuture {
  type GlobalState (line 181) | pub struct GlobalState {
  method drop (line 187) | fn drop(&mut self) {
  function restore_blocking_status (line 192) | fn restore_blocking_status(s: &GlobalState) {
  type ImplPollEvented (line 206) | type ImplPollEvented = ::tokio_reactor::PollEvented<UnixFile<std::fs::Fi...
  type FileWrapper (line 209) | struct FileWrapper(Rc<RefCell<ImplPollEvented>>);
  method read (line 213) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  method shutdown (line 219) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 224) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 227) | fn flush(&mut self) -> IoResult<()> {
  function get_file_peer_impl (line 232) | fn get_file_peer_impl(p: &Path) -> Result<Peer> {
  function get_file_peer (line 245) | pub fn get_file_peer(p: &Path) -> BoxedNewPeerFuture {
  function get_fd_peer_impl (line 250) | fn get_fd_peer_impl(fd: i32) -> Result<Peer> {
  function get_fd_peer (line 259) | pub fn get_fd_peer(fd: i32) -> BoxedNewPeerFuture {

FILE: src/stdio_threaded_peer.rs
  type ThreadedStdio (line 10) | pub struct ThreadedStdio;
  method construct (line 12) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  function get_stdio_peer (line 73) | pub fn get_stdio_peer() -> BoxedNewPeerFuture {

FILE: src/timestamp_peer.rs
  type TimestampPeer (line 15) | pub struct TimestampPeer<T: Specifier>(pub T);
  method construct (line 17) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  function timestamp_peer (line 39) | pub fn timestamp_peer(inner_peer: Peer, monotonic: bool) -> BoxedNewPeer...
  type TimestampWrapper (line 45) | struct TimestampWrapper(Box<dyn AsyncRead>, Option<Instant>);
  method read (line 48) | fn read(&mut self, b: &mut [u8]) -> Result<usize, IoError> {

FILE: src/trivial_peer.rs
  type Literal (line 20) | pub struct Literal(pub Vec<u8>);
    method fmt (line 28) | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), ...
  method construct (line 22) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type Assert (line 51) | pub struct Assert(pub Vec<u8>);
    method fmt (line 59) | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), ...
  method construct (line 53) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type Assert2 (line 80) | pub struct Assert2(pub Vec<u8>);
    method fmt (line 88) | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), ...
  method construct (line 82) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type Clogged (line 109) | pub struct Clogged;
  method construct (line 111) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type LiteralPeer (line 129) | pub struct LiteralPeer {
  function get_literal_peer_now (line 133) | pub fn get_literal_peer_now(b: Vec<u8>) -> LiteralPeer {
  function get_literal_peer (line 139) | pub fn get_literal_peer(b: Vec<u8>) -> BoxedNewPeerFuture {
  function get_assert_peer (line 145) | pub fn get_assert_peer(b: Vec<u8>) -> BoxedNewPeerFuture {
  function get_assert2_peer (line 151) | pub fn get_assert2_peer(b: Vec<u8>) -> BoxedNewPeerFuture {
  function get_clogged_peer (line 158) | pub fn get_clogged_peer() -> BoxedNewPeerFuture {
  method read (line 168) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  type DevNull (line 178) | pub struct DevNull;
  method shutdown (line 181) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 186) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 189) | fn flush(&mut self) -> IoResult<()> {
  method read (line 195) | fn read(&mut self, _buf: &mut [u8]) -> std::result::Result<usize, std::i...
  type AssertPeer (line 200) | struct AssertPeer(Vec<u8>, Vec<u8>, bool);
  method shutdown (line 202) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 215) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 219) | fn flush(&mut self) -> IoResult<()> {
  type CloggedPeer (line 224) | pub struct CloggedPeer;
  method shutdown (line 226) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 231) | fn write(&mut self, _buf: &[u8]) -> IoResult<usize> {
  method flush (line 234) | fn flush(&mut self) -> IoResult<()> {
  method read (line 240) | fn read(&mut self, _buf: &mut [u8]) -> std::result::Result<usize, std::i...
  type PrependRead (line 249) | pub struct PrependRead {
  method read (line 258) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  type PrependWrite (line 278) | pub struct PrependWrite {
  method shutdown (line 285) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 290) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 304) | fn flush(&mut self) -> IoResult<()> {
  type Log (line 310) | pub struct Log<T: Specifier>(pub T);
  method construct (line 312) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type LogRead (line 341) | pub struct LogRead (pub Box<dyn AsyncRead>);
  function log_buffer (line 343) | fn log_buffer(tag: &'static str, buf: &[u8]) {
  method read (line 356) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  type LogWrite (line 370) | pub struct LogWrite(pub Box<dyn AsyncWrite>);
  method shutdown (line 373) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 378) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 391) | fn flush(&mut self) -> IoResult<()> {
  type Random (line 398) | pub struct Random;
  method construct (line 400) | fn construct(&self, _cp: ConstructParams) -> PeerConstructor {
  type RandomReader (line 425) | pub struct RandomReader ();
  method read (line 431) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  type ExitOnSpecificByte (line 439) | pub struct ExitOnSpecificByte<T: Specifier>(pub T);
  method construct (line 441) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type ExitOnSpecificByteReader (line 473) | pub struct ExitOnSpecificByteReader {
  method read (line 483) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  type DropOnBackpressure (line 503) | pub struct DropOnBackpressure<T: Specifier>(pub T);
  method construct (line 505) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type DropOnBackpressureWriter (line 538) | pub struct DropOnBackpressureWriter {
  method write (line 543) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 554) | fn flush(&mut self) -> IoResult<()> {
  method shutdown (line 567) | fn shutdown(&mut self) -> tokio::prelude::Poll<(), std::io::Error> {

FILE: src/unix_peer.rs
  type UnixConnect (line 27) | pub struct UnixConnect(pub PathBuf);
  method construct (line 29) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type UnixListen (line 58) | pub struct UnixListen(pub PathBuf);
  method construct (line 60) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type UnixDgram (line 111) | pub struct UnixDgram(pub PathBuf, pub PathBuf);
  method construct (line 113) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  function to_abstract (line 153) | fn to_abstract(x: &str) -> PathBuf {
  type AbstractConnect (line 158) | pub struct AbstractConnect(pub String);
  method construct (line 160) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type AbstractListen (line 194) | pub struct AbstractListen(pub String);
  method construct (line 196) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  type AbstractDgram (line 230) | pub struct AbstractDgram(pub String, pub String);
  method construct (line 232) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type MyUnixStream (line 296) | struct MyUnixStream(Rc<UnixStream>, bool);
  method read (line 299) | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
  method write (line 305) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 309) | fn flush(&mut self) -> IoResult<()> {
  method shutdown (line 317) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method drop (line 324) | fn drop(&mut self) {
  function unix_connect_peer (line 332) | pub fn unix_connect_peer(addr: &Path) -> BoxedNewPeerFuture {
  function unix_listen_peer (line 349) | pub fn unix_listen_peer(addr: &Path, opts: &Rc<Options>) -> BoxedNewPeer...
  type DgramPeer (line 404) | struct DgramPeer {
  type DgramPeerHandle (line 411) | struct DgramPeerHandle(Rc<RefCell<DgramPeer>>);
  function dgram_peer (line 413) | pub fn dgram_peer(bindaddr: &Path, connectaddr: &Path, opts: &Rc<Options...
  function dgram_peer_workaround (line 431) | pub fn dgram_peer_workaround(
  method read (line 511) | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
  method write (line 518) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 523) | fn flush(&mut self) -> IoResult<()> {
  method shutdown (line 531) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  type HacksForMigratingFromTokioCore (line 536) | trait HacksForMigratingFromTokioCore {
    method recv (line 537) | fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize>;
    method send (line 538) | fn send(&self, buf: &[u8]) -> std::io::Result<usize>;
    method recv (line 542) | fn recv(&self, buf: &mut [u8]) -> std::io::Result<usize> {
    method send (line 549) | fn send(&self, buf: &[u8]) -> std::io::Result<usize> {

FILE: src/unix_seqpacket_peer.rs
  type SeqpacketConnect (line 13) | pub struct SeqpacketConnect(pub PathBuf);
  method construct (line 15) | fn construct(&self, _: ConstructParams) -> PeerConstructor {
  type SeqpacketListen (line 48) | pub struct SeqpacketListen(pub PathBuf);
  method construct (line 50) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  function seqpacket_connect_peer (line 81) | pub fn seqpacket_connect_peer(addr: &Path) -> BoxedNewPeerFuture {
  function seqpacket_listen_peer (line 135) | pub fn seqpacket_listen_peer(addr: &Path, opts: &Rc<Options>) -> BoxedNe...

FILE: src/util.rs
  function wouldblock (line 7) | pub fn wouldblock<T>() -> std::io::Result<T> {
  function brokenpipe (line 10) | pub fn brokenpipe<T>() -> std::io::Result<T> {
  function io_other_error (line 13) | pub fn io_other_error<E: std::error::Error + Send + Sync + 'static>(e: E...
  method map (line 19) | pub fn map<F>(self, func: F) -> Self
  method get_only_first_conn (line 55) | pub fn get_only_first_conn(self, l2r: L2rUser) -> BoxedNewPeerFuture {
  function once (line 78) | pub fn once(x: BoxedNewPeerFuture) -> PeerConstructor {
  function multi (line 81) | pub fn multi(x: BoxedNewPeerStream) -> PeerConstructor {
  function peer_err (line 85) | pub fn peer_err<E: std::error::Error + 'static>(e: E) -> BoxedNewPeerFut...
  function peer_err2 (line 90) | pub fn peer_err2(e: Box<dyn std::error::Error>) -> BoxedNewPeerFuture {
  function peer_err_s (line 95) | pub fn peer_err_s<E: std::error::Error + 'static>(e: E) -> BoxedNewPeerS...
  function peer_err_sb (line 100) | pub fn peer_err_sb(e: Box<dyn std::error::Error + 'static>) -> BoxedNewP...
  function peer_strerr (line 105) | pub fn peer_strerr(e: &str) -> BoxedNewPeerFuture {
  function simple_err (line 109) | pub fn simple_err(e: String) -> std::io::Error {
  function simple_err2 (line 113) | pub fn simple_err2(e: &'static str) -> Box<dyn std::error::Error> {
  function box_up_err (line 117) | pub fn box_up_err<E: std::error::Error + 'static>(e: E) -> Box<dyn std::...
  method new (line 122) | pub fn new<R: AsyncRead + 'static, W: AsyncWrite + 'static>(r: R, w: W, ...

FILE: src/windows_np_peer.rs
  type NamedPipeConnect (line 22) | pub struct NamedPipeConnect(pub PathBuf);
  method construct (line 24) | fn construct(&self, _p: ConstructParams) -> PeerConstructor {
  function named_pipe_connect_peer (line 47) | fn named_pipe_connect_peer(
  type NamedPipeConnectPeer (line 56) | struct NamedPipeConnectPeer(Rc<RefCell<NamedPipe>>);
  method read (line 59) | fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
  method write (line 67) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 73) | fn flush(&mut self) -> IoResult<()> {
  method shutdown (line 83) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {

FILE: src/ws_client_peer.rs
  type WsClient (line 22) | pub struct WsClient(pub Url);
  method construct (line 24) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type WsClientSecure (line 59) | pub struct WsClientSecure(pub Url);
  method construct (line 62) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type WsConnect (line 96) | pub struct WsConnect<T: Specifier>(pub T);
  method construct (line 98) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  function get_ws_client_peer_impl (line 137) | fn get_ws_client_peer_impl<S, F>(uri: &Url, opts: Rc<Options>, f: F) -> ...
  function get_ws_client_peer (line 183) | pub fn get_ws_client_peer(uri: &Url, opts: Rc<Options>) -> BoxedNewPeerF...
  function get_ws_client_peer_wrapped (line 245) | pub fn get_ws_client_peer_wrapped(uri: &Url, inner: Peer, opts: Rc<Optio...

FILE: src/ws_lowlevel_peer.rs
  type WsLlClient (line 19) | pub struct WsLlClient<T: Specifier>(pub T);
  method construct (line 21) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  type WsLlServer (line 48) | pub struct WsLlServer<T: Specifier>(pub T);
  method construct (line 50) | fn construct(&self, p: ConstructParams) -> PeerConstructor {
  function get_ws_lowlevel_peer (line 76) | pub fn get_ws_lowlevel_peer(mode: WsLlContext, mut inner: Peer, opts: Rc...

FILE: src/ws_peer.rs
  type MultiProducerWsSink (line 24) | type MultiProducerWsSink<T> = Rc<
  type WsSource (line 29) | type WsSource<T> = futures::stream::SplitStream<
  type WsSinkWithOneBufferedMessage (line 32) | pub struct WsSinkWithOneBufferedMessage<T> {
  type CompressionMethod (line 39) | pub enum CompressionMethod {
    method uncompress (line 48) | fn uncompress(&self, x: Vec<u8>) -> Vec<u8> {
    method compress (line 91) | fn compress(&self, x: Vec<u8>) -> Vec<u8> {
    method uncompress (line 134) | fn uncompress(&self, x: Vec<u8>) -> Vec<u8> {
    method compress (line 144) | fn compress(&self, x: Vec<u8>) -> Vec<u8> {
  type WsReadWrapper (line 154) | pub struct WsReadWrapper<T: WsStream + 'static> {
  method read (line 174) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  type Mode1 (line 324) | pub enum Mode1 {
  type WsWriteWrapper (line 329) | pub struct WsWriteWrapper<T: WsStream + 'static> {
  method shutdown (line 344) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 372) | fn write(&mut self, buf_: &[u8]) -> IoResult<usize> {
  method flush (line 468) | fn flush(&mut self) -> IoResult<()> {
  method drop (line 483) | fn drop(&mut self) {
  type PeerForWs (line 489) | pub struct PeerForWs(pub Peer);
  method read (line 495) | fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io...
  method shutdown (line 500) | fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
  method write (line 505) | fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
  method flush (line 508) | fn flush(&mut self) -> IoResult<()> {
  type WsPingerState (line 513) | enum WsPingerState {
  type WsPinger (line 520) | pub struct WsPinger<T: WsStream + 'static> {
  function new (line 530) | pub fn new(
  type Item (line 549) | type Item = ();
  type Error (line 550) | type Error = ();
  function poll (line 552) | fn poll(&mut self) -> ::futures::Poll<(), ()> {
  type Duplex (line 633) | pub type Duplex<S> = ::tokio_codec::Framed<S, websocket::r#async::Messag...
  function finish_building_ws_peer (line 635) | pub fn finish_building_ws_peer<S>(opts: &super::Options, duplex: Duplex<...

FILE: src/ws_server_peer.rs
  type WsServer (line 20) | pub struct WsServer<T: Specifier>(pub T);
  method construct (line 22) | fn construct(&self, cp: ConstructParams) -> PeerConstructor {
  function ws_upgrade_peer (line 111) | pub fn ws_upgrade_peer(

FILE: tests/test.rs
  function dflt (line 12) | fn dflt() -> Options {
  function trivial (line 72) | fn trivial() {
  function tcp (line 86) | fn tcp() {
  function ws (line 110) | fn ws() {
  function ws_ll (line 134) | fn ws_ll() {
  function ws_persist (line 159) | fn ws_persist() {
  function unix (line 194) | fn unix() {
  function abstract_ (line 223) | fn abstract_() {
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (602K chars).
[
  {
    "path": ".dockerignore",
    "chars": 7,
    "preview": "target\n"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 467,
    "preview": "# see https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-depen"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "chars": 528,
    "preview": "name: CI\n\non:\n  push:\n    branches: [ \"master\" ]\n  pull_request:\n    branches: [ \"master\" ]\n\nenv:\n  CARGO_TERM_COLOR: al"
  },
  {
    "path": ".github/workflows/container-image-buildah.yml",
    "chars": 7567,
    "preview": "name: Container Image\n\non:\n  workflow_dispatch:\n    inputs:\n      platforms:\n        description: \"comma-separated list "
  },
  {
    "path": ".gitignore",
    "chars": 7,
    "preview": "target\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 10484,
    "preview": "<a name=\"v1.14.0\"></a>\n# [Sunset (v1.14.0)](https://github.com/vi/websocat/releases/tag/v1.14.0) - 12 Nov 2024\n\n* Attemp"
  },
  {
    "path": "Cargo.lock.legacy",
    "chars": 51003,
    "preview": "# This file is automatically @generated by Cargo.\n# It is not intended for manual editing.\n[[package]]\nname = \"adler\"\nve"
  },
  {
    "path": "Cargo.toml",
    "chars": 3581,
    "preview": "[package]\nname = \"websocat\"\nversion = \"1.14.1\"\nauthors = [\"Vitaly \\\"_Vi\\\" Shukela <vi0oss@gmail.com>\"]\nlicense = \"MIT\"\nr"
  },
  {
    "path": "Dockerfile",
    "chars": 780,
    "preview": "# Build stage\nFROM rust:1.87.0-alpine3.20 AS cargo-build\n\nRUN apk add --no-cache musl-dev pkgconfig openssl-dev\n\nWORKDIR"
  },
  {
    "path": "Dockerfile.debian",
    "chars": 1005,
    "preview": "# Build stage\nFROM rust:1.87.0-bookworm AS cargo-build\n\nRUN apt-get update\nRUN apt-get install -y libgcc-12-dev libc6-de"
  },
  {
    "path": "LICENSE",
    "chars": 1071,
    "preview": "MIT License\n\nCopyright (c) 2016 Vitaly Shukela\n\nPermission is hereby granted, free of charge, to any person obtaining a "
  },
  {
    "path": "README.md",
    "chars": 29820,
    "preview": "# websocat\nNetcat, curl and socat for [WebSockets](https://en.wikipedia.org/wiki/WebSocket).\n\n[![Gitter](https://badges."
  },
  {
    "path": "doc.md",
    "chars": 44223,
    "preview": "\n# Websocat Reference (in progress)\n\nWebsocat has many command-line options and special format for positional arguments."
  },
  {
    "path": "misc/prebuilt_release_settings.sh",
    "chars": 779,
    "preview": "targetsettings() {\n  EXTRA_CARGO_FLAGS=\"--features=vendored_openssl,openssl-probe\"\n  case \"$1\" in\n     i686-unknown-linu"
  },
  {
    "path": "moreexamples.md",
    "chars": 25076,
    "preview": "More examples to avoid bloating up README or specifier-specific docs.\n\n\n# SSL (TLS) and wss://\n\n## Connecting to wss:// "
  },
  {
    "path": "src/all_peers.rs",
    "chars": 5208,
    "preview": "// This is an X-Macro.\n#[macro_export]\nmacro_rules! list_of_all_specifier_classes {\n    ($your_macro:ident) => {\n       "
  },
  {
    "path": "src/broadcast_reuse_peer.rs",
    "chars": 7938,
    "preview": "extern crate futures;\nextern crate tokio_io;\n\nuse futures::future::ok;\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse sup"
  },
  {
    "path": "src/crypto_peer.rs",
    "chars": 6675,
    "preview": "use argon2::Argon2;\nuse futures::Async;\nuse futures::future::ok;\n\nuse std::rc::Rc;\n\nuse super::{BoxedNewPeerFuture, Peer"
  },
  {
    "path": "src/file_peer.rs",
    "chars": 3687,
    "preview": "use futures;\nuse futures::Async;\nuse std;\nuse std::io::Result as IoResult;\nuse std::io::{Read, Write};\nuse std::path::{P"
  },
  {
    "path": "src/foreachmsg_peer.rs",
    "chars": 14117,
    "preview": "use futures::future::ok;\n\nuse std::rc::Rc;\n\nuse super::{BoxedNewPeerFuture, Peer};\nuse super::{ConstructParams, PeerCons"
  },
  {
    "path": "src/help.rs",
    "chars": 6725,
    "preview": "use super::{Opt, SpecifierClass, StructOpt};\n\nfn spechelp(sc: &dyn SpecifierClass, overlays: bool, advanced: bool) {\n   "
  },
  {
    "path": "src/http_peer.rs",
    "chars": 18742,
    "preview": "\n#![allow(unused)]\n#![allow(clippy::needless_pass_by_value,clippy::cast_lossless,clippy::identity_op)]\nuse futures::futu"
  },
  {
    "path": "src/http_serve.rs",
    "chars": 4339,
    "preview": "use self::hyper::http::h1::Incoming;\nuse self::hyper::method::Method;\nuse self::hyper::uri::RequestUri;\nuse self::hyper:"
  },
  {
    "path": "src/jsonrpc_peer.rs",
    "chars": 4279,
    "preview": "use futures::future::ok;\n\nuse std::rc::Rc;\n\nuse super::{BoxedNewPeerFuture, Peer};\nuse super::{ConstructParams, PeerCons"
  },
  {
    "path": "src/lengthprefixed_peer.rs",
    "chars": 8284,
    "preview": "use futures::future::ok;\n\nuse std::rc::Rc;\n\nuse crate::{io_other_error, simple_err, peer_strerr};\n\nuse super::{BoxedNewP"
  },
  {
    "path": "src/lib.rs",
    "chars": 6721,
    "preview": "//! Note: library usage is not semver/API-stable\n//!\n//! Type evolution of a websocat run:\n//!\n//! 1. `&str` - string as"
  },
  {
    "path": "src/line_peer.rs",
    "chars": 9183,
    "preview": "use futures::future::ok;\n\nuse std::rc::Rc;\n\nuse super::{BoxedNewPeerFuture, Peer};\nuse super::{ConstructParams, PeerCons"
  },
  {
    "path": "src/lints.rs",
    "chars": 27564,
    "preview": "#![allow(clippy::collapsible_if,clippy::needless_pass_by_value)]\n\nuse super::{Options, Result, SpecifierClass, Specifier"
  },
  {
    "path": "src/main.rs",
    "chars": 39072,
    "preview": "#![allow(renamed_and_removed_lints)]\n#![allow(unknown_lints)]\n#![allow(clippy::deprecated_cfg_attr)]\n\n#[macro_use]\nexter"
  },
  {
    "path": "src/mirror_peer.rs",
    "chars": 6024,
    "preview": "use super::{BoxedNewPeerFuture, Peer};\n\nuse super::{brokenpipe, io_other_error, wouldblock};\nuse futures;\nuse futures::s"
  },
  {
    "path": "src/my_copy.rs",
    "chars": 6377,
    "preview": "use std::io;\n\nuse futures::{Future, Poll};\n\nuse crate::{AsyncRead, AsyncWrite};\n\n#[derive(Debug, Copy, Clone)]\npub struc"
  },
  {
    "path": "src/net_peer.rs",
    "chars": 16848,
    "preview": "extern crate net2;\n\nuse futures;\nuse futures::future::Future;\nuse futures::stream::Stream;\nuse futures::unsync::oneshot:"
  },
  {
    "path": "src/options.rs",
    "chars": 4421,
    "preview": "pub use super::socks5_peer::SocksSocketAddr;\n\nuse super::readdebt::DebtHandling;\n\nuse std::ffi::OsString;\nuse std::net::"
  },
  {
    "path": "src/primitive_reuse_peer.rs",
    "chars": 4081,
    "preview": "extern crate futures;\nextern crate tokio_io;\n\nuse futures::future::ok;\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse sup"
  },
  {
    "path": "src/process_peer.rs",
    "chars": 8906,
    "preview": "extern crate tokio_process;\n\nuse futures;\nuse std::io::Result as IoResult;\nuse std::io::{Read, Write};\nuse std::{self, p"
  },
  {
    "path": "src/prometheus_peer.rs",
    "chars": 9634,
    "preview": "use futures::future::ok;\nuse futures::{Async};\nuse prometheus::core::{AtomicU64, Atomic};\n\nuse std::cell::RefCell;\nuse s"
  },
  {
    "path": "src/readdebt.rs",
    "chars": 2213,
    "preview": "use std;\n\n#[derive(Debug, Clone, Copy)]\npub enum DebtHandling {\n    Silent,\n    Warn,\n    DropMessage,\n}\n\npub enum ZeroM"
  },
  {
    "path": "src/reconnect_peer.rs",
    "chars": 10571,
    "preview": "extern crate futures;\nextern crate tokio_io;\n\nuse futures::future::ok;\nuse std::cell::RefCell;\nuse std::rc::Rc;\n\nuse sup"
  },
  {
    "path": "src/sessionserve.rs",
    "chars": 11095,
    "preview": "use super::futures::{Future, Stream};\nuse super::{\n    futures, my_copy, ConstructParams, L2rUser, L2rWriter, Options, P"
  },
  {
    "path": "src/socks5_peer.rs",
    "chars": 14192,
    "preview": "#![allow(clippy::needless_pass_by_value,clippy::cast_lossless,clippy::identity_op)]\nuse futures::future::{err, ok, Futur"
  },
  {
    "path": "src/specifier.rs",
    "chars": 11198,
    "preview": "use super::{L2rUser, Options, Result};\nuse super::{PeerConstructor, ProgramState};\nuse std;\nuse std::cell::RefCell;\nuse "
  },
  {
    "path": "src/specparse.rs",
    "chars": 4334,
    "preview": "use super::{Result};\nuse super::specifier::{Specifier, SpecifierClass, SpecifierStack, SpecifierNode};\nuse std::rc::Rc;\n"
  },
  {
    "path": "src/ssl_peer.rs",
    "chars": 8343,
    "preview": "use futures::future::{ok, Future};\n\nuse std::rc::Rc;\n\nuse super::{box_up_err, peer_err, BoxedNewPeerFuture, Peer};\nuse s"
  },
  {
    "path": "src/stdio_peer.rs",
    "chars": 7601,
    "preview": "#[cfg(unix)]\nextern crate tokio_file_unix;\nextern crate tokio_reactor;\n#[cfg(all(unix, feature = \"signal_handler\"))]\next"
  },
  {
    "path": "src/stdio_threaded_peer.rs",
    "chars": 2000,
    "preview": "extern crate tokio_stdin_stdout;\n\nuse super::{BoxedNewPeerFuture, Peer};\n\nuse super::{once, ConstructParams, PeerConstru"
  },
  {
    "path": "src/timestamp_peer.rs",
    "chars": 2426,
    "preview": "use futures::future::ok;\n\nuse std::rc::Rc;\n\nuse super::{BoxedNewPeerFuture, Peer};\nuse super::{ConstructParams, PeerCons"
  },
  {
    "path": "src/trivial_peer.rs",
    "chars": 15661,
    "preview": "use super::{BoxedNewPeerFuture, Peer};\n\nuse futures;\nuse rand::RngCore;\nuse std;\nuse std::io::Result as IoResult;\nuse st"
  },
  {
    "path": "src/unix_peer.rs",
    "chars": 17151,
    "preview": "extern crate tokio_reactor;\nextern crate tokio_uds;\n\nextern crate libc;\n\nuse futures;\nuse futures::stream::Stream;\nuse s"
  },
  {
    "path": "src/unix_seqpacket_peer.rs",
    "chars": 7574,
    "preview": "extern crate tokio_reactor;\n\nuse super::{\n    futures, libc, multi, once, peer_err_s, simple_err, BoxedNewPeerFuture, Bo"
  },
  {
    "path": "src/util.rs",
    "chars": 4821,
    "preview": "use super::{\n    futures, AsyncRead, AsyncWrite, BoxedNewPeerFuture, BoxedNewPeerStream, L2rUser, Peer,\n    PeerConstruc"
  },
  {
    "path": "src/windows_np_peer.rs",
    "chars": 2123,
    "preview": "extern crate tokio_named_pipes;\n\nuse futures;\nuse std;\nuse std::io::Result as IoResult;\nuse std::io::{Read, Write};\nuse "
  },
  {
    "path": "src/ws_client_peer.rs",
    "chars": 8327,
    "preview": "extern crate hyper;\nextern crate websocket;\n\nuse self::websocket::client::r#async::ClientNew;\nuse self::websocket::strea"
  },
  {
    "path": "src/ws_lowlevel_peer.rs",
    "chars": 2742,
    "preview": "#![allow(unused)]\n\nextern crate websocket_base;\n\nuse futures::future::Future;\nuse futures::stream::Stream;\n\nuse std::cel"
  },
  {
    "path": "src/ws_peer.rs",
    "chars": 26711,
    "preview": "extern crate tokio_codec;\nextern crate websocket;\nextern crate base64;\n\nuse self::websocket::stream::r#async::Stream as "
  },
  {
    "path": "src/ws_server_peer.rs",
    "chars": 10087,
    "preview": "extern crate hyper;\nextern crate websocket;\n\nuse self::hyper::uri::RequestUri::AbsolutePath;\n\nuse self::websocket::WebSo"
  },
  {
    "path": "test.sh",
    "chars": 1454,
    "preview": "#!/bin/bash\n\nif [ \"$TRAVIS_OS_NAME\" = \"osx\" ]; then\n    echo \"Not supported on Mac\";\n    exit 0\nfi\n\nset -ex\n\nPATH=target"
  },
  {
    "path": "test_help.sh",
    "chars": 2596,
    "preview": "#!/bin/bash\n\n# This test tracks how much of Websocat functionality is implemented by inspecting the help message\n\ntrue $"
  },
  {
    "path": "tests/test.rs",
    "chars": 4825,
    "preview": "extern crate websocat;\n\nextern crate env_logger;\nextern crate futures;\nextern crate tokio;\nextern crate tokio_timer;\n\nus"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the vi/websocat GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (559.8 KB), approximately 153.7k tokens, and a symbol index with 588 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!