Skip to content

Commit 1e9a793

Browse files
Merge remote-tracking branch 'upstream' into secfixfinal
2 parents 2731ece + 2cb3789 commit 1e9a793

19 files changed

Lines changed: 715 additions & 178 deletions

binarylog/grpc_binarylog_v1/binarylog.pb.go

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/internal.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,10 @@ var (
245245
AsyncReporterCleanupDelegate = func(cleanup func()) func() {
246246
return cleanup
247247
}
248+
249+
// XDSFilterWrapperOption returns a ServerOption that sets the internal
250+
// stream wrapper used for server-side xDS HTTP filters.
251+
XDSFilterWrapperOption any // func(func(grpc.ServerStream) (grpc.ServerStream, error)) grpc.ServerOption
248252
)
249253

250254
// HealthChecker defines the signature of the client-side LB channel health

internal/resolver/config_selector.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,6 @@ type RPCConfig struct {
5858
Interceptor any
5959
}
6060

61-
// ServerInterceptor is an interceptor for incoming RPC's on gRPC server side.
62-
type ServerInterceptor interface {
63-
// AllowRPC checks if an incoming RPC is allowed to proceed based on
64-
// information about connection RPC was received on, and HTTP Headers. This
65-
// information will be piped into context.
66-
AllowRPC(ctx context.Context) error // TODO: Make this a real interceptor for filters such as rate limiting.
67-
// Close closes the interceptor. Once called, no new calls to NewStream are
68-
// accepted. Ongoing calls to NewStream are allowed to complete.
69-
Close()
70-
}
71-
7261
type csKeyType string
7362

7463
const csKey = csKeyType("grpc.internal.resolver.configSelector")

internal/xds/httpfilter/httpfilter.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ type ClientInterceptor interface {
9595
// Note: RPCInfo.Context is currently unused and will be nil.
9696
NewStream(ctx context.Context, ri iresolver.RPCInfo, newStream func(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStream, error), opts ...grpc.CallOption) (grpc.ClientStream, error)
9797

98-
// Close closes the interceptor. Once called, no new calls to NewStream are
99-
// accepted. Ongoing calls to NewStream are allowed to complete.
98+
// Close closes the interceptor. No new RPCs will be dispatched to this
99+
// interceptor, but ongoing calls to NewStream are allowed to complete.
100100
Close()
101101
}
102102

@@ -131,6 +131,25 @@ type ClientFilter interface {
131131
Close()
132132
}
133133

134+
// ServerInterceptor is an interceptor for incoming RPC's on gRPC server side.
135+
type ServerInterceptor interface {
136+
// InterceptRPC intercepts an incoming RPC on the server side.
137+
//
138+
// On success, implementations must return either the original ServerStream
139+
// or a wrapped ServerStream, with a nil error.
140+
//
141+
// Returning a non-nil error will terminate the RPC with that error.
142+
// Implementations are expected to return an error created using the status
143+
// package; otherwise, the RPC will fail with an UNKNOWN status code.
144+
//
145+
// Implementations should never return (nil, nil).
146+
InterceptRPC(ss grpc.ServerStream) (grpc.ServerStream, error)
147+
148+
// Close closes the interceptor. No new RPCs will be dispatched to this
149+
// interceptor, but ongoing calls to InterceptRPC are allowed to complete.
150+
Close()
151+
}
152+
134153
// ServerFilterBuilder is an optional interface that a Builder can implement to
135154
// indicate its capability to build server-side filters.
136155
type ServerFilterBuilder interface {
@@ -149,7 +168,7 @@ type ServerFilter interface {
149168
//
150169
// It is valid for this method to return a nil Interceptor and a nil error.
151170
// In this case, the RPC will not be intercepted by this filter.
152-
BuildServerInterceptor(config, override FilterConfig) (iresolver.ServerInterceptor, error)
171+
BuildServerInterceptor(config, override FilterConfig) (ServerInterceptor, error)
153172

154173
// Close is called when the filter is no longer needed.
155174
Close()

internal/xds/httpfilter/rbac/rbac.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,11 @@
2020
package rbac
2121

2222
import (
23-
"context"
2423
"errors"
2524
"fmt"
2625
"strings"
2726

28-
"google.golang.org/grpc/internal/resolver"
27+
"google.golang.org/grpc"
2928
"google.golang.org/grpc/internal/xds/httpfilter"
3029
"google.golang.org/grpc/internal/xds/rbac"
3130
"google.golang.org/protobuf/proto"
@@ -236,7 +235,7 @@ type serverFilter struct{}
236235

237236
func (serverFilter) Close() {}
238237

239-
func (serverFilter) BuildServerInterceptor(cfg httpfilter.FilterConfig, override httpfilter.FilterConfig) (resolver.ServerInterceptor, error) {
238+
func (serverFilter) BuildServerInterceptor(cfg httpfilter.FilterConfig, override httpfilter.FilterConfig) (httpfilter.ServerInterceptor, error) {
240239
if cfg == nil {
241240
return nil, fmt.Errorf("rbac: nil config provided")
242241
}
@@ -270,8 +269,11 @@ type interceptor struct {
270269
chainEngine *rbac.ChainEngine
271270
}
272271

273-
func (i *interceptor) AllowRPC(ctx context.Context) error {
274-
return i.chainEngine.IsAuthorized(ctx)
272+
func (i *interceptor) InterceptRPC(ss grpc.ServerStream) (grpc.ServerStream, error) {
273+
if err := i.chainEngine.IsAuthorized(ss.Context()); err != nil {
274+
return nil, err
275+
}
276+
return ss, nil
275277
}
276278

277279
func (i *interceptor) Close() {}

internal/xds/httpfilter/router/router.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ package router
2222
import (
2323
"fmt"
2424

25-
iresolver "google.golang.org/grpc/internal/resolver"
2625
"google.golang.org/grpc/internal/xds/httpfilter"
2726
"google.golang.org/protobuf/proto"
2827
"google.golang.org/protobuf/types/known/anypb"
@@ -104,7 +103,7 @@ func (filter) BuildClientInterceptor(cfg, override httpfilter.FilterConfig) (htt
104103
return nil, nil
105104
}
106105

107-
func (filter) BuildServerInterceptor(cfg, override httpfilter.FilterConfig) (iresolver.ServerInterceptor, error) {
106+
func (filter) BuildServerInterceptor(cfg, override httpfilter.FilterConfig) (httpfilter.ServerInterceptor, error) {
108107
if _, ok := cfg.(config); !ok {
109108
return nil, fmt.Errorf("router: incorrect config type provided (%T): %v", cfg, cfg)
110109
}

internal/xds/server/filter_chain_manager.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,15 @@
1818
package server
1919

2020
import (
21-
"context"
2221
"errors"
2322
"fmt"
2423
"net/netip"
2524
"slices"
2625
"strings"
2726
"sync/atomic"
2827

28+
"google.golang.org/grpc"
2929
"google.golang.org/grpc/codes"
30-
"google.golang.org/grpc/internal/resolver"
3130
"google.golang.org/grpc/internal/xds/httpfilter"
3231
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource"
3332
"google.golang.org/grpc/status"
@@ -209,7 +208,7 @@ type virtualHostWithInterceptors struct {
209208
type routeWithInterceptors struct {
210209
matcher *xdsresource.CompositeMatcher
211210
actionType xdsresource.RouteActionType
212-
interceptor resolver.ServerInterceptor
211+
interceptor httpfilter.ServerInterceptor
213212
}
214213

215214
type lookupParams struct {
@@ -500,9 +499,9 @@ func (rc *usableRouteConfiguration) statusErrWithNodeID(c codes.Code, msg string
500499
return status.Error(c, fmt.Sprintf("[xDS node id: %v]: %s", rc.nodeID, fmt.Sprintf(msg, args...)))
501500
}
502501

503-
func (fc *filterChain) newInterceptor(routeOverride, virtualHostOverride map[string]httpfilter.FilterConfig, provider serverFilterProvider) (_ resolver.ServerInterceptor, _ []httpfilter.ServerFilter, err error) {
502+
func (fc *filterChain) newInterceptor(routeOverride, virtualHostOverride map[string]httpfilter.FilterConfig, provider serverFilterProvider) (_ httpfilter.ServerInterceptor, _ []httpfilter.ServerFilter, err error) {
504503
serverFilters := []httpfilter.ServerFilter{}
505-
interceptors := make([]resolver.ServerInterceptor, 0, len(fc.httpFilters))
504+
interceptors := make([]httpfilter.ServerInterceptor, 0, len(fc.httpFilters))
506505
defer func() {
507506
if err != nil {
508507
for _, sf := range serverFilters {
@@ -549,16 +548,18 @@ func (fc *filterChain) newInterceptor(routeOverride, virtualHostOverride map[str
549548
}
550549

551550
type interceptorList struct {
552-
interceptors []resolver.ServerInterceptor
551+
interceptors []httpfilter.ServerInterceptor
553552
}
554553

555-
func (il *interceptorList) AllowRPC(ctx context.Context) error {
554+
func (il *interceptorList) InterceptRPC(ss grpc.ServerStream) (grpc.ServerStream, error) {
555+
var err error
556556
for _, i := range il.interceptors {
557-
if err := i.AllowRPC(ctx); err != nil {
558-
return err
557+
ss, err = i.InterceptRPC(ss)
558+
if err != nil {
559+
return nil, err
559560
}
560561
}
561-
return nil
562+
return ss, nil
562563
}
563564

564565
func (il *interceptorList) Close() {

internal/xds/server/filter_chain_manager_test.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
package server
1919

2020
import (
21-
"context"
2221
"errors"
2322
"fmt"
2423
"net/netip"
@@ -28,8 +27,8 @@ import (
2827

2928
"github.com/google/go-cmp/cmp"
3029
"github.com/google/go-cmp/cmp/cmpopts"
30+
"google.golang.org/grpc"
3131
"google.golang.org/grpc/credentials/tls/certprovider"
32-
iresolver "google.golang.org/grpc/internal/resolver"
3332
"google.golang.org/grpc/internal/testutils"
3433
"google.golang.org/grpc/internal/testutils/xds/e2e"
3534
"google.golang.org/grpc/internal/xds/bootstrap"
@@ -569,7 +568,7 @@ func (fb *filterBuilder) Close() {}
569568

570569
var _ httpfilter.ServerFilterBuilder = &filterBuilder{}
571570

572-
func (fb *filterBuilder) BuildServerInterceptor(config httpfilter.FilterConfig, override httpfilter.FilterConfig) (iresolver.ServerInterceptor, error) {
571+
func (fb *filterBuilder) BuildServerInterceptor(config httpfilter.FilterConfig, override httpfilter.FilterConfig) (httpfilter.ServerInterceptor, error) {
573572
var level string
574573
level = config.(filterCfg).level
575574

@@ -583,8 +582,8 @@ type serverInterceptor struct {
583582
level string
584583
}
585584

586-
func (si *serverInterceptor) AllowRPC(context.Context) error {
587-
return errors.New(si.level)
585+
func (si *serverInterceptor) InterceptRPC(grpc.ServerStream) (grpc.ServerStream, error) {
586+
return nil, errors.New(si.level)
588587
}
589588

590589
func (si *serverInterceptor) Close() {}
@@ -699,8 +698,6 @@ func (s) TestHTTPFilterInstantiation(t *testing.T) {
699698
wantErrs: []string{topLevel, vhLevel, rLevel},
700699
},
701700
}
702-
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
703-
defer cancel()
704701
for _, test := range tests {
705702
t.Run(test.name, func(t *testing.T) {
706703
fc := filterChain{
@@ -727,7 +724,8 @@ func (s) TestHTTPFilterInstantiation(t *testing.T) {
727724
var errs []string
728725
for _, vh := range urc.vhs {
729726
for _, r := range vh.routes {
730-
errs = append(errs, r.interceptor.AllowRPC(ctx).Error())
727+
_, err := r.interceptor.InterceptRPC(nil)
728+
errs = append(errs, err.Error())
731729
}
732730
}
733731
if !cmp.Equal(errs, test.wantErrs) {

internal/xds/server/routing.go

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,25 @@
1919
package server
2020

2121
import (
22-
"context"
2322
"errors"
24-
"fmt"
2523
"strings"
2624

2725
"google.golang.org/grpc"
2826
"google.golang.org/grpc/codes"
2927
"google.golang.org/grpc/internal/transport"
3028
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource"
3129
"google.golang.org/grpc/metadata"
32-
"google.golang.org/grpc/status"
3330
)
3431

3532
// RouteAndProcess routes the incoming RPC to a configured route in the route
3633
// table and also processes the RPC by running the incoming RPC through any HTTP
3734
// Filters configured.
38-
func RouteAndProcess(ctx context.Context) error {
35+
func RouteAndProcess(ss grpc.ServerStream) (grpc.ServerStream, error) {
36+
ctx := ss.Context()
3937
conn := transport.GetConnection(ctx)
4038
cw, ok := conn.(*connWrapper)
4139
if !ok {
42-
return errors.New("missing virtual hosts in incoming context")
40+
return nil, errors.New("missing virtual hosts in incoming context")
4341
}
4442

4543
rc := cw.urc.Load()
@@ -50,28 +48,28 @@ func RouteAndProcess(ctx context.Context) error {
5048
if logger.V(2) {
5149
logger.Infof("RPC on connection with xDS Configuration error: %v", rc.err)
5250
}
53-
return status.Error(codes.Unavailable, fmt.Sprintf("error from xDS configuration for matched route configuration: %v", rc.err))
51+
return nil, rc.statusErrWithNodeID(codes.Unavailable, "error from xDS configuration for matched route configuration: %v", rc.err)
5452
}
5553

5654
mn, ok := grpc.Method(ctx)
5755
if !ok {
58-
return errors.New("missing method name in incoming context")
56+
return nil, rc.statusErrWithNodeID(codes.Internal, "missing method name in incoming context")
5957
}
6058
md, ok := metadata.FromIncomingContext(ctx)
6159
if !ok {
62-
return errors.New("missing metadata in incoming context")
60+
return nil, rc.statusErrWithNodeID(codes.Internal, "missing metadata in incoming context")
6361
}
6462
// A41 added logic to the core grpc implementation to guarantee that once the
6563
// RPC gets to this point, there will be a single, unambiguous authority
6664
// present in the header map. But add a defensive check to ensure authority
6765
// header is present.
6866
authority := md.Get(":authority")
6967
if len(authority) == 0 {
70-
return rc.statusErrWithNodeID(codes.Internal, "no :authority header present")
68+
return nil, rc.statusErrWithNodeID(codes.Internal, "no :authority header present")
7169
}
7270
vh := findBestMatchingVirtualHostServer(authority[0], rc.vhs)
7371
if vh == nil {
74-
return rc.statusErrWithNodeID(codes.Unavailable, "the incoming RPC did not match a configured Virtual Host")
72+
return nil, rc.statusErrWithNodeID(codes.Unavailable, "the incoming RPC did not match a configured Virtual Host")
7573
}
7674

7775
var rwi *routeWithInterceptors
@@ -81,19 +79,19 @@ func RouteAndProcess(ctx context.Context) error {
8179
// server-side; a route with an inappropriate action causes RPCs
8280
// matching that route to fail with UNAVAILABLE." - A36
8381
if r.actionType != xdsresource.RouteActionNonForwardingAction {
84-
return rc.statusErrWithNodeID(codes.Unavailable, "the incoming RPC matched to a route that was not of action type non forwarding")
82+
return nil, rc.statusErrWithNodeID(codes.Unavailable, "the incoming RPC matched to a route that was not of action type non forwarding")
8583
}
8684
rwi = &r
8785
break
8886
}
8987
}
9088
if rwi == nil {
91-
return rc.statusErrWithNodeID(codes.Unavailable, "the incoming RPC did not match a configured Route")
89+
return nil, rc.statusErrWithNodeID(codes.Unavailable, "the incoming RPC did not match a configured Route")
9290
}
93-
if err := rwi.interceptor.AllowRPC(ctx); err != nil {
94-
return rc.statusErrWithNodeID(codes.PermissionDenied, "Incoming RPC is not allowed: %v", err)
91+
if rwi.interceptor != nil {
92+
return rwi.interceptor.InterceptRPC(ss)
9593
}
96-
return nil
94+
return ss, nil
9795
}
9896

9997
// findBestMatchingVirtualHostServer returns the virtual host whose domains field best

internal/xds/server/routing_test.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ func (s *testServerTransportStream) SetHeader(metadata.MD) error { return nil }
125125
func (s *testServerTransportStream) SendHeader(metadata.MD) error { return nil }
126126
func (s *testServerTransportStream) SetTrailer(metadata.MD) error { return nil }
127127

128+
type testServerStream struct {
129+
grpc.ServerStream
130+
ctx context.Context
131+
}
132+
133+
func (s *testServerStream) Context() context.Context {
134+
return s.ctx
135+
}
136+
128137
func (s) TestRouteAndProcess_MissingAuthority(t *testing.T) {
129138
var ptr atomic.Pointer[usableRouteConfiguration]
130139
ptr.Store(&usableRouteConfiguration{})
@@ -135,7 +144,8 @@ func (s) TestRouteAndProcess_MissingAuthority(t *testing.T) {
135144
ctx = grpc.NewContextWithServerTransportStream(ctx, &testServerTransportStream{method: "/test.Service/Method"})
136145
ctx = metadata.NewIncomingContext(ctx, metadata.MD{})
137146

138-
err := RouteAndProcess(ctx)
147+
ss := &testServerStream{ctx: ctx}
148+
_, err := RouteAndProcess(ss)
139149
if status.Code(err) != codes.Internal {
140150
t.Fatalf("RouteAndProcess() returned error code %v, want %v", status.Code(err), codes.Internal)
141151
}

0 commit comments

Comments
 (0)