@@ -45,15 +45,15 @@ type Middleware interface {
4545var _ Middleware = (* middleware )(nil )
4646
4747type middleware struct {
48- host handler.Host
49- runtime wazero.Runtime
50- hostModule , guestModule wazero.CompiledModule
51- moduleConfig wazero.ModuleConfig
52- guestConfig []byte
53- logger api.Logger
54- pool sync.Pool
55- features handler.Features
56- instanceCounter uint64
48+ host handler.Host
49+ runtime wazero.Runtime
50+ guestModule wazero.CompiledModule
51+ moduleConfig wazero.ModuleConfig
52+ guestConfig []byte
53+ logger api.Logger
54+ pool sync.Pool
55+ features handler.Features
56+ instanceCounter uint64
5757}
5858
5959func (m * middleware ) Features () handler.Features {
@@ -83,29 +83,30 @@ func NewMiddleware(ctx context.Context, guest []byte, host handler.Host, opts ..
8383 logger : o .logger ,
8484 }
8585
86- if m .hostModule , err = m .compileHost (ctx ); err != nil {
87- _ = m .Close (ctx )
86+ if m .guestModule , err = m .compileGuest (ctx , guest ); err != nil {
87+ _ = wr .Close (ctx )
8888 return nil , err
8989 }
9090
91- if _ , err = wasi_snapshot_preview1 . Instantiate ( ctx , m . runtime ); err != nil {
92- return nil , fmt . Errorf ( "wasm: error instantiating wasi: %w" , err )
93- }
94-
95- // Note: host modules don't use configuration
96- _ , err = m . runtime . InstantiateModule (ctx , m . hostModule , wazero . NewModuleConfig () )
97- if err != nil {
98- _ = m . runtime . Close ( ctx )
99- return nil , fmt . Errorf ( "wasm: error instantiating host: %w" , err )
100- }
101-
102- if m . guestModule , err = m . compileGuest (ctx , guest ); err != nil {
103- _ = m . Close ( ctx )
104- return nil , err
91+ // Detect and handle any host imports or lack thereof.
92+ imports := detectImports ( m . guestModule . ImportedFunctions () )
93+ switch {
94+ case imports & importWasiP1 != 0 :
95+ if _ , err = wasi_snapshot_preview1 . Instantiate ( ctx , m . runtime ); err != nil {
96+ _ = wr . Close (ctx )
97+ return nil , fmt . Errorf ( "wasm: error instantiating wasi: %w" , err )
98+ }
99+ fallthrough // proceed to configure any http_handler imports
100+ case imports & importHttpHandler != 0 :
101+ if _ , err = m . instantiateHost ( ctx ); err != nil {
102+ _ = wr . Close (ctx )
103+ return nil , fmt . Errorf ( "wasm: error instantiating host: %w" , err )
104+ }
105105 }
106106
107+ // Eagerly add one instance to the pool. Doing so helps to fail fast.
107108 if g , err := m .newGuest (ctx ); err != nil {
108- _ = m .Close (ctx )
109+ _ = wr .Close (ctx )
109110 return nil , err
110111 } else {
111112 m .pool .Put (g )
@@ -139,11 +140,11 @@ func (m *middleware) HandleRequest(ctx context.Context) (outCtx context.Context,
139140 err = guestErr
140141 return
141142 }
142- defer m .pool .Put (g )
143143
144- s := & requestState {features : m .features }
144+ s := & requestState {features : m .features , putPool : m . pool . Put , g : g }
145145 defer func () {
146- if ctxNext != 0 { // will call the next handler
146+ callNext := ctxNext != 0
147+ if callNext { // will call the next handler
147148 if closeErr := s .closeRequest (); err == nil {
148149 err = closeErr
149150 }
@@ -173,16 +174,10 @@ func (m *middleware) getOrCreateGuest(ctx context.Context) (*guest, error) {
173174
174175// HandleResponse implements Middleware.HandleResponse
175176func (m * middleware ) HandleResponse (ctx context.Context , reqCtx uint32 , hostErr error ) error {
176- g , err := m .getOrCreateGuest (ctx )
177- if err != nil {
178- return err
179- }
180- defer m .pool .Put (g )
181-
182177 s := requestStateFromContext (ctx )
183178 defer s .Close ()
184179
185- return g .handleResponse (ctx , reqCtx , hostErr )
180+ return s . g .handleResponse (ctx , reqCtx , hostErr )
186181}
187182
188183// Close implements api.Closer
@@ -529,7 +524,7 @@ func (m *middleware) readBody(ctx context.Context, mod wazeroapi.Module, stack [
529524 panic ("unsupported body kind: " + strconv .Itoa (int (kind )))
530525 }
531526
532- eofLen := readBody (ctx , mod , buf , bufLimit , r )
527+ eofLen := readBody (mod , buf , bufLimit , r )
533528
534529 stack [0 ] = eofLen
535530}
@@ -562,10 +557,10 @@ func (m *middleware) writeBody(ctx context.Context, mod wazeroapi.Module, params
562557 panic ("unsupported body kind: " + strconv .Itoa (int (kind )))
563558 }
564559
565- writeBody (ctx , mod , buf , bufLen , w )
560+ writeBody (mod , buf , bufLen , w )
566561}
567562
568- func writeBody (ctx context. Context , mod wazeroapi.Module , buf , bufLen uint32 , w io.Writer ) {
563+ func writeBody (mod wazeroapi.Module , buf , bufLen uint32 , w io.Writer ) {
569564 // buf_len 0 means to overwrite with nothing
570565 var b []byte
571566 if bufLen > 0 {
@@ -596,7 +591,7 @@ func (m *middleware) setStatusCode(ctx context.Context, params []uint64) {
596591 m .host .SetStatusCode (ctx , statusCode )
597592}
598593
599- func readBody (ctx context. Context , mod wazeroapi.Module , buf uint32 , bufLimit handler.BufLimit , r io.Reader ) (eofLen uint64 ) {
594+ func readBody (mod wazeroapi.Module , buf uint32 , bufLimit handler.BufLimit , r io.Reader ) (eofLen uint64 ) {
600595 // buf_limit 0 serves no purpose as implementations won't return EOF on it.
601596 if bufLimit == 0 {
602597 panic (fmt .Errorf ("buf_limit==0 reading body" ))
@@ -645,8 +640,8 @@ func mustBeforeNextOrFeature(ctx context.Context, feature handler.Features, op,
645640
646641const i32 , i64 = wazeroapi .ValueTypeI32 , wazeroapi .ValueTypeI64
647642
648- func (m * middleware ) compileHost (ctx context.Context ) (wazero. CompiledModule , error ) {
649- if compiled , err := m .runtime .NewHostModuleBuilder (handler .HostModule ).
643+ func (m * middleware ) instantiateHost (ctx context.Context ) (wazeroapi. Module , error ) {
644+ return m .runtime .NewHostModuleBuilder (handler .HostModule ).
650645 NewFunctionBuilder ().
651646 WithGoFunction (wazeroapi .GoFunc (m .enableFeatures ), []wazeroapi.ValueType {i32 }, []wazeroapi.ValueType {i32 }).
652647 WithParameterNames ("features" ).Export (handler .FuncEnableFeatures ).
@@ -701,11 +696,7 @@ func (m *middleware) compileHost(ctx context.Context) (wazero.CompiledModule, er
701696 NewFunctionBuilder ().
702697 WithGoFunction (wazeroapi .GoFunc (m .setStatusCode ), []wazeroapi.ValueType {i32 }, []wazeroapi.ValueType {}).
703698 WithParameterNames ("status_code" ).Export (handler .FuncSetStatusCode ).
704- Compile (ctx ); err != nil {
705- return nil , fmt .Errorf ("wasm: error compiling host: %w" , err )
706- } else {
707- return compiled , nil
708- }
699+ Instantiate (ctx )
709700}
710701
711702func mustHeaderMutable (ctx context.Context , op string , kind handler.HeaderKind ) {
@@ -766,3 +757,23 @@ func writeStringIfUnderLimit(mem wazeroapi.Memory, offset, limit handler.BufLimi
766757 mem .WriteString (offset , v )
767758 return
768759}
760+
761+ type imports uint
762+
763+ const (
764+ importWasiP1 imports = 1 << iota
765+ importHttpHandler
766+ )
767+
768+ func detectImports (importedFns []wazeroapi.FunctionDefinition ) (imports imports ) {
769+ for _ , f := range importedFns {
770+ moduleName , _ , _ := f .Import ()
771+ switch moduleName {
772+ case handler .HostModule :
773+ imports |= importHttpHandler
774+ case wasi_snapshot_preview1 .ModuleName :
775+ imports |= importWasiP1
776+ }
777+ }
778+ return
779+ }
0 commit comments