-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[v0.3] Request metadata #4
Comments
This is probably a good idea to return to now that 0.2 is done. Just sketching some thoughts based on a discussion with @lann today: I think there are two cases:
Case (1) is the easier case to sketch in WIT and I'm thinking looks roughly like: package wasi:http;
interface types {
...
resource request {
...
/// request-metadata is a child resource and follows the same child rules as headers and body
metadata: func() -> request-metadata
}
resource request-metadata {
peer-IP-address: func() -> option<...>
set-peer-IP-address: func(...)
...
}
} and similarly for For case (2), the middleware/vendor can leverage the Component Model's parametric polymorphism (and WIT's package my-auth-middleware:api;
interface metadata {
use wasi:http/types.{request-metadata};
get-user: func(req: borrow<request-metadata>) -> ...
} Thus, from, let's say JS, you could write: import { * as auth } from 'my-auth-middleware:api/metadata';
export func handle(request) {
let user = auth.getUser(request.metadata);
...
} If we wanted to make this syntactically nicer so that For reference, a component using world auth-guest {
import wasi:http/types;
import my-auth-middleware:api/metadata;
import wasi:http/outgoing-handler;
export wasi:http/incoming-handler;
} Note that An alternative approach to Case (2) is to extend WASI HTTP with some totally dynamic fields/values: package wasi:http;
interface types {
resource request-metadata {
set-dynamic: func(key: string, value: list<u8>);
get-dynamic: func(key: string) -> option<list<u8>>;
} I expect this is what some HTTP standard libraries do and maybe there are some good use cases for it (it's better than smuggling the info through headers), so maybe we should do it too, but it seems worse from a performance and declarative-interfaces perspective. |
As discussed, I really like the interface that this parametric polymorphism provides. My main concern is with the implementation of composition. For example, if I want to implement auth "middleware" by wrapping a wasi-http handler component in an auth component, I believe this design either requires host magic or it requires the auth component to implement "donut wrapping" of its parent's wasi-http interface(s)/types. The former (host magic) would probably be fine for certain "standard-ish" metadata but it isn't clear to me how it would be extensible. The latter (donut wrapping) seems plausible in principle but I'm not sure that the details of its implementation have been explored enough to be comfortable with depending on it for 0.3. |
Yeah, that's a fair point, virtualization is definitely important. For this particular scenario, I think we might be able to get away with something that isn't optimal (it creates 1 more component instance than if we had full donut-wrapping producer toolchain support), but is at least is expressible in WAC/WIT today (I think?). So the overall composed component could look like:
where
and
and It's not optimal, but perhaps we could use this use case to push forward producer tooling to support donut wrapping directly so that WDYT? |
I'll have to let others chime in on the composition implementation but the approach looks straightforward enough to me in the near term (0.3). Thanks! |
Going back to #4 (comment) "case (1)", I wonder if it could/should be unified with (2) by defining "first-party" metadata in that same form as "third-party" metadata, e.g. package wasi:http;
interface peer-metadata {
use types.{request-metadata};
peer-IP-address: func(req: borrow<request-metadata>) -> option<...>;
...
} This would produce less-nice bindings (absent new bindgen features) for these particular functions but it would be consistent with - and establish the pattern for - "third-party" metadata. It could also dovetail nicely with optional imports to statically express whether an implementer provides the given metadata. Edit: somewhat of an aside, |
Ah, good point! It also replaces dynamic |
@dicej pointed out that we'll run into a current WIT limitation when trying to write that package my-auth-middleware:private-api;
interface private-methods {
use host-http.{request as host-request};
use virtual-http.{request as virtual-request};
wrap: func(r: host-request, auth-data: ...) -> virtual-request;
} Normally, this would fail validation because package my-auth-middleware:private-api;
world import-adapter {
import wasi:http/types;
import wasi:http/handler;
export wasi:http/types;
export my-auth-middleware:api/metadata;
export private-methods with { host-http = import wasi:http/types, virtual-http = export wasi:http/types };
export wasi:http/handler;
} The above I realized there's another approach in which package my-auth-middleware:private-api;
interface virtual-http-types {
... copy-paste wasi:http/types
}
interface private-methods {
use wasi:http/types.{request as host-request};
use virtual-http-types.{request as virtual-request};
wrap: func(r: host-request, auth-data: ...) -> virtual-request;
}
world import-adapter {
import wasi:http/types;
import wasi:http/handler;
export virtual-http-types;
export my-auth-middleware:api/metadata;
export private-methods;
export wasi:http/handler;
} and the WAC would be updated to do the renaming from
which is allowed because ultimately So, altogether, I think we have multiple options for how to express this. |
Original context: #3 (comment)
There are certain pieces of metadata that are commonly associated with requests but aren't part of HTTP itself, e.g.:
This kind of metadata can be inserted into requests as headers, but this has historically been a source of security and name collision issues and I hope we can offer a better alternative.
A few options to consider:
handle
The text was updated successfully, but these errors were encountered: