Skip to content

Commit

Permalink
chore: add trailers + headers handling logic
Browse files Browse the repository at this point in the history
Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
  • Loading branch information
rustatian committed Sep 10, 2024
1 parent 375ca44 commit 096eb3d
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 38 deletions.
3 changes: 0 additions & 3 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,12 @@ linters: # All available linters list: <https://golangci-lint.run/usage/linters/
- asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
- bodyclose # Checks whether HTTP response body is closed successfully
- dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
- dupl # Tool for code clone detection
- errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
- errorlint # find code that will cause problems with the error wrapping scheme introduced in Go 1.13
- exhaustive # check exhaustiveness of enum switch statements
- copyloopvar # checks for pointers to enclosing loop variables
- gochecknoglobals # Checks that no globals are present in Go code
- gocognit # Computes and checks the cognitive complexity of functions
- gocritic # The most opinionated Go source code linter
- gocyclo # Computes and checks the cyclomatic complexity of functions
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
- goimports # Goimports does everything that gofmt does. Additionally it checks unused imports
- revive
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ require (
go.uber.org/zap v1.27.0
golang.org/x/net v0.29.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1
google.golang.org/grpc v1.66.0
google.golang.org/grpc v1.66.1
google.golang.org/protobuf v1.34.2
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM=
google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
10 changes: 10 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,8 @@ golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5D
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw=
golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 h1:EDuYyU/MkFXllv9QF9819VlI9a4tzGuCbhG0ExK9o1U=
Expand Down Expand Up @@ -1483,10 +1485,13 @@ golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
Expand Down Expand Up @@ -1525,6 +1530,8 @@ golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
Expand Down Expand Up @@ -1552,6 +1559,8 @@ golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
Expand Down Expand Up @@ -1592,6 +1601,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920183334-c177e329c48b/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240823204242-4ba0660f739c/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
Expand Down
79 changes: 53 additions & 26 deletions proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const (
delimiter string = "|:|"
apiErr string = "error"
headers string = "headers"
trailers string = "trailers"
)

type Pool interface {
Expand Down Expand Up @@ -151,7 +152,12 @@ func (p *Proxy) methodHandler(method string) func(srv any, ctx context.Context,
}

handler := func(ctx context.Context, req any) (any, error) {
return p.invoke(ctx, method, req.(*codec.RawMessage))
switch r := req.(type) {
case *codec.RawMessage:
return p.invoke(ctx, method, r)
default:
return nil, errors.Errorf("unexpected request type %T", r)
}
}

return interceptor(ctx, in, info, handler)
Expand All @@ -162,6 +168,9 @@ func (p *Proxy) invoke(ctx context.Context, method string, in *codec.RawMessage)
pld := p.getPld()
defer p.putPld(pld)

// experimental grpc API
st := grpc.ServerTransportStreamFromContext(ctx)

err := p.makePayload(ctx, method, in, pld)
if err != nil {
return nil, err
Expand Down Expand Up @@ -192,14 +201,7 @@ func (p *Proxy) invoke(ctx context.Context, method string, in *codec.RawMessage)
return nil, errors.Str("worker empty response")
}

md, err := p.responseMetadata(r)
if err != nil {
_ = grpc.SetHeader(ctx, md)
return nil, err
}

ctx = metadata.NewIncomingContext(ctx, md)
err = grpc.SetHeader(ctx, md)
err = p.responseMetadata(st, r)
if err != nil {
return nil, err
}
Expand All @@ -208,39 +210,64 @@ func (p *Proxy) invoke(ctx context.Context, method string, in *codec.RawMessage)
}

// responseMetadata extracts metadata from roadrunner response Payload.Context and converts it to metadata.MD
func (p *Proxy) responseMetadata(resp *payload.Payload) (metadata.MD, error) {
var md metadata.MD
func (p *Proxy) responseMetadata(st grpc.ServerTransportStream, resp *payload.Payload) error {
if resp == nil || len(resp.Context) == 0 {
return md, nil
return nil
}

var rpcMetadata map[string]string
err := json.Unmarshal(resp.Context, &rpcMetadata)
if err != nil {
return md, err
return err
}

if len(rpcMetadata) > 0 {
// new meta should be used
mdn := metadata.New(map[string]string{})
// old meta should not be used in response
md = metadata.New(rpcMetadata)
// old meta should not be used in response in new API
md := metadata.New(rpcMetadata)

// we assume that if there are no new headers and trailers, an old PHP-GRPC client is used
if len(md.Get(headers)) == 0 && len(md.Get(trailers)) == 0 {
// backward compatibility
_ = st.SetHeader(md)
goto parseErr
}

// New API headers
if len(md.Get(headers)) > 0 {
mdh := make(map[string]any)
err = json.Unmarshal([]byte(md.Get(headers)[0]), &mdh)
if err != nil {
// we don't need to return this error, log it
p.log.Error("error unmarshalling headers", zap.Error(err))
goto api
}

for k, v := range mdh {
switch tt := v.(type) {
case string:
mdn.Append(k, tt)
_ = st.SetHeader(metadata.Pairs(k, tt))
case int:
_ = st.SetHeader(metadata.Pairs(k, strconv.Itoa(tt)))
default:
p.log.Warn("skipping header with unsupported type", zap.String("key", k), zap.Any("value", v))
}
}
}

// New API trailers
if len(md.Get(trailers)) > 0 {
mdh := make(map[string]any)
err = json.Unmarshal([]byte(md.Get(trailers)[0]), &mdh)
if err != nil {
// we don't need to return this error, log it
p.log.Error("error unmarshalling trailers", zap.Error(err))
}

for k, v := range mdh {
switch tt := v.(type) {
case string:
_ = st.SetTrailer(metadata.Pairs(k, tt))
case int:
mdn.Append(k, strconv.Itoa(tt))
_ = st.SetTrailer(metadata.Pairs(k, strconv.Itoa(tt)))
default:
p.log.Warn("skipping header with unsupported type", zap.String("key", k), zap.Any("value", v))
}
Expand All @@ -253,26 +280,26 @@ func (p *Proxy) responseMetadata(resp *payload.Payload) (metadata.MD, error) {
but, we use this only in case of PHP exception happened
*/
api:
parseErr:
if len(md.Get(apiErr)) > 0 {
st := &spb.Status{}

// get an error
data, err := base64.StdEncoding.DecodeString(md.Get(apiErr)[0])
if err != nil {
return mdn, err
return err
}

err = proto.Unmarshal(data, st)
if err != nil {
return mdn, err
return err
}

return mdn, status.ErrorProto(st)
return status.ErrorProto(st)
}
}

return md, nil
return nil
}

// makePayload generates RoadRunner compatible payload based on GRPC message.
Expand Down Expand Up @@ -350,7 +377,7 @@ func wrapError(err error) error {
}

if phpCode > 0 && phpCode < math.MaxUint32 {
code = codes.Code(phpCode) //nolint:gosec
code = codes.Code(phpCode)

Check failure on line 380 in proxy/proxy.go

View workflow job for this annotation

GitHub Actions / Golang-CI (lint)

G115: integer overflow conversion uint64 -> uint32 (gosec)

Check failure on line 380 in proxy/proxy.go

View workflow job for this annotation

GitHub Actions / Golang-CI (lint)

G115: integer overflow conversion uint64 -> uint32 (gosec)
}

st := status.New(code, chunks[1]).Proto()
Expand Down
4 changes: 2 additions & 2 deletions tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ require (
github.com/roadrunner-server/status/v5 v5.0.3
github.com/stretchr/testify v1.9.0
go.uber.org/zap v1.27.0
google.golang.org/grpc v1.66.0
google.golang.org/grpc v1.66.1
google.golang.org/protobuf v1.34.2
)

Expand Down Expand Up @@ -102,7 +102,7 @@ require (
go.temporal.io/sdk v1.29.0 // indirect
go.temporal.io/sdk/contrib/opentelemetry v0.6.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions tests/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
Expand Down Expand Up @@ -320,8 +320,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM=
google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down

0 comments on commit 096eb3d

Please sign in to comment.