Browser WebAssembly with golang http client

2022-03-21

I was looking into webassembly again today in the hope of somehow using it to call Google Cloud Storage using its own go SDK client libraries.

I got that to work and will have a followup post about it. ..but..

Along the way to set that up, to my surprise i found out that golang’s net/http clients actually work within browser wasm. This was really interesting and didn’t think it was possible due to the wasm sandbox in the browser

I only stumbled across that after reading Alessandro Segala's excellent blog here:

I decided to implement that end-to-end and write a small sample on my own derived from his work and from Omri Cohen's Run Go In The Browser Using WebAssembly.

Basically, this sample code here shows you how to compile and run a go-webassembly that does two things:

  • convert some text to base64
  • fetch an external resource in direct and streaming modes.

Both these are again derived from the the references above so this really isn’t anything i did…i just documented it as an end-to-end sample.


You can find the source here



Creating a go-webassembly app is nothing new…even i did one a couple weeks back that is outright impractical:

Note, this is about browser wasm …not wasm running in a proxy like Envoy…that has a lot more capabilities and can surely make http or even gRPC api calls on its own:

What the issue i’m demonstrating here is browser wasm making an http call in go. Why is that so difficult? well, wasm in the browser is itself prohibited from making http requests….but….the following PR jL9Lyma0nmo allowed go’s net/http package to call javascrpts fetch() transparently.

That is, whenever an http client in go is used in browswer, wasm, it internally calls fetch()….its interesting that this workaround exists but i’m not complaining!

If you want to read up on how this works internally or the specifics of the streaming fetch capability, please see the documentation and the PR cited above…i’ll just focus on getting the impatient up and running…

Setup

Anyway, lets set this up so you can run locally

I’m using https for the webserver which you will run and due to the certs, its just as easy if you setup a local redirect:

set in /etc/hosts:

127.0.0.1 gcs.somedomain.com

Now, just compile the wasm if you want to

compile

git clone https://github.com/salrashid123/wasm_http_go.git

cd wasm_http_go/

GOOS=js GOARCH=wasm go build -o  server/static/wasm/main.wasm  main.go

Now run the webserver

cd server
go run server.go

Note that the webserver loads wasm

  • index.html, see
	<script src="js/wasm.js" defer></script>

which inturn bootstraps the main.wasm file:

'use strict';

const WASM_URL = 'wasm/main.wasm';

var wasm;

function init() {
  const go = new Go();
  if ('instantiateStreaming' in WebAssembly) {
    WebAssembly.instantiateStreaming(fetch(WASM_URL), go.importObject).then(function (obj) {
      wasm = obj.instance;
      go.run(wasm);
    })
  } else {
    fetch(WASM_URL).then(resp =>
      resp.arrayBuffer()
    ).then(bytes =>
      WebAssembly.instantiate(bytes, go.importObject).then(function (obj) {
        wasm = obj.instance;
        go.run(wasm);
      })
    )
  }
}

init();

Ok, lets access the browser. In an incognito window, goto https://gcs.somedomain.com:8080/static/. Ignore the cert warning

Test base64 encoding with wasm:

  • enter PlainText, click submit

Test direct fetch or streaming.

  • Click the corresponding “Submit” buttons.

The streaming one will read chunks of data and output it to javascript-land while the sync one will read the fetch results into memory before returning. It’d be better if you use streaming since you probably dont’ want to OOM wasm runtime.

a stack of pancakes


TinyGo

We’re using plain go to compile into wasm…i tried to use tinygo but i didn’t work

There would’ve been a small savings here interms of size:

$ GOOS=js GOARCH=wasm go build -o  server/static/wasm/main.wasm  main.go
$ ls -larth server/static/wasm/main.wasm
   6.6M Mar 21 13:09 server/static/wasm/main.wasm

$ tinygo build -o server/static/wasm/main.wasm -target wasm ./main.go
   4.3M Mar 21 13:07 server/static/wasm/main.wasm

This site supports webmentions. Send me a mention via this form.