Skip to content

Consider extending the proxy world with an origin #167

@lukewagner

Description

@lukewagner

A common pattern for HTTP middleware (like express.js or proxy-wasm) is to create a linear chain of handlers that requests flow down (and responses flow back up) where each handler can manipulate (or block) the request/response before passing it on to the next handler in the chain. While processing a request, a handler can make any number of async "side" HTTP requests that don't flow down the linear chain. Thus there are two ways an HTTP request flows out of a handler: (1) to the next handler in the chain and (2) as a side call. E.g., in proxy-wasm, (2) is expressed by proxy_http_call which is quite separate from all the callbacks used for (1).

Ideally, since components and wasi:http are all about composition, we should be able to capture this pattern directly by simply linking components together (e.g, using wac). However, since wasi:http/proxy only has one way to issue outgoing HTTP requests, there's no simple way to distinguish (1) from (2) via linking (something more dynamic/complex is required).

Before the proposed change, one bit of terminology: RFC 9110 defines a "(reverse) proxy" as a kind of "intermediary" that sits between the client and the "origin". Thus, "proxy" implies the existence of a designated "origin".

Based on this, I thought perhaps we should have two worlds in wasi:http:

package wasi:http;
world service {
  import imports;  // as currently defined
  export handler;
}
world proxy {
  include service;
  import origin;
}
interface origin {
  use types.{request, response, error-code};
  handle: func(r: request) -> result<response, error-code>;
}

or, in summary: rename proxy to service and then define proxy to extend service with an origin (which is structurally the same as handler but with a different interface name). A proxy component thus imports two handle functions and can statically dispatch HTTP requests to either one and forward responses from either one. The distinct handler and origin names allow a WAC user to easily create a middleware chain with side requests.

I'm not especially wed to the name service, so alternative suggestions are welcome, but I kinda like the idea that a component targeting wasi:http/service is a sort of ultra-minimal (serverless) microservice. Moreover, I can see wasi:http/service being included by other bigger service worlds (e.g. wasi:cloud/service).

Thoughts?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions