diff --git a/js/modules/k6/grpc/client.go b/js/modules/k6/grpc/client.go index acde94093b49..8b51fa6a87a1 100644 --- a/js/modules/k6/grpc/client.go +++ b/js/modules/k6/grpc/client.go @@ -459,8 +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 + var strval string + if strings.HasSuffix(hk, "-bin") { + var binval []byte + 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 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{