From f65127c7e8334a3c8e38c5e1dcc528a2469269aa Mon Sep 17 00:00:00 2001 From: Sapphire Becker Date: Thu, 27 Jul 2023 17:16:47 -0700 Subject: [PATCH 1/5] Support binary passed in GRPC metadata Use Uint8Array type in metadata declaration to avoid any reencoding issues in goja. --- js/modules/k6/grpc/client.go | 6 +++++- js/modules/k6/grpc/client_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/js/modules/k6/grpc/client.go b/js/modules/k6/grpc/client.go index acde94093b49..4eced57fee22 100644 --- a/js/modules/k6/grpc/client.go +++ b/js/modules/k6/grpc/client.go @@ -461,7 +461,11 @@ func (c *Client) parseInvokeParams(paramsVal goja.Value) (*invokeParams, error) // TODO(rogchap): Should we manage a string slice? strval, ok := kv.(string) if !ok { - return result, fmt.Errorf("metadata %q value must be a string", hk) + binval, ok := kv.([]byte) + if !ok { + return result, fmt.Errorf("metadata %q value must be a string or []byte", hk) + } + strval = string(binval) } result.Metadata[hk] = strval } diff --git a/js/modules/k6/grpc/client_test.go b/js/modules/k6/grpc/client_test.go index a0506f88c1e0..a10fa263a033 100644 --- a/js/modules/k6/grpc/client_test.go +++ b/js/modules/k6/grpc/client_test.go @@ -485,6 +485,31 @@ func TestClient(t *testing.T) { } `}, }, + { + name: "RequestBinHeaders", + initString: codeBlock{ + code: ` + var client = new grpc.Client(); + client.load([], "../../../../lib/testutils/httpmultibin/grpc_testing/test.proto");`, + }, + setup: func(tb *httpmultibin.HTTPMultiBin) { + tb.GRPCStub.EmptyCallFunc = func(ctx context.Context, _ *grpc_testing.Empty) (*grpc_testing.Empty, error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok || len(md["x-load-tester-bin"]) == 0 || md["x-load-tester-bin"][0] != string([]byte{2, 200}) { + return nil, status.Error(codes.FailedPrecondition, "") + } + + return &grpc_testing.Empty{}, nil + } + }, + vuString: codeBlock{code: ` + client.connect("GRPCBIN_ADDR"); + var resp = client.invoke("grpc.testing.TestService/EmptyCall", {}, { metadata: { "X-Load-Tester-bin": new Uint8Array([2, 200]) } }) + if (resp.status !== grpc.StatusOK) { + throw new Error("failed to send correct headers in the request") + } + `}, + }, { name: "ResponseMessage", initString: codeBlock{ From 8e049d2c05051574612f2a5e0b87f00cb1dc1ff1 Mon Sep 17 00:00:00 2001 From: Sapphire Becker Date: Tue, 8 Aug 2023 19:46:22 -0700 Subject: [PATCH 2/5] Require -bin suffix to accept binary grpc metadata --- js/modules/k6/grpc/client.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/js/modules/k6/grpc/client.go b/js/modules/k6/grpc/client.go index 4eced57fee22..d7247e1df46b 100644 --- a/js/modules/k6/grpc/client.go +++ b/js/modules/k6/grpc/client.go @@ -461,11 +461,15 @@ func (c *Client) parseInvokeParams(paramsVal goja.Value) (*invokeParams, error) // TODO(rogchap): Should we manage a string slice? strval, ok := kv.(string) if !ok { - binval, ok := kv.([]byte) - if !ok { - return result, fmt.Errorf("metadata %q value must be a string or []byte", hk) + if strings.HasSuffix(hk, "-bin") { + binval, ok := kv.([]byte) + if !ok { + return result, fmt.Errorf("metadata %q value must be a string or binary", hk) + } + strval = string(binval) + } else { + return result, fmt.Errorf("metadata %q value must be a string", hk) } - strval = string(binval) } result.Metadata[hk] = strval } From c7c7ae62bdc1e98b1f4c9d247fe034d05594bc92 Mon Sep 17 00:00:00 2001 From: Sapphire Becker Date: Tue, 15 Aug 2023 10:20:49 -0700 Subject: [PATCH 3/5] Add reference to spec for GRPC -bin metadata --- js/modules/k6/grpc/client.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/modules/k6/grpc/client.go b/js/modules/k6/grpc/client.go index d7247e1df46b..6aeb5df6600b 100644 --- a/js/modules/k6/grpc/client.go +++ b/js/modules/k6/grpc/client.go @@ -461,6 +461,8 @@ func (c *Client) parseInvokeParams(paramsVal goja.Value) (*invokeParams, error) // TODO(rogchap): Should we manage a string slice? strval, ok := kv.(string) if !ok { + // The spec defines that Binary-valued keys end in -bin + // https://grpc.io/docs/what-is-grpc/core-concepts/#metadata if strings.HasSuffix(hk, "-bin") { binval, ok := kv.([]byte) if !ok { From 85c852cea89d06957628aeb8f57c9c20f58ef218 Mon Sep 17 00:00:00 2001 From: Sapphire Becker Date: Mon, 21 Aug 2023 11:07:12 -0700 Subject: [PATCH 4/5] check bin metadata first, require -bin be binary (technically breaking change) --- js/modules/k6/grpc/client.go | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/js/modules/k6/grpc/client.go b/js/modules/k6/grpc/client.go index 6aeb5df6600b..73ab72db808c 100644 --- a/js/modules/k6/grpc/client.go +++ b/js/modules/k6/grpc/client.go @@ -459,19 +459,17 @@ func (c *Client) parseInvokeParams(paramsVal goja.Value) (*invokeParams, error) } for hk, kv := range rawHeaders { // TODO(rogchap): Should we manage a string slice? - strval, ok := kv.(string) - if !ok { - // The spec defines that Binary-valued keys end in -bin - // https://grpc.io/docs/what-is-grpc/core-concepts/#metadata - if strings.HasSuffix(hk, "-bin") { - binval, ok := kv.([]byte) - if !ok { - return result, fmt.Errorf("metadata %q value must be a string or binary", hk) - } - strval = string(binval) - } else { - return result, fmt.Errorf("metadata %q value must be a string", hk) + // The spec defines that Binary-valued keys end in -bin + // https://grpc.io/docs/what-is-grpc/core-concepts/#metadata + var strval string + if strings.HasSuffix(hk, "-bin") { + binval, ok := kv.([]byte) + if !ok { + return result, fmt.Errorf("metadata %q value must be binary", hk) } + strval = string(binval) + } else if strval, ok = kv.(string); !ok { + return result, fmt.Errorf("metadata %q value must be a string", hk) } result.Metadata[hk] = strval } From fb373ca42c594dea7117441fbcd41c9a60958ed8 Mon Sep 17 00:00:00 2001 From: Sapphire Becker Date: Wed, 23 Aug 2023 11:49:29 -0700 Subject: [PATCH 5/5] govet fix --- js/modules/k6/grpc/client.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/modules/k6/grpc/client.go b/js/modules/k6/grpc/client.go index 73ab72db808c..8b51fa6a87a1 100644 --- a/js/modules/k6/grpc/client.go +++ b/js/modules/k6/grpc/client.go @@ -463,7 +463,8 @@ func (c *Client) parseInvokeParams(paramsVal goja.Value) (*invokeParams, error) // https://grpc.io/docs/what-is-grpc/core-concepts/#metadata var strval string if strings.HasSuffix(hk, "-bin") { - binval, ok := kv.([]byte) + var binval []byte + binval, ok = kv.([]byte) if !ok { return result, fmt.Errorf("metadata %q value must be binary", hk) }