diff options
| author | KubeEdge Bot <48982446+kubeedge-bot@users.noreply.github.com> | 2024-07-11 10:16:54 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-11 10:16:54 +0800 |
| commit | 530bedfb151c4d1ac226c14a332fde59c7f2266c (patch) | |
| tree | 3ec616656344be9013c26929e03347bb12c35c82 /vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go | |
| parent | Merge pull request #5545 from luomengY/automated-cherry-pick-of-#5467-upstrea... (diff) | |
| parent | update k8s version to v1.27.15 in CI (diff) | |
| download | kubeedge-530bedfb151c4d1ac226c14a332fde59c7f2266c.tar.gz | |
Merge pull request #5699 from Shelley-BaoYue/bump-k8s-v1.27.15
Bump k8s from v1.27.7 to v1.27.15
Diffstat (limited to 'vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go')
| -rw-r--r-- | vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go | 98 |
1 files changed, 92 insertions, 6 deletions
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go index 46a4aabaf..8ba71a9e0 100644 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go +++ b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go @@ -6,10 +6,13 @@ import ( "fmt" "net/http" "net/textproto" + "regexp" "strings" "github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/health/grpc_health_v1" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" @@ -23,15 +26,15 @@ const ( // path string before doing any routing. UnescapingModeLegacy UnescapingMode = iota - // EscapingTypeExceptReserved unescapes all path parameters except RFC 6570 + // UnescapingModeAllExceptReserved unescapes all path parameters except RFC 6570 // reserved characters. UnescapingModeAllExceptReserved - // EscapingTypeExceptSlash unescapes URL path parameters except path - // seperators, which will be left as "%2F". + // UnescapingModeAllExceptSlash unescapes URL path parameters except path + // separators, which will be left as "%2F". UnescapingModeAllExceptSlash - // URL path parameters will be fully decoded. + // UnescapingModeAllCharacters unescapes all URL path parameters. UnescapingModeAllCharacters // UnescapingModeDefault is the default escaping type. @@ -40,6 +43,10 @@ const ( UnescapingModeDefault = UnescapingModeLegacy ) +var ( + encodedPathSplitter = regexp.MustCompile("(/|%2F)") +) + // A HandlerFunc handles a specific pair of path pattern and HTTP method. type HandlerFunc func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) @@ -113,11 +120,30 @@ func DefaultHeaderMatcher(key string) (string, bool) { // This matcher will be called with each header in http.Request. If matcher returns true, that header will be // passed to gRPC context. To transform the header before passing to gRPC context, matcher should return modified header. func WithIncomingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption { + for _, header := range fn.matchedMalformedHeaders() { + grpclog.Warningf("The configured forwarding filter would allow %q to be sent to the gRPC server, which will likely cause errors. See https://github.com/grpc/grpc-go/pull/4803#issuecomment-986093310 for more information.", header) + } + return func(mux *ServeMux) { mux.incomingHeaderMatcher = fn } } +// matchedMalformedHeaders returns the malformed headers that would be forwarded to gRPC server. +func (fn HeaderMatcherFunc) matchedMalformedHeaders() []string { + if fn == nil { + return nil + } + headers := make([]string, 0) + for header := range malformedHTTPHeaders { + out, accept := fn(header) + if accept && isMalformedHTTPHeader(out) { + headers = append(headers, out) + } + } + return headers +} + // WithOutgoingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for outgoing response from gateway. // // This matcher will be called with each header in response header metadata. If matcher returns true, that header will be @@ -179,6 +205,57 @@ func WithDisablePathLengthFallback() ServeMuxOption { } } +// WithHealthEndpointAt returns a ServeMuxOption that will add an endpoint to the created ServeMux at the path specified by endpointPath. +// When called the handler will forward the request to the upstream grpc service health check (defined in the +// gRPC Health Checking Protocol). +// +// See here https://grpc-ecosystem.github.io/grpc-gateway/docs/operations/health_check/ for more information on how +// to setup the protocol in the grpc server. +// +// If you define a service as query parameter, this will also be forwarded as service in the HealthCheckRequest. +func WithHealthEndpointAt(healthCheckClient grpc_health_v1.HealthClient, endpointPath string) ServeMuxOption { + return func(s *ServeMux) { + // error can be ignored since pattern is definitely valid + _ = s.HandlePath( + http.MethodGet, endpointPath, func(w http.ResponseWriter, r *http.Request, _ map[string]string, + ) { + _, outboundMarshaler := MarshalerForRequest(s, r) + + resp, err := healthCheckClient.Check(r.Context(), &grpc_health_v1.HealthCheckRequest{ + Service: r.URL.Query().Get("service"), + }) + if err != nil { + s.errorHandler(r.Context(), s, outboundMarshaler, w, r, err) + return + } + + w.Header().Set("Content-Type", "application/json") + + if resp.GetStatus() != grpc_health_v1.HealthCheckResponse_SERVING { + var err error + switch resp.GetStatus() { + case grpc_health_v1.HealthCheckResponse_NOT_SERVING, grpc_health_v1.HealthCheckResponse_UNKNOWN: + err = status.Error(codes.Unavailable, resp.String()) + case grpc_health_v1.HealthCheckResponse_SERVICE_UNKNOWN: + err = status.Error(codes.NotFound, resp.String()) + } + + s.errorHandler(r.Context(), s, outboundMarshaler, w, r, err) + return + } + + _ = outboundMarshaler.NewEncoder(w).Encode(resp) + }) + } +} + +// WithHealthzEndpoint returns a ServeMuxOption that will add a /healthz endpoint to the created ServeMux. +// +// See WithHealthEndpointAt for the general implementation. +func WithHealthzEndpoint(healthCheckClient grpc_health_v1.HealthClient) ServeMuxOption { + return WithHealthEndpointAt(healthCheckClient, "/healthz") +} + // NewServeMux returns a new ServeMux whose internal mapping is empty. func NewServeMux(opts ...ServeMuxOption) *ServeMux { serveMux := &ServeMux{ @@ -229,7 +306,7 @@ func (s *ServeMux) HandlePath(meth string, pathPattern string, h HandlerFunc) er return nil } -// ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.Path. +// ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.URL.Path. func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() @@ -245,7 +322,16 @@ func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { path = r.URL.RawPath } - components := strings.Split(path[1:], "/") + var components []string + // since in UnescapeModeLegacy, the URL will already have been fully unescaped, if we also split on "%2F" + // in this escaping mode we would be double unescaping but in UnescapingModeAllCharacters, we still do as the + // path is the RawPath (i.e. unescaped). That does mean that the behavior of this function will change its default + // behavior when the UnescapingModeDefault gets changed from UnescapingModeLegacy to UnescapingModeAllExceptReserved + if s.unescapingMode == UnescapingModeAllCharacters { + components = encodedPathSplitter.Split(path[1:], -1) + } else { + components = strings.Split(path[1:], "/") + } if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) { r.Method = strings.ToUpper(override) |
