[HN Gopher] WAGI: WebAssembly Gateway Interface
       ___________________________________________________________________
        
       WAGI: WebAssembly Gateway Interface
        
       Author : drocer88
       Score  : 91 points
       Date   : 2021-09-18 13:25 UTC (9 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | mbStavola wrote:
       | I was working on something similar but I found that without
       | interface types[1] you end up with a platform that's kinda
       | primitive and pretty unergonomic. I honestly expect to see an
       | explosion of projects in this vein once interface types are a
       | real thing.
       | 
       | [1]: https://github.com/WebAssembly/interface-
       | types/blob/master/p...
        
         | isaacimagine wrote:
         | Imo, interface types are the only thing standing between Wasm
         | and a Cambrian Explosion of Wasm plugin architectures. Up until
         | now it's been go through JS or roll it yourself. Exciting
         | stuff!
        
       | nerdponx wrote:
       | Does WebAssembly even make sense as a standalone runtime, like
       | the JVM? Is "server-side WebAssembly" going to be "a thing", or
       | is it just a compatibility kludge?
       | 
       | And what of all these languages that compile to JS, like
       | Typescript, Reason, Kotlin, et al? Is JS a sound "IR" between the
       | frontend and WebAssembly? Or would it be better to compile things
       | directly to WebAssembly?
        
         | dgb23 wrote:
         | There was a fairly recent article from Cloudflare providing
         | tooling support for Rust->WASM on their Workers (serverless,
         | sandboxed HTTP/Web centric plattform).
         | 
         | WASM has some interesting properties, like sandboxing, a small
         | set of instructions you can fit in your head and some fairly
         | high level constructs (for a compilation target).
         | 
         | However I don't quite know what other benefits it provides. It
         | certainly cannot compete with the JVM/CLR on many fronts. And I
         | don't see quite a lot of use-cases yet that cannot be covered
         | with just integrating V8. Happy to learn more about that
         | (actual rationales).
        
         | japanuspus wrote:
         | Not just for web either: if you ship WebAssembly bytecode as
         | part of your python package, you can push your platform
         | dependencies out to a wasm runtime and skip most of the build
         | matrix.
         | 
         | A runtime like wasmer-python [0] is only 1.5MB.
         | 
         | [0]: https://github.com/wasmerio/wasmer-python
        
         | fragile_frogs wrote:
         | > If WASM+WASI existed in 2008, we wouldn't have needed to
         | created Docker.
         | 
         | Source:
         | https://twitter.com/solomonstre/status/1111004913222324225?l...
        
         | BiteCode_dev wrote:
         | 1 - it's sandboxed by default
         | 
         | 2 - it's the only things that also run on the web
         | 
         | 3 - it's probably going to be ubiquitous because of that,
         | meaning it will be a great platform to target by default
         | 
         | 4 - it could potentially mean any platform run any code from
         | any other one without having to deal with wrappers: you would
         | write a lib in go or rust, and then run it as is in python
        
           | pjmlp wrote:
           | Someone just rediscovered IBM TIMI,Amsterdam Compiler Kit EM,
           | CLR MSIL, among plenty of others.
           | 
           | Sandboxing is of little help when external events can cause
           | internal memory corruption that change module's expected
           | outcomes.
           | 
           | It is as good as typical OS process.
        
         | gpm wrote:
         | Yes, wasm makes sense as a standalone runtime. It's basically
         | just like any other bytecode.
         | 
         | Like any bytecode (including jvm's), it comes at a performance
         | penalty over bare asm. I personally don't anticipate it will
         | replicate jvm's success as being a runtime when there is no
         | reason for a runtime to exist - since it shouldn't be much
         | harder to compile wasm (and languages that compile to wasm) to
         | native asm ahead of time. On the other hand I wouldn't have
         | predicted jvm's success either.
         | 
         | In places where you _want_ a runtime though, like in shared
         | computation models where it gives you security /performance
         | advantages, it makes perfect sense. It looks like it's probably
         | going to succeed there to me.
         | 
         | Compiling X -> JS -> Wasm doesn't make much sense. Not only is
         | wasm a language with cleaner semantics to compile to, but JS
         | doesn't actually really fit wasm semantics particularly well.
         | In fact, while I could have missed something, I'm not aware of
         | any good JS->wasm compilers. The closest I can think of is
         | https://www.assemblyscript.org/ - and it's not 100% JS
         | compatible.
        
         | ignoramous wrote:
         | > _Does WebAssembly even make sense as a standalone runtime,
         | like the JVM? Is "server-side WebAssembly" going to be "a
         | thing", or is it just a compatibility kludge?_
         | 
         | Yes, see: https://bytecodealliance.org/articles/1-year-update
         | 
         | > _Or would it be better to compile things directly to
         | WebAssembly?_
         | 
         | It'd be even better to roll out one's own Lambda@Edge:
         | https://krustlet.dev/
        
         | invokestatic wrote:
         | I think a lot of people, myself included, have been waiting for
         | a low-level, polyglot, and lighter weight runtime than the JVM.
         | WebAssembly currently provides the best tooling for this. That
         | said, I'm not really convinced of the server-side use case
         | except for sandboxing untrusted code. Especially in rust, where
         | the language itself provides safety guarantees that the VM
         | makes redundant.
        
           | zozbot234 wrote:
           | The safety guarantees are not redundant, they're quite
           | complementary. WASM doesn't protect you from violating memory
           | safety _within_ your programs; its sandbox only protects the
           | rest of the system from whatever the WASM program does.
        
           | pjmlp wrote:
           | Why waiting?
           | 
           | There have been plenty of similar stacks, JVM is just one
           | among many.
        
         | simonw wrote:
         | I think server-side WASM is going to be huge, because it could
         | finally give us an easy to run code in a secure sandbox.
         | 
         | Imagine being able to run a complex C dependency (with a high
         | risk of buffer overflows) risk-free because it's running in a
         | WASM sandbox?
         | 
         | Or building features that allow users to provide their own
         | executable code (for plugins and extensions and other
         | customization features) where they code is executed in a
         | sandbox with strictly controlled CPU/memory/network and API
         | access control.
        
           | Matthias247 wrote:
           | I'm not sure the amount of C code that one wants to run into
           | a server that is not system level code (doesn't make syscalls
           | itself and implements the server/ business logic) is
           | noticeable.
           | 
           | And only if that would be the case the use of WASM would be
           | an advantage. For general extensibility we had Java servlets,
           | Lua modules, PHP modules, etc in webservers for decades.
           | 
           | Maybe it's interesting for source code obfuscation purposes
           | or in order to allow migration of server logic between
           | different languages. But even that was possible before - and
           | I don't think the Market need was huge.
        
             | watermelon0 wrote:
             | There are many tools such as ffmpeg, that you might want to
             | run on untrusted input (e.g. file uploads), and in many
             | cases performance is not that important.
             | 
             | Java servlets, Lua and PHP modules cannot be run securely,
             | and there are vulnerabilities for all of them.
        
               | fiddlerwoaroof wrote:
               | > Java servlets, Lua and PHP modules cannot be run
               | securely, and there are vulnerabilities for all of them
               | 
               | The thing is, the JVM was designed with the explicit
               | intention of making it possible to run untrusted code
               | safely: how do we know we got it right this time? The
               | problem really isn't the VM, it's the APIs and
               | authorization model for access to the underlying system's
               | features.
        
               | gpm wrote:
               | Because browsers have a good track record of getting this
               | right, and sufficient funding to get this right, and the
               | server-side work gets to piggy-back on that.
               | 
               | Also because the API surface area that server side apps
               | need is really just not big, JVM had a lot of problems
               | because it tried to do too much.
        
             | simonw wrote:
             | I want to use the best-of-breed libraries for image
             | handling, movie decoding and suchlike - and most of those
             | are still written in C.
        
           | croes wrote:
           | If you want safe code you have to write safe code. Putting it
           | into a sandbox gives you fake security.
        
             | wtetzner wrote:
             | > If you want safe code you have to write safe code
             | 
             | That doesn't help if you need to run other people's code.
        
               | croes wrote:
               | Then you have to forgo safety.
        
               | simonw wrote:
               | Tell that to Heroku, GitHub (Actions), Vercel and the
               | whole of AWS, Google Cloud and Microsoft Azure! Running
               | other people's code is a multi-billion dollar business
               | opportunity.
        
               | croes wrote:
               | Since when does multi-billion dollar opportunity corelate
               | with safety?
        
             | skybrian wrote:
             | Running untrusted code in a sandbox made client-side web
             | apps possible, so I think there's more to it than that.
        
               | croes wrote:
               | But you wouldn't say it's safe just less unsafe.
        
               | skybrian wrote:
               | Maybe safety isn't binary? We are usually more
               | sophisticated about evaluating risks than that.
               | 
               | If all you think about is whether things are safe versus
               | unsafe, everything is "fake security" and you'll never
               | come up with defense in depth.
        
           | pjmlp wrote:
           | You mean like CLR or IBM mainframes language environments?
           | 
           | Yeah, I wonder how it would look like. /s
        
           | irq-1 wrote:
           | Right. WASM will protect _the server_ from the apps, which
           | means you don 't need to audit or trust what you run. That
           | old PHP website? Compile to WASM and you might lose any data
           | it can touch, but it won't expose the server in any way -- no
           | getting a login shell or sudo exploits, etc...
        
             | nerdponx wrote:
             | Forgive me if this is a newbie question, but what makes the
             | Wasm runtime more of a "sandbox" than e.g. CPython or the
             | JVM? Do you need explicit permission/authorization from the
             | host machine in order to do things like file and network
             | i/o? Surely such a system isn't any more foolproof than SSH
             | w/ a restricted shell, KVM, etc.?
        
       | astlouis44 wrote:
       | WebAssembly gaming is going to be huge.
        
       | fnord77 wrote:
       | so this is like WSGI? The almost 30 year old design pattern that
       | blocks on requests waiting for a response from the downstream app
       | and really isn't scalabe?
        
         | supermatt wrote:
         | wsgi isnt inherently blocking. it is a protocol and it is up to
         | the implementation on both sides if the interface as to how it
         | is handled.
         | 
         | that said, according to the docs this seems to be cgi 1.1 which
         | equates to a process per request, which afaik isnt so scalable.
        
           | zozbot234 wrote:
           | WASM "processes" need not be the same as OS-level processes.
           | So I don't think this would have the scalability issues of
           | plain CGI.
        
             | supermatt wrote:
             | interesting! i will have to have a look into this
        
             | Matthias247 wrote:
             | Right. And the Wasm runtime could run multiple Wasm
             | processes on one OS thread. If one program blocks on
             | stdin/stdput it gets descheduled and the next one can run.
             | Which basically provides the same M:N scheduling that
             | highly scalable Webservers would use.
        
         | formerly_proven wrote:
         | It's not, this is a CGI implementation. WSGI is an in-process
         | API and can support multiple requests in flight. Kind of weird
         | to call this a gateway interface instead of something like
         | wasm_cgi.
         | 
         | > Wagi is an implementation of CGI for WebAssembly.
        
         | giancarlostoro wrote:
         | ASGI is the replacement for WSGI. Honestly I never noticed
         | insane latency with WSGI.
        
       | als0 wrote:
       | Can anyone recommend a good introduction to WASM and WASI?
       | Something that covers standalone and browser based?
        
         | isaacimagine wrote:
         | 1 minute intro:
         | 
         | Wasm is a high-level assembly language that has both a textual
         | and binary format. It can be interpreted or compiled to a
         | native representation, and has tight integration with modern JS
         | engines (though JS is not required to run Wasm).
         | 
         | WASI (WebAssembly System Interface) is a runtime environment
         | standard for Wasm that allows Wasm applications to integrate
         | with 'standard' Unix APIs. These can be forwarded to the host
         | system or emulated.
         | 
         | For more info, honestly just going to the Wasm site, the
         | standard, or one of the runtime implementations and exploring
         | from there is the way to go.
         | 
         | It's best to learn by doing, so if you know a language that can
         | compile to Wasm, it's always a fun project to try to write
         | something using it. Rust, D, C, Zig, and AssemblyScript all
         | have pretty good tooling.
         | 
         | Hope this helps!
        
       | nynx wrote:
       | Why would they put things in environment variables instead of
       | having new imported functions to grab various values?
        
         | the_duke wrote:
         | I think the goal with this one was to be zero-friction and
         | allow any WASI module to serve requests, without requiring
         | language-specific bindings.
         | 
         | It's obviously not a great design, and a more serious
         | standardized version would use interface types. But that still
         | seems quite a ways off.
        
         | tyingq wrote:
         | That's what the various CGI specs require, and the project is
         | to implement something very close to CGI in WASM.
        
           | puppet-master wrote:
           | Reproducing ancient defects from the CGI spec in the process,
           | such as the inability to represent duplicate header names.
        
             | guntars wrote:
             | Wonder why they wouldn't pass in the whole request on
             | stdin? That would also mean that instances could be pre-
             | started in anticipation of a request and not just when one
             | is already waiting.
        
               | Matthias247 wrote:
               | To allow processing of large request and response bodies.
               | Imagine a 1Gb PUT or GET. You don't want to spend 1Gb RAM
               | for handling those. And you also don't want to wait
               | multiple minutes to hours to have the body buffered and
               | can actually present it to application logic.
        
               | guntars wrote:
               | Not sure I follow. A reasonable framework would stream
               | both the incoming request as well as the response. If the
               | WASM module wants to read the whole thing into memory,
               | it's free to do so, but you could have it process the
               | request piecemeal. It's just reading the request from a
               | file descriptor and writing the response to another one.
               | Not that different when those fds are actually sockets.
        
               | Matthias247 wrote:
               | Oh sorry. I misread it and thought you are asking why the
               | request isn't passed in complete form as an environment
               | variable too. I guess you are asking why the request
               | headers are not transferred via stdin too? My guess it's
               | just because that's how CGI works. It prevents from
               | having apps do the parsing work. Plus what could be
               | passed wouldn't be the original request anyway. If the
               | Webserver handles http2 or http3 headers would always
               | need to be repacked into a format that the script
               | understands.
        
               | tyingq wrote:
               | On passing environment variables instead of the full
               | request, probably to make it more accessible to get
               | started with the existing popular languages (C, Perl,
               | Tcl, Shell Scripts, mostly) without having to write all
               | the request parsing. There was also less "stuff" in the
               | request than today. No cookies, no file uploads, and so
               | on. They also passed things in that weren't in the
               | request itself, like REMOTE_ADDR, REMOTE_HOST,
               | SERVER_PORT, PATH_INFO and so on. So it seemed natural to
               | just put everything in environment variables, other than
               | the $CONTENT_LENGTH bytes that followed the header.
               | 
               | As for the fork() per request, I believe mostly because
               | they were starting with requirements where avoiding
               | fork() wasn't important. Conserving memory was probably
               | more important, given the timeframe. CGI programs that
               | leaked memory would have been common if they were
               | daemons. For most web servers, there also probably
               | weren't that many requests.
               | 
               | It was also a common existing pattern. Many of the
               | services on unix boxes worked the same way...one daemon
               | (inetd) would start instances of daemons per request and
               | they would serve only one request.
               | 
               | That said, NSAPI appeared pretty quickly after CGI, then
               | FastCGI, etc. Still pushing environment variables for
               | headers, but stopping the request->fork->exit pattern and
               | allowing persistent daemons.
        
             | tyingq wrote:
             | RFC2616 says this:
             | 
             |  _" It MUST be possible to combine the multiple header
             | fields into one "field-name: field-value" pair, without
             | changing the semantics of the message, by appending each
             | subsequent field-value to the first, each separated by a
             | comma."_
             | 
             | So, if the implementation folds the multiple headers into
             | one with the various values as a comma separated list, it
             | should all be compliant. I don't know rust well enough to
             | tell if this one is compliant...it reads like it is not
             | (looks like last header wins): https://github.com/deislabs/
             | wagi/blob/main/src/http_util.rs#...
             | 
             | Edit: It seems RFC7230 keeps most of that language, but
             | makes one exception for Set-Cookie, but that's outbound in
             | this context so it doesn't apply.
        
       | fleetfox wrote:
       | Interesting. What about web sockets?
        
       | gavinray wrote:
       | This is awesome to see!
       | 
       | I have been working on something like this for a while too. But
       | it uses GraalVM and it's "Polyglot" runtime to provide support
       | for JS/Ruby/Python/WASM/LLVM languages.
       | 
       | It's packaged as a single binary using graal-native + Quarkus, or
       | if you don't care about that (faster startup time/lower memory
       | use/no JVM needed) but need maximum performance, you can run it
       | as a regular JVM service as well.
       | 
       | It was born out of a need for a polyglot Functions-as-a-Service
       | platform but without the weight of container orchestration -- I
       | needed something I could deploy as a single binary.
       | 
       | Essentially OpenFaaS/OpenWhisk, minus containers.
       | 
       | It doesn't use CGI as a request/response specification though, it
       | uses Vert.x "RoutingContext" interface which has methods like
       | _".getBodyAsJson() "_, _".params( 'something')"_, _".header(
       | 'foo')"_, etc.                 https://vertx.io/docs/apidocs/io/v
       | ertx/ext/web/RoutingContext.html
       | 
       | An open standard like CGI probably would have been better, but
       | Graal has marshalling facilities for sharing object types between
       | languages, so the most user-friendly/ergonomic thing to do was to
       | share the underlying web request object itself across language
       | boundaries, including all the methods you can call on it.
       | 
       | ---
       | 
       | This has given me motivation to finally finish it so I can
       | publish + open-source it!
        
       | luckystarr wrote:
       | This looks like CGI on WebAssembly. Do the wagi scripts have to
       | be spawned upon every request, or can the somehow persist in
       | memory?
        
         | iampims wrote:
         | They are loaded at boot an executed for each matching requests.
        
       ___________________________________________________________________
       (page generated 2021-09-18 23:01 UTC)