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 0000000000..74ac0c5e53 Binary files /dev/null and b/middleware/http/wasm/internal/e2e-guests/config/main.wasm differ diff --git a/middleware/http/wasm/internal/e2e-guests/output/main.go b/middleware/http/wasm/internal/e2e-guests/output/main.go index 759dd10c12..08162512b3 100644 --- a/middleware/http/wasm/internal/e2e-guests/output/main.go +++ b/middleware/http/wasm/internal/e2e-guests/output/main.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 ensures tests can prove logging or stdio isn't missed, both // during initialization (main) and request (rewrite). package main diff --git a/middleware/http/wasm/internal/e2e-guests/rewrite/main.go b/middleware/http/wasm/internal/e2e-guests/rewrite/main.go index 0709daf91c..9325f9600d 100644 --- a/middleware/http/wasm/internal/e2e-guests/rewrite/main.go +++ b/middleware/http/wasm/internal/e2e-guests/rewrite/main.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/internal/e2e_test.go b/middleware/http/wasm/internal/e2e_test.go index efbcf58003..21c91ce34f 100644 --- a/middleware/http/wasm/internal/e2e_test.go +++ b/middleware/http/wasm/internal/e2e_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 internal_test import ( @@ -25,11 +38,12 @@ var guestWasm map[string][]byte const ( guestWasmOutput = "output" guestWasmRewrite = "rewrite" + guestWasmConfig = "config" ) // TestMain ensures we can read the test wasm prior to running e2e tests. func TestMain(m *testing.M) { - wasms := []string{guestWasmOutput, guestWasmRewrite} + wasms := []string{guestWasmOutput, guestWasmRewrite, guestWasmConfig} guestWasm = make(map[string][]byte, len(wasms)) for _, name := range wasms { if wasm, err := os.ReadFile(path.Join("e2e-guests", name, "main.wasm")); err != nil { @@ -48,9 +62,10 @@ func Test_EndToEnd(t *testing.T) { l.SetOutput(&buf) type testCase struct { - name string - guest []byte - test func(t *testing.T, handler http.Handler, log *bytes.Buffer) + name string + guest []byte + property map[string]string + test func(t *testing.T, handler http.Handler, log *bytes.Buffer) } tests := []testCase{ @@ -127,6 +142,14 @@ func Test_EndToEnd(t *testing.T) { require.Equal(t, "/v1.0/hello?name=teddy", r.URL.RequestURI()) }, }, + { + name: "log config to console", + guest: guestWasm[guestWasmConfig], + property: map[string]string{"guestConfig": "config bytes in any format"}, + test: func(t *testing.T, handler http.Handler, log *bytes.Buffer) { + require.Contains(t, log.String(), "config bytes in any format") + }, + }, } t.Run("local", func(t *testing.T) { @@ -139,6 +162,11 @@ func Test_EndToEnd(t *testing.T) { require.NoError(t, os.WriteFile(wasmPath, tc.guest, 0o600)) meta := metadata.Base{Properties: map[string]string{"url": "file://" + wasmPath}} + 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) {})) @@ -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) {}))