From c957420341ea71c26e23160aaed13deadd53a2c5 Mon Sep 17 00:00:00 2001 From: Taction Date: Mon, 7 Aug 2023 15:04:38 +0800 Subject: [PATCH] Wasm middleware: add ability to pass config to guest (#2918) Signed-off-by: zhangchao --- middleware/http/wasm/benchmark_test.go | 21 +++++++-- middleware/http/wasm/example/router.go | 13 ++++++ middleware/http/wasm/httpwasm.go | 30 ++++++++++++- middleware/http/wasm/httpwasm_test.go | 13 ++++++ .../wasm/internal/e2e-guests/config/main.go | 25 +++++++++++ .../wasm/internal/e2e-guests/config/main.wasm | Bin 0 -> 6679 bytes .../wasm/internal/e2e-guests/output/main.go | 13 ++++++ .../wasm/internal/e2e-guests/rewrite/main.go | 13 ++++++ middleware/http/wasm/internal/e2e_test.go | 41 ++++++++++++++++-- 9 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 middleware/http/wasm/internal/e2e-guests/config/main.go create mode 100755 middleware/http/wasm/internal/e2e-guests/config/main.wasm diff --git a/middleware/http/wasm/benchmark_test.go b/middleware/http/wasm/benchmark_test.go index c74d7c2938..57c54994f0 100644 --- a/middleware/http/wasm/benchmark_test.go +++ b/middleware/http/wasm/benchmark_test.go @@ -1,3 +1,16 @@ +/* +Copyright 2023 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package wasm import ( @@ -28,8 +41,8 @@ func BenchmarkNative(b *testing.B) { } func BenchmarkTinygo(b *testing.B) { - path := "file://internal/e2e-guests/rewrite/main.wasm" - benchmarkMiddleware(b, path) + url := "file://internal/e2e-guests/rewrite/main.wasm" + benchmarkMiddleware(b, url) } // BenchmarkWat gives baseline performance for the same handler by @@ -39,8 +52,8 @@ func BenchmarkWat(b *testing.B) { benchmarkMiddleware(b, url) } -func benchmarkMiddleware(b *testing.B, path string) { - md := metadata.Base{Properties: map[string]string{"url": path}} +func benchmarkMiddleware(b *testing.B, url string) { + md := metadata.Base{Properties: map[string]string{"url": url}} l := logger.NewLogger(b.Name()) l.SetOutput(io.Discard) diff --git a/middleware/http/wasm/example/router.go b/middleware/http/wasm/example/router.go index a0d5c5ff8e..311808f3a8 100644 --- a/middleware/http/wasm/example/router.go +++ b/middleware/http/wasm/example/router.go @@ -1,3 +1,16 @@ +/* +Copyright 2023 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package main import ( diff --git a/middleware/http/wasm/httpwasm.go b/middleware/http/wasm/httpwasm.go index df57241ff0..9fef5850d1 100644 --- a/middleware/http/wasm/httpwasm.go +++ b/middleware/http/wasm/httpwasm.go @@ -1,3 +1,16 @@ +/* +Copyright 2023 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package wasm import ( @@ -22,6 +35,12 @@ type middleware struct { logger logger.Logger } +type Metadata struct { + // GuestConfig is an optional configuration passed to WASM guests. + // Users can pass an arbitrary string to be parsed by the guest code. + GuestConfig string `mapstructure:"guestConfig"` +} + func NewMiddleware(logger logger.Logger) dapr.Middleware { return &middleware{logger: logger} } @@ -36,18 +55,27 @@ func (m *middleware) GetHandler(ctx context.Context, metadata dapr.Metadata) (fu // getHandler is extracted for unit testing. func (m *middleware) getHandler(ctx context.Context, metadata dapr.Metadata) (*requestHandler, error) { + // parse common wasm metadata configuration meta, err := wasm.GetInitMetadata(ctx, metadata.Base) if err != nil { return nil, fmt.Errorf("wasm: failed to parse metadata: %w", err) } + // parse wasm middleware specific metadata + var middlewareMeta Metadata + err = mdutils.DecodeMetadata(metadata.Base, &middlewareMeta) + if err != nil { + return nil, fmt.Errorf("wasm: failed to parse wasm middleware metadata: %w", err) + } + var stdout, stderr bytes.Buffer mw, err := wasmnethttp.NewMiddleware(ctx, meta.Guest, handler.Logger(m), handler.ModuleConfig(wasm.NewModuleConfig(meta). WithName(meta.GuestName). WithStdout(&stdout). // reset per request - WithStderr(&stderr))) // reset per request + WithStderr(&stderr)), // reset per request + handler.GuestConfig([]byte(middlewareMeta.GuestConfig))) if err != nil { return nil, err } diff --git a/middleware/http/wasm/httpwasm_test.go b/middleware/http/wasm/httpwasm_test.go index 347c70fc46..670896ce0f 100644 --- a/middleware/http/wasm/httpwasm_test.go +++ b/middleware/http/wasm/httpwasm_test.go @@ -1,3 +1,16 @@ +/* +Copyright 2023 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package wasm import ( diff --git a/middleware/http/wasm/internal/e2e-guests/config/main.go b/middleware/http/wasm/internal/e2e-guests/config/main.go new file mode 100644 index 0000000000..c0694f58e3 --- /dev/null +++ b/middleware/http/wasm/internal/e2e-guests/config/main.go @@ -0,0 +1,25 @@ +/* +Copyright 2023 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package main ensures tests can prove logging or stdio isn't missed, both +// during initialization (main) and request (rewrite). +package main + +import ( + "github.com/http-wasm/http-wasm-guest-tinygo/handler" + "github.com/http-wasm/http-wasm-guest-tinygo/handler/api" +) + +func main() { + handler.Host.Log(api.LogLevelInfo, string(handler.Host.GetConfig())) +} diff --git a/middleware/http/wasm/internal/e2e-guests/config/main.wasm b/middleware/http/wasm/internal/e2e-guests/config/main.wasm new file mode 100755 index 0000000000000000000000000000000000000000..74ac0c5e53d68fde1b7469cfd7b4d5eb181306fa GIT binary patch literal 6679 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 0 { + for k, v := range tc.property { + meta.Properties[k] = v + } + } handlerFn, err := wasm.NewMiddleware(l).GetHandler(context.Background(), middleware.Metadata{Base: meta}) require.NoError(t, err) handler := handlerFn(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) @@ -182,6 +210,11 @@ func Test_EndToEnd(t *testing.T) { defer ts.Close() meta := metadata.Base{Properties: map[string]string{"url": ts.URL + "/guest.wasm"}} + if len(tc.property) > 0 { + for k, v := range tc.property { + meta.Properties[k] = v + } + } handlerFn, err := wasm.NewMiddleware(l).GetHandler(context.Background(), middleware.Metadata{Base: meta}) require.NoError(t, err) handler := handlerFn(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))