Skip to content

Commit

Permalink
feat(grpc): dump invalid utf8 strings as hex
Browse files Browse the repository at this point in the history
  • Loading branch information
zoncoen committed Oct 31, 2023
1 parent 810e749 commit 403cfc7
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 27 deletions.
36 changes: 18 additions & 18 deletions protocol/grpc/expect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ func TestExpect_Build(t *testing.T) {
},
},
v: response{
Header: metadata.MD{
Header: newMDMarshaler(metadata.MD{
"content-type": []string{
"application/grpc",
},
},
}),
rvalues: []reflect.Value{
reflect.ValueOf(&test.EchoResponse{}),
reflect.Zero(reflectutil.TypeError),
Expand All @@ -125,11 +125,11 @@ func TestExpect_Build(t *testing.T) {
},
},
v: response{
Trailer: metadata.MD{
Trailer: newMDMarshaler(metadata.MD{
"content-type": []string{
"application/grpc",
},
},
}),
rvalues: []reflect.Value{
reflect.ValueOf(&test.EchoResponse{}),
reflect.Zero(reflectutil.TypeError),
Expand Down Expand Up @@ -282,16 +282,16 @@ func TestExpect_Build(t *testing.T) {
},
}).Err()),
},
Header: metadata.MD{
Header: newMDMarshaler(metadata.MD{
"content-type": []string{
"application/grpc",
},
},
Trailer: metadata.MD{
}),
Trailer: newMDMarshaler(metadata.MD{
"version": []string{
"v1.0.0",
},
},
}),
},
},
}
Expand Down Expand Up @@ -451,11 +451,11 @@ func TestExpect_Build(t *testing.T) {
},
},
v: response{
Header: metadata.MD{
Header: newMDMarshaler(metadata.MD{
"content-type": []string{
"application/grpc",
},
},
}),
rvalues: []reflect.Value{
reflect.ValueOf(&test.EchoResponse{}),
reflect.Zero(reflectutil.TypeError),
Expand All @@ -474,11 +474,11 @@ func TestExpect_Build(t *testing.T) {
},
},
v: response{
Header: metadata.MD{
Header: newMDMarshaler(metadata.MD{
"content-type": []string{
"application/grpc",
},
},
}),
rvalues: []reflect.Value{
reflect.ValueOf(&test.EchoResponse{}),
reflect.Zero(reflectutil.TypeError),
Expand All @@ -497,11 +497,11 @@ func TestExpect_Build(t *testing.T) {
},
},
v: response{
Header: metadata.MD{
Header: newMDMarshaler(metadata.MD{
"content-type": []string{
"application/grpc",
},
},
}),
rvalues: []reflect.Value{
reflect.ValueOf(&test.EchoResponse{}),
reflect.Zero(reflectutil.TypeError),
Expand All @@ -520,11 +520,11 @@ func TestExpect_Build(t *testing.T) {
},
},
v: response{
Trailer: metadata.MD{
Trailer: newMDMarshaler(metadata.MD{
"content-type": []string{
"application/grpc",
},
},
}),
rvalues: []reflect.Value{
reflect.ValueOf(&test.EchoResponse{}),
reflect.Zero(reflectutil.TypeError),
Expand All @@ -543,11 +543,11 @@ func TestExpect_Build(t *testing.T) {
},
},
v: response{
Trailer: metadata.MD{
Trailer: newMDMarshaler(metadata.MD{
"content-type": []string{
"application/grpc",
},
},
}),
rvalues: []reflect.Value{
reflect.ValueOf(&test.EchoResponse{}),
reflect.Zero(reflectutil.TypeError),
Expand Down
52 changes: 43 additions & 9 deletions protocol/grpc/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package grpc

import (
"bytes"
"encoding/hex"
"fmt"
"reflect"
"strings"
"unicode/utf8"

"github.com/goccy/go-yaml"
"google.golang.org/grpc"
Expand Down Expand Up @@ -32,8 +34,8 @@ type Request struct {

type response struct {
Status responseStatus `yaml:"status,omitempty"`
Header metadata.MD `yaml:"header,omitempty"`
Trailer metadata.MD `yaml:"trailer,omitempty"`
Header *mdMarshaler `yaml:"header,omitempty"`
Trailer *mdMarshaler `yaml:"trailer,omitempty"`
Message interface{} `yaml:"message,omitempty"`
rvalues []reflect.Value `yaml:"-"`
}
Expand All @@ -44,6 +46,31 @@ type responseStatus struct {
Details yaml.MapSlice `yaml:"details,omitempty"`
}

func newMDMarshaler(md metadata.MD) *mdMarshaler { return (*mdMarshaler)(&md) }

type mdMarshaler metadata.MD

func (m *mdMarshaler) MarshalYAML() ([]byte, error) {
mp := make(metadata.MD, len(*m))
for k, vs := range *m {
vs := vs
if !strings.HasSuffix(k, "-bin") {
mp[k] = vs
continue
}
s := make([]string, len(vs))
for i, v := range vs {
v := v
if !utf8.ValidString(v) {
v = hex.EncodeToString([]byte(v))
}
s[i] = v
}
mp[k] = s
}
return yaml.Marshal(mp)
}

const (
indentNum = 2
)
Expand Down Expand Up @@ -169,13 +196,16 @@ func invoke(ctx *context.Context, method reflect.Value, r *Request) (*context.Co
}

ctx = ctx.WithRequest(req)
dumpReq := &Request{

Check failure on line 199 in protocol/grpc/request.go

View workflow job for this annotation

GitHub Actions / golangci

[golangci] protocol/grpc/request.go#L199

Client, Metadata, Body are missing in Request (exhaustruct)
Raw output
protocol/grpc/request.go:199:16: Client, Metadata, Body are missing in Request (exhaustruct)
			dumpReq := &Request{
			            ^
Method: r.Method,
Message: req,
}
reqMD, _ := metadata.FromOutgoingContext(reqCtx)
if len(reqMD) > 0 {
dumpReq.Metadata = newMDMarshaler(reqMD)
}
//nolint:exhaustruct
if b, err := yaml.Marshal(Request{
Method: r.Method,
Metadata: reqMD,
Message: req,
}); err == nil {
if b, err := yaml.Marshal(dumpReq); err == nil {
ctx.Reporter().Logf("request:\n%s", r.addIndent(string(b), indentNum))
} else {
ctx.Reporter().Logf("failed to dump request:\n%s", err)
Expand Down Expand Up @@ -206,11 +236,15 @@ func invoke(ctx *context.Context, method reflect.Value, r *Request) (*context.Co
Message: "",
Details: nil,
},
Header: header,
Trailer: trailer,
Message: message,
rvalues: rvalues,
}
if len(header) > 0 {
resp.Header = newMDMarshaler(header)
}
if len(trailer) > 0 {
resp.Trailer = newMDMarshaler(trailer)
}
if err != nil {
if sts, ok := status.FromError(err); ok {
resp.Status.Code = sts.Code().String()
Expand Down
61 changes: 61 additions & 0 deletions protocol/grpc/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import (
"reflect"
"strings"
"testing"
"unicode/utf8"

"github.com/goccy/go-yaml"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/sergi/go-diff/diffmatchpatch"
"github.com/zoncoen/scenarigo/context"
"github.com/zoncoen/scenarigo/internal/mockutil"
"github.com/zoncoen/scenarigo/internal/testutil"
Expand All @@ -19,6 +21,7 @@ import (
spb "google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
Expand Down Expand Up @@ -438,3 +441,61 @@ func TestBuildRequestBody(t *testing.T) {
})
}
}

func TestMDMarshaler_MarshalYAML(t *testing.T) {
r := utf8.RuneError
tests := map[string]struct {
md metadata.MD
expected string
}{
"nil": {
expected: `method: Foo
metadata: {}
`,
},
"empty": {
md: metadata.MD{},
expected: `method: Foo
metadata: {}
`,
},
"no -bin": {
md: metadata.MD{
"grpc-status": {codes.Internal.String()},
},
expected: `method: Foo
metadata:
grpc-status:
- Internal
`,
},
"has -bin": {
md: metadata.MD{
"grpc-status-details-bin": {"test", string([]byte{byte(r)})},
},
expected: `method: Foo
metadata:
grpc-status-details-bin:
- test
- fd
`,
},
}
for name, test := range tests {
test := test
t.Run(name, func(t *testing.T) {
b, err := yaml.Marshal(Request{
Method: "Foo",
Metadata: newMDMarshaler(test.md),
})
if err != nil {
t.Fatal(err)
}
if got, expected := string(b), test.expected; got != expected {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(expected, got, false)
t.Errorf("differs:\n%s", dmp.DiffPrettyText(diffs))
}
})
}
}

0 comments on commit 403cfc7

Please sign in to comment.