<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ryo Ota</title>
    <description>The latest articles on DEV Community by Ryo Ota (@nwtgck).</description>
    <link>https://dev.to/nwtgck</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F72478%2Fe8a81766-a1ae-4441-8e98-7d4faeb88309.png</url>
      <title>DEV Community: Ryo Ota</title>
      <link>https://dev.to/nwtgck</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nwtgck"/>
    <language>en</language>
    <item>
      <title>Secure TCP tunnel from anywhere with curl and nc for single connection</title>
      <dc:creator>Ryo Ota</dc:creator>
      <pubDate>Wed, 11 May 2022 12:41:38 +0000</pubDate>
      <link>https://dev.to/nwtgck/secure-tcp-tunnel-from-anywhere-with-curl-and-nc-for-single-connection-2k5i</link>
      <guid>https://dev.to/nwtgck/secure-tcp-tunnel-from-anywhere-with-curl-and-nc-for-single-connection-2k5i</guid>
      <description>&lt;p&gt;This post provides a secure and highly transparent way for port forwarding or tunneling a single TCP connection, using only &lt;code&gt;nc&lt;/code&gt; and &lt;code&gt;curl&lt;/code&gt;. Moreover, it also provides more secure tunneling with end-to-end encryptions using &lt;code&gt;openssl&lt;/code&gt; and &lt;code&gt;socat&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0o6mcfr4uzr8k9mz7pl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0o6mcfr4uzr8k9mz7pl.gif" alt="SSH port forwarding using nc and curl over Piping Server"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server host&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/aaa | nc localhost 22 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/bbb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | nc &lt;span class="nt"&gt;-lp&lt;/span&gt; 2222 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Why port forwarding from anywhere?
&lt;/h2&gt;

&lt;p&gt;Today's application is everywhere. We often want to access an application on our remote machine. It is useful to make the remote application as if it is in local. To achieve that, port forwarding or tunneling is widely used for accessing a private remote port from a local machine. A common approach for secure port forwarding is using &lt;code&gt;ssh -L&lt;/code&gt;. This is a very secure connection over SSH. However, exposing SSH port in public may not be allowed because of firewall or NAT. We sometimes need to port forward seamlessly no matter where we are. Besides, since SSH is very powerful, it allows us to use a shell by default even when we want to use only port forwarding without arbitrary command execution. In addition, some environments may not allow to install and run an SSH server, which usually needs the root permission.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why nc and curl?
&lt;/h2&gt;

&lt;p&gt;Some tools allow us to port forward from anywhere. However, as far as I know, they require us to install their own dedicated command. Some of them are open source projects, but I wanted a more transparent way because a shorter chain of trust should be better.&lt;/p&gt;

&lt;p&gt;I found a higher transparent way that uses existing and widely used commands: &lt;code&gt;nc&lt;/code&gt; and &lt;code&gt;curl&lt;/code&gt;. The original idea of a port forwarding with &lt;code&gt;socat&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, and &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; was proposed in &lt;a href="https://qiita.com/Cryolite/items/ed8fa237dd8eab54ef2f" rel="noopener noreferrer"&gt;a Japanese article&lt;/a&gt; by @Cryolite. Meanwhile, this post introduces a way using &lt;code&gt;nc&lt;/code&gt; (&lt;code&gt;netcat&lt;/code&gt;), which is more widely used and installed than &lt;code&gt;socat&lt;/code&gt;, and the way allows simple integration with other commands using Unix pipe. It is very helpful when using an untrustable server because we can integrate it with an encryption command such as &lt;code&gt;openssl&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Piping Server
&lt;/h2&gt;

&lt;p&gt;Here is an introduction to &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;. I developed Piping Server, which streams any data infinitely between every device over pure HTTP/HTTPS.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nwtgck" rel="noopener noreferrer"&gt;
        nwtgck
      &lt;/a&gt; / &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;
        piping-server
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Infinitely transfer between every device over pure HTTP with pipes or browsers
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Piping Server&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/piping-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c2b87528eacfe9d491d0f912e2900b7259aae0a7cee8cf2a6a3f040ead58f4ed/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f706970696e672d7365727665722e737667" alt="npm"&gt;&lt;/a&gt; &lt;a href="https://www.codefactor.io/repository/github/nwtgck/piping-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/24a6232ea92b9ab623f218849802fb33f3389198e531b3c5ac60f07a31fb5bf7/68747470733a2f2f7777772e636f6465666163746f722e696f2f7265706f7369746f72792f6769746875622f6e777467636b2f706970696e672d7365727665722f6261646765" alt="CodeFactor"&gt;&lt;/a&gt; &lt;a href="https://ci.appveyor.com/project/nwtgck/piping-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/408b3e2f2c2660302841650a45087aa7a33be492804da9e4cfebb7c9443886d2/68747470733a2f2f63692e6170707665796f722e636f6d2f6170692f70726f6a656374732f7374617475732f673037356f333064357070346d3070613f7376673d74727565" alt="Build status"&gt;&lt;/a&gt; &lt;a href="https://github.com/nwtgck/piping-server/actions" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/nwtgck/piping-server/workflows/Node%20CI/badge.svg" alt="GitHub Actions"&gt;&lt;/a&gt; &lt;a href="https://hub.docker.com/r/nwtgck/piping-server/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7961f6d8d919a7dacdb559d8fdac16b9f7f0e8c69fc5bba3d1f4a8631cf90ba7/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f6175746f6d617465642f6e777467636b2f706970696e672d7365727665722e737667" alt="Docker Automated build"&gt;&lt;/a&gt; &lt;a href="https://microbadger.com/images/nwtgck/piping-server" title="Get your own image badge on microbadger.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8bea780bb470264900796a36af77cced9fc38c9e8cfc1d92707798d2cdb46d15/68747470733a2f2f696d616765732e6d6963726f6261646765722e636f6d2f6261646765732f696d6167652f6e777467636b2f706970696e672d7365727665722e737667" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Infinitely transfer between every device over HTTP/HTTPS&lt;br&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/nwtgck/piping-serverdemo_images/piping-server-terminal-hello.gif"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnwtgck%2Fpiping-serverdemo_images%2Fpiping-server-terminal-hello.gif" alt="Piping Server hello" width="600"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Transfer&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Piping Server is simple. You can transfer as follows.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Send&lt;/span&gt;
&lt;span class="pl-c1"&gt;echo&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;hello, world&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; curl -T - https://ppng.io/hello&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Get&lt;/span&gt;
curl https://ppng.io/hello &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; hello.txt&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Piping Server transfers data to &lt;code&gt;POST /hello&lt;/code&gt; or &lt;code&gt;PUT /hello&lt;/code&gt; into &lt;code&gt;GET /hello&lt;/code&gt;. The path &lt;code&gt;/hello&lt;/code&gt; can be anything such as &lt;code&gt;/mypath&lt;/code&gt; or &lt;code&gt;/mypath/123/&lt;/code&gt;. A sender and receivers who specify the same path can transfer. Both the sender and the recipient can start the transfer first. The first one waits for the other.&lt;/p&gt;
&lt;p&gt;You can also use Web UI like &lt;a href="https://ppng.io" rel="nofollow noopener noreferrer"&gt;https://ppng.io&lt;/a&gt; on your browser. A more modern UI is found in &lt;a href="https://piping-ui.org" rel="nofollow noopener noreferrer"&gt;https://piping-ui.org&lt;/a&gt;, which supports E2E encryption.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Stream&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The most important thing is that the data are streamed. This means that you can &lt;strong&gt;transfer any data infinitely&lt;/strong&gt;. The demo below transfers an infinite text stream with &lt;code&gt;seq inf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nwtgck/piping-serverdemo_images/seq-inf.gif"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnwtgck%2Fpiping-serverdemo_images%2Fseq-inf.gif" alt="infnite text stream" width="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Ideas&lt;/h2&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; is an HTTP server. A sender and recipient who specify the same path such as &lt;code&gt;/mypath&lt;/code&gt; can transfer. The image below is the concept of Piping Server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjc2n5bz3vx76dwqp2g7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjc2n5bz3vx76dwqp2g7s.png" alt="The concept of Piping Server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image above shows the sender who does POST &lt;code&gt;/mypath&lt;/code&gt; and the recipient who does GET &lt;code&gt;/mypath&lt;/code&gt; can transfer. Both the sender and the recipient can start the transfer first. The first one waits for the other. After the sender and recipient connection is established, &lt;code&gt;/mypath&lt;/code&gt; is protected not to be connected until the connection is closed. Closing the path frees the path and anyone can start a new transfer at the path.&lt;/p&gt;

&lt;p&gt;Both POST and PUT methods are the same effect in &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;. Here is a simple example of transferring "hello" to a receiver.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sender: PUT /mypath
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;hello | curl &lt;span class="nt"&gt;-T&lt;/span&gt; - https://ppng.io/mypath
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;receiver: GET /mypath
&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl https://ppng.io/mypath
&lt;span class="go"&gt;hello
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server transfers any kind of data including text and binaries. In addition, the data through a Piping Server are infinitely streamed. The data are only on memory just for a moment and never saved. I posted &lt;a href="https://dev.to/nwtgck/the-power-of-pure-http-screen-share-real-time-messaging-ssh-and-vnc-5ghc"&gt;The Power of Pure HTTP&lt;/a&gt;, which shows how powerful HTTP is and what &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; can do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Public servers
&lt;/h3&gt;

&lt;p&gt;Here are some available public servers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ppng.io" rel="noopener noreferrer"&gt;https://ppng.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://piping.nwtgck.repl.co" rel="noopener noreferrer"&gt;https://piping.nwtgck.repl.co&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ppng.herokuapp.com" rel="noopener noreferrer"&gt;https://ppng.herokuapp.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://piping.nwtgck.repl.co" rel="noopener noreferrer"&gt;https://piping.nwtgck.repl.co&lt;/a&gt; may be faster depending on your location. You can host one using &lt;code&gt;docker run -p 8181:8080 nwtgck/piping-server&lt;/code&gt; instantly or other ways including portable binaries: &lt;a href="https://github.com/nwtgck/piping-server/wiki/How-to-self-host-Piping-Server" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server/wiki/How-to-self-host-Piping-Server&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Port forwarding command
&lt;/h2&gt;

&lt;p&gt;Here is the main part of this post. &lt;/p&gt;

&lt;p&gt;Suppose you have two machines named "server host" which serves 22 port and "client host", and you want to use the 22 port in the server host as a new 2222 port in the client host. The following commands forward the 22 port in the server host to the 2222 port in the client host.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server host&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/aaa | nc localhost 22 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/bbb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | nc &lt;span class="nt"&gt;-lp&lt;/span&gt; 2222 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-s&lt;/code&gt; slient without progress message&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-S&lt;/code&gt; shows error even when &lt;code&gt;-s&lt;/code&gt; used&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-N&lt;/code&gt; Smooth streaming, disalbing buffering of the output stream&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cheat sheat
&lt;/h3&gt;

&lt;p&gt;Though it's very cool to remember and type the commands, we can go to &lt;a href="https://piping-server-command.nwtgck.org" rel="noopener noreferrer"&gt;https://piping-server-command.nwtgck.org&lt;/a&gt; to copy the commands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywgd7eu78hyz0ouzfej6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywgd7eu78hyz0ouzfej6.gif" alt="piping server command sheet"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  GNU nc vs OpenBSD nc vs socat
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;netcat&lt;/code&gt; (&lt;code&gt;nc&lt;/code&gt;) has some variants. The ways of listening are different as follows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GNU nc: &lt;code&gt;nc -lp 2222&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;OpenBSD nc: &lt;code&gt;nc -l 2222&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;socat: &lt;code&gt;socat TCP-LISTEN:2222,reuseaddr -&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host (GNU nc)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | nc &lt;span class="nt"&gt;-lp&lt;/span&gt; 2222 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;span class="c"&gt;# client host (OpenBSD nc)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | nc &lt;span class="nt"&gt;-l&lt;/span&gt; 2222 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;span class="c"&gt;# client host (socat)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | socat TCP-LISTEN:2222,reuseaddr - | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SSH demo
&lt;/h3&gt;

&lt;p&gt;Here is a demo video of forwarding 22 port in my "basil" server to my local 2222 port.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0o6mcfr4uzr8k9mz7pl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0o6mcfr4uzr8k9mz7pl.gif" alt="SSH port forwarding using nc and curl over Piping Server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;SSH is very powerful because you use can create a SOCKS proxy with &lt;code&gt;ssh -D 1080 ...&lt;/code&gt; like a simple VPN, do rsync for fast resumable file transfer, use GUI with &lt;code&gt;ssh -X ...&lt;/code&gt; and mount a remote file system with &lt;a href="https://en.wikipedia.org/wiki/SSHFS" rel="noopener noreferrer"&gt;SSHFS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The example is about SSH since it is literally a well-known protocol. This method allows any TCP port to be forwarded for a single connection not only SSH.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mechanism
&lt;/h2&gt;

&lt;p&gt;The goal of tunneling is as follows, forwarding the 22 port of "server program" to the 2222 port of "client program."&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9qbj7k2jufbja2mk2kte.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9qbj7k2jufbja2mk2kte.png" alt="Mechanism for tunnel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The diagram below illustrates how the two commands above connect each other. All outgoing connections are HTTPS. This means that the tunneling requirements are the same as web browsing. Therefore, you can do the tunneling anywhere.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh21pmuodyvox1eyxtpxw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh21pmuodyvox1eyxtpxw.png" alt="Mechanism of tunnelilng with nc and curl over Piping Server"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;You can control the timing of port forwarding. Each server host side and client host side can start the command first. Each side can close the tunnel by Ctrl+C at any time and the other side command exits at that time, and this frees the paths. Piping Server guarantees the transferred protocol data is only on memory and never stored. The server also guarantees that after port forwarding is established at paths, no one can establish and get the data at the paths until the pre-established tunnel is closed. &lt;/p&gt;
&lt;h2&gt;
  
  
  High transparency
&lt;/h2&gt;

&lt;p&gt;I believe "The less you trust in, the more secure you are."  &lt;/p&gt;

&lt;p&gt;Some tunneling tools require installing additional dedicated CLI. In contrast, the way uses only &lt;code&gt;nc&lt;/code&gt; (netcat) and &lt;code&gt;curl&lt;/code&gt; commands. They are widely used and accepted, and most people know how they work and have already trusted them. You just use the common commands, not need to install and trust extra tools. We can obviously understand that the commands never send any extra information, such as private information or credentials. This means there is no black box at all. Besides, the commands are short enough to remember.&lt;/p&gt;

&lt;p&gt;All communication outside is complete in HTTP/HTTPS. The protocol is also familiar, widely used, accepted, and trusted already. Piping Server is &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;open on GitHub&lt;/a&gt;, developed in TypeScript and Node.js. Other implementations in &lt;a href="https://github.com/nwtgck/piping-server-rust" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; and &lt;a href="https://github.com/nwtgck/go-piping-server" rel="noopener noreferrer"&gt;Go&lt;/a&gt; are provided as open-source. The server is designed to keep simple as possible to verify the source and reduce the potential of bugs.&lt;/p&gt;

&lt;p&gt;In order to improve transparency more and get independent from the pre-hosted public servers, you can &lt;a href="https://github.com/nwtgck/piping-server/wiki/How-to-self-host-Piping-Server" rel="noopener noreferrer"&gt;self host Piping Server&lt;/a&gt;.  When you prefer to limit traffic with basic auth or path, etc., &lt;a href="https://github.com/nwtgck/rich-piping-server" rel="noopener noreferrer"&gt;Rich Piping Server&lt;/a&gt;, which uses internally the original Piping Server as a library, is useful. &lt;/p&gt;

&lt;p&gt;We need to trust a few existing widely accepted command-line tools and &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;. Even if the source of the server is public, the server might have vulnerabilities or might be modified maliciously. To avoid those concerns, I will introduce end-to-end encryption (E2E encryption) for higher-level security. E2E encryption allows us not to trust the server and make us secure.&lt;/p&gt;
&lt;h2&gt;
  
  
  Universal end-to-end encryption
&lt;/h2&gt;

&lt;p&gt;The section describes secure tunneling even if a &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; is untrustable. As you know, all HTTPS traffic to the server is encrypted. However, what if the server is compromised or malicious? Tunneling SSH is one of the solutions. This section provides a more universal end-to-end encryption way for any protocol.&lt;/p&gt;

&lt;p&gt;The idea is simple, which decrypts incoming streams and encrypts outgoing streams as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server host (idea)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/aaa | &amp;lt;decrypt&amp;gt; | nc localhost 22 | &amp;lt;encrypt&amp;gt; |curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/bbb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host (idea)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | &amp;lt;decrypt&amp;gt; | nc &lt;span class="nt"&gt;-lp&lt;/span&gt; 2222 | &amp;lt;encrypt&amp;gt; | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The real commands using &lt;code&gt;openssl&lt;/code&gt; are as follows. Although &lt;code&gt;openssl&lt;/code&gt; commands are used, any kind of encryption commands can be replaced with existing commands or future-invented commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server host&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/aaa | &lt;span class="nb"&gt;stdbuf&lt;/span&gt; &lt;span class="nt"&gt;-i0&lt;/span&gt; &lt;span class="nt"&gt;-o0&lt;/span&gt; openssl aes-256-ctr &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-pass&lt;/span&gt; &lt;span class="s2"&gt;"pass:mypass"&lt;/span&gt; &lt;span class="nt"&gt;-bufsize&lt;/span&gt; 1 &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; | nc localhost 22 | &lt;span class="nb"&gt;stdbuf&lt;/span&gt; &lt;span class="nt"&gt;-i0&lt;/span&gt; &lt;span class="nt"&gt;-o0&lt;/span&gt; openssl aes-256-ctr &lt;span class="nt"&gt;-pass&lt;/span&gt; &lt;span class="s2"&gt;"pass:mypass"&lt;/span&gt; &lt;span class="nt"&gt;-bufsize&lt;/span&gt; 1 &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/bbb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | &lt;span class="nb"&gt;stdbuf&lt;/span&gt; &lt;span class="nt"&gt;-i0&lt;/span&gt; &lt;span class="nt"&gt;-o0&lt;/span&gt; openssl aes-256-ctr &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-pass&lt;/span&gt; &lt;span class="s2"&gt;"pass:mypass"&lt;/span&gt; &lt;span class="nt"&gt;-bufsize&lt;/span&gt; 1 &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; | nc &lt;span class="nt"&gt;-lp&lt;/span&gt; 2222 | &lt;span class="nb"&gt;stdbuf&lt;/span&gt; &lt;span class="nt"&gt;-i0&lt;/span&gt; &lt;span class="nt"&gt;-o0&lt;/span&gt; openssl aes-256-ctr &lt;span class="nt"&gt;-pass&lt;/span&gt; &lt;span class="s2"&gt;"pass:mypass"&lt;/span&gt; &lt;span class="nt"&gt;-bufsize&lt;/span&gt; 1 &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;stdbuf -i0 -o0 &amp;lt;command&amp;gt;&lt;/code&gt; disables buffers for real-time streaming.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;aes-256-ctr&lt;/code&gt; is a stream cipher.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-pbkdf2&lt;/code&gt; derives key from the password using &lt;a href="https://en.wikipedia.org/wiki/PBKDF2" rel="noopener noreferrer"&gt;PBKDF2&lt;/a&gt;. This is optional but makes it more secure.&lt;/li&gt;
&lt;li&gt;The password is &lt;code&gt;mypass&lt;/code&gt;. You can replaced with better one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The commands below allow us to input password and hides passwords from commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server host&lt;/span&gt;
&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"password: "&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; pass &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/aaa | &lt;span class="nb"&gt;stdbuf&lt;/span&gt; &lt;span class="nt"&gt;-i0&lt;/span&gt; &lt;span class="nt"&gt;-o0&lt;/span&gt; openssl aes-256-ctr &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-pass&lt;/span&gt; &lt;span class="s2"&gt;"pass:&lt;/span&gt;&lt;span class="nv"&gt;$pass&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-bufsize&lt;/span&gt; 1 &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; | nc localhost 22 | &lt;span class="nb"&gt;stdbuf&lt;/span&gt; &lt;span class="nt"&gt;-i0&lt;/span&gt; &lt;span class="nt"&gt;-o0&lt;/span&gt; openssl aes-256-ctr &lt;span class="nt"&gt;-pass&lt;/span&gt; &lt;span class="s2"&gt;"pass:&lt;/span&gt;&lt;span class="nv"&gt;$pass&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-bufsize&lt;/span&gt; 1 &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/bbb&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;unset &lt;/span&gt;pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host&lt;/span&gt;
&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"password: "&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; pass &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | &lt;span class="nb"&gt;stdbuf&lt;/span&gt; &lt;span class="nt"&gt;-i0&lt;/span&gt; &lt;span class="nt"&gt;-o0&lt;/span&gt; openssl aes-256-ctr &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-pass&lt;/span&gt; &lt;span class="s2"&gt;"pass:&lt;/span&gt;&lt;span class="nv"&gt;$pass&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-bufsize&lt;/span&gt; 1 &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; | nc &lt;span class="nt"&gt;-lp&lt;/span&gt; 2222 | &lt;span class="nb"&gt;stdbuf&lt;/span&gt; &lt;span class="nt"&gt;-i0&lt;/span&gt; &lt;span class="nt"&gt;-o0&lt;/span&gt; openssl aes-256-ctr &lt;span class="nt"&gt;-pass&lt;/span&gt; &lt;span class="s2"&gt;"pass:&lt;/span&gt;&lt;span class="nv"&gt;$pass&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-bufsize&lt;/span&gt; 1 &lt;span class="nt"&gt;-pbkdf2&lt;/span&gt; | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;unset &lt;/span&gt;pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands are also in &lt;a href="https://piping-server-command.nwtgck.org/" rel="noopener noreferrer"&gt;the cheat sheet&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web browser, not only terminal and the commands
&lt;/h2&gt;

&lt;p&gt;High interoperability matters because it realizes fewer dependencies and less lock-in. This section shows the interoperability, replacing nc and curl with JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://piping-ssh.nwtgck.org/" rel="noopener noreferrer"&gt;Piping SSH&lt;/a&gt; and &lt;a href="https://piping-vnc.nwtgck.org" rel="noopener noreferrer"&gt;Piping VNC&lt;/a&gt; run on Web browser. This means a Web browser is an alternative frontend of &lt;code&gt;curl ... | nc -lp ... | curl ...&lt;/code&gt; and a terminal. Those apps have SSH and VNC (RBF protocol) implementations in JavaScript, thanks to authors of based projects. This means that they work on your local device and never process on the server side. The server is only a Piping Server only for data transferring. See &lt;a href="https://dev.to/nwtgck/the-power-of-pure-http-screen-share-real-time-messaging-ssh-and-vnc-5ghc"&gt;my previous post&lt;/a&gt; for detail.&lt;/p&gt;

&lt;p&gt;Those apps require "fetch() upload streaming", which is only available now in Chromium-based browsers &amp;gt;= 85 with "Experimental Web Platform features" enabled. &lt;a href="https://github.com/whatwg/fetch/pull/425#issuecomment-531680634" rel="noopener noreferrer"&gt;Every major vendors has positive reaction to the "fetch() upload streamingl"&lt;/a&gt;. The video below is an example using Piping SSH.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6avmh1v8856lvu2o5kn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv6avmh1v8856lvu2o5kn.gif" alt="piping ssh"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Virtual_Network_Computing" rel="noopener noreferrer"&gt;VNC&lt;/a&gt; is widely used for remote desktop. The example below has two windows, a Ubuntu on a virtual machine and Piping VNC on Chrome on my local machine. It shows relatively smooth remote desktop.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8upb0trordt8qr4aeni.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw8upb0trordt8qr4aeni.gif" alt="piping vnc"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The port forwarding way has high interoperability because the forwarding command, &lt;code&gt;curl ... | nc ... | curl ...&lt;/code&gt; , in the example videos is the same even when a client runs on Web browser. In this example, &lt;code&gt;fetch()&lt;/code&gt; in JavaScript replaces nc, curl, and terminal. As another example, &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/net/URLConnection.html" rel="noopener noreferrer"&gt;java.net.URLConnection&lt;/a&gt; and &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html" rel="noopener noreferrer"&gt;java.net.Socket&lt;/a&gt; in Java and &lt;a href="https://pkg.go.dev/net#Dial" rel="noopener noreferrer"&gt;net.Dial()&lt;/a&gt; and &lt;a href="https://pkg.go.dev/net/http#Client.Do" rel="noopener noreferrer"&gt;http&lt;/a&gt; in Go language can replace them.&lt;/p&gt;
&lt;h2&gt;
  
  
  E2E encryption VNC
&lt;/h2&gt;

&lt;p&gt;Although the transport to Piping Server is encrypted with TLS because of HTTPS, E2E encryption for VNC is secure if the server is untrustable.&lt;/p&gt;

&lt;p&gt;You can put a check in "Encrypt with OpenSSL AES CTR" below in Piping VNC. It has the same effect as &lt;code&gt;openssl aes-256-ctr -d -pass "pass:mypass" -bufsize 1 -pbkdf2 -iter 100000 -md sha256&lt;/code&gt; mentioned in the "Universal end-to-end encryption" section above.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ulewvaa66noxkf740wp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ulewvaa66noxkf740wp.png" alt="Piping VNC OpenSSL AES CTR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Piping VNC automatically generates a command you should type on the server host side.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmyizm8ok9i0odpx4o6oj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmyizm8ok9i0odpx4o6oj.png" alt="Piping VNC command hint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How is it possible in Web browser? I made &lt;a href="https://github.com/nwtgck/openssl-aes-ctr-stream-npm" rel="noopener noreferrer"&gt;https://github.com/nwtgck/openssl-aes-ctr-stream-npm&lt;/a&gt; for using OpenSSL-compatible AES CTR encryption/decryption in Web browser. The concept is very simple as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Encrypt the ReadableStream `uploadReadableStream`&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encryptedUploadReadableStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;opensslAesCtrStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;aesCtrEncryptWithPbkdf2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;uploadReadableStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;options&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Transfer the encrypted stream&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pipingServerUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;encryptedUploadReadableStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(simplified version of &lt;a href="https://github.com/nwtgck/piping-vnc-web/blob/8f2df75c7452b515fcc2ba36fe9cbf6218c673fc/core/websock.js#L205-L214" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-vnc-web/blob/8f2df75c7452b515fcc2ba36fe9cbf6218c673fc/core/websock.js#L205-L214&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;openssl-aes-ctr-stream&lt;/code&gt; implementation is shorter than 200 lines: &lt;a href="https://github.com/nwtgck/openssl-aes-ctr-stream-npm/blob/d071752009b0c6262f6c27722b438cb73cdb7cab/src/index.ts" rel="noopener noreferrer"&gt;https://github.com/nwtgck/openssl-aes-ctr-stream-npm/blob/d071752009b0c6262f6c27722b438cb73cdb7cab/src/index.ts&lt;/a&gt;. The major browsers provide &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle#browser_compatibility" rel="noopener noreferrer"&gt;Web Crypto API&lt;/a&gt;. &lt;code&gt;openssl-aes-ctr-stream&lt;/code&gt; uses AES-CTR in the Web Crypto API.&lt;/p&gt;

&lt;p&gt;Here is a demo video of E2E encryption VNC. Because of the E2E encryption, the screen is laggier than without it.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs814g5irv5ls2kowwfeo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs814g5irv5ls2kowwfeo.gif" alt="E2E encryption Piping VNC"&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://piping-vnc.nwtgck.org" rel="noopener noreferrer"&gt;https://piping-vnc.nwtgck.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because the protocol of OpenSSL is open, we can stay highly interoperable with implementation in the other language.&lt;/p&gt;
&lt;h2&gt;
  
  
  Universal end-to-end encryption over TLS
&lt;/h2&gt;

&lt;p&gt;This section introduces the way to encrypt pre-listened TCP port using TLS with socat. This is also a universal E2E encryption way. The advantages of the way are that you can use well-trusted TLS and encryptions with sharing certificates instead a password. &lt;/p&gt;

&lt;p&gt;In the server host, create certificates as follows. It generates &lt;code&gt;server.crt&lt;/code&gt;,  &lt;code&gt;server.key&lt;/code&gt; and &lt;code&gt;server.pem&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server host&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:4096 &lt;span class="nt"&gt;-keyout&lt;/span&gt; server.key &lt;span class="nt"&gt;-out&lt;/span&gt; server.crt &lt;span class="nt"&gt;-days&lt;/span&gt; 3653 &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s1"&gt;'/CN=localhost/'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;server.key server.crt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; server.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a client host, create certificates as follows. It generates &lt;code&gt;client.crt&lt;/code&gt;,  &lt;code&gt;client.key&lt;/code&gt; and &lt;code&gt;client.pem&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host&lt;/span&gt;
openssl req &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa:4096 &lt;span class="nt"&gt;-keyout&lt;/span&gt; client.key &lt;span class="nt"&gt;-out&lt;/span&gt; client.crt &lt;span class="nt"&gt;-days&lt;/span&gt; 3653 &lt;span class="nt"&gt;-sha256&lt;/span&gt; &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s1"&gt;'/CN=localhost/'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;client.key client.crt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; client.pem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Share &lt;code&gt;server.crt&lt;/code&gt; to the client host and share &lt;code&gt;client.crt&lt;/code&gt; to the server host respectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  server host
&lt;/h3&gt;

&lt;p&gt;Suppose the server host serves 8181 port and you want to forward the 8181 to a client with encryption. Open two terminals in server host and run the following commands. Make sure to run socat in the directory which has &lt;code&gt;server.pem&lt;/code&gt; and &lt;code&gt;client.crt&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;socat openssl-listen:4433,reuseaddr,cert&lt;span class="o"&gt;=&lt;/span&gt;server.pem,cafile&lt;span class="o"&gt;=&lt;/span&gt;client.crt tcp:localhost:8181
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/aaa | nc localhost 4433 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/bbb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  client host
&lt;/h3&gt;

&lt;p&gt;Open two terminals in the client host and run the following commands. Make sure to run socat in the directory which has &lt;code&gt;client.pem&lt;/code&gt; and &lt;code&gt;server.crt&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | nc &lt;span class="nt"&gt;-lp&lt;/span&gt; 5433 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;socat tcp-listen:8282,reuseaddr openssl-connect:localhost:5433,openssl-commonname&lt;span class="o"&gt;=&lt;/span&gt;localhost,cert&lt;span class="o"&gt;=&lt;/span&gt;client.pem,cafile&lt;span class="o"&gt;=&lt;/span&gt;server.crt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the 8282 port in the client host is the decrypted TCP port forwarded to 8181 in the server host. When the protocol of the 8181 port in the server host is HTTP, you can use &lt;code&gt;curl localhost:8282&lt;/code&gt; in the client host.&lt;/p&gt;

&lt;p&gt;Here is a graph to describe how this E2EE works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[server host 8181 &amp;lt;--&amp;gt; 4433] &amp;lt;-- TLS over HTTPS --&amp;gt; [Piping Server] &amp;lt;-- TLS over HTTPS --&amp;gt; [5433 &amp;lt;--&amp;gt; 8282 client host]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The way is based on &lt;a href="http://www.dest-unreach.org/socat/doc/socat-openssltunnel.html" rel="noopener noreferrer"&gt;Securing Traffic Between two Socat Instances Using SSL&lt;/a&gt; found on the socat official page. If you encountered &lt;code&gt;Invalid argument&lt;/code&gt; error in macOS with socat, you can upgrade socat 1.7.4.2 or later, which is fixed.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Universal end-to-end encryption over SSH
&lt;/h2&gt;

&lt;p&gt;You can simply use &lt;code&gt;ssh -L&lt;/code&gt; as follows when a machine on server host side has SSH server. SSH also multiplexes TCP connections over single SSH connection.&lt;/p&gt;

&lt;p&gt;Suppose you want to forward 8080 port in server host with encryption to 8181 port in client host. Suppose the server host listens SSH on 22 port. The command below forwards 22 to 2222 and 8080 to 8181.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server host&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/aaa | nc localhost 22 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/bbb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host 1/2&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | nc &lt;span class="nt"&gt;-lp&lt;/span&gt; 2222 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host 2/2&lt;/span&gt;
ssh &lt;span class="nt"&gt;-p&lt;/span&gt; 2222 &lt;span class="nt"&gt;-L&lt;/span&gt; 8181:localhost:8080 &amp;lt;server host user&amp;gt;@localhost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you can access localhost:8181 in the client host.&lt;/p&gt;

&lt;h2&gt;
  
  
  bonus: Multiple TCP connections
&lt;/h2&gt;

&lt;p&gt;The way introduced here allows forwarding a single TCP connection. A single TCP connection is enough for SSH and VNC (RFB protocol). This feature sometimes contributes to greater security since one connection is always guaranteed. However, for instance, HTTP generally requires multiple TCP connections even when HTTP/2, which multiplexes  request and response streams, is available.&lt;/p&gt;

&lt;p&gt;A simple solution is to multiplex TCP requests over Unix pipe. In order to multiplex TCP requests, &lt;a href="https://github.com/hashicorp/yamux" rel="noopener noreferrer"&gt;Yamux&lt;/a&gt; is available created by Hashicorp, who creates &lt;a href="https://www.vagrantup.com/" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt;, &lt;a href="https://www.terraform.io/" rel="noopener noreferrer"&gt;Terraform&lt;/a&gt;, and so on. The protocol of Yamux is inspired by SPDY, which is the basis of HTTP/2 specification. The protocol spec is found in &lt;a href="https://github.com/hashicorp/yamux/blob/master/spec.md" rel="noopener noreferrer"&gt;https://github.com/hashicorp/yamux/blob/master/spec.md&lt;/a&gt;. libp2p, which is used in &lt;a href="https://ipfs.io/" rel="noopener noreferrer"&gt;IPFS&lt;/a&gt;, also uses Yamux as one choice of multiplexes and maintains Go and Rust versions of Yamux libraries.&lt;/p&gt;

&lt;p&gt;I made a yamux CLI and distribute its portable binaries for multi-platforms. You can install it from &lt;a href="https://github.com/nwtgck/yamux-cli" rel="noopener noreferrer"&gt;https://github.com/nwtgck/yamux-cli&lt;/a&gt; and replaces &lt;code&gt;nc&lt;/code&gt; with &lt;code&gt;yamux&lt;/code&gt; as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server host&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/aaa | yamux localhost 8080 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/bbb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | yamux &lt;span class="nt"&gt;-l&lt;/span&gt; 8181 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzec8x744u4k6byaor28f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzec8x744u4k6byaor28f.gif" alt="yamux + curl"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also combine this yamux and E2E commands to make it more secure.&lt;/p&gt;

&lt;p&gt;This topic is in a bonus section since its way requires an additional CLI. The way of the section "Universal end-to-end encryption over SSH" also allows multiple TCP connections because &lt;code&gt;ssh -L&lt;/code&gt; also multiplexes TCP connections.&lt;/p&gt;

&lt;h2&gt;
  
  
  bonus: UDP
&lt;/h2&gt;

&lt;p&gt;TCP is a perfect fit for Unix pipe because TCP delivers streams. In contrast, UDP delivers datagrams, so boundaries are needed to deliver multiple datagrams over Unix pipe. I successfully run &lt;code&gt;dig&lt;/code&gt; command for forwarded DNS using &lt;code&gt;nc -u&lt;/code&gt;. However, multiple datagrams are not processed. To solve this problem, I made an experimental option to &lt;code&gt;yamux&lt;/code&gt; cli for UDP.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server host (experimental)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/aaa | yamux &lt;span class="nt"&gt;-u&lt;/span&gt; localhost 53 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/bbb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client host (experimental)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSN&lt;/span&gt; https://ppng.io/bbb | yamux &lt;span class="nt"&gt;-ul&lt;/span&gt; 1053 | curl &lt;span class="nt"&gt;-sSNT&lt;/span&gt; - https://ppng.io/aaa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"Experimental" means that I may change the way of transferring over Yamux. Datagrams from the same address are delivered over the same Yamux stream. The data structure is simple, which has datagram length in 4 bytes in network byte order and raw datagram.&lt;/p&gt;

&lt;p&gt;In my experiment, HTTP/3, HTTP over QUIC, can be port forwarded over Piping Server. Actually, I realized HTTP/3 Piping Server over Piping Server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://qiita.com/Cryolite/items/ed8fa237dd8eab54ef2f" rel="noopener noreferrer"&gt;Japanese article of port forwarding using socat and curl&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;GitHub repository of Pipnig Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nwtgck/piping-server-rust" rel="noopener noreferrer"&gt;GitHub repository Piping Server in Rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nwtgck/piping-server/wiki/How-to-self-host-Piping-Server" rel="noopener noreferrer"&gt;How to self host Piping Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://piping-server-command.nwtgck.org" rel="noopener noreferrer"&gt;Command cheat sheet&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cover image by &lt;a href="https://unsplash.com/@errior?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Fabian Jung&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>networking</category>
      <category>security</category>
      <category>transparency</category>
    </item>
    <item>
      <title>Why HTTP streaming upload matters on Web browser</title>
      <dc:creator>Ryo Ota</dc:creator>
      <pubDate>Wed, 10 Nov 2021 11:32:42 +0000</pubDate>
      <link>https://dev.to/nwtgck/why-http-streaming-upload-matters-on-web-browser-559k</link>
      <guid>https://dev.to/nwtgck/why-http-streaming-upload-matters-on-web-browser-559k</guid>
      <description>&lt;p&gt;We want to make the web better. I believe fetch() upload streaming is a key to making the web simpler, safer and faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Available, but giving up to shipping ...
&lt;/h2&gt;

&lt;p&gt;Looking back in history, the document of fetch() upload streaming seems to have started 7 years ago. The latest document is under whatwg/fetch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Favkmuwuivl8tcsjwsea1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Favkmuwuivl8tcsjwsea1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yutakahirano/fetch-with-streams/commits/master?after=3653e535378143663ade61e13064ce3561fbcf68+34" rel="noopener noreferrer"&gt;https://github.com/yutakahirano/fetch-with-streams/commits/master?after=3653e535378143663ade61e13064ce3561fbcf68+34&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Main browser vendors have positive reactions as follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpmdzg3tv2i99rsgj725z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpmdzg3tv2i99rsgj725z.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/whatwg/fetch/pull/425#issuecomment-531680634" rel="noopener noreferrer"&gt;https://github.com/whatwg/fetch/pull/425#issuecomment-531680634&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At last, we have the fetch() upload streaming feature since Chrome 85. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wm8mbdco9ald6o304cq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wm8mbdco9ald6o304cq.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a&gt;chrome://flags/#enable-experimental-web-platform-features&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;However, the Chromium team is going to give up to shipping the feature&lt;/strong&gt;. That is the reason why the post is here.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We worked with a parter but we failed to show benefits of the feature, so we're giving up shipping the feature. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://bugs.chromium.org/p/chromium/issues/detail?id=688906#c57" rel="noopener noreferrer"&gt;https://bugs.chromium.org/p/chromium/issues/detail?id=688906#c57&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.chrome.com/origintrials/#/view_trial/3524066708417413121" rel="noopener noreferrer"&gt;The origin trial&lt;/a&gt; ends today, Nov 10, 2021.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Web browser needs fetch() upload streaming
&lt;/h2&gt;

&lt;p&gt;HTTP is the core transfer technology on the web. It is an open, widely used and trusted protocol. And we are building more rich and complex applications on the web. Some of them may deal with high-resolution videos and others may provide high-level security with E2E encryption. The fetch() upload streaming allows us to do both upload and data transformations at the same. So, we can upload while encoding rich videos in client-side. We can upload while encrypting files in client-side, which archives E2E encryption. In addition, it is easy to combine multiple transformations and build a complex one. &lt;strong&gt;The fetch() upload streaming is more efficient in terms of both time and space&lt;/strong&gt; than transforming whole data.&lt;/p&gt;

&lt;p&gt;The most important thing is that it has high compatibility. Our world is made up of all kinds of software that are integrated together. Streaming upload in HTTP is already available in common software such as Java (JVM languages), Node.js, Go, Swift, curl, etc. &lt;strong&gt;These common software has built-in HTTP streaming upload&lt;/strong&gt;. &lt;strong&gt;I believe that built-in availability is the biggest difference&lt;/strong&gt; from WebSocket, WebRTC and upcoming WebTransport. The streaming upload coming to web browser makes web server simpler, instead of creating another WebSocket API, etc. only for web browser. Eliminating extra entrances or branches can reduce code size, reduce unexpected behaviors and improve maintainability and safety. HTTP is a widely accepted protocol and provide practical API than raw TCP. As far as I know, HTTP is the only one that has this power.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple, but powerful
&lt;/h2&gt;

&lt;p&gt;API is very simple as follows. You can pass ReadableStream to &lt;code&gt;fetch()&lt;/code&gt;. The streaming upload is the most general transfer in HTTP, which allows us to transfer conventional fixed-length data and infinite data stream.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;myReadableStream&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here is an example of how to create ReadableStream emitting infinite random bytes.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myReadableStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReadableStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nf"&gt;pull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// random bytes&lt;/span&gt;
    &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here is how to convert MediaStream to ReadableStream. This can apply screen share, web camera, voice or other sources which are from MediaStream.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="c1"&gt;// Convert MediaStream to ReadableStream&lt;/span&gt;&lt;br&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mediaStreamToReadableStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mediaStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeslice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReadableStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;br&gt;
    &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recorder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MediaRecorder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mediaStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
      &lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ondataavailable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
        &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;&lt;br&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;&lt;br&gt;
      &lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeslice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c1"&gt;// Usage:&lt;/span&gt;&lt;br&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mediaStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDisplayMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;br&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myReadableStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mediaStreamToReadableStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mediaStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Everything over HTTP&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;As another real example, here is a stream encrypting another stream using OpenPGP. The demo shows end-to-end encrypting (E2EE), encrypting, uploading, downloading and decrypting at the same time. In the demo below, the client is a web browser. Yet, &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;gpg&lt;/code&gt; are also compatible with sending and receiving since behind-the-system is a pure HTTP streaming upload.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkitdhqqck1aoadlg6bzg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkitdhqqck1aoadlg6bzg.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nwtgck/piping-ui-web/issues/433#issuecomment-830734031" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-ui-web/issues/433#issuecomment-830734031&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is another example. This is &lt;a href="https://github.com/nwtgck/piping-ssh-web/blob/31af6a4f130445a184dd3bb0376ed092f5fe2370/src/index.js#L201-L223" rel="noopener noreferrer"&gt;SSH over HTTP&lt;/a&gt;. Everything including SSH client is complete in web browser. SSH client is also implemented in web browser powered by &lt;a href="https://github.com/stuicey/SSHy" rel="noopener noreferrer"&gt;SSHy&lt;/a&gt; project. So, this is also E2E encryption under SSH.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhmzvl761y9m9jzb143j.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhmzvl761y9m9jzb143j.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nwtgck/piping-ssh-web" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-ssh-web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is &lt;a href="https://github.com/nwtgck/piping-vnc-web/blob/8f2df75c7452b515fcc2ba36fe9cbf6218c673fc/core/websock.js#L208-L238" rel="noopener noreferrer"&gt;VNC over HTTP&lt;/a&gt;. VNC is for remote control. VNC client is complete in web browser powered by &lt;a href="https://github.com/novnc/noVNC" rel="noopener noreferrer"&gt;noVNC&lt;/a&gt; project. The application below also provides &lt;a href="https://github.com/nwtgck/piping-vnc-web/blob/8f2df75c7452b515fcc2ba36fe9cbf6218c673fc/core/websock.js#L206" rel="noopener noreferrer"&gt;E2E encryption using &lt;code&gt;openssl aes-256-ctr&lt;/code&gt;-command-compatible way&lt;/a&gt; which encrypts streamingly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywba7cad4cwk8v57ixwy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fywba7cad4cwk8v57ixwy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nwtgck/piping-vnc-web" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-vnc-web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those two applications tunnel a TCP port over pure HTTP. So, simple commands using &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;nc&lt;/code&gt; or &lt;code&gt;socat&lt;/code&gt; can also be a client, not only web browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  With built-in software
&lt;/h2&gt;

&lt;p&gt;It is worth noting that in those examples, the web browser is just one of clients. This means &lt;code&gt;java.net.HttpURLConnection&lt;/code&gt; in the &lt;strong&gt;standard library&lt;/strong&gt; in JVM languages can be a client, &lt;code&gt;net/http&lt;/code&gt; in the &lt;strong&gt;standard library&lt;/strong&gt; in Go can be a client, &lt;code&gt;URLSession#uploadTask(withStreamedRequest: request)&lt;/code&gt; in &lt;strong&gt;Foundation&lt;/strong&gt; in Swift can be a client. The fetch() upload streaming allows our web browsers to be one. Without it, this highly compatibile feature is not available since there is no alternative and it is impossible to create a polyfill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The feature allows us to transfer infinitely in real-time and give efficiency in both time and space, which was never allowed before and it is impossible to create polyfill. It also gives us to communicate with other built-in software seemly and keep web servers simpler, safe and more maintainable.&lt;/p&gt;

&lt;p&gt;I love the feature. I love the fetch() upload streaming. Infinite stream has infinite possibilities. I hope this post would be a good one for you to know how great this feature is.&lt;/p&gt;

&lt;h2&gt;
  
  
  More about the feature
&lt;/h2&gt;

&lt;p&gt;The links below would be helpful to know more.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fetch.spec.whatwg.org/#concept-body-stream" rel="noopener noreferrer"&gt;whatwg spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugs.chromium.org/p/chromium/issues/detail?id=688906" rel="noopener noreferrer"&gt;Chromium issue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1387483" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugs.webkit.org/show_bug.cgi?id=203617" rel="noopener noreferrer"&gt;Safari&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.dev/fetch-upload-streaming" rel="noopener noreferrer"&gt;web.dev&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.chromestatus.com/feature/5274139738767360" rel="noopener noreferrer"&gt;Chrome Platform Status&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/document/d/e/2PACX-1vQ26giyHPPhxrgVorNtkVSsJPOWecc6c6wHFLFbbl27r0BIBEgRwahh2b37Uk7HfXvZoW1Cu_ed-bRm/pub" rel="noopener noreferrer"&gt;Chromium Design Doc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/nwtgck/the-power-of-pure-http-screen-share-real-time-messaging-ssh-and-vnc-5ghc"&gt;my post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://scrapbox.io/nwtgck/SSH%E6%8E%A5%E7%B6%9A%E3%82%92Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AE%E7%B4%94%E7%B2%8B%E3%81%AAHTTP%E4%B8%8A%E3%81%A7%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B" rel="noopener noreferrer"&gt;my post in Japanese (SSH)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://scrapbox.io/nwtgck/%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88%E3%83%87%E3%82%B9%E3%82%AF%E3%83%88%E3%83%83%E3%83%97%E6%93%8D%E4%BD%9C%E3%82%92Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AE%E7%B4%94%E7%B2%8B%E3%81%AAHTTP%E4%B8%8A%E3%81%A7%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B%EF%BC%88VNC%EF%BC%89" rel="noopener noreferrer"&gt;my post in Japanese (VNC)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@rzunikoff?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Robert  Zunikoff&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/stream?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>chromium</category>
      <category>chrome</category>
    </item>
    <item>
      <title>The Power of Pure HTTP – screen share, real-time messaging, SSH and VNC</title>
      <dc:creator>Ryo Ota</dc:creator>
      <pubDate>Thu, 17 Dec 2020 15:27:07 +0000</pubDate>
      <link>https://dev.to/nwtgck/the-power-of-pure-http-screen-share-real-time-messaging-ssh-and-vnc-5ghc</link>
      <guid>https://dev.to/nwtgck/the-power-of-pure-http-screen-share-real-time-messaging-ssh-and-vnc-5ghc</guid>
      <description>&lt;p&gt;Hi all. Today, I'd like to show you the power of &lt;strong&gt;pure HTTP&lt;/strong&gt; stream, which allows us to do screen sharing, video chatting, real-time text messaging, SSH, VNC, and so on. The demo videos below show &lt;strong&gt;SSH and VNC&lt;/strong&gt; over pure HTTP. Let's dive into this!&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fybf1uh546zgbb9dpefo8.gif" alt="SSH over Piping Server"&gt;&lt;/td&gt;
    &lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgm08i1qrqkfuzy9p22kx.gif" alt="VNC over Piping Server"&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;&lt;a href="https://github.com/nwtgck/piping-ssh-web" rel="noopener noreferrer"&gt;SSH on Web browser&lt;/a&gt;&lt;/td&gt;
    &lt;td&gt;&lt;a href="https://github.com/nwtgck/piping-vnc-web" rel="noopener noreferrer"&gt;VNC on Web browser&lt;/a&gt;&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why HTTP?
&lt;/h2&gt;

&lt;p&gt;HTTP is everywhere for everyone and everything, which allows us to communicate in any situation. HTTP is one of the most mature protocols and wildly used. You can find HTTP in web browser in personal computers including Windows, Mac and Linux, smartphones and tablets including Android, iPhone and iPad, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;wget&lt;/code&gt; commands in your terminal, some IoT devices, automation tools such as &lt;a href="https://support.apple.com/guide/shortcuts/welcome/ios" rel="noopener noreferrer"&gt;Shortcuts&lt;/a&gt; iOS app and &lt;a href="https://www.microsoft.com/en-us/p/microsoft-flow/9nkn0p5l9n84" rel="noopener noreferrer"&gt;Microsoft Flow&lt;/a&gt;, Web Hooks and so on. Additionally, HTTP is an evolving protocol as HTTP/2, HTTP/3 and getting faster.&lt;/p&gt;

&lt;p&gt;Usuary, an HTTP request has a short life, used for fetching HTML/CSS/JavaScript, media and API requests. So, this post introduces long-life HTTP request, which does real-time communications over pure HTTP stream without WebSocket and WebRTC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Piping Server
&lt;/h2&gt;

&lt;p&gt;I made &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;, which allows us to transfer data between every device.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nwtgck" rel="noopener noreferrer"&gt;
        nwtgck
      &lt;/a&gt; / &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;
        piping-server
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Infinitely transfer between every device over pure HTTP with pipes or browsers
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Piping Server&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/piping-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c2b87528eacfe9d491d0f912e2900b7259aae0a7cee8cf2a6a3f040ead58f4ed/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f706970696e672d7365727665722e737667" alt="npm"&gt;&lt;/a&gt; &lt;a href="https://www.codefactor.io/repository/github/nwtgck/piping-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/24a6232ea92b9ab623f218849802fb33f3389198e531b3c5ac60f07a31fb5bf7/68747470733a2f2f7777772e636f6465666163746f722e696f2f7265706f7369746f72792f6769746875622f6e777467636b2f706970696e672d7365727665722f6261646765" alt="CodeFactor"&gt;&lt;/a&gt; &lt;a href="https://ci.appveyor.com/project/nwtgck/piping-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/408b3e2f2c2660302841650a45087aa7a33be492804da9e4cfebb7c9443886d2/68747470733a2f2f63692e6170707665796f722e636f6d2f6170692f70726f6a656374732f7374617475732f673037356f333064357070346d3070613f7376673d74727565" alt="Build status"&gt;&lt;/a&gt; &lt;a href="https://github.com/nwtgck/piping-server/actions" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/nwtgck/piping-server/workflows/Node%20CI/badge.svg" alt="GitHub Actions"&gt;&lt;/a&gt; &lt;a href="https://hub.docker.com/r/nwtgck/piping-server/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7961f6d8d919a7dacdb559d8fdac16b9f7f0e8c69fc5bba3d1f4a8631cf90ba7/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f6175746f6d617465642f6e777467636b2f706970696e672d7365727665722e737667" alt="Docker Automated build"&gt;&lt;/a&gt; &lt;a href="https://microbadger.com/images/nwtgck/piping-server" title="Get your own image badge on microbadger.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8bea780bb470264900796a36af77cced9fc38c9e8cfc1d92707798d2cdb46d15/68747470733a2f2f696d616765732e6d6963726f6261646765722e636f6d2f6261646765732f696d6167652f6e777467636b2f706970696e672d7365727665722e737667" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Infinitely transfer between every device over HTTP/HTTPS&lt;br&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/nwtgck/piping-serverdemo_images/piping-server-terminal-hello.gif"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnwtgck%2Fpiping-serverdemo_images%2Fpiping-server-terminal-hello.gif" alt="Piping Server hello" width="600"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Transfer&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Piping Server is simple. You can transfer as follows.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Send&lt;/span&gt;
&lt;span class="pl-c1"&gt;echo&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;hello, world&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; curl -T - https://ppng.io/hello&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Get&lt;/span&gt;
curl https://ppng.io/hello &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; hello.txt&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Piping Server transfers data to &lt;code&gt;POST /hello&lt;/code&gt; or &lt;code&gt;PUT /hello&lt;/code&gt; into &lt;code&gt;GET /hello&lt;/code&gt;. The path &lt;code&gt;/hello&lt;/code&gt; can be anything such as &lt;code&gt;/mypath&lt;/code&gt; or &lt;code&gt;/mypath/123/&lt;/code&gt;. A sender and receivers who specify the same path can transfer. Both the sender and the recipient can start the transfer first. The first one waits for the other.&lt;/p&gt;
&lt;p&gt;You can also use Web UI like &lt;a href="https://ppng.io" rel="nofollow noopener noreferrer"&gt;https://ppng.io&lt;/a&gt; on your browser. A more modern UI is found in &lt;a href="https://piping-ui.org" rel="nofollow noopener noreferrer"&gt;https://piping-ui.org&lt;/a&gt;, which supports E2E encryption.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Stream&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The most important thing is that the data are streamed. This means that you can &lt;strong&gt;transfer any data infinitely&lt;/strong&gt;. The demo below transfers an infinite text stream with &lt;code&gt;seq inf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nwtgck/piping-serverdemo_images/seq-inf.gif"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnwtgck%2Fpiping-serverdemo_images%2Fseq-inf.gif" alt="infnite text stream" width="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Ideas&lt;/h2&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; is simple. A sender and recipient who specify the same path such as &lt;code&gt;/hello&lt;/code&gt; can transfer. The image below is the concept of transfer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjc2n5bz3vx76dwqp2g7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjc2n5bz3vx76dwqp2g7s.png" alt="The concept of Piping Server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image shows the sender who POSTs &lt;code&gt;/mypath&lt;/code&gt; and the recipient GETs &lt;code&gt;/mypath&lt;/code&gt; can transfer. Both the sender and the recipient can start the transfer first. The first one waits for the other. Both POST and PUT methods are the same in &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can transfer a text by using &lt;code&gt;fetch()&lt;/code&gt; in JavaScript like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Send&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ppng.io/hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello, world&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Get&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ppng.io/hello&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="c1"&gt;// =&amp;gt; "hello, world"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use &lt;code&gt;curl&lt;/code&gt; command like below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsxo2v4pq5llq21exw0pm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsxo2v4pq5llq21exw0pm.gif" alt="Piping Server text transfer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also transfer binary data such as an image and a video like below. As you can see, the recipient just opened the URL on the browser to get the image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fveuc48jx49423odtn719.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fveuc48jx49423odtn719.gif" alt="Piping Server image transfer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;HTTP is everywhere. So we can transfer data freely without any extra tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infinitely transfer
&lt;/h3&gt;

&lt;p&gt;The most notable feature of &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; is allowing you to &lt;strong&gt;transfer infinite data&lt;/strong&gt;. The demo below shows inputting  text streams into the web browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj44x8zr5hh8hjymph6u3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj44x8zr5hh8hjymph6u3.gif" alt="sender: curl, receiver: browser"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Send folder
&lt;/h4&gt;

&lt;p&gt;You can transfer a folder (a directory), which has multiple files as follows. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnqcq3aik7lfhbt6qhwpk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnqcq3aik7lfhbt6qhwpk.gif" alt="Piping Server directory sending"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Send folder&lt;/span&gt;
&lt;span class="nb"&gt;tar &lt;/span&gt;c ./mydir | curl &lt;span class="nt"&gt;-T&lt;/span&gt; - https://ppng.io/mypath
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Get folder&lt;/span&gt;
curl https://ppng.io/mypath | &lt;span class="nb"&gt;tar &lt;/span&gt;xv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The files are packing while uploading in the sender and unpacking while downloading in the recipient. Stream makes this possible without creating a temporary file.&lt;/p&gt;

&lt;p&gt;It is easy to end-to-end encrypt your data and transfer as follows.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;send: &lt;code&gt;... | openssl aes-256-cbc | curl -T ...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;get: &lt;code&gt;curl ... | openssl aes-256-cbc -d&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is also easy to reduce the size by compression as follows.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;send: &lt;code&gt;... | gzip | curl -T ...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;get: &lt;code&gt;curl ... | zcat&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can transform data as you want such as &lt;code&gt;gpg&lt;/code&gt;, &lt;code&gt;zip&lt;/code&gt; or tools invented in the future. Combining pipe is efficient in terms of both time and memory. Unix pipe is an amazing way to combine software. The name of Piping Server is derived from Unix pipe.&lt;/p&gt;

&lt;p&gt;The most common use case of &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; is a file transfer. For transferring files, you can use &lt;a href="https://github.com/nwtgck/piping-ui-web" rel="noopener noreferrer"&gt;Piping UI&lt;/a&gt;, which allows you to transfer securely with end-to-end encryption over many devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Transfer huge data for a long time
&lt;/h2&gt;

&lt;p&gt;Here are simple experiments to transfer data over HTTP using &lt;strong&gt;local and remote&lt;/strong&gt; &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The demo video below shows 45TB is transferred for 2,092 hours (87 days) over HTTP via remote &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;, using &lt;code&gt;cat /dev/zero | curl -T- ...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhpijr3jofzs2rg80v6c6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhpijr3jofzs2rg80v6c6.gif" alt="remote Piping Server 45TB, 87 days"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image below shows transferred 1,110TB (≈ 1PB) for 64 days over HTTP via local &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp0wd1ww1upnev2q90qcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp0wd1ww1upnev2q90qcw.png" alt="local Piping Server 1110TB, 64 days"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These experiments show a huge amount of data can be continuously transferred over a single HTTP request and a single HTTP request lives long enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Infinite stream for Web browser
&lt;/h2&gt;

&lt;p&gt;Infinite stream sending over HTTP had come to Web browser at last!&lt;/p&gt;

&lt;p&gt;Google Chrome 85 or above has the feature as origin trial. Open &lt;code&gt;chrome://flags&lt;/code&gt; and enable "Experimental Web Platform features" as follows&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgxh2jb55z15v10fz5i1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgxh2jb55z15v10fz5i1b.png" alt="Experimental Web Platform features"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Other main browsers such as Firefox and Safari are also interested in this feature.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmjxvlrbl9ixbi4atk4b9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmjxvlrbl9ixbi4atk4b9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/whatwg/fetch/pull/425#issuecomment-531680634" rel="noopener noreferrer"&gt;Uploading a Request made from a ReadableStream body by yutakahirano · Pull Request #425 · whatwg/fetch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a nutshell, this feature allows us to send &lt;code&gt;ReadableStream&lt;/code&gt; as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ReadableStream&lt;/span&gt; &lt;span class="nx"&gt;here&lt;/span&gt;&lt;span class="o"&gt;!&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Simple text messaging
&lt;/h3&gt;

&lt;p&gt;Here is a simple text messaging on Web browser with &lt;code&gt;fetch()&lt;/code&gt; and &lt;code&gt;ReadableStream&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbp82n02rzubl7p9ayg9s.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbp82n02rzubl7p9ayg9s.gif" alt="sender: browser, receiver: browser"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code below creates &lt;code&gt;ReadableStream&lt;/code&gt; from user input and sends the input stream to &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;. The recipient just opens the URL on the browser and sees streamed text messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;readableStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReadableStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myinput&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onkeyup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ppng.io/mytext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;readableStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain;charset=UTF-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;allowHTTP1ForStreamingUpload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(full: &lt;a href="https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/text_stream.html" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/text_stream.html&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;allowHTTP1ForStreamingUpload&lt;/code&gt; in the code is a temporary property in Chrome to allow us to use this feature over HTTP/1.1 (see: &lt;a href="https://chromium.googlesource.com/chromium/src/+/4c75c0c9f730589ad8d6c33af919d6b105be1462" rel="noopener noreferrer"&gt;4c75c0c9f730589ad8d6c33af919d6b105be1462 - chromium/src - Git at Google&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Screen sharing
&lt;/h3&gt;

&lt;p&gt;You can share your screen in almost the same way as the text streaming above. Get &lt;code&gt;MediaStream&lt;/code&gt; and convert to &lt;code&gt;ReadableStream&lt;/code&gt; and send the stream to &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; with &lt;code&gt;fetch()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0unx6iydwnvl8ayf5y11.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0unx6iydwnvl8ayf5y11.gif" alt="Piping Server screen sharing"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The function &lt;code&gt;mediaStreamToReadableStream()&lt;/code&gt; below converts &lt;code&gt;MediaStream&lt;/code&gt; to &lt;code&gt;ReadableStream&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get display&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mediaStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDisplayMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="c1"&gt;// Convert MediaStream to ReadableStream&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;readableStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mediaStreamToReadableStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mediaStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ppng.io/myvideo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;readableStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;allowHTTP1ForStreamingUpload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;

&lt;span class="c1"&gt;// Convert MediaStream to ReadableStream&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;mediaStreamToReadableStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mediaStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;timeslice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReadableStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recorder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MediaRecorder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mediaStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ondataavailable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeslice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(full: &lt;a href="https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/screen_share.html" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/screen_share.html&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The recipient just opens the HTML below with one &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- viewer --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://ppng.io/myvideo"&lt;/span&gt; &lt;span class="na"&gt;autoplay&lt;/span&gt; &lt;span class="na"&gt;muted&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/video&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way is friendy to command-line tools too. You can also view the screen with &lt;code&gt;curl https://ppng.io/myvideo | ffplay -&lt;/code&gt;. You can also send your screen with &lt;code&gt;ffmpeg&lt;/code&gt; command. See &lt;a href="https://trac.ffmpeg.org/wiki/Capture/Desktop" rel="noopener noreferrer"&gt;Capture/Desktop – FFmpeg&lt;/a&gt; for more info.&lt;/p&gt;

&lt;h3&gt;
  
  
  Voice and video chatting
&lt;/h3&gt;

&lt;p&gt;For voice or video chatting, all you need to do is to replace the code, &lt;code&gt;const mediaStream =&lt;/code&gt; above with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Voice&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mediaStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;echoCancellation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// video + voice&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mediaStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mediaDevices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUserMedia&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;video&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;echoCancellation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(voice: &lt;a href="https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/simple_phone.html" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/simple_phone.html&lt;/a&gt;)&lt;br&gt;&lt;br&gt;
(video + voice: &lt;a href="https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/video_chat.html" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/video_chat.html&lt;/a&gt;)  &lt;/p&gt;

&lt;p&gt;Then, you can use the &lt;code&gt;mediaStreamToReadableStream()&lt;/code&gt; to converts those &lt;code&gt;MediaStream&lt;/code&gt;s to &lt;code&gt;ReadableStream&lt;/code&gt;s to specify &lt;code&gt;body:&lt;/code&gt; in &lt;code&gt;fetch()&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Video filtering
&lt;/h3&gt;

&lt;p&gt;You can get &lt;code&gt;MediaStream&lt;/code&gt; from the canvas. The function below creates a video and a canvas in memory and transforms a &lt;code&gt;MediaStream&lt;/code&gt; to another one. &lt;a href="http://joelb.me/jsmanipulate/" rel="noopener noreferrer"&gt;JSManipulate&lt;/a&gt; is used. You may create a filter app like Snap Camera.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Filter for sepia&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sepiaMediaStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mediaStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;memVideo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;video&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;memVideo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;srcObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mediaStream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;memVideo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;memVideo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;memVideo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;videoHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;srcCanvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dstCanvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;canvas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;srcCanvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dstCanvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;srcCanvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dstCanvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;srcCtx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;srcCanvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dstCtx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dstCanvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="nx"&gt;srcCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drawImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memVideo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;srcCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getImageData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;JSManipulate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sepia&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;dstCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;putImageData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;})();&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dstCanvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureStream&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(full: &lt;a href="https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/screen_share_with_filter.html" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/screen_share_with_filter.html&lt;/a&gt;)&lt;br&gt;&lt;br&gt;
(demo video: &lt;a href="https://youtu.be/VcKJR8D8IFA" rel="noopener noreferrer"&gt;https://youtu.be/VcKJR8D8IFA&lt;/a&gt;)  &lt;/p&gt;
&lt;h3&gt;
  
  
  Compression
&lt;/h3&gt;

&lt;p&gt;Compress data with gzip as follows. In Chrome, you can easily compress a stream with &lt;code&gt;readableStream.pipeThrough(new CompressionStream('gzip'))&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F15teu6ebr4ikjzosb3at.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F15teu6ebr4ikjzosb3at.gif"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;readableStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReadableStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nf"&gt;pull&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// random bytes&lt;/span&gt;
    &lt;span class="nx"&gt;ctrl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getRandomValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint32Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;pipeThrough&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CompressionStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gzip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ppng.io/mytext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;readableStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;allowHTTP1ForStreamingUpload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(full: &lt;a href="https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/gzip_inifinite_stream.html" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-streaming-upload-htmls/blob/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/gzip_inifinite_stream.html&lt;/a&gt;)&lt;br&gt;
The sample code sends infinite random bytes with compression over &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  End-to-end encryption for infinite stream
&lt;/h3&gt;

&lt;p&gt;You can safely transfer your stream even if a server is untrustable. You can encrypt any &lt;code&gt;ReadableStream&lt;/code&gt; with the code below using &lt;a href="https://github.com/openpgpjs/openpgpjs" rel="noopener noreferrer"&gt;OpenPGP.js&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Encrypt ReadableStream with password by OpenPGP&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;encryptStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;readableStream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;openpgp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromBinary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;readableStream&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;passwords&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;armor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openpgp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;packets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://youtu.be/lxpxeB_0UDk" rel="noopener noreferrer"&gt;https://youtu.be/lxpxeB_0UDk&lt;/a&gt; is a demo video of end-to-end encrypted screen sharing over &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Service Worker is used on the viewer-side. The purpose of using Service Worker is for getting a decrypted video at &lt;code&gt;https://localhost:8080/e2ee_screen_share/swvideo#myvideo&lt;/code&gt;. Service Worker is used as a proxy. See the full code for detail: &lt;a href="https://github.com/nwtgck/piping-server-streaming-upload-htmls/tree/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/e2ee_screen_share" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-streaming-upload-htmls/tree/a107dd1fb1bbee9991a9278b10d9eaf88b52c395/e2ee_screen_share&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Web browsers have &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API" rel="noopener noreferrer"&gt;Web Crypto&lt;/a&gt;, which can generate keys safely and do Diffie-Hellman key exchange an untrustable channel. For example, &lt;a href="https://github.com/nwtgck/piping-ui-web" rel="noopener noreferrer"&gt;Piping UI&lt;/a&gt;, which is a file transfer tool, exchanges public keys and encrypts a file by using ECDH and &lt;a href="https://github.com/openpgpjs/openpgpjs" rel="noopener noreferrer"&gt;OpenPGP.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Access the repository below to get other examples using &lt;code&gt;fetch()&lt;/code&gt; upload streaming feature with &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://github.com/nwtgck/piping-server-streaming-upload-htmls" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-streaming-upload-htmls&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  SSH over HTTP
&lt;/h2&gt;

&lt;p&gt;As you see, any data can be streamed over HTTP. So, this means a protocol can be over HTTP via &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why Piping Server?
&lt;/h3&gt;

&lt;p&gt;There are some environments that can not release ports public. For such kind of environment, when you have the only outward-connection to HTTP/HTTPS ports, you can use SSH. A possible example is for GitHub Actions, which does not support SSH debug like CircleCI (see: &lt;a href="https://github.com/nwtgck/actions-comment-run/tree/0cd21bd0c811a3f27ea219bdb5788cc2dc23d789#ssh-in-github-actions-over-piping-server" rel="noopener noreferrer"&gt;SSH in GitHub Actions over Piping Server&lt;/a&gt;). &lt;/p&gt;
&lt;h3&gt;
  
  
  SSH client in JavaScirpt
&lt;/h3&gt;

&lt;p&gt;I found a wonderful project, &lt;a href="https://github.com/stuicey/SSHy" rel="noopener noreferrer"&gt;SSHy&lt;/a&gt; whose JavaScript speaks SSH. The data communication is over WebSocket, so I just need to switch WebSocket to HTTP with &lt;code&gt;fetch()&lt;/code&gt;. Unfortunately, although &lt;a href="https://github.com/stuicey/SSHy" rel="noopener noreferrer"&gt;SSHy&lt;/a&gt; is not actively maintained now, this is a perfect fit for my proof of concept to speak SSH over HTTP using &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;. We could port OpenSSH by using &lt;a href="https://emscripten.org/" rel="noopener noreferrer"&gt;Emscripten&lt;/a&gt;, write Rust and compile to Web Assembly, or do something in the future.&lt;/p&gt;

&lt;p&gt;By using &lt;a href="https://github.com/stuicey/SSHy" rel="noopener noreferrer"&gt;SSHy&lt;/a&gt;, it is possible to SSH with only Web browser and &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;. The data streamed to &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; is securely encrypted since the communication is SSH.&lt;/p&gt;
&lt;h3&gt;
  
  
  How to SSH over Piping Server?
&lt;/h3&gt;

&lt;p&gt;Create two sets of connections over &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; for duplex communication. One of them is for sending data to your peer. The other one is for receiving data from your peer. On HTTP/2, multiple HTTP requests are bundled into one TCP connection.&lt;/p&gt;

&lt;p&gt;The command below is an example to forward 22 port over HTTP via &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;. This way was proposed by &lt;a href="https://github.com/Cryolite" rel="noopener noreferrer"&gt;@Cryolite&lt;/a&gt; in a Japanese great post &lt;a href="https://qiita.com/Cryolite/items/ed8fa237dd8eab54ef2f" rel="noopener noreferrer"&gt;https://qiita.com/Cryolite/items/ed8fa237dd8eab54ef2f&lt;/a&gt;. The data to the 22 port is downloading from &lt;code&gt;/path1&lt;/code&gt; and the data from the 22 port is uploading to &lt;code&gt;/path2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# server-host&lt;/span&gt;
socat &lt;span class="s1"&gt;'EXEC:curl -NsS https\://ppng.io/path1!!EXEC:curl -NsST - https\://ppng.io/path2'&lt;/span&gt; TCP:127.0.0.1:22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The way makes possible NAT traversal without releasing port public over HTTP.&lt;/p&gt;

&lt;p&gt;The command below creates the tunnel with the command above. The 22 port is forwarded to 31376 port in your another machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# client-host&lt;/span&gt;
socat TCP-LISTEN:31376 &lt;span class="s1"&gt;'EXEC:curl -NsS https\://ppng.io/path2!!EXEC:curl -NsST - https\://ppng.io/path1'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can do &lt;code&gt;ssh -p 31376 &amp;lt;user&amp;gt;@localhost&lt;/code&gt; in the machine in another terminal. This is a versatile way to forward a port to another device, not only SSH.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transport implementations of SSHy
&lt;/h3&gt;

&lt;p&gt;The implementation below sends bytes over WebSocket.&lt;br&gt;
&lt;a href="https://github.com/stuicey/SSHy/blob/82941c8ae15359fd387109dcee3a218808df0bb0/index.html#L259-L264" rel="noopener noreferrer"&gt;https://github.com/stuicey/SSHy/blob/82941c8ae15359fd387109dcee3a218808df0bb0/index.html#L259-L264&lt;/a&gt;&lt;br&gt;
&lt;code&gt;ws&lt;/code&gt;, WebSocket instance has a user-defined method, &lt;code&gt;sendB64()&lt;/code&gt; and send Base64-encoded string. A proxy server called &lt;a href="https://github.com/stuicey/wsproxy" rel="noopener noreferrer"&gt;stuicey/wsproxy&lt;/a&gt; is used, which is for proxying WebSocket to TCP (in this case SSH).&lt;/p&gt;

&lt;p&gt;The implementation below receives bytes over WebSocket.&lt;br&gt;
&lt;a href="https://github.com/stuicey/SSHy/blob/82941c8ae15359fd387109dcee3a218808df0bb0/index.html#L233-L236" rel="noopener noreferrer"&gt;https://github.com/stuicey/SSHy/blob/82941c8ae15359fd387109dcee3a218808df0bb0/index.html#L233-L236&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  SSH over Piping Server
&lt;/h4&gt;

&lt;p&gt;These sending and receiving parts are replaced &lt;code&gt;fetch()&lt;/code&gt; and a way of using &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;. The code below is the replaced implementation.&lt;br&gt;
&lt;a href="https://github.com/nwtgck/piping-ssh-web/blob/287e89ef05173e69d1302b29acf2abbe858ee78b/index.html#L187-L219" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-ssh-web/blob/287e89ef05173e69d1302b29acf2abbe858ee78b/index.html#L187-L219&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The application is called Piping SSH. Here is a demo video.  In it, logging in Ubuntu machine from the web browser and type &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;htop&lt;/code&gt; command.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fybf1uh546zgbb9dpefo8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fybf1uh546zgbb9dpefo8.gif" alt="SSH over Piping Server"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application: &lt;a href="https://piping-ssh.nwtgck.org" rel="noopener noreferrer"&gt;https://piping-ssh.nwtgck.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/nwtgck/piping-ssh-web" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-ssh-web&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  TIPS: Keep-alive of SSH
&lt;/h3&gt;

&lt;p&gt;In Chrome, an HTTP request is stopped when no bytes arrived for 60 seconds. To resolve the issue, you can set &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt; as follows in your SSH server setting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# /etc/ssh/sshd_config
# ...
ClientAliveInterval 20
ClientAliveCountMax 3
# ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  VNC over HTTP
&lt;/h2&gt;

&lt;p&gt;VNC (Virtual Network Computing) is widely used for controlling the computer remotely.&lt;/p&gt;

&lt;p&gt;Here is the demo video. The front window is a Chrome, Web browser and the back one is a controlled machine on Ubuntu on VirtualBox.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgm08i1qrqkfuzy9p22kx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgm08i1qrqkfuzy9p22kx.gif" alt="VNC over Piping Server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application: &lt;a href="https://piping-vnc.nwtgck.org" rel="noopener noreferrer"&gt;https://piping-vnc.nwtgck.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/nwtgck/piping-vnc-web" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-vnc-web&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Ubuntu 20.04 users, to enable VNC, you can turn on Settings &amp;gt; Sharing and run &lt;code&gt;gsettings set org.gnome.Vino require-encryption false&lt;/code&gt; to avoid an error, "Failed when connecting: Unsupported security types (types: 18)".&lt;/p&gt;

&lt;p&gt;VNC is also available for Windows. Here is a demo controlling Windows 10 from Chrome. It was more smooth on a real Windows machine since the windows machine in the demo below was running on VirtualBox. &lt;a href="https://www.uvnc.com" rel="noopener noreferrer"&gt;UltraVNC&lt;/a&gt; is running on the Windows machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxc72hqv25a083sftd1bw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxc72hqv25a083sftd1bw.gif" alt="Piping VNC controlling Windows 10"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fetch-uploading feature is also available on Android Chrome. The demo below controls Windows 10 by an Android smartphone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fummq5s2lsf37csq225q8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fummq5s2lsf37csq225q8.gif" alt="Piping VNC controlled by Android"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For windows users, you can a download tunneling tool over Piping Server here: &lt;a href="https://github.com/nwtgck/go-piping-tunnel" rel="noopener noreferrer"&gt;https://github.com/nwtgck/go-piping-tunnel&lt;/a&gt;. It is convenient to create a simple .bat file as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;.\piping&lt;span class="na"&gt;-tunnel &lt;/span&gt;&lt;span class="kd"&gt;server&lt;/span&gt; &lt;span class="na"&gt;-p &lt;/span&gt;&lt;span class="m"&gt;5900&lt;/span&gt; &lt;span class="kd"&gt;path1&lt;/span&gt; &lt;span class="kd"&gt;path2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;piping-tunnel&lt;/code&gt; has the same feature of the &lt;code&gt;socat&lt;/code&gt; + &lt;code&gt;curl&lt;/code&gt; command. For mac users, you can install by &lt;code&gt;brew install nwtgck/piping-tunnel/piping-tunnel&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;The application is fully based on &lt;a href="https://github.com/novnc/noVNC" rel="noopener noreferrer"&gt;noVNC&lt;/a&gt;, which is a VNC client written in JavaScript. Only transport implementations are replaced with the way of using fetch and &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; instead of WebSocket.&lt;/p&gt;

&lt;p&gt;Here is the diff for replacing WebSocket transportation with fetch and &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://github.com/nwtgck/piping-vnc-web/commit/1e1f2863160bfab8c9fbfc4c6970cd2b31135bfd" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-vnc-web/commit/1e1f2863160bfab8c9fbfc4c6970cd2b31135bfd&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Network in Web browser
&lt;/h3&gt;

&lt;p&gt;Here is the network in the Chrome DevTools. There are only two pure HTTPS connections. &lt;code&gt;v86&lt;/code&gt; is uploading and &lt;code&gt;7vk&lt;/code&gt; is downloading. As you can see the download size of &lt;code&gt;v86&lt;/code&gt; is increasing. Although &lt;code&gt;7vk&lt;/code&gt; is uploading, the view in the current Chrome says "pending".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxawnbz1123x94qm2rzz8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxawnbz1123x94qm2rzz8.gif" alt="Piping VNC network"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  fetch() upload streaming
&lt;/h2&gt;

&lt;p&gt;I have been following this feature. Here are useful links to get information about the fetch() upload streaming feature.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;whatwg: &lt;a href="https://fetch.spec.whatwg.org/#concept-body-stream" rel="noopener noreferrer"&gt;Fetch Standard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;whatwg issue: &lt;a href="https://github.com/whatwg/fetch/pull/425" rel="noopener noreferrer"&gt;Uploading a Request made from a ReadableStream body by yutakahirano · Pull Request #425 · whatwg/fetch&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chromium commits: &lt;a href="https://bugs.chromium.org/p/chromium/issues/detail?id=688906" rel="noopener noreferrer"&gt;688906 - Streaming upload support - chromium&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.chromestatus.com/feature/5274139738767360" rel="noopener noreferrer"&gt;fetch() upload streaming - Chrome Platform Status&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;web.dev: &lt;a href="https://web.dev/fetch-upload-streaming/" rel="noopener noreferrer"&gt;Streaming requests with the fetch API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Firefox: &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1387483" rel="noopener noreferrer"&gt;1387483 - [Meta-Bug] Support ReadableStream as Request.body in fetch API&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Firefox: &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1469359" rel="noopener noreferrer"&gt;1469359 - Support ReadableStream as Request.body in fetch API in necko&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Safari: &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=203617" rel="noopener noreferrer"&gt;203617 – "ReadableStream uploading is not supported" when fetch()ing a Request that has been logged to console&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Public Piping Server
&lt;/h2&gt;

&lt;p&gt;Here are public Piping Servers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ppng.io" rel="noopener noreferrer"&gt;https://ppng.io&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;alias: &lt;a href="https://piping.ml" rel="noopener noreferrer"&gt;https://piping.ml&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;These aliases can be different servers in the future.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://piping.glitch.me" rel="noopener noreferrer"&gt;https://piping.glitch.me&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://piping-47q675ro2guv.runkit.sh" rel="noopener noreferrer"&gt;https://piping-47q675ro2guv.runkit.sh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ppng.herokuapp.com" rel="noopener noreferrer"&gt;https://ppng.herokuapp.com&lt;/a&gt; (NOTE: Heroku does not support streaming)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Self-hosted Piping Server
&lt;/h2&gt;

&lt;p&gt;Run &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; on &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt; as follows using Docker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 nwtgck/piping-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Single binaries are also available on &lt;a href="https://github.com/nwtgck/piping-server-pkg" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-pkg&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here are easier ways to get public your Piping Server is to use Glitch and Runkit.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;remix from &lt;a href="https://glitch.com/%7Epiping" rel="noopener noreferrer"&gt;https://glitch.com/~piping&lt;/a&gt; and serve it&lt;/li&gt;
&lt;li&gt;clone from &lt;a href="https://runkit.com/nwtgck/piping/" rel="noopener noreferrer"&gt;https://runkit.com/nwtgck/piping/&lt;/a&gt; and serve it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Piping Server with JWT authentication
&lt;/h3&gt;

&lt;p&gt;To restrict users to use &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;, you can use &lt;a href="https://github.com/nwtgck/jwt-piping-server" rel="noopener noreferrer"&gt;https://github.com/nwtgck/jwt-piping-server&lt;/a&gt; with an example using &lt;a href="https://auth0.com" rel="noopener noreferrer"&gt;Auth0&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Piping Server in Rust
&lt;/h2&gt;

&lt;p&gt;Piping Server is also written in Rust. This is the fastest &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; now.&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/nwtgck/piping-server-rust" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-rust&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Base posts
&lt;/h2&gt;

&lt;p&gt;Here are my posts based on this post.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/nwtgck/data-streaming-with-every-device-over-httphttps-mo4"&gt;Data Streaming between Every Device over HTTP/HTTPS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;(Japanese): &lt;a href="https://scrapbox.io/nwtgck/Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E4%B8%8A%E3%81%A7%E7%B4%94%E7%B2%8B%E3%81%AAHTTP%E3%81%A0%E3%81%91%E3%81%A7%E5%8D%98%E6%96%B9%E5%90%91%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%BF%E3%82%A4%E3%83%A0%E9%80%9A%E4%BF%A1%E3%82%92%E5%8F%AF%E8%83%BD%E3%81%AB%E3%81%99%E3%82%8BHTTP%E3%81%AE%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89%E3%81%8C%E9%81%82%E3%81%AB%E3%82%84%E3%81%A3%E3%81%A6%E3%81%8F%E3%82%8B" rel="noopener noreferrer"&gt;https://scrapbox.io/nwtgck/Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E4%B8%8A%E3%81%A7%E7%B4%94%E7%B2%8B%E3%81%AAHTTP%E3%81%A0%E3%81%91%E3%81%A7%E5%8D%98%E6%96%B9%E5%90%91%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%BF%E3%82%A4%E3%83%A0%E9%80%9A%E4%BF%A1%E3%82%92%E5%8F%AF%E8%83%BD%E3%81%AB%E3%81%99%E3%82%8BHTTP%E3%81%AE%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89%E3%81%8C%E9%81%82%E3%81%AB%E3%82%84%E3%81%A3%E3%81%A6%E3%81%8F%E3%82%8B&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(Japanese): &lt;a href="https://scrapbox.io/nwtgck/SSH%E6%8E%A5%E7%B6%9A%E3%82%92Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AE%E7%B4%94%E7%B2%8B%E3%81%AAHTTP%E4%B8%8A%E3%81%A7%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B" rel="noopener noreferrer"&gt;https://scrapbox.io/nwtgck/SSH%E6%8E%A5%E7%B6%9A%E3%82%92Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AE%E7%B4%94%E7%B2%8B%E3%81%AAHTTP%E4%B8%8A%E3%81%A7%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;(Japanese): &lt;a href="https://scrapbox.io/nwtgck/%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88PC%E6%93%8D%E4%BD%9C%E3%82%92Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AE%E7%B4%94%E7%B2%8B%E3%81%AAHTTP%E4%B8%8A%E3%81%A7%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B%EF%BC%88VNC%EF%BC%89" rel="noopener noreferrer"&gt;https://scrapbox.io/nwtgck/%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88PC%E6%93%8D%E4%BD%9C%E3%82%92Web%E3%83%96%E3%83%A9%E3%82%A6%E3%82%B6%E3%81%AE%E7%B4%94%E7%B2%8B%E3%81%AAHTTP%E4%B8%8A%E3%81%A7%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8B%EF%BC%88VNC%EF%BC%89&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  More
&lt;/h2&gt;

&lt;p&gt;The link below is the repository of &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt;.&lt;br&gt;
GitHub: &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Get more information from the link below about &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;Piping Server&lt;/a&gt; such as end-to-end encrypted file transfer, with basic auth, real-time drawing and so on.&lt;br&gt;
&lt;a href="https://github.com/nwtgck/piping-server/wiki/Ecosystem-around-Piping-Server" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server/wiki/Ecosystem-around-Piping-Server&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>linux</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Try QUIC in Node.js on Docker</title>
      <dc:creator>Ryo Ota</dc:creator>
      <pubDate>Mon, 30 Mar 2020 11:56:31 +0000</pubDate>
      <link>https://dev.to/nwtgck/try-quic-in-node-js-on-docker-l8c</link>
      <guid>https://dev.to/nwtgck/try-quic-in-node-js-on-docker-l8c</guid>
      <description>&lt;p&gt;Hi! I made a Docker image for QUIC in Node.js for everyone to try QUIC easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub repository
&lt;/h2&gt;

&lt;p&gt;Here is the GitHub repository.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qF2jUiUG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-6a5bca60a4ebf959a6df7f08217acd07ac2bc285164fae041eacb8a148b1bab9.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nwtgck"&gt;
        nwtgck
      &lt;/a&gt; / &lt;a href="https://github.com/nwtgck/docker-node-quic"&gt;
        docker-node-quic
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Docker image for Node.js with QUIC
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;h1&gt;
docker-node-quic&lt;/h1&gt;
&lt;p&gt;Docker image for &lt;a href="https://github.com/nodejs/quic"&gt;Node.js with QUIC&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Usage&lt;/h2&gt;
&lt;p&gt;You can docker-run with &lt;code&gt;docker run -it nwtgck/node-quic&lt;/code&gt; as follows.&lt;/p&gt;
&lt;div class="highlight highlight-text-shell-session"&gt;&lt;pre&gt;$ &lt;span class="pl-s1"&gt;docker run -it nwtgck/node-quic&lt;/span&gt;
&lt;span class="pl-c1"&gt;Welcome to Node.js v14.0.0-pre.&lt;/span&gt;
&lt;span class="pl-c1"&gt;Type ".help" for more information.&lt;/span&gt;
&amp;gt; &lt;span class="pl-s1"&gt;const { createQuicSocket } = require(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;net&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;span class="pl-k"&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class="pl-c1"&gt;undefined&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can get more detail examples and descriptions about the usage of QUIC in Node.js in the following.&lt;br&gt;
&lt;a href="https://github.com/nodejs/quic/blob/cee2e5d079ca2b55e421d81df1ad131c1bfeecc6/doc/api/quic.md"&gt;quic/quic.md at cee2e5d079ca2b55e421d81df1ad131c1bfeecc6 · nodejs/quic&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
Article&lt;/h2&gt;
&lt;p&gt;Here is an article to get example.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dev.to/nwtgck/try-quic-in-node-js-on-docker-l8c" rel="nofollow"&gt;Try QUIC in Node.js on Docker - DEV Community 👩‍💻👨‍💻&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nwtgck/docker-node-quic"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;You can use the docker image by &lt;code&gt;docker run -it nwtgck/node-quic&lt;/code&gt; and use QUIC by &lt;code&gt;const { createQuicSocket } = require('net');&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create echo server
&lt;/h2&gt;

&lt;p&gt;As an example, let's create an echo server.&lt;/p&gt;

&lt;p&gt;First, you can create self-signed certificates as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;ssl_certs
&lt;span class="nb"&gt;cd &lt;/span&gt;ssl_certs
openssl genrsa 2024 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; server.key
openssl req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-key&lt;/span&gt; server.key &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/C=JP"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; server.csr
openssl x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-days&lt;/span&gt; 3650 &lt;span class="nt"&gt;-signkey&lt;/span&gt; server.key &amp;lt; server.csr &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; server.crt
&lt;span class="nb"&gt;cd&lt;/span&gt; -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Second, create &lt;code&gt;my_echo_server.js&lt;/code&gt; as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// my_echo_server.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createQuicSocket&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;net&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./ssl_certs/server.key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./ssl_certs/server.crt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ca&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./ssl_certs/server.csr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1234&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Create the QUIC UDP IPv4 socket bound to local IP port 1234&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createQuicSocket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Tell the socket to operate as a server using the given&lt;/span&gt;
&lt;span class="c1"&gt;// key and certificate to secure new connections, using&lt;/span&gt;
&lt;span class="c1"&gt;// the fictional 'hello' application protocol.&lt;/span&gt;
&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;alpn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// The peer opened a new stream!&lt;/span&gt;
  &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Echo server&lt;/span&gt;
    &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;listening&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// The socket is listening for sessions!&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`listening on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input something!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createQuicSocket&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;ca&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;requestCert&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;alpn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;servername&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;localhost&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openStream&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// stdin -&amp;gt; stream&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client(on-secure): &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
  &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;client(on-secure): end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Graceful shutdown&lt;/span&gt;
    &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, enter a docker container as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$PWD&lt;/span&gt;:/playground nwtgck/node-quic bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And, type the following commands in the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Move the playground&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; /playground/
&lt;span class="c"&gt;# Run echo server&lt;/span&gt;
node my_echo_server.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the container, you can use existing packages because &lt;code&gt;npm&lt;/code&gt; command is available. You can expose UDP port by &lt;code&gt;-p 1234:1234/udp&lt;/code&gt; with &lt;code&gt;docker run&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Here is a demo.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ni7-W1q6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yvrugre2awzlelpyzqmx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ni7-W1q6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/yvrugre2awzlelpyzqmx.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your inputs on stdin are echoed by the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Official document: &lt;a href="https://github.com/nodejs/quic/blob/cee2e5d079ca2b55e421d81df1ad131c1bfeecc6/doc/api/quic.md"&gt;quic/quic.md at cee2e5d079ca2b55e421d81df1ad131c1bfeecc6 · nodejs/quic&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Echo server ref: &lt;a href="https://www.nearform.com/blog/a-quic-update-for-node-js/"&gt;A QUIC Update for Node.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;My Japanese post: &lt;a href="https://scrapbox.io/nwtgck/Node.js%E3%81%AEQUIC%E3%82%92%E5%85%88%E5%8F%96%E3%82%8A%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86"&gt;https://scrapbox.io/nwtgck/Node.js%E3%81%AEQUIC%E3%82%92%E5%85%88%E5%8F%96%E3%82%8A%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>quic</category>
      <category>docker</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Simple Chat over only HTTP without WebSocket and WebRTC, using Piping Server</title>
      <dc:creator>Ryo Ota</dc:creator>
      <pubDate>Thu, 06 Jun 2019 16:01:38 +0000</pubDate>
      <link>https://dev.to/nwtgck/simple-chat-over-only-http-without-websocket-and-webrtc-1n4m</link>
      <guid>https://dev.to/nwtgck/simple-chat-over-only-http-without-websocket-and-webrtc-1n4m</guid>
      <description>&lt;p&gt;Hi all! I'd like to show you a simple text chat over HTTP/HTTPS using Piping Server, which was introduced in &lt;a href="https://dev.to/nwtgck/data-streaming-with-every-device-over-httphttps-mo4"&gt;Data Streaming between Every Device over HTTP/HTTPS&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo video
&lt;/h2&gt;

&lt;p&gt;Here is a simple demo video of the chat.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/WeLkjg7nsvY"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use Piping Server in JavaScript?
&lt;/h2&gt;

&lt;p&gt;The purpose of Piping Server is data transfer.&lt;br&gt;
Here is an usage. Send by POST method, Get by GET method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Send&lt;/span&gt;
&lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ppng.io/mytext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello, world&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// Get&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://ppng.io/mytext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// === 'hello, world'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can change &lt;code&gt;/mytext&lt;/code&gt; and "&lt;a href="https://ppng.io"&gt;https://ppng.io&lt;/a&gt;" freely. An easy way to run Piping Server is using Heroku. You can click [Deploy to Heroku] on &lt;a href="https://github.com/nwtgck/piping-server"&gt;Piping Server on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By using this, you can build a simple chat without WebSocket or WebRTC.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try on CodePen
&lt;/h2&gt;

&lt;p&gt;Codepen: &lt;a href="https://codepen.io/nwtgck/pen/xNoKgx"&gt;https://codepen.io/nwtgck/pen/xNoKgx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nwtgck/embed/xNoKgx?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/nwtgck/embed/xNoKgx?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Both CodePens are the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Full code
&lt;/h2&gt;

&lt;p&gt;Here is the whole code of chat.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Simple Chat via Piping Server&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nc"&gt;.me&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Your ID"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;'your_id'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Peer ID"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;'peer_id'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;'receiveLoop(this)'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Connect&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;'position: absolute; bottom: 0;'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Message"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;'message'&lt;/span&gt; &lt;span class="na"&gt;size=&lt;/span&gt;&lt;span class="s"&gt;'50'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"send()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Send&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;hr&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;'talks'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!--This will be added by JavaScript --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// Receive-loop&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;receiveLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;your_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;peer_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;btn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Get peer's response&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://ppng.io/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;peer_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;your_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="c1"&gt;// Create talk element&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;talk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="c1"&gt;// Set peer's message&lt;/span&gt;
          &lt;span class="nx"&gt;talk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="c1"&gt;// Add peer's message&lt;/span&gt;
          &lt;span class="nx"&gt;talks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;talk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Send your message&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Send your message&lt;/span&gt;
      &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://ppng.io/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;your_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;peer_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;method&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="c1"&gt;// Create talk element&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;talk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;talk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;talk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;me&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;talks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;talk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="c1"&gt;// Empty your message&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Secure chat via Piping Server
&lt;/h2&gt;

&lt;p&gt;You can find more secure chat in the following. The application is written in Vue in TypeScript.&lt;br&gt;
GitHub: &lt;a href="https://github.com/nwtgck/piping-chat-web"&gt;https://github.com/nwtgck/piping-chat-web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The features are the following.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;End-to-End Encryption by AES &lt;a href="https://en.wikipedia.org/wiki/Galois/Counter_Mode"&gt;GCM&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Forward_secrecy"&gt;Forward Secrecy&lt;/a&gt; by &lt;a href="https://en.wikipedia.org/wiki/Elliptic-curve_Diffie%E2%80%93Hellman"&gt;ECDH&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Public Key Authentication like SSH&lt;/li&gt;
&lt;li&gt;via &lt;a href="https://github.com/nwtgck/piping-server"&gt;Piping Server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Static hosting&lt;/li&gt;
&lt;li&gt;Progressive Web App (PWA)&lt;/li&gt;
&lt;li&gt;Accountless&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/karanganesan"&gt;@karanganesan&lt;/a&gt; told me that a simpler example will be useful. This is why I wrote this post. Thanks Karan!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;can you share any simpler examples of using Piping Server like : only pure vanilla javascript and bare minimum like working chat using piping without any Vue JS or anything.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>showdev</category>
      <category>javascript</category>
      <category>vue</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Data Streaming between Every Device over HTTP/HTTPS</title>
      <dc:creator>Ryo Ota</dc:creator>
      <pubDate>Sat, 09 Feb 2019 10:41:17 +0000</pubDate>
      <link>https://dev.to/nwtgck/data-streaming-with-every-device-over-httphttps-mo4</link>
      <guid>https://dev.to/nwtgck/data-streaming-with-every-device-over-httphttps-mo4</guid>
      <description>&lt;p&gt;Hi all! I'm very new to the DEV community. Today, I'd like to introduce data stream transfer between almost every device over HTTP/HTTPS made for use with Unix Pipe and also for browser!&lt;/p&gt;

&lt;h2&gt;
  
  
  What do I want to solve?
&lt;/h2&gt;

&lt;p&gt;We sometimes want to transfer data between Mac, Windows, Linux, Unix, iPhone, Android... Although we have AirDrop, Google Drive, Dropbox, Slack, WhatsApp, Skype, &lt;code&gt;netcat&lt;/code&gt;, &lt;code&gt;ssh&lt;/code&gt; or etc, we need to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find a common service used by both sender and receiver&lt;/li&gt;
&lt;li&gt;Install additional GUI software&lt;/li&gt;
&lt;li&gt;Sign up some service&lt;/li&gt;
&lt;li&gt;Solve NAT traversal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, almost existing data transfer services are not CUI-friendly or not GUI-friendly.&lt;/p&gt;

&lt;p&gt;So, I made a solution to the problems above. The system allows you to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transfer data with almost every device&lt;/li&gt;
&lt;li&gt;Use it without additional installation&lt;/li&gt;
&lt;li&gt;Use it with Unix/Linux Pipe and it's engineer-friendly&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Actual Usages
&lt;/h2&gt;

&lt;p&gt;I'd like to introduce how to use the system I made.&lt;/p&gt;

&lt;p&gt;Here is a demo to transfer &lt;code&gt;seq 100000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkwm8mdrlu8hr5l38oovl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkwm8mdrlu8hr5l38oovl.gif" alt="piping seq"&gt;&lt;/a&gt;&lt;br&gt;
Send: &lt;code&gt;seq 100000 | curl -T - https://ppng.io/myseq&lt;/code&gt;&lt;br&gt;
Get: &lt;code&gt;curl https://ppng.io/myseq&lt;/code&gt;&lt;/p&gt;



&lt;p&gt;Here is a demo to transfer a 100MB file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8qkvg7tkmep5ryeh2ofx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8qkvg7tkmep5ryeh2ofx.gif" alt="piping 100 MB file"&gt;&lt;/a&gt;&lt;br&gt;
Send: &lt;code&gt;cat 100MB.dat | curl -T - https://ppng.io/mydata&lt;/code&gt;&lt;br&gt;
Get: &lt;code&gt;curl https://ppng.io/mydata &amp;gt; mydata&lt;/code&gt;&lt;/p&gt;



&lt;p&gt;You can transfer any data by using pipe. For example,&lt;/p&gt;

&lt;p&gt;Compress &amp;amp; Send: &lt;code&gt;cat myfile | gzip | curl -T ...&lt;/code&gt;&lt;br&gt;
Get &amp;amp; Decompress: &lt;code&gt;curl ... | zcat &amp;gt; myfile&lt;/code&gt;&lt;br&gt;
and&lt;br&gt;
Encrypt &amp;amp; Send: &lt;code&gt;cat myfile | openssl aes-256-cbc | curl -T ...&lt;/code&gt;&lt;br&gt;
Get &amp;amp; Decript: &lt;code&gt;curl ... | openssl aes-256-cbc -d &amp;gt; myfile&lt;/code&gt;&lt;br&gt;
and&lt;br&gt;
Send directory(zip): &lt;code&gt;zip -q -r - ./mydir | curl -T - https://ppng.io/mydir.zip&lt;/code&gt;&lt;br&gt;
Send directory(tar.gz): &lt;code&gt;tar zfcp - ./mydir | curl -T - https://ppng.io/mydir.tar.gz&lt;/code&gt;&lt;/p&gt;



&lt;p&gt;Here is a demo to transfer data &lt;strong&gt;to a browser&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8yiu3zxvmm2cxdowg0ig.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F8yiu3zxvmm2cxdowg0ig.gif" alt="piping from CUI to broswer"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Here is a demo to transfer data &lt;strong&gt;from a browser&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ff9hzl0b812zvloos34g8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ff9hzl0b812zvloos34g8.gif" alt="piping from browser to CUI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means you can transfer a file from Android/iPhone/iPad... to another device!&lt;/p&gt;


&lt;h3&gt;
  
  
  Transfer to Multiple Receivers
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa337vdmul0ozqyk7vd5r.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa337vdmul0ozqyk7vd5r.gif" alt="piping multiple"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Terminal Screen Sharing!
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9blobmr61goaesjcqcxg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F9blobmr61goaesjcqcxg.gif" alt="piping terminal share"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Share: &lt;code&gt;script -f &amp;gt;(curl -T - https://ppng.io/myscript &amp;gt;&amp;amp;/dev/null)&lt;/code&gt;&lt;br&gt;
View: &lt;code&gt;curl https://ppng.io/myscript&lt;/code&gt;&lt;br&gt;
(Use &lt;code&gt;script -F&lt;/code&gt; in Mac instead of &lt;code&gt;script -f&lt;/code&gt;)&lt;/p&gt;
&lt;h2&gt;
  
  
  GitHub Repository
&lt;/h2&gt;

&lt;p&gt;The project is Piping Server found in the link below.&lt;br&gt;
GitHub: &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/nwtgck" rel="noopener noreferrer"&gt;
        nwtgck
      &lt;/a&gt; / &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;
        piping-server
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Infinitely transfer between every device over pure HTTP with pipes or browsers
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Piping Server&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.npmjs.com/package/piping-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c2b87528eacfe9d491d0f912e2900b7259aae0a7cee8cf2a6a3f040ead58f4ed/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f706970696e672d7365727665722e737667" alt="npm"&gt;&lt;/a&gt; &lt;a href="https://www.codefactor.io/repository/github/nwtgck/piping-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/24a6232ea92b9ab623f218849802fb33f3389198e531b3c5ac60f07a31fb5bf7/68747470733a2f2f7777772e636f6465666163746f722e696f2f7265706f7369746f72792f6769746875622f6e777467636b2f706970696e672d7365727665722f6261646765" alt="CodeFactor"&gt;&lt;/a&gt; &lt;a href="https://ci.appveyor.com/project/nwtgck/piping-server" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/408b3e2f2c2660302841650a45087aa7a33be492804da9e4cfebb7c9443886d2/68747470733a2f2f63692e6170707665796f722e636f6d2f6170692f70726f6a656374732f7374617475732f673037356f333064357070346d3070613f7376673d74727565" alt="Build status"&gt;&lt;/a&gt; &lt;a href="https://github.com/nwtgck/piping-server/actions" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/nwtgck/piping-server/workflows/Node%20CI/badge.svg" alt="GitHub Actions"&gt;&lt;/a&gt; &lt;a href="https://hub.docker.com/r/nwtgck/piping-server/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7961f6d8d919a7dacdb559d8fdac16b9f7f0e8c69fc5bba3d1f4a8631cf90ba7/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f6175746f6d617465642f6e777467636b2f706970696e672d7365727665722e737667" alt="Docker Automated build"&gt;&lt;/a&gt; &lt;a href="https://microbadger.com/images/nwtgck/piping-server" title="Get your own image badge on microbadger.com" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8bea780bb470264900796a36af77cced9fc38c9e8cfc1d92707798d2cdb46d15/68747470733a2f2f696d616765732e6d6963726f6261646765722e636f6d2f6261646765732f696d6167652f6e777467636b2f706970696e672d7365727665722e737667" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Infinitely transfer between every device over HTTP/HTTPS&lt;br&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/nwtgck/piping-serverdemo_images/piping-server-terminal-hello.gif"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnwtgck%2Fpiping-serverdemo_images%2Fpiping-server-terminal-hello.gif" alt="Piping Server hello" width="600"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Transfer&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Piping Server is simple. You can transfer as follows.&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Send&lt;/span&gt;
&lt;span class="pl-c1"&gt;echo&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;'&lt;/span&gt;hello, world&lt;span class="pl-pds"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;|&lt;/span&gt; curl -T - https://ppng.io/hello&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Get&lt;/span&gt;
curl https://ppng.io/hello &lt;span class="pl-k"&gt;&amp;gt;&lt;/span&gt; hello.txt&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Piping Server transfers data to &lt;code&gt;POST /hello&lt;/code&gt; or &lt;code&gt;PUT /hello&lt;/code&gt; into &lt;code&gt;GET /hello&lt;/code&gt;. The path &lt;code&gt;/hello&lt;/code&gt; can be anything such as &lt;code&gt;/mypath&lt;/code&gt; or &lt;code&gt;/mypath/123/&lt;/code&gt;. A sender and receivers who specify the same path can transfer. Both the sender and the recipient can start the transfer first. The first one waits for the other.&lt;/p&gt;
&lt;p&gt;You can also use Web UI like &lt;a href="https://ppng.io" rel="nofollow noopener noreferrer"&gt;https://ppng.io&lt;/a&gt; on your browser. A more modern UI is found in &lt;a href="https://piping-ui.org" rel="nofollow noopener noreferrer"&gt;https://piping-ui.org&lt;/a&gt;, which supports E2E encryption.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Stream&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;The most important thing is that the data are streamed. This means that you can &lt;strong&gt;transfer any data infinitely&lt;/strong&gt;. The demo below transfers an infinite text stream with &lt;code&gt;seq inf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/nwtgck/piping-serverdemo_images/seq-inf.gif"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fnwtgck%2Fpiping-serverdemo_images%2Fseq-inf.gif" alt="infnite text stream" width="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Ideas&lt;/h2&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;This project is written in TypeScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Public Servers
&lt;/h2&gt;

&lt;p&gt;Here are public servers. My recommendation is &lt;a href="https://ppng.io" rel="noopener noreferrer"&gt;https://ppng.io&lt;/a&gt; because it has a short name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ppng.io/" rel="noopener noreferrer"&gt;https://ppng.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ppng.herokuapp.com" rel="noopener noreferrer"&gt;https://ppng.herokuapp.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://piping-92sr2pvuwg14.runkit.sh/" rel="noopener noreferrer"&gt;https://piping-92sr2pvuwg14.runkit.sh/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my policy, you can freely run the servers. I'd like to describe how to run later.&lt;/p&gt;

&lt;p&gt;You can get engineer-friendly help from the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;curl https://ppng.io/help
&amp;lt;Help will be displayed here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;I think Piping Server is like a TURN server in Pear-to-Pear. Piping Server relays your data to another device to solve NAT traversal.&lt;/p&gt;

&lt;p&gt;A body of POST/PUT HTTP request is passed to a body of GET HTTP response.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Run Piping Server
&lt;/h2&gt;

&lt;p&gt;We have several ways to run Piping Server. I'd like to introduce one by one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Heroku
&lt;/h3&gt;

&lt;p&gt;Push [Deploy to Heroku] button in &lt;a href="https://github.com/nwtgck/piping-server" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Portable Binary Executable
&lt;/h3&gt;

&lt;p&gt;The following commands make a Piping Server run on &lt;a href="http://localhost:8888" rel="noopener noreferrer"&gt;http://localhost:8888&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://github.com/nwtgck/piping-server-pkg/releases/download/v0.8.7/piping-server-macos
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x piping-server-macos
./piping-server-macos &lt;span class="nt"&gt;--http-port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8888
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also find other platform releases in GitHub Releases in &lt;a href="https://github.com/nwtgck/piping-server-pkg" rel="noopener noreferrer"&gt;https://github.com/nwtgck/piping-server-pkg&lt;/a&gt;. The portable executables are produced by &lt;a href="https://github.com/zeit/pkg" rel="noopener noreferrer"&gt;zeit/pkg&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;docker run&lt;/code&gt; make a Piping Server run on &lt;a href="http://localhost:8888" rel="noopener noreferrer"&gt;http://localhost:8888&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;always &lt;span class="nt"&gt;-p&lt;/span&gt; 8888:80 nwtgck/piping-server &lt;span class="nt"&gt;--http-port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  npm
&lt;/h3&gt;

&lt;p&gt;The following commands make Piping Server run on &lt;a href="http://localhost:8888" rel="noopener noreferrer"&gt;http://localhost:8888&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# install
npm install -g piping-server
# run
piping-server --http-port=8888
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Possibility of Data Transfer over HTTP
&lt;/h2&gt;

&lt;p&gt;I'm conducting an experiment to reveal how many data can be transferred over HTTP.&lt;br&gt;
I started the experiment 55 days and 7 hours ago and over 1000 terabyte data were transferred.&lt;/p&gt;

&lt;p&gt;The method of the experiment is as follows.&lt;br&gt;
Infinitely send: &lt;code&gt;cat /dev/urandom | curl -T - localhost:8888/rand&lt;/code&gt;&lt;br&gt;
Infinitely discard: &lt;code&gt;curl localhost:8888/rand &amp;gt; /dev/null&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Transfer Speed Compared with Go
&lt;/h2&gt;

&lt;p&gt;Here is a simple comparison in transfer speed between TypeScript/Node.js and Go implementations. As a result of the videos, there seem to be almost no differences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TypeScript/Node.js&lt;/strong&gt;:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ufijpqHlJww"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go:&lt;/strong&gt;&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/NuKvDwB9JSU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Repo Go ver.: &lt;a href="https://github.com/nwtgck/go-piping-server" rel="noopener noreferrer"&gt;https://github.com/nwtgck/go-piping-server&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Japanese Post
&lt;/h2&gt;

&lt;p&gt;Here is my original Japanese post: &lt;a href="https://qiita.com/nwtgck/items/78309fc529da7776cba0" rel="noopener noreferrer"&gt;https://qiita.com/nwtgck/items/78309fc529da7776cba0&lt;/a&gt;.&lt;br&gt;
You can get more information there.&lt;/p&gt;

&lt;p&gt;Thank you very much for reading. Have a wonderful day!&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>typescript</category>
      <category>linux</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
