1
1
use std:: { net:: SocketAddr , str, str:: FromStr } ;
2
2
3
3
use crate :: { Body , ChainedRequestHandler , HttpExecutor , HttpInstance , HttpTrigger , Store } ;
4
- use anyhow:: bail;
5
4
use anyhow:: { anyhow, Context , Result } ;
6
5
use futures:: TryFutureExt ;
7
6
use http:: { HeaderName , HeaderValue } ;
@@ -11,7 +10,7 @@ use outbound_http::OutboundHttpComponent;
11
10
use spin_core:: async_trait;
12
11
use spin_core:: wasi_2023_10_18:: exports:: wasi:: http:: incoming_handler:: Guest as IncomingHandler2023_10_18 ;
13
12
use spin_core:: wasi_2023_11_10:: exports:: wasi:: http:: incoming_handler:: Guest as IncomingHandler2023_11_10 ;
14
- use spin_core:: Instance ;
13
+ use spin_core:: { Component , Engine , Instance } ;
15
14
use spin_http:: body;
16
15
use spin_http:: routes:: RouteMatch ;
17
16
use spin_trigger:: TriggerAppEngine ;
@@ -43,26 +42,21 @@ impl HttpExecutor for HttpHandlerExecutor {
43
42
) ;
44
43
45
44
let ( instance, mut store) = engine. prepare_instance ( component_id) . await ?;
46
- let HttpInstance :: Component ( instance) = instance else {
45
+ let HttpInstance :: Component ( instance, ty ) = instance else {
47
46
unreachable ! ( )
48
47
} ;
49
48
50
49
set_http_origin_from_request ( & mut store, engine. clone ( ) , self , & req) ;
51
50
52
- let resp = match HandlerType :: from_exports ( instance. exports ( & mut store) ) {
53
- Some ( HandlerType :: Wasi ) => {
54
- Self :: execute_wasi ( store, instance, base, route_match, req, client_addr) . await ?
55
- }
56
- Some ( HandlerType :: Spin ) => {
51
+ let resp = match ty {
52
+ HandlerType :: Spin => {
57
53
Self :: execute_spin ( store, instance, base, route_match, req, client_addr)
58
54
. await
59
55
. map_err ( contextualise_err) ?
60
56
}
61
- None => bail ! (
62
- "Expected component to either export `{WASI_HTTP_EXPORT_2023_10_18}`, \
63
- `{WASI_HTTP_EXPORT_2023_11_10}`, `{WASI_HTTP_EXPORT_0_2_0}`, \
64
- or `fermyon:spin/inbound-http` but it exported none of those"
65
- ) ,
57
+ _ => {
58
+ Self :: execute_wasi ( store, instance, ty, base, route_match, req, client_addr) . await ?
59
+ }
66
60
} ;
67
61
68
62
tracing:: info!(
@@ -157,6 +151,7 @@ impl HttpHandlerExecutor {
157
151
async fn execute_wasi (
158
152
mut store : Store ,
159
153
instance : Instance ,
154
+ ty : HandlerType ,
160
155
base : & str ,
161
156
route_match : & RouteMatch ,
162
157
mut req : Request < Body > ,
@@ -188,31 +183,33 @@ impl HttpHandlerExecutor {
188
183
Handler2023_10_18 ( IncomingHandler2023_10_18 ) ,
189
184
}
190
185
191
- let handler = match instance
192
- . exports ( & mut store)
193
- . instance ( "wasi:http/[email protected] " )
194
- {
195
- Some ( mut instance) => Some ( Handler :: Handler2023_10_18 ( IncomingHandler2023_10_18 :: new (
196
- & mut instance,
197
- ) ?) ) ,
198
- None => None ,
199
- } ;
200
- let handler = match handler {
201
- Some ( handler) => Some ( handler) ,
202
- None => match instance
203
- . exports ( & mut store)
204
- . instance ( "wasi:http/[email protected] " )
186
+ let handler =
205
187
{
206
- Some ( mut instance) => Some ( Handler :: Handler2023_11_10 (
207
- IncomingHandler2023_11_10 :: new ( & mut instance) ?,
208
- ) ) ,
209
- None => None ,
210
- } ,
211
- } ;
212
- let handler = match handler {
213
- Some ( handler) => handler,
214
- None => Handler :: Latest ( Proxy :: new ( & mut store, & instance) ?) ,
215
- } ;
188
+ let mut exports = instance. exports ( & mut store) ;
189
+ match ty {
190
+ HandlerType :: Wasi2023_10_18 => {
191
+ let mut instance = exports
192
+ . instance ( WASI_HTTP_EXPORT_2023_10_18 )
193
+ . ok_or_else ( || {
194
+ anyhow ! ( "export of `{WASI_HTTP_EXPORT_2023_10_18}` not an instance" )
195
+ } ) ?;
196
+ Handler :: Handler2023_10_18 ( IncomingHandler2023_10_18 :: new ( & mut instance) ?)
197
+ }
198
+ HandlerType :: Wasi2023_11_10 => {
199
+ let mut instance = exports
200
+ . instance ( WASI_HTTP_EXPORT_2023_11_10 )
201
+ . ok_or_else ( || {
202
+ anyhow ! ( "export of `{WASI_HTTP_EXPORT_2023_11_10}` not an instance" )
203
+ } ) ?;
204
+ Handler :: Handler2023_11_10 ( IncomingHandler2023_11_10 :: new ( & mut instance) ?)
205
+ }
206
+ HandlerType :: Wasi0_2 => {
207
+ drop ( exports) ;
208
+ Handler :: Latest ( Proxy :: new ( & mut store, & instance) ?)
209
+ }
210
+ HandlerType :: Spin => panic ! ( "should have used execute_spin instead" ) ,
211
+ }
212
+ } ;
216
213
217
214
let span = tracing:: debug_span!( "execute_wasi" ) ;
218
215
let handle = task:: spawn (
@@ -336,28 +333,52 @@ impl HttpHandlerExecutor {
336
333
}
337
334
338
335
/// Whether this handler uses the custom Spin http handler interface for wasi-http
339
- enum HandlerType {
336
+ #[ derive( Copy , Clone ) ]
337
+ pub enum HandlerType {
340
338
Spin ,
341
- Wasi ,
339
+ Wasi0_2 ,
340
+ Wasi2023_11_10 ,
341
+ Wasi2023_10_18 ,
342
342
}
343
343
344
344
const WASI_HTTP_EXPORT_2023_10_18 : & str =
"wasi:http/[email protected] " ;
345
345
const WASI_HTTP_EXPORT_2023_11_10 : & str =
"wasi:http/[email protected] " ;
346
346
const WASI_HTTP_EXPORT_0_2_0 : & str =
"wasi:http/[email protected] " ;
347
347
348
348
impl HandlerType {
349
- /// Determine the handler type from the exports
350
- fn from_exports ( mut exports : wasmtime:: component:: Exports < ' _ > ) -> Option < HandlerType > {
351
- if exports. instance ( WASI_HTTP_EXPORT_2023_10_18 ) . is_some ( )
352
- || exports. instance ( WASI_HTTP_EXPORT_2023_11_10 ) . is_some ( )
353
- || exports. instance ( WASI_HTTP_EXPORT_0_2_0 ) . is_some ( )
354
- {
355
- return Some ( HandlerType :: Wasi ) ;
356
- }
357
- if exports. instance ( "fermyon:spin/inbound-http" ) . is_some ( ) {
358
- return Some ( HandlerType :: Spin ) ;
349
+ /// Determine the handler type from the exports of a component
350
+ pub fn from_component < T > ( engine : & Engine < T > , component : & Component ) -> Result < HandlerType > {
351
+ let mut handler_ty = None ;
352
+
353
+ let mut set = |ty : HandlerType | {
354
+ if handler_ty. is_none ( ) {
355
+ handler_ty = Some ( ty) ;
356
+ Ok ( ( ) )
357
+ } else {
358
+ Err ( anyhow ! (
359
+ "component exports multiple different handlers but \
360
+ it's expected to export only one"
361
+ ) )
362
+ }
363
+ } ;
364
+ let ty = component. component_type ( ) ;
365
+ for ( name, _) in ty. exports ( engine. as_ref ( ) ) {
366
+ match name {
367
+ WASI_HTTP_EXPORT_2023_10_18 => set ( HandlerType :: Wasi2023_10_18 ) ?,
368
+ WASI_HTTP_EXPORT_2023_11_10 => set ( HandlerType :: Wasi2023_11_10 ) ?,
369
+ WASI_HTTP_EXPORT_0_2_0 => set ( HandlerType :: Wasi0_2 ) ?,
370
+ "fermyon:spin/inbound-http" => set ( HandlerType :: Spin ) ?,
371
+ _ => { }
372
+ }
359
373
}
360
- None
374
+
375
+ handler_ty. ok_or_else ( || {
376
+ anyhow ! (
377
+ "Expected component to either export `{WASI_HTTP_EXPORT_2023_10_18}`, \
378
+ `{WASI_HTTP_EXPORT_2023_11_10}`, `{WASI_HTTP_EXPORT_0_2_0}`, \
379
+ or `fermyon:spin/inbound-http` but it exported none of those"
380
+ )
381
+ } )
361
382
}
362
383
}
363
384
0 commit comments