snapshot of https://github.com/grpc/grpc-go.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
Testing / vet-proto (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Stale bot / stale (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-15 20:40:15 +05:00
commit e241b33f26
1365 changed files with 339570 additions and 0 deletions

View File

@@ -0,0 +1,192 @@
/*
*
* Copyright 2026 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package server
import (
"errors"
"strings"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/internal/transport"
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource"
"google.golang.org/grpc/metadata"
)
// RouteAndProcess routes the incoming RPC to a configured route in the route
// table and also processes the RPC by running the incoming RPC through any HTTP
// Filters configured.
func RouteAndProcess(ss grpc.ServerStream) (grpc.ServerStream, error) {
ctx := ss.Context()
conn := transport.GetConnection(ctx)
cw, ok := conn.(*connWrapper)
if !ok {
return nil, errors.New("missing virtual hosts in incoming context")
}
rc := cw.urc.Load()
// Error out at routing l7 level with a status code UNAVAILABLE, represents
// an nack before usable route configuration or resource not found for RDS
// or error combining LDS + RDS (Shouldn't happen).
if rc.err != nil {
if logger.V(2) {
logger.Infof("RPC on connection with xDS Configuration error: %v", rc.err)
}
return nil, rc.statusErrWithNodeID(codes.Unavailable, "error from xDS configuration for matched route configuration: %v", rc.err)
}
mn, ok := grpc.Method(ctx)
if !ok {
return nil, rc.statusErrWithNodeID(codes.Internal, "missing method name in incoming context")
}
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, rc.statusErrWithNodeID(codes.Internal, "missing metadata in incoming context")
}
// A41 added logic to the core grpc implementation to guarantee that once the
// RPC gets to this point, there will be a single, unambiguous authority
// present in the header map. But add a defensive check to ensure authority
// header is present.
authority := md.Get(":authority")
if len(authority) == 0 {
return nil, rc.statusErrWithNodeID(codes.Internal, "no :authority header present")
}
vh := findBestMatchingVirtualHostServer(authority[0], rc.vhs)
if vh == nil {
return nil, rc.statusErrWithNodeID(codes.Unavailable, "the incoming RPC did not match a configured Virtual Host")
}
var rwi *routeWithInterceptors
for _, r := range vh.routes {
if r.matcher.Match(mn, md) {
// "NonForwardingAction is expected for all Routes used on
// server-side; a route with an inappropriate action causes RPCs
// matching that route to fail with UNAVAILABLE." - A36
if r.actionType != xdsresource.RouteActionNonForwardingAction {
return nil, rc.statusErrWithNodeID(codes.Unavailable, "the incoming RPC matched to a route that was not of action type non forwarding")
}
rwi = &r
break
}
}
if rwi == nil {
return nil, rc.statusErrWithNodeID(codes.Unavailable, "the incoming RPC did not match a configured Route")
}
if rwi.interceptor != nil {
return rwi.interceptor.InterceptRPC(ss)
}
return ss, nil
}
// findBestMatchingVirtualHostServer returns the virtual host whose domains field best
// matches host
//
// The domains field support 4 different matching pattern types:
//
// - Exact match
// - Suffix match (e.g. “*ABC”)
// - Prefix match (e.g. “ABC*)
// - Universal match (e.g. “*”)
//
// The best match is defined as:
// - A match is better if it’s matching pattern type is better.
// * Exact match > suffix match > prefix match > universal match.
//
// - If two matches are of the same pattern type, the longer match is
// better.
// * This is to compare the length of the matching pattern, e.g. “*ABCDE” >
// “*ABC”
func findBestMatchingVirtualHostServer(authority string, vHosts []virtualHostWithInterceptors) *virtualHostWithInterceptors {
var (
matchVh *virtualHostWithInterceptors
matchType = domainMatchTypeInvalid
matchLen int
)
for _, vh := range vHosts {
for _, domain := range vh.domains {
typ, matched := match(domain, authority)
if typ == domainMatchTypeInvalid {
// The rds response is invalid.
return nil
}
if matchType.betterThan(typ) || matchType == typ && matchLen >= len(domain) || !matched {
// The previous match has better type, or the previous match has
// better length, or this domain isn't a match.
continue
}
matchVh = &vh
matchType = typ
matchLen = len(domain)
}
}
return matchVh
}
type domainMatchType int
const (
domainMatchTypeInvalid domainMatchType = iota
domainMatchTypeUniversal
domainMatchTypePrefix
domainMatchTypeSuffix
domainMatchTypeExact
)
// Exact > Suffix > Prefix > Universal > Invalid.
func (t domainMatchType) betterThan(b domainMatchType) bool {
return t > b
}
func matchTypeForDomain(d string) domainMatchType {
if d == "" {
return domainMatchTypeInvalid
}
if d == "*" {
return domainMatchTypeUniversal
}
if strings.HasPrefix(d, "*") {
return domainMatchTypeSuffix
}
if strings.HasSuffix(d, "*") {
return domainMatchTypePrefix
}
if strings.Contains(d, "*") {
return domainMatchTypeInvalid
}
return domainMatchTypeExact
}
func match(domain, host string) (domainMatchType, bool) {
switch typ := matchTypeForDomain(domain); typ {
case domainMatchTypeInvalid:
return typ, false
case domainMatchTypeUniversal:
return typ, true
case domainMatchTypePrefix:
// abc.*
return typ, strings.HasPrefix(host, strings.TrimSuffix(domain, "*"))
case domainMatchTypeSuffix:
// *.123
return typ, strings.HasSuffix(host, strings.TrimPrefix(domain, "*"))
case domainMatchTypeExact:
return typ, domain == host
default:
return domainMatchTypeInvalid, false
}
}