From faf85e847a1c950291cefe0f52a8a23b6a68af2c Mon Sep 17 00:00:00 2001 From: Oleg Bespalov Date: Thu, 31 Aug 2023 11:48:45 +0200 Subject: [PATCH] Support binary metadata Add support for binary metadata (postfixed with `-bin`). This ports changes from the https://github.com/grafana/k6/pull/3234 --- grpc/client_test.go | 25 +++++++++++++++++++++++++ grpc/params.go | 17 ++++++++++++++--- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/grpc/client_test.go b/grpc/client_test.go index d583a0f..5475649 100644 --- a/grpc/client_test.go +++ b/grpc/client_test.go @@ -335,6 +335,31 @@ func TestClient(t *testing.T) { } `}, }, + { + name: "RequestBinHeaders", + initString: codeBlock{ + code: ` + var client = new grpc.Client(); + client.load([], "../grpc/testdata/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{ diff --git a/grpc/params.go b/grpc/params.go index 498667e..14e3af9 100644 --- a/grpc/params.go +++ b/grpc/params.go @@ -47,12 +47,23 @@ func newCallParams(vu modules.VU, input goja.Value) (*callParams, error) { return result, errors.New("metadata must be an object with key-value pairs") } for hk, kv := range rawHeaders { - strval, ok := kv.(string) - if !ok { + var val string + + // The gRPC spec defines that Binary-valued keys end in -bin + // https://grpc.io/docs/what-is-grpc/core-concepts/#metadata + if strings.HasSuffix(hk, "-bin") { + var binVal []byte + if binVal, ok = kv.([]byte); !ok { + return result, fmt.Errorf("metadata %q value must be binary", hk) + } + + // https://github.com/grpc/grpc-go/blob/v1.57.0/Documentation/grpc-metadata.md#storing-binary-data-in-metadata + val = string(binVal) + } else if val, ok = kv.(string); !ok { return result, fmt.Errorf("metadata %q value must be a string", hk) } - result.Metadata.Append(hk, strval) + result.Metadata.Append(hk, val) } case "tags": if err := common.ApplyCustomUserTags(rt, &result.TagsAndMeta, params.Get(k)); err != nil {