Networking
Networking under WebAssembly
WebAssembly runs in a sandbox environment and doesn’t support direct network socket connections for security reasons. This means that traditional R networking and file downloading approaches need some extra work to be used with webR.
Luckily, webR provides two solutions to enable network connectivity:
- Basic downloads using base R’s
download.file()
. - Advanced networking using a WebSocket proxy, for packages like curl and httr2.
Basic downloads with download.file()
For simple file downloads, webR patches the download.file()
function to work inside a web browser. The patch works by intercepting requests and handling them using JavaScript APIs. This method is easy to use and in many cases is sufficient.
Limitations
The approach works well for basic HTTP(S) downloads, but it does come with some limitations imposed by the security of the browser environment:
The server hosting the file must supply CORS (Cross-Origin Resource Sharing) headers to permit cross-origin requests.
Only simple HTTP/HTTPS
GET
requests are supported. You cannot use another HTTP method, set headers, or use any of the advanced options available in curl/httr2.
Many web APIs and servers don’t supply CORS headers with their content, which is why you might need the WebSocket proxy method below.
Simple Download Example
# Download a file directly, no other setup required
download.file("https://raw.githubusercontent.com/tidyverse/ggplot2/refs/heads/main/data-raw/diamonds.csv", "diamonds.csv")
Advanced networking with a WebSocket proxy
For more complex networking, webR can proxy network connections through WebSockets. This enables the curl and httr2 packages, along with other TCP connections.
The functionality is provided by Emscripten, which emulates the underlying POSIX Socket APIs with communication over WebSockets. You can read more about this kind of networking support in the Emscripten documentation.
The main drawback of this approach is that it requires a special proxy server (outside of webR) which can route all our traffic over a websocket. Below it is explained how to setup such a proxy server.
Using curl and httr2 in webR
If you have access to a SOCKS proxy with support for WebSocket-to-TCP connections, you can use standard proxy settings directly. Emscripten will convert the network connections into WebSocket connections automatically.
For curl, set the proxy
option:
library(curl)
# Set up the proxy
<- new_handle(proxy = "socks5h://socks.example.com:443")
handle
# Make requests
<- curl_fetch_memory("https://hb.cran.dev/get", handle = handle) response
For httr2, use the req_proxy()
function:
library(httr2)
library(jsonlite)
# Create a request with proxy
<- request("https://hb.cran.dev/get") |>
response req_proxy("socks5h://socks.example.com:443") |>
req_perform()
# Extract the response
<- response |> resp_body_json() data
Running a local WebSocket proxy
If you don’t have access to a SOCKS proxy with support for WebSocket-to-TCP connections, you may be able to start one locally on your device.
You’ll need to set up two components outside of webR:
- A WebSocket-to-TCP proxy - We’ll use
websockify
. - A SOCKS proxy - We’ll connect to an SSH server and use port forwarding to create a SOCKS proxy.
Step 1: Install the WebSocket-to-TCP proxy
Install websockify
on your system. This can be done via pip
, other Python environment tools, or your system’s package manager.
# Using pip, with a Python virtual environment if needed
source .venv/bin/activate
pip install websockify
# You can start websockify directly if using uv
uvx websockify [...]
Step 2: Setup a SOCKS proxy
On Unix systems, you can usually start a SOCKS proxy with the following OpenSSH command:
# Replace `localhost` if you're not using a local SSH server
ssh -N -D 8581 localhost
On Windows systems, a local SOCKS proxy can be started with PuTTY in the Tunnels panel.
What this does: Creates a SOCKS proxy on port 8581 that routes traffic through the SSH connection.
Step 3: Start websockify
In a new terminal, start websockify
to bridge WebSocket connections to your SOCKS proxy:
websockify localhost:8580 localhost:8581
What this does: Creates a WebSocket server on port 8580 that forwards connections to your SOCKS proxy on port 8581.
Step 4: Setup webR
Since we have started websockify
without support for SSL, we must configure webR to connect to WebSockets over the ws://
protocol.
At the top of your script, before trying to connect to a HTTPS URL, first execute:
::eval_js("SOCKFS.websocketArgs.url = 'ws://'") webr
Finally, once setup is complete, configure curl or httr2 in the previous section using socks5h://localhost:8050
as your proxy URL.