mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 01:32:25 -05:00 
			
		
		
		
	feat: initial tracing support (#1623)
This commit is contained in:
		
					parent
					
						
							
								878ed48de3
							
						
					
				
			
			
				commit
				
					
						6392e00653
					
				
			
		
					 472 changed files with 102600 additions and 12 deletions
				
			
		
							
								
								
									
										91
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/BUILD.bazel
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,91 @@ | |||
| load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") | ||||
| 
 | ||||
| package(default_visibility = ["//visibility:public"]) | ||||
| 
 | ||||
| go_library( | ||||
|     name = "runtime", | ||||
|     srcs = [ | ||||
|         "context.go", | ||||
|         "convert.go", | ||||
|         "doc.go", | ||||
|         "errors.go", | ||||
|         "fieldmask.go", | ||||
|         "handler.go", | ||||
|         "marshal_httpbodyproto.go", | ||||
|         "marshal_json.go", | ||||
|         "marshal_jsonpb.go", | ||||
|         "marshal_proto.go", | ||||
|         "marshaler.go", | ||||
|         "marshaler_registry.go", | ||||
|         "mux.go", | ||||
|         "pattern.go", | ||||
|         "proto2_convert.go", | ||||
|         "query.go", | ||||
|     ], | ||||
|     importpath = "github.com/grpc-ecosystem/grpc-gateway/v2/runtime", | ||||
|     deps = [ | ||||
|         "//internal/httprule", | ||||
|         "//utilities", | ||||
|         "@go_googleapis//google/api:httpbody_go_proto", | ||||
|         "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", | ||||
|         "@org_golang_google_grpc//codes", | ||||
|         "@org_golang_google_grpc//grpclog", | ||||
|         "@org_golang_google_grpc//metadata", | ||||
|         "@org_golang_google_grpc//status", | ||||
|         "@org_golang_google_protobuf//encoding/protojson", | ||||
|         "@org_golang_google_protobuf//proto", | ||||
|         "@org_golang_google_protobuf//reflect/protoreflect", | ||||
|         "@org_golang_google_protobuf//reflect/protoregistry", | ||||
|         "@org_golang_google_protobuf//types/known/durationpb", | ||||
|         "@org_golang_google_protobuf//types/known/timestamppb", | ||||
|         "@org_golang_google_protobuf//types/known/wrapperspb", | ||||
|     ], | ||||
| ) | ||||
| 
 | ||||
| go_test( | ||||
|     name = "runtime_test", | ||||
|     size = "small", | ||||
|     srcs = [ | ||||
|         "context_test.go", | ||||
|         "convert_test.go", | ||||
|         "errors_test.go", | ||||
|         "fieldmask_test.go", | ||||
|         "handler_test.go", | ||||
|         "marshal_httpbodyproto_test.go", | ||||
|         "marshal_json_test.go", | ||||
|         "marshal_jsonpb_test.go", | ||||
|         "marshal_proto_test.go", | ||||
|         "marshaler_registry_test.go", | ||||
|         "mux_test.go", | ||||
|         "pattern_test.go", | ||||
|         "query_test.go", | ||||
|     ], | ||||
|     embed = [":runtime"], | ||||
|     deps = [ | ||||
|         "//runtime/internal/examplepb", | ||||
|         "//utilities", | ||||
|         "@com_github_google_go_cmp//cmp", | ||||
|         "@com_github_google_go_cmp//cmp/cmpopts", | ||||
|         "@go_googleapis//google/api:httpbody_go_proto", | ||||
|         "@go_googleapis//google/rpc:errdetails_go_proto", | ||||
|         "@go_googleapis//google/rpc:status_go_proto", | ||||
|         "@io_bazel_rules_go//proto/wkt:field_mask_go_proto", | ||||
|         "@org_golang_google_grpc//codes", | ||||
|         "@org_golang_google_grpc//metadata", | ||||
|         "@org_golang_google_grpc//status", | ||||
|         "@org_golang_google_protobuf//encoding/protojson", | ||||
|         "@org_golang_google_protobuf//proto", | ||||
|         "@org_golang_google_protobuf//testing/protocmp", | ||||
|         "@org_golang_google_protobuf//types/known/durationpb", | ||||
|         "@org_golang_google_protobuf//types/known/emptypb", | ||||
|         "@org_golang_google_protobuf//types/known/structpb", | ||||
|         "@org_golang_google_protobuf//types/known/timestamppb", | ||||
|         "@org_golang_google_protobuf//types/known/wrapperspb", | ||||
|     ], | ||||
| ) | ||||
| 
 | ||||
| alias( | ||||
|     name = "go_default_library", | ||||
|     actual = ":runtime", | ||||
|     visibility = ["//visibility:public"], | ||||
| ) | ||||
							
								
								
									
										345
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										345
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,345 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"net/textproto" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"google.golang.org/grpc/codes" | ||||
| 	"google.golang.org/grpc/metadata" | ||||
| 	"google.golang.org/grpc/status" | ||||
| ) | ||||
| 
 | ||||
| // MetadataHeaderPrefix is the http prefix that represents custom metadata | ||||
| // parameters to or from a gRPC call. | ||||
| const MetadataHeaderPrefix = "Grpc-Metadata-" | ||||
| 
 | ||||
| // MetadataPrefix is prepended to permanent HTTP header keys (as specified | ||||
| // by the IANA) when added to the gRPC context. | ||||
| const MetadataPrefix = "grpcgateway-" | ||||
| 
 | ||||
| // MetadataTrailerPrefix is prepended to gRPC metadata as it is converted to | ||||
| // HTTP headers in a response handled by grpc-gateway | ||||
| const MetadataTrailerPrefix = "Grpc-Trailer-" | ||||
| 
 | ||||
| const metadataGrpcTimeout = "Grpc-Timeout" | ||||
| const metadataHeaderBinarySuffix = "-Bin" | ||||
| 
 | ||||
| const xForwardedFor = "X-Forwarded-For" | ||||
| const xForwardedHost = "X-Forwarded-Host" | ||||
| 
 | ||||
| var ( | ||||
| 	// DefaultContextTimeout is used for gRPC call context.WithTimeout whenever a Grpc-Timeout inbound | ||||
| 	// header isn't present. If the value is 0 the sent `context` will not have a timeout. | ||||
| 	DefaultContextTimeout = 0 * time.Second | ||||
| ) | ||||
| 
 | ||||
| type ( | ||||
| 	rpcMethodKey       struct{} | ||||
| 	httpPathPatternKey struct{} | ||||
| 
 | ||||
| 	AnnotateContextOption func(ctx context.Context) context.Context | ||||
| ) | ||||
| 
 | ||||
| func WithHTTPPathPattern(pattern string) AnnotateContextOption { | ||||
| 	return func(ctx context.Context) context.Context { | ||||
| 		return withHTTPPathPattern(ctx, pattern) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func decodeBinHeader(v string) ([]byte, error) { | ||||
| 	if len(v)%4 == 0 { | ||||
| 		// Input was padded, or padding was not necessary. | ||||
| 		return base64.StdEncoding.DecodeString(v) | ||||
| 	} | ||||
| 	return base64.RawStdEncoding.DecodeString(v) | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| AnnotateContext adds context information such as metadata from the request. | ||||
| 
 | ||||
| At a minimum, the RemoteAddr is included in the fashion of "X-Forwarded-For", | ||||
| except that the forwarded destination is not another HTTP service but rather | ||||
| a gRPC service. | ||||
| */ | ||||
| func AnnotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string, options ...AnnotateContextOption) (context.Context, error) { | ||||
| 	ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName, options...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if md == nil { | ||||
| 		return ctx, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return metadata.NewOutgoingContext(ctx, md), nil | ||||
| } | ||||
| 
 | ||||
| // AnnotateIncomingContext adds context information such as metadata from the request. | ||||
| // Attach metadata as incoming context. | ||||
| func AnnotateIncomingContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string, options ...AnnotateContextOption) (context.Context, error) { | ||||
| 	ctx, md, err := annotateContext(ctx, mux, req, rpcMethodName, options...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if md == nil { | ||||
| 		return ctx, nil | ||||
| 	} | ||||
| 
 | ||||
| 	return metadata.NewIncomingContext(ctx, md), nil | ||||
| } | ||||
| 
 | ||||
| func annotateContext(ctx context.Context, mux *ServeMux, req *http.Request, rpcMethodName string, options ...AnnotateContextOption) (context.Context, metadata.MD, error) { | ||||
| 	ctx = withRPCMethod(ctx, rpcMethodName) | ||||
| 	for _, o := range options { | ||||
| 		ctx = o(ctx) | ||||
| 	} | ||||
| 	var pairs []string | ||||
| 	timeout := DefaultContextTimeout | ||||
| 	if tm := req.Header.Get(metadataGrpcTimeout); tm != "" { | ||||
| 		var err error | ||||
| 		timeout, err = timeoutDecode(tm) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, status.Errorf(codes.InvalidArgument, "invalid grpc-timeout: %s", tm) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for key, vals := range req.Header { | ||||
| 		key = textproto.CanonicalMIMEHeaderKey(key) | ||||
| 		for _, val := range vals { | ||||
| 			// For backwards-compatibility, pass through 'authorization' header with no prefix. | ||||
| 			if key == "Authorization" { | ||||
| 				pairs = append(pairs, "authorization", val) | ||||
| 			} | ||||
| 			if h, ok := mux.incomingHeaderMatcher(key); ok { | ||||
| 				// Handles "-bin" metadata in grpc, since grpc will do another base64 | ||||
| 				// encode before sending to server, we need to decode it first. | ||||
| 				if strings.HasSuffix(key, metadataHeaderBinarySuffix) { | ||||
| 					b, err := decodeBinHeader(val) | ||||
| 					if err != nil { | ||||
| 						return nil, nil, status.Errorf(codes.InvalidArgument, "invalid binary header %s: %s", key, err) | ||||
| 					} | ||||
| 
 | ||||
| 					val = string(b) | ||||
| 				} | ||||
| 				pairs = append(pairs, h, val) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if host := req.Header.Get(xForwardedHost); host != "" { | ||||
| 		pairs = append(pairs, strings.ToLower(xForwardedHost), host) | ||||
| 	} else if req.Host != "" { | ||||
| 		pairs = append(pairs, strings.ToLower(xForwardedHost), req.Host) | ||||
| 	} | ||||
| 
 | ||||
| 	if addr := req.RemoteAddr; addr != "" { | ||||
| 		if remoteIP, _, err := net.SplitHostPort(addr); err == nil { | ||||
| 			if fwd := req.Header.Get(xForwardedFor); fwd == "" { | ||||
| 				pairs = append(pairs, strings.ToLower(xForwardedFor), remoteIP) | ||||
| 			} else { | ||||
| 				pairs = append(pairs, strings.ToLower(xForwardedFor), fmt.Sprintf("%s, %s", fwd, remoteIP)) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if timeout != 0 { | ||||
| 		//nolint:govet  // The context outlives this function | ||||
| 		ctx, _ = context.WithTimeout(ctx, timeout) | ||||
| 	} | ||||
| 	if len(pairs) == 0 { | ||||
| 		return ctx, nil, nil | ||||
| 	} | ||||
| 	md := metadata.Pairs(pairs...) | ||||
| 	for _, mda := range mux.metadataAnnotators { | ||||
| 		md = metadata.Join(md, mda(ctx, req)) | ||||
| 	} | ||||
| 	return ctx, md, nil | ||||
| } | ||||
| 
 | ||||
| // ServerMetadata consists of metadata sent from gRPC server. | ||||
| type ServerMetadata struct { | ||||
| 	HeaderMD  metadata.MD | ||||
| 	TrailerMD metadata.MD | ||||
| } | ||||
| 
 | ||||
| type serverMetadataKey struct{} | ||||
| 
 | ||||
| // NewServerMetadataContext creates a new context with ServerMetadata | ||||
| func NewServerMetadataContext(ctx context.Context, md ServerMetadata) context.Context { | ||||
| 	return context.WithValue(ctx, serverMetadataKey{}, md) | ||||
| } | ||||
| 
 | ||||
| // ServerMetadataFromContext returns the ServerMetadata in ctx | ||||
| func ServerMetadataFromContext(ctx context.Context) (md ServerMetadata, ok bool) { | ||||
| 	md, ok = ctx.Value(serverMetadataKey{}).(ServerMetadata) | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // ServerTransportStream implements grpc.ServerTransportStream. | ||||
| // It should only be used by the generated files to support grpc.SendHeader | ||||
| // outside of gRPC server use. | ||||
| type ServerTransportStream struct { | ||||
| 	mu      sync.Mutex | ||||
| 	header  metadata.MD | ||||
| 	trailer metadata.MD | ||||
| } | ||||
| 
 | ||||
| // Method returns the method for the stream. | ||||
| func (s *ServerTransportStream) Method() string { | ||||
| 	return "" | ||||
| } | ||||
| 
 | ||||
| // Header returns the header metadata of the stream. | ||||
| func (s *ServerTransportStream) Header() metadata.MD { | ||||
| 	s.mu.Lock() | ||||
| 	defer s.mu.Unlock() | ||||
| 	return s.header.Copy() | ||||
| } | ||||
| 
 | ||||
| // SetHeader sets the header metadata. | ||||
| func (s *ServerTransportStream) SetHeader(md metadata.MD) error { | ||||
| 	if md.Len() == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	s.mu.Lock() | ||||
| 	s.header = metadata.Join(s.header, md) | ||||
| 	s.mu.Unlock() | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // SendHeader sets the header metadata. | ||||
| func (s *ServerTransportStream) SendHeader(md metadata.MD) error { | ||||
| 	return s.SetHeader(md) | ||||
| } | ||||
| 
 | ||||
| // Trailer returns the cached trailer metadata. | ||||
| func (s *ServerTransportStream) Trailer() metadata.MD { | ||||
| 	s.mu.Lock() | ||||
| 	defer s.mu.Unlock() | ||||
| 	return s.trailer.Copy() | ||||
| } | ||||
| 
 | ||||
| // SetTrailer sets the trailer metadata. | ||||
| func (s *ServerTransportStream) SetTrailer(md metadata.MD) error { | ||||
| 	if md.Len() == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	s.mu.Lock() | ||||
| 	s.trailer = metadata.Join(s.trailer, md) | ||||
| 	s.mu.Unlock() | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func timeoutDecode(s string) (time.Duration, error) { | ||||
| 	size := len(s) | ||||
| 	if size < 2 { | ||||
| 		return 0, fmt.Errorf("timeout string is too short: %q", s) | ||||
| 	} | ||||
| 	d, ok := timeoutUnitToDuration(s[size-1]) | ||||
| 	if !ok { | ||||
| 		return 0, fmt.Errorf("timeout unit is not recognized: %q", s) | ||||
| 	} | ||||
| 	t, err := strconv.ParseInt(s[:size-1], 10, 64) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return d * time.Duration(t), nil | ||||
| } | ||||
| 
 | ||||
| func timeoutUnitToDuration(u uint8) (d time.Duration, ok bool) { | ||||
| 	switch u { | ||||
| 	case 'H': | ||||
| 		return time.Hour, true | ||||
| 	case 'M': | ||||
| 		return time.Minute, true | ||||
| 	case 'S': | ||||
| 		return time.Second, true | ||||
| 	case 'm': | ||||
| 		return time.Millisecond, true | ||||
| 	case 'u': | ||||
| 		return time.Microsecond, true | ||||
| 	case 'n': | ||||
| 		return time.Nanosecond, true | ||||
| 	default: | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| // isPermanentHTTPHeader checks whether hdr belongs to the list of | ||||
| // permanent request headers maintained by IANA. | ||||
| // http://www.iana.org/assignments/message-headers/message-headers.xml | ||||
| func isPermanentHTTPHeader(hdr string) bool { | ||||
| 	switch hdr { | ||||
| 	case | ||||
| 		"Accept", | ||||
| 		"Accept-Charset", | ||||
| 		"Accept-Language", | ||||
| 		"Accept-Ranges", | ||||
| 		"Authorization", | ||||
| 		"Cache-Control", | ||||
| 		"Content-Type", | ||||
| 		"Cookie", | ||||
| 		"Date", | ||||
| 		"Expect", | ||||
| 		"From", | ||||
| 		"Host", | ||||
| 		"If-Match", | ||||
| 		"If-Modified-Since", | ||||
| 		"If-None-Match", | ||||
| 		"If-Schedule-Tag-Match", | ||||
| 		"If-Unmodified-Since", | ||||
| 		"Max-Forwards", | ||||
| 		"Origin", | ||||
| 		"Pragma", | ||||
| 		"Referer", | ||||
| 		"User-Agent", | ||||
| 		"Via", | ||||
| 		"Warning": | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| // RPCMethod returns the method string for the server context. The returned | ||||
| // string is in the format of "/package.service/method". | ||||
| func RPCMethod(ctx context.Context) (string, bool) { | ||||
| 	m := ctx.Value(rpcMethodKey{}) | ||||
| 	if m == nil { | ||||
| 		return "", false | ||||
| 	} | ||||
| 	ms, ok := m.(string) | ||||
| 	if !ok { | ||||
| 		return "", false | ||||
| 	} | ||||
| 	return ms, true | ||||
| } | ||||
| 
 | ||||
| func withRPCMethod(ctx context.Context, rpcMethodName string) context.Context { | ||||
| 	return context.WithValue(ctx, rpcMethodKey{}, rpcMethodName) | ||||
| } | ||||
| 
 | ||||
| // HTTPPathPattern returns the HTTP path pattern string relating to the HTTP handler, if one exists. | ||||
| // The format of the returned string is defined by the google.api.http path template type. | ||||
| func HTTPPathPattern(ctx context.Context) (string, bool) { | ||||
| 	m := ctx.Value(httpPathPatternKey{}) | ||||
| 	if m == nil { | ||||
| 		return "", false | ||||
| 	} | ||||
| 	ms, ok := m.(string) | ||||
| 	if !ok { | ||||
| 		return "", false | ||||
| 	} | ||||
| 	return ms, true | ||||
| } | ||||
| 
 | ||||
| func withHTTPPathPattern(ctx context.Context, httpPathPattern string) context.Context { | ||||
| 	return context.WithValue(ctx, httpPathPatternKey{}, httpPathPattern) | ||||
| } | ||||
							
								
								
									
										322
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/convert.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,322 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"google.golang.org/protobuf/encoding/protojson" | ||||
| 	"google.golang.org/protobuf/types/known/durationpb" | ||||
| 	"google.golang.org/protobuf/types/known/timestamppb" | ||||
| 	"google.golang.org/protobuf/types/known/wrapperspb" | ||||
| ) | ||||
| 
 | ||||
| // String just returns the given string. | ||||
| // It is just for compatibility to other types. | ||||
| func String(val string) (string, error) { | ||||
| 	return val, nil | ||||
| } | ||||
| 
 | ||||
| // StringSlice converts 'val' where individual strings are separated by | ||||
| // 'sep' into a string slice. | ||||
| func StringSlice(val, sep string) ([]string, error) { | ||||
| 	return strings.Split(val, sep), nil | ||||
| } | ||||
| 
 | ||||
| // Bool converts the given string representation of a boolean value into bool. | ||||
| func Bool(val string) (bool, error) { | ||||
| 	return strconv.ParseBool(val) | ||||
| } | ||||
| 
 | ||||
| // BoolSlice converts 'val' where individual booleans are separated by | ||||
| // 'sep' into a bool slice. | ||||
| func BoolSlice(val, sep string) ([]bool, error) { | ||||
| 	s := strings.Split(val, sep) | ||||
| 	values := make([]bool, len(s)) | ||||
| 	for i, v := range s { | ||||
| 		value, err := Bool(v) | ||||
| 		if err != nil { | ||||
| 			return values, err | ||||
| 		} | ||||
| 		values[i] = value | ||||
| 	} | ||||
| 	return values, nil | ||||
| } | ||||
| 
 | ||||
| // Float64 converts the given string representation into representation of a floating point number into float64. | ||||
| func Float64(val string) (float64, error) { | ||||
| 	return strconv.ParseFloat(val, 64) | ||||
| } | ||||
| 
 | ||||
| // Float64Slice converts 'val' where individual floating point numbers are separated by | ||||
| // 'sep' into a float64 slice. | ||||
| func Float64Slice(val, sep string) ([]float64, error) { | ||||
| 	s := strings.Split(val, sep) | ||||
| 	values := make([]float64, len(s)) | ||||
| 	for i, v := range s { | ||||
| 		value, err := Float64(v) | ||||
| 		if err != nil { | ||||
| 			return values, err | ||||
| 		} | ||||
| 		values[i] = value | ||||
| 	} | ||||
| 	return values, nil | ||||
| } | ||||
| 
 | ||||
| // Float32 converts the given string representation of a floating point number into float32. | ||||
| func Float32(val string) (float32, error) { | ||||
| 	f, err := strconv.ParseFloat(val, 32) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return float32(f), nil | ||||
| } | ||||
| 
 | ||||
| // Float32Slice converts 'val' where individual floating point numbers are separated by | ||||
| // 'sep' into a float32 slice. | ||||
| func Float32Slice(val, sep string) ([]float32, error) { | ||||
| 	s := strings.Split(val, sep) | ||||
| 	values := make([]float32, len(s)) | ||||
| 	for i, v := range s { | ||||
| 		value, err := Float32(v) | ||||
| 		if err != nil { | ||||
| 			return values, err | ||||
| 		} | ||||
| 		values[i] = value | ||||
| 	} | ||||
| 	return values, nil | ||||
| } | ||||
| 
 | ||||
| // Int64 converts the given string representation of an integer into int64. | ||||
| func Int64(val string) (int64, error) { | ||||
| 	return strconv.ParseInt(val, 0, 64) | ||||
| } | ||||
| 
 | ||||
| // Int64Slice converts 'val' where individual integers are separated by | ||||
| // 'sep' into a int64 slice. | ||||
| func Int64Slice(val, sep string) ([]int64, error) { | ||||
| 	s := strings.Split(val, sep) | ||||
| 	values := make([]int64, len(s)) | ||||
| 	for i, v := range s { | ||||
| 		value, err := Int64(v) | ||||
| 		if err != nil { | ||||
| 			return values, err | ||||
| 		} | ||||
| 		values[i] = value | ||||
| 	} | ||||
| 	return values, nil | ||||
| } | ||||
| 
 | ||||
| // Int32 converts the given string representation of an integer into int32. | ||||
| func Int32(val string) (int32, error) { | ||||
| 	i, err := strconv.ParseInt(val, 0, 32) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return int32(i), nil | ||||
| } | ||||
| 
 | ||||
| // Int32Slice converts 'val' where individual integers are separated by | ||||
| // 'sep' into a int32 slice. | ||||
| func Int32Slice(val, sep string) ([]int32, error) { | ||||
| 	s := strings.Split(val, sep) | ||||
| 	values := make([]int32, len(s)) | ||||
| 	for i, v := range s { | ||||
| 		value, err := Int32(v) | ||||
| 		if err != nil { | ||||
| 			return values, err | ||||
| 		} | ||||
| 		values[i] = value | ||||
| 	} | ||||
| 	return values, nil | ||||
| } | ||||
| 
 | ||||
| // Uint64 converts the given string representation of an integer into uint64. | ||||
| func Uint64(val string) (uint64, error) { | ||||
| 	return strconv.ParseUint(val, 0, 64) | ||||
| } | ||||
| 
 | ||||
| // Uint64Slice converts 'val' where individual integers are separated by | ||||
| // 'sep' into a uint64 slice. | ||||
| func Uint64Slice(val, sep string) ([]uint64, error) { | ||||
| 	s := strings.Split(val, sep) | ||||
| 	values := make([]uint64, len(s)) | ||||
| 	for i, v := range s { | ||||
| 		value, err := Uint64(v) | ||||
| 		if err != nil { | ||||
| 			return values, err | ||||
| 		} | ||||
| 		values[i] = value | ||||
| 	} | ||||
| 	return values, nil | ||||
| } | ||||
| 
 | ||||
| // Uint32 converts the given string representation of an integer into uint32. | ||||
| func Uint32(val string) (uint32, error) { | ||||
| 	i, err := strconv.ParseUint(val, 0, 32) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	return uint32(i), nil | ||||
| } | ||||
| 
 | ||||
| // Uint32Slice converts 'val' where individual integers are separated by | ||||
| // 'sep' into a uint32 slice. | ||||
| func Uint32Slice(val, sep string) ([]uint32, error) { | ||||
| 	s := strings.Split(val, sep) | ||||
| 	values := make([]uint32, len(s)) | ||||
| 	for i, v := range s { | ||||
| 		value, err := Uint32(v) | ||||
| 		if err != nil { | ||||
| 			return values, err | ||||
| 		} | ||||
| 		values[i] = value | ||||
| 	} | ||||
| 	return values, nil | ||||
| } | ||||
| 
 | ||||
| // Bytes converts the given string representation of a byte sequence into a slice of bytes | ||||
| // A bytes sequence is encoded in URL-safe base64 without padding | ||||
| func Bytes(val string) ([]byte, error) { | ||||
| 	b, err := base64.StdEncoding.DecodeString(val) | ||||
| 	if err != nil { | ||||
| 		b, err = base64.URLEncoding.DecodeString(val) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	return b, nil | ||||
| } | ||||
| 
 | ||||
| // BytesSlice converts 'val' where individual bytes sequences, encoded in URL-safe | ||||
| // base64 without padding, are separated by 'sep' into a slice of bytes slices slice. | ||||
| func BytesSlice(val, sep string) ([][]byte, error) { | ||||
| 	s := strings.Split(val, sep) | ||||
| 	values := make([][]byte, len(s)) | ||||
| 	for i, v := range s { | ||||
| 		value, err := Bytes(v) | ||||
| 		if err != nil { | ||||
| 			return values, err | ||||
| 		} | ||||
| 		values[i] = value | ||||
| 	} | ||||
| 	return values, nil | ||||
| } | ||||
| 
 | ||||
| // Timestamp converts the given RFC3339 formatted string into a timestamp.Timestamp. | ||||
| func Timestamp(val string) (*timestamppb.Timestamp, error) { | ||||
| 	var r timestamppb.Timestamp | ||||
| 	val = strconv.Quote(strings.Trim(val, `"`)) | ||||
| 	unmarshaler := &protojson.UnmarshalOptions{} | ||||
| 	err := unmarshaler.Unmarshal([]byte(val), &r) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &r, nil | ||||
| } | ||||
| 
 | ||||
| // Duration converts the given string into a timestamp.Duration. | ||||
| func Duration(val string) (*durationpb.Duration, error) { | ||||
| 	var r durationpb.Duration | ||||
| 	val = strconv.Quote(strings.Trim(val, `"`)) | ||||
| 	unmarshaler := &protojson.UnmarshalOptions{} | ||||
| 	err := unmarshaler.Unmarshal([]byte(val), &r) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &r, nil | ||||
| } | ||||
| 
 | ||||
| // Enum converts the given string into an int32 that should be type casted into the | ||||
| // correct enum proto type. | ||||
| func Enum(val string, enumValMap map[string]int32) (int32, error) { | ||||
| 	e, ok := enumValMap[val] | ||||
| 	if ok { | ||||
| 		return e, nil | ||||
| 	} | ||||
| 
 | ||||
| 	i, err := Int32(val) | ||||
| 	if err != nil { | ||||
| 		return 0, fmt.Errorf("%s is not valid", val) | ||||
| 	} | ||||
| 	for _, v := range enumValMap { | ||||
| 		if v == i { | ||||
| 			return i, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return 0, fmt.Errorf("%s is not valid", val) | ||||
| } | ||||
| 
 | ||||
| // EnumSlice converts 'val' where individual enums are separated by 'sep' | ||||
| // into a int32 slice. Each individual int32 should be type casted into the | ||||
| // correct enum proto type. | ||||
| func EnumSlice(val, sep string, enumValMap map[string]int32) ([]int32, error) { | ||||
| 	s := strings.Split(val, sep) | ||||
| 	values := make([]int32, len(s)) | ||||
| 	for i, v := range s { | ||||
| 		value, err := Enum(v, enumValMap) | ||||
| 		if err != nil { | ||||
| 			return values, err | ||||
| 		} | ||||
| 		values[i] = value | ||||
| 	} | ||||
| 	return values, nil | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| 	Support fot google.protobuf.wrappers on top of primitive types | ||||
| */ | ||||
| 
 | ||||
| // StringValue well-known type support as wrapper around string type | ||||
| func StringValue(val string) (*wrapperspb.StringValue, error) { | ||||
| 	return &wrapperspb.StringValue{Value: val}, nil | ||||
| } | ||||
| 
 | ||||
| // FloatValue well-known type support as wrapper around float32 type | ||||
| func FloatValue(val string) (*wrapperspb.FloatValue, error) { | ||||
| 	parsedVal, err := Float32(val) | ||||
| 	return &wrapperspb.FloatValue{Value: parsedVal}, err | ||||
| } | ||||
| 
 | ||||
| // DoubleValue well-known type support as wrapper around float64 type | ||||
| func DoubleValue(val string) (*wrapperspb.DoubleValue, error) { | ||||
| 	parsedVal, err := Float64(val) | ||||
| 	return &wrapperspb.DoubleValue{Value: parsedVal}, err | ||||
| } | ||||
| 
 | ||||
| // BoolValue well-known type support as wrapper around bool type | ||||
| func BoolValue(val string) (*wrapperspb.BoolValue, error) { | ||||
| 	parsedVal, err := Bool(val) | ||||
| 	return &wrapperspb.BoolValue{Value: parsedVal}, err | ||||
| } | ||||
| 
 | ||||
| // Int32Value well-known type support as wrapper around int32 type | ||||
| func Int32Value(val string) (*wrapperspb.Int32Value, error) { | ||||
| 	parsedVal, err := Int32(val) | ||||
| 	return &wrapperspb.Int32Value{Value: parsedVal}, err | ||||
| } | ||||
| 
 | ||||
| // UInt32Value well-known type support as wrapper around uint32 type | ||||
| func UInt32Value(val string) (*wrapperspb.UInt32Value, error) { | ||||
| 	parsedVal, err := Uint32(val) | ||||
| 	return &wrapperspb.UInt32Value{Value: parsedVal}, err | ||||
| } | ||||
| 
 | ||||
| // Int64Value well-known type support as wrapper around int64 type | ||||
| func Int64Value(val string) (*wrapperspb.Int64Value, error) { | ||||
| 	parsedVal, err := Int64(val) | ||||
| 	return &wrapperspb.Int64Value{Value: parsedVal}, err | ||||
| } | ||||
| 
 | ||||
| // UInt64Value well-known type support as wrapper around uint64 type | ||||
| func UInt64Value(val string) (*wrapperspb.UInt64Value, error) { | ||||
| 	parsedVal, err := Uint64(val) | ||||
| 	return &wrapperspb.UInt64Value{Value: parsedVal}, err | ||||
| } | ||||
| 
 | ||||
| // BytesValue well-known type support as wrapper around bytes[] type | ||||
| func BytesValue(val string) (*wrapperspb.BytesValue, error) { | ||||
| 	parsedVal, err := Bytes(val) | ||||
| 	return &wrapperspb.BytesValue{Value: parsedVal}, err | ||||
| } | ||||
							
								
								
									
										5
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/doc.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/doc.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| /* | ||||
| Package runtime contains runtime helper functions used by | ||||
| servers which protoc-gen-grpc-gateway generates. | ||||
| */ | ||||
| package runtime | ||||
							
								
								
									
										180
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/errors.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/errors.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,180 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"google.golang.org/grpc/codes" | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| 	"google.golang.org/grpc/status" | ||||
| ) | ||||
| 
 | ||||
| // ErrorHandlerFunc is the signature used to configure error handling. | ||||
| type ErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, error) | ||||
| 
 | ||||
| // StreamErrorHandlerFunc is the signature used to configure stream error handling. | ||||
| type StreamErrorHandlerFunc func(context.Context, error) *status.Status | ||||
| 
 | ||||
| // RoutingErrorHandlerFunc is the signature used to configure error handling for routing errors. | ||||
| type RoutingErrorHandlerFunc func(context.Context, *ServeMux, Marshaler, http.ResponseWriter, *http.Request, int) | ||||
| 
 | ||||
| // HTTPStatusError is the error to use when needing to provide a different HTTP status code for an error | ||||
| // passed to the DefaultRoutingErrorHandler. | ||||
| type HTTPStatusError struct { | ||||
| 	HTTPStatus int | ||||
| 	Err        error | ||||
| } | ||||
| 
 | ||||
| func (e *HTTPStatusError) Error() string { | ||||
| 	return e.Err.Error() | ||||
| } | ||||
| 
 | ||||
| // HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status. | ||||
| // See: https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto | ||||
| func HTTPStatusFromCode(code codes.Code) int { | ||||
| 	switch code { | ||||
| 	case codes.OK: | ||||
| 		return http.StatusOK | ||||
| 	case codes.Canceled: | ||||
| 		return http.StatusRequestTimeout | ||||
| 	case codes.Unknown: | ||||
| 		return http.StatusInternalServerError | ||||
| 	case codes.InvalidArgument: | ||||
| 		return http.StatusBadRequest | ||||
| 	case codes.DeadlineExceeded: | ||||
| 		return http.StatusGatewayTimeout | ||||
| 	case codes.NotFound: | ||||
| 		return http.StatusNotFound | ||||
| 	case codes.AlreadyExists: | ||||
| 		return http.StatusConflict | ||||
| 	case codes.PermissionDenied: | ||||
| 		return http.StatusForbidden | ||||
| 	case codes.Unauthenticated: | ||||
| 		return http.StatusUnauthorized | ||||
| 	case codes.ResourceExhausted: | ||||
| 		return http.StatusTooManyRequests | ||||
| 	case codes.FailedPrecondition: | ||||
| 		// Note, this deliberately doesn't translate to the similarly named '412 Precondition Failed' HTTP response status. | ||||
| 		return http.StatusBadRequest | ||||
| 	case codes.Aborted: | ||||
| 		return http.StatusConflict | ||||
| 	case codes.OutOfRange: | ||||
| 		return http.StatusBadRequest | ||||
| 	case codes.Unimplemented: | ||||
| 		return http.StatusNotImplemented | ||||
| 	case codes.Internal: | ||||
| 		return http.StatusInternalServerError | ||||
| 	case codes.Unavailable: | ||||
| 		return http.StatusServiceUnavailable | ||||
| 	case codes.DataLoss: | ||||
| 		return http.StatusInternalServerError | ||||
| 	} | ||||
| 
 | ||||
| 	grpclog.Infof("Unknown gRPC error code: %v", code) | ||||
| 	return http.StatusInternalServerError | ||||
| } | ||||
| 
 | ||||
| // HTTPError uses the mux-configured error handler. | ||||
| func HTTPError(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, err error) { | ||||
| 	mux.errorHandler(ctx, mux, marshaler, w, r, err) | ||||
| } | ||||
| 
 | ||||
| // DefaultHTTPErrorHandler is the default error handler. | ||||
| // If "err" is a gRPC Status, the function replies with the status code mapped by HTTPStatusFromCode. | ||||
| // If "err" is a HTTPStatusError, the function replies with the status code provide by that struct. This is | ||||
| // intended to allow passing through of specific statuses via the function set via WithRoutingErrorHandler | ||||
| // for the ServeMux constructor to handle edge cases which the standard mappings in HTTPStatusFromCode | ||||
| // are insufficient for. | ||||
| // If otherwise, it replies with http.StatusInternalServerError. | ||||
| // | ||||
| // The response body written by this function is a Status message marshaled by the Marshaler. | ||||
| func DefaultHTTPErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, err error) { | ||||
| 	// return Internal when Marshal failed | ||||
| 	const fallback = `{"code": 13, "message": "failed to marshal error message"}` | ||||
| 
 | ||||
| 	var customStatus *HTTPStatusError | ||||
| 	if errors.As(err, &customStatus) { | ||||
| 		err = customStatus.Err | ||||
| 	} | ||||
| 
 | ||||
| 	s := status.Convert(err) | ||||
| 	pb := s.Proto() | ||||
| 
 | ||||
| 	w.Header().Del("Trailer") | ||||
| 	w.Header().Del("Transfer-Encoding") | ||||
| 
 | ||||
| 	contentType := marshaler.ContentType(pb) | ||||
| 	w.Header().Set("Content-Type", contentType) | ||||
| 
 | ||||
| 	if s.Code() == codes.Unauthenticated { | ||||
| 		w.Header().Set("WWW-Authenticate", s.Message()) | ||||
| 	} | ||||
| 
 | ||||
| 	buf, merr := marshaler.Marshal(pb) | ||||
| 	if merr != nil { | ||||
| 		grpclog.Infof("Failed to marshal error message %q: %v", s, merr) | ||||
| 		w.WriteHeader(http.StatusInternalServerError) | ||||
| 		if _, err := io.WriteString(w, fallback); err != nil { | ||||
| 			grpclog.Infof("Failed to write response: %v", err) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	md, ok := ServerMetadataFromContext(ctx) | ||||
| 	if !ok { | ||||
| 		grpclog.Infof("Failed to extract ServerMetadata from context") | ||||
| 	} | ||||
| 
 | ||||
| 	handleForwardResponseServerMetadata(w, mux, md) | ||||
| 
 | ||||
| 	// RFC 7230 https://tools.ietf.org/html/rfc7230#section-4.1.2 | ||||
| 	// Unless the request includes a TE header field indicating "trailers" | ||||
| 	// is acceptable, as described in Section 4.3, a server SHOULD NOT | ||||
| 	// generate trailer fields that it believes are necessary for the user | ||||
| 	// agent to receive. | ||||
| 	doForwardTrailers := requestAcceptsTrailers(r) | ||||
| 
 | ||||
| 	if doForwardTrailers { | ||||
| 		handleForwardResponseTrailerHeader(w, md) | ||||
| 		w.Header().Set("Transfer-Encoding", "chunked") | ||||
| 	} | ||||
| 
 | ||||
| 	st := HTTPStatusFromCode(s.Code()) | ||||
| 	if customStatus != nil { | ||||
| 		st = customStatus.HTTPStatus | ||||
| 	} | ||||
| 
 | ||||
| 	w.WriteHeader(st) | ||||
| 	if _, err := w.Write(buf); err != nil { | ||||
| 		grpclog.Infof("Failed to write response: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if doForwardTrailers { | ||||
| 		handleForwardResponseTrailer(w, md) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func DefaultStreamErrorHandler(_ context.Context, err error) *status.Status { | ||||
| 	return status.Convert(err) | ||||
| } | ||||
| 
 | ||||
| // DefaultRoutingErrorHandler is our default handler for routing errors. | ||||
| // By default http error codes mapped on the following error codes: | ||||
| //   NotFound -> grpc.NotFound | ||||
| //   StatusBadRequest -> grpc.InvalidArgument | ||||
| //   MethodNotAllowed -> grpc.Unimplemented | ||||
| //   Other -> grpc.Internal, method is not expecting to be called for anything else | ||||
| func DefaultRoutingErrorHandler(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, r *http.Request, httpStatus int) { | ||||
| 	sterr := status.Error(codes.Internal, "Unexpected routing error") | ||||
| 	switch httpStatus { | ||||
| 	case http.StatusBadRequest: | ||||
| 		sterr = status.Error(codes.InvalidArgument, http.StatusText(httpStatus)) | ||||
| 	case http.StatusMethodNotAllowed: | ||||
| 		sterr = status.Error(codes.Unimplemented, http.StatusText(httpStatus)) | ||||
| 	case http.StatusNotFound: | ||||
| 		sterr = status.Error(codes.NotFound, http.StatusText(httpStatus)) | ||||
| 	} | ||||
| 	mux.errorHandler(ctx, mux, marshaler, w, r, sterr) | ||||
| } | ||||
							
								
								
									
										165
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/fieldmask.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/fieldmask.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,165 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"sort" | ||||
| 
 | ||||
| 	"google.golang.org/genproto/protobuf/field_mask" | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| 	"google.golang.org/protobuf/reflect/protoreflect" | ||||
| ) | ||||
| 
 | ||||
| func getFieldByName(fields protoreflect.FieldDescriptors, name string) protoreflect.FieldDescriptor { | ||||
| 	fd := fields.ByName(protoreflect.Name(name)) | ||||
| 	if fd != nil { | ||||
| 		return fd | ||||
| 	} | ||||
| 
 | ||||
| 	return fields.ByJSONName(name) | ||||
| } | ||||
| 
 | ||||
| // FieldMaskFromRequestBody creates a FieldMask printing all complete paths from the JSON body. | ||||
| func FieldMaskFromRequestBody(r io.Reader, msg proto.Message) (*field_mask.FieldMask, error) { | ||||
| 	fm := &field_mask.FieldMask{} | ||||
| 	var root interface{} | ||||
| 
 | ||||
| 	if err := json.NewDecoder(r).Decode(&root); err != nil { | ||||
| 		if err == io.EOF { | ||||
| 			return fm, nil | ||||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	queue := []fieldMaskPathItem{{node: root, msg: msg.ProtoReflect()}} | ||||
| 	for len(queue) > 0 { | ||||
| 		// dequeue an item | ||||
| 		item := queue[0] | ||||
| 		queue = queue[1:] | ||||
| 
 | ||||
| 		m, ok := item.node.(map[string]interface{}) | ||||
| 		switch { | ||||
| 		case ok: | ||||
| 			// if the item is an object, then enqueue all of its children | ||||
| 			for k, v := range m { | ||||
| 				if item.msg == nil { | ||||
| 					return nil, fmt.Errorf("JSON structure did not match request type") | ||||
| 				} | ||||
| 
 | ||||
| 				fd := getFieldByName(item.msg.Descriptor().Fields(), k) | ||||
| 				if fd == nil { | ||||
| 					return nil, fmt.Errorf("could not find field %q in %q", k, item.msg.Descriptor().FullName()) | ||||
| 				} | ||||
| 
 | ||||
| 				if isDynamicProtoMessage(fd.Message()) { | ||||
| 					for _, p := range buildPathsBlindly(k, v) { | ||||
| 						newPath := p | ||||
| 						if item.path != "" { | ||||
| 							newPath = item.path + "." + newPath | ||||
| 						} | ||||
| 						queue = append(queue, fieldMaskPathItem{path: newPath}) | ||||
| 					} | ||||
| 					continue | ||||
| 				} | ||||
| 
 | ||||
| 				if isProtobufAnyMessage(fd.Message()) { | ||||
| 					_, hasTypeField := v.(map[string]interface{})["@type"] | ||||
| 					if hasTypeField { | ||||
| 						queue = append(queue, fieldMaskPathItem{path: k}) | ||||
| 						continue | ||||
| 					} else { | ||||
| 						return nil, fmt.Errorf("could not find field @type in %q in message %q", k, item.msg.Descriptor().FullName()) | ||||
| 					} | ||||
| 
 | ||||
| 				} | ||||
| 
 | ||||
| 				child := fieldMaskPathItem{ | ||||
| 					node: v, | ||||
| 				} | ||||
| 				if item.path == "" { | ||||
| 					child.path = string(fd.FullName().Name()) | ||||
| 				} else { | ||||
| 					child.path = item.path + "." + string(fd.FullName().Name()) | ||||
| 				} | ||||
| 
 | ||||
| 				switch { | ||||
| 				case fd.IsList(), fd.IsMap(): | ||||
| 					// As per: https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/field_mask.proto#L85-L86 | ||||
| 					// Do not recurse into repeated fields. The repeated field goes on the end of the path and we stop. | ||||
| 					fm.Paths = append(fm.Paths, child.path) | ||||
| 				case fd.Message() != nil: | ||||
| 					child.msg = item.msg.Get(fd).Message() | ||||
| 					fallthrough | ||||
| 				default: | ||||
| 					queue = append(queue, child) | ||||
| 				} | ||||
| 			} | ||||
| 		case len(item.path) > 0: | ||||
| 			// otherwise, it's a leaf node so print its path | ||||
| 			fm.Paths = append(fm.Paths, item.path) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Sort for deterministic output in the presence | ||||
| 	// of repeated fields. | ||||
| 	sort.Strings(fm.Paths) | ||||
| 
 | ||||
| 	return fm, nil | ||||
| } | ||||
| 
 | ||||
| func isProtobufAnyMessage(md protoreflect.MessageDescriptor) bool { | ||||
| 	return md != nil && (md.FullName() == "google.protobuf.Any") | ||||
| } | ||||
| 
 | ||||
| func isDynamicProtoMessage(md protoreflect.MessageDescriptor) bool { | ||||
| 	return md != nil && (md.FullName() == "google.protobuf.Struct" || md.FullName() == "google.protobuf.Value") | ||||
| } | ||||
| 
 | ||||
| // buildPathsBlindly does not attempt to match proto field names to the | ||||
| // json value keys.  Instead it relies completely on the structure of | ||||
| // the unmarshalled json contained within in. | ||||
| // Returns a slice containing all subpaths with the root at the | ||||
| // passed in name and json value. | ||||
| func buildPathsBlindly(name string, in interface{}) []string { | ||||
| 	m, ok := in.(map[string]interface{}) | ||||
| 	if !ok { | ||||
| 		return []string{name} | ||||
| 	} | ||||
| 
 | ||||
| 	var paths []string | ||||
| 	queue := []fieldMaskPathItem{{path: name, node: m}} | ||||
| 	for len(queue) > 0 { | ||||
| 		cur := queue[0] | ||||
| 		queue = queue[1:] | ||||
| 
 | ||||
| 		m, ok := cur.node.(map[string]interface{}) | ||||
| 		if !ok { | ||||
| 			// This should never happen since we should always check that we only add | ||||
| 			// nodes of type map[string]interface{} to the queue. | ||||
| 			continue | ||||
| 		} | ||||
| 		for k, v := range m { | ||||
| 			if mi, ok := v.(map[string]interface{}); ok { | ||||
| 				queue = append(queue, fieldMaskPathItem{path: cur.path + "." + k, node: mi}) | ||||
| 			} else { | ||||
| 				// This is not a struct, so there are no more levels to descend. | ||||
| 				curPath := cur.path + "." + k | ||||
| 				paths = append(paths, curPath) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return paths | ||||
| } | ||||
| 
 | ||||
| // fieldMaskPathItem stores a in-progress deconstruction of a path for a fieldmask | ||||
| type fieldMaskPathItem struct { | ||||
| 	// the list of prior fields leading up to node connected by dots | ||||
| 	path string | ||||
| 
 | ||||
| 	// a generic decoded json object the current item to inspect for further path extraction | ||||
| 	node interface{} | ||||
| 
 | ||||
| 	// parent message | ||||
| 	msg protoreflect.Message | ||||
| } | ||||
							
								
								
									
										223
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/handler.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/handler.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,223 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"net/textproto" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"google.golang.org/genproto/googleapis/api/httpbody" | ||||
| 	"google.golang.org/grpc/codes" | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| 	"google.golang.org/grpc/status" | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| ) | ||||
| 
 | ||||
| // ForwardResponseStream forwards the stream from gRPC server to REST client. | ||||
| func ForwardResponseStream(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, req *http.Request, recv func() (proto.Message, error), opts ...func(context.Context, http.ResponseWriter, proto.Message) error) { | ||||
| 	f, ok := w.(http.Flusher) | ||||
| 	if !ok { | ||||
| 		grpclog.Infof("Flush not supported in %T", w) | ||||
| 		http.Error(w, "unexpected type of web server", http.StatusInternalServerError) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	md, ok := ServerMetadataFromContext(ctx) | ||||
| 	if !ok { | ||||
| 		grpclog.Infof("Failed to extract ServerMetadata from context") | ||||
| 		http.Error(w, "unexpected error", http.StatusInternalServerError) | ||||
| 		return | ||||
| 	} | ||||
| 	handleForwardResponseServerMetadata(w, mux, md) | ||||
| 
 | ||||
| 	w.Header().Set("Transfer-Encoding", "chunked") | ||||
| 	if err := handleForwardResponseOptions(ctx, w, nil, opts); err != nil { | ||||
| 		HTTPError(ctx, mux, marshaler, w, req, err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	var delimiter []byte | ||||
| 	if d, ok := marshaler.(Delimited); ok { | ||||
| 		delimiter = d.Delimiter() | ||||
| 	} else { | ||||
| 		delimiter = []byte("\n") | ||||
| 	} | ||||
| 
 | ||||
| 	var wroteHeader bool | ||||
| 	for { | ||||
| 		resp, err := recv() | ||||
| 		if err == io.EOF { | ||||
| 			return | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			handleForwardResponseStreamError(ctx, wroteHeader, marshaler, w, req, mux, err) | ||||
| 			return | ||||
| 		} | ||||
| 		if err := handleForwardResponseOptions(ctx, w, resp, opts); err != nil { | ||||
| 			handleForwardResponseStreamError(ctx, wroteHeader, marshaler, w, req, mux, err) | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if !wroteHeader { | ||||
| 			w.Header().Set("Content-Type", marshaler.ContentType(resp)) | ||||
| 		} | ||||
| 
 | ||||
| 		var buf []byte | ||||
| 		httpBody, isHTTPBody := resp.(*httpbody.HttpBody) | ||||
| 		switch { | ||||
| 		case resp == nil: | ||||
| 			buf, err = marshaler.Marshal(errorChunk(status.New(codes.Internal, "empty response"))) | ||||
| 		case isHTTPBody: | ||||
| 			buf = httpBody.GetData() | ||||
| 		default: | ||||
| 			result := map[string]interface{}{"result": resp} | ||||
| 			if rb, ok := resp.(responseBody); ok { | ||||
| 				result["result"] = rb.XXX_ResponseBody() | ||||
| 			} | ||||
| 
 | ||||
| 			buf, err = marshaler.Marshal(result) | ||||
| 		} | ||||
| 
 | ||||
| 		if err != nil { | ||||
| 			grpclog.Infof("Failed to marshal response chunk: %v", err) | ||||
| 			handleForwardResponseStreamError(ctx, wroteHeader, marshaler, w, req, mux, err) | ||||
| 			return | ||||
| 		} | ||||
| 		if _, err = w.Write(buf); err != nil { | ||||
| 			grpclog.Infof("Failed to send response chunk: %v", err) | ||||
| 			return | ||||
| 		} | ||||
| 		wroteHeader = true | ||||
| 		if _, err = w.Write(delimiter); err != nil { | ||||
| 			grpclog.Infof("Failed to send delimiter chunk: %v", err) | ||||
| 			return | ||||
| 		} | ||||
| 		f.Flush() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func handleForwardResponseServerMetadata(w http.ResponseWriter, mux *ServeMux, md ServerMetadata) { | ||||
| 	for k, vs := range md.HeaderMD { | ||||
| 		if h, ok := mux.outgoingHeaderMatcher(k); ok { | ||||
| 			for _, v := range vs { | ||||
| 				w.Header().Add(h, v) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func handleForwardResponseTrailerHeader(w http.ResponseWriter, md ServerMetadata) { | ||||
| 	for k := range md.TrailerMD { | ||||
| 		tKey := textproto.CanonicalMIMEHeaderKey(fmt.Sprintf("%s%s", MetadataTrailerPrefix, k)) | ||||
| 		w.Header().Add("Trailer", tKey) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func handleForwardResponseTrailer(w http.ResponseWriter, md ServerMetadata) { | ||||
| 	for k, vs := range md.TrailerMD { | ||||
| 		tKey := fmt.Sprintf("%s%s", MetadataTrailerPrefix, k) | ||||
| 		for _, v := range vs { | ||||
| 			w.Header().Add(tKey, v) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // responseBody interface contains method for getting field for marshaling to the response body | ||||
| // this method is generated for response struct from the value of `response_body` in the `google.api.HttpRule` | ||||
| type responseBody interface { | ||||
| 	XXX_ResponseBody() interface{} | ||||
| } | ||||
| 
 | ||||
| // ForwardResponseMessage forwards the message "resp" from gRPC server to REST client. | ||||
| func ForwardResponseMessage(ctx context.Context, mux *ServeMux, marshaler Marshaler, w http.ResponseWriter, req *http.Request, resp proto.Message, opts ...func(context.Context, http.ResponseWriter, proto.Message) error) { | ||||
| 	md, ok := ServerMetadataFromContext(ctx) | ||||
| 	if !ok { | ||||
| 		grpclog.Infof("Failed to extract ServerMetadata from context") | ||||
| 	} | ||||
| 
 | ||||
| 	handleForwardResponseServerMetadata(w, mux, md) | ||||
| 
 | ||||
| 	// RFC 7230 https://tools.ietf.org/html/rfc7230#section-4.1.2 | ||||
| 	// Unless the request includes a TE header field indicating "trailers" | ||||
| 	// is acceptable, as described in Section 4.3, a server SHOULD NOT | ||||
| 	// generate trailer fields that it believes are necessary for the user | ||||
| 	// agent to receive. | ||||
| 	doForwardTrailers := requestAcceptsTrailers(req) | ||||
| 
 | ||||
| 	if doForwardTrailers { | ||||
| 		handleForwardResponseTrailerHeader(w, md) | ||||
| 		w.Header().Set("Transfer-Encoding", "chunked") | ||||
| 	} | ||||
| 
 | ||||
| 	handleForwardResponseTrailerHeader(w, md) | ||||
| 
 | ||||
| 	contentType := marshaler.ContentType(resp) | ||||
| 	w.Header().Set("Content-Type", contentType) | ||||
| 
 | ||||
| 	if err := handleForwardResponseOptions(ctx, w, resp, opts); err != nil { | ||||
| 		HTTPError(ctx, mux, marshaler, w, req, err) | ||||
| 		return | ||||
| 	} | ||||
| 	var buf []byte | ||||
| 	var err error | ||||
| 	if rb, ok := resp.(responseBody); ok { | ||||
| 		buf, err = marshaler.Marshal(rb.XXX_ResponseBody()) | ||||
| 	} else { | ||||
| 		buf, err = marshaler.Marshal(resp) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		grpclog.Infof("Marshal error: %v", err) | ||||
| 		HTTPError(ctx, mux, marshaler, w, req, err) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if _, err = w.Write(buf); err != nil { | ||||
| 		grpclog.Infof("Failed to write response: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if doForwardTrailers { | ||||
| 		handleForwardResponseTrailer(w, md) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func requestAcceptsTrailers(req *http.Request) bool { | ||||
| 	te := req.Header.Get("TE") | ||||
| 	return strings.Contains(strings.ToLower(te), "trailers") | ||||
| } | ||||
| 
 | ||||
| func handleForwardResponseOptions(ctx context.Context, w http.ResponseWriter, resp proto.Message, opts []func(context.Context, http.ResponseWriter, proto.Message) error) error { | ||||
| 	if len(opts) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	for _, opt := range opts { | ||||
| 		if err := opt(ctx, w, resp); err != nil { | ||||
| 			grpclog.Infof("Error handling ForwardResponseOptions: %v", err) | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func handleForwardResponseStreamError(ctx context.Context, wroteHeader bool, marshaler Marshaler, w http.ResponseWriter, req *http.Request, mux *ServeMux, err error) { | ||||
| 	st := mux.streamErrorHandler(ctx, err) | ||||
| 	msg := errorChunk(st) | ||||
| 	if !wroteHeader { | ||||
| 		w.Header().Set("Content-Type", marshaler.ContentType(msg)) | ||||
| 		w.WriteHeader(HTTPStatusFromCode(st.Code())) | ||||
| 	} | ||||
| 	buf, merr := marshaler.Marshal(msg) | ||||
| 	if merr != nil { | ||||
| 		grpclog.Infof("Failed to marshal an error: %v", merr) | ||||
| 		return | ||||
| 	} | ||||
| 	if _, werr := w.Write(buf); werr != nil { | ||||
| 		grpclog.Infof("Failed to notify error to client: %v", werr) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func errorChunk(st *status.Status) map[string]proto.Message { | ||||
| 	return map[string]proto.Message{"error": st.Proto()} | ||||
| } | ||||
							
								
								
									
										32
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_httpbodyproto.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_httpbodyproto.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"google.golang.org/genproto/googleapis/api/httpbody" | ||||
| ) | ||||
| 
 | ||||
| // HTTPBodyMarshaler is a Marshaler which supports marshaling of a | ||||
| // google.api.HttpBody message as the full response body if it is | ||||
| // the actual message used as the response. If not, then this will | ||||
| // simply fallback to the Marshaler specified as its default Marshaler. | ||||
| type HTTPBodyMarshaler struct { | ||||
| 	Marshaler | ||||
| } | ||||
| 
 | ||||
| // ContentType returns its specified content type in case v is a | ||||
| // google.api.HttpBody message, otherwise it will fall back to the default Marshalers | ||||
| // content type. | ||||
| func (h *HTTPBodyMarshaler) ContentType(v interface{}) string { | ||||
| 	if httpBody, ok := v.(*httpbody.HttpBody); ok { | ||||
| 		return httpBody.GetContentType() | ||||
| 	} | ||||
| 	return h.Marshaler.ContentType(v) | ||||
| } | ||||
| 
 | ||||
| // Marshal marshals "v" by returning the body bytes if v is a | ||||
| // google.api.HttpBody message, otherwise it falls back to the default Marshaler. | ||||
| func (h *HTTPBodyMarshaler) Marshal(v interface{}) ([]byte, error) { | ||||
| 	if httpBody, ok := v.(*httpbody.HttpBody); ok { | ||||
| 		return httpBody.Data, nil | ||||
| 	} | ||||
| 	return h.Marshaler.Marshal(v) | ||||
| } | ||||
							
								
								
									
										45
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_json.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_json.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| ) | ||||
| 
 | ||||
| // JSONBuiltin is a Marshaler which marshals/unmarshals into/from JSON | ||||
| // with the standard "encoding/json" package of Golang. | ||||
| // Although it is generally faster for simple proto messages than JSONPb, | ||||
| // it does not support advanced features of protobuf, e.g. map, oneof, .... | ||||
| // | ||||
| // The NewEncoder and NewDecoder types return *json.Encoder and | ||||
| // *json.Decoder respectively. | ||||
| type JSONBuiltin struct{} | ||||
| 
 | ||||
| // ContentType always Returns "application/json". | ||||
| func (*JSONBuiltin) ContentType(_ interface{}) string { | ||||
| 	return "application/json" | ||||
| } | ||||
| 
 | ||||
| // Marshal marshals "v" into JSON | ||||
| func (j *JSONBuiltin) Marshal(v interface{}) ([]byte, error) { | ||||
| 	return json.Marshal(v) | ||||
| } | ||||
| 
 | ||||
| // Unmarshal unmarshals JSON data into "v". | ||||
| func (j *JSONBuiltin) Unmarshal(data []byte, v interface{}) error { | ||||
| 	return json.Unmarshal(data, v) | ||||
| } | ||||
| 
 | ||||
| // NewDecoder returns a Decoder which reads JSON stream from "r". | ||||
| func (j *JSONBuiltin) NewDecoder(r io.Reader) Decoder { | ||||
| 	return json.NewDecoder(r) | ||||
| } | ||||
| 
 | ||||
| // NewEncoder returns an Encoder which writes JSON stream into "w". | ||||
| func (j *JSONBuiltin) NewEncoder(w io.Writer) Encoder { | ||||
| 	return json.NewEncoder(w) | ||||
| } | ||||
| 
 | ||||
| // Delimiter for newline encoded JSON streams. | ||||
| func (j *JSONBuiltin) Delimiter() []byte { | ||||
| 	return []byte("\n") | ||||
| } | ||||
							
								
								
									
										344
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										344
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_jsonpb.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,344 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	"google.golang.org/protobuf/encoding/protojson" | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| ) | ||||
| 
 | ||||
| // JSONPb is a Marshaler which marshals/unmarshals into/from JSON | ||||
| // with the "google.golang.org/protobuf/encoding/protojson" marshaler. | ||||
| // It supports the full functionality of protobuf unlike JSONBuiltin. | ||||
| // | ||||
| // The NewDecoder method returns a DecoderWrapper, so the underlying | ||||
| // *json.Decoder methods can be used. | ||||
| type JSONPb struct { | ||||
| 	protojson.MarshalOptions | ||||
| 	protojson.UnmarshalOptions | ||||
| } | ||||
| 
 | ||||
| // ContentType always returns "application/json". | ||||
| func (*JSONPb) ContentType(_ interface{}) string { | ||||
| 	return "application/json" | ||||
| } | ||||
| 
 | ||||
| // Marshal marshals "v" into JSON. | ||||
| func (j *JSONPb) Marshal(v interface{}) ([]byte, error) { | ||||
| 	if _, ok := v.(proto.Message); !ok { | ||||
| 		return j.marshalNonProtoField(v) | ||||
| 	} | ||||
| 
 | ||||
| 	var buf bytes.Buffer | ||||
| 	if err := j.marshalTo(&buf, v); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return buf.Bytes(), nil | ||||
| } | ||||
| 
 | ||||
| func (j *JSONPb) marshalTo(w io.Writer, v interface{}) error { | ||||
| 	p, ok := v.(proto.Message) | ||||
| 	if !ok { | ||||
| 		buf, err := j.marshalNonProtoField(v) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		_, err = w.Write(buf) | ||||
| 		return err | ||||
| 	} | ||||
| 	b, err := j.MarshalOptions.Marshal(p) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = w.Write(b) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	// protoMessageType is stored to prevent constant lookup of the same type at runtime. | ||||
| 	protoMessageType = reflect.TypeOf((*proto.Message)(nil)).Elem() | ||||
| ) | ||||
| 
 | ||||
| // marshalNonProto marshals a non-message field of a protobuf message. | ||||
| // This function does not correctly marshal arbitrary data structures into JSON, | ||||
| // it is only capable of marshaling non-message field values of protobuf, | ||||
| // i.e. primitive types, enums; pointers to primitives or enums; maps from | ||||
| // integer/string types to primitives/enums/pointers to messages. | ||||
| func (j *JSONPb) marshalNonProtoField(v interface{}) ([]byte, error) { | ||||
| 	if v == nil { | ||||
| 		return []byte("null"), nil | ||||
| 	} | ||||
| 	rv := reflect.ValueOf(v) | ||||
| 	for rv.Kind() == reflect.Ptr { | ||||
| 		if rv.IsNil() { | ||||
| 			return []byte("null"), nil | ||||
| 		} | ||||
| 		rv = rv.Elem() | ||||
| 	} | ||||
| 
 | ||||
| 	if rv.Kind() == reflect.Slice { | ||||
| 		if rv.IsNil() { | ||||
| 			if j.EmitUnpopulated { | ||||
| 				return []byte("[]"), nil | ||||
| 			} | ||||
| 			return []byte("null"), nil | ||||
| 		} | ||||
| 
 | ||||
| 		if rv.Type().Elem().Implements(protoMessageType) { | ||||
| 			var buf bytes.Buffer | ||||
| 			err := buf.WriteByte('[') | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			for i := 0; i < rv.Len(); i++ { | ||||
| 				if i != 0 { | ||||
| 					err = buf.WriteByte(',') | ||||
| 					if err != nil { | ||||
| 						return nil, err | ||||
| 					} | ||||
| 				} | ||||
| 				if err = j.marshalTo(&buf, rv.Index(i).Interface().(proto.Message)); err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 			} | ||||
| 			err = buf.WriteByte(']') | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 
 | ||||
| 			return buf.Bytes(), nil | ||||
| 		} | ||||
| 
 | ||||
| 		if rv.Type().Elem().Implements(typeProtoEnum) { | ||||
| 			var buf bytes.Buffer | ||||
| 			err := buf.WriteByte('[') | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			for i := 0; i < rv.Len(); i++ { | ||||
| 				if i != 0 { | ||||
| 					err = buf.WriteByte(',') | ||||
| 					if err != nil { | ||||
| 						return nil, err | ||||
| 					} | ||||
| 				} | ||||
| 				if j.UseEnumNumbers { | ||||
| 					_, err = buf.WriteString(strconv.FormatInt(rv.Index(i).Int(), 10)) | ||||
| 				} else { | ||||
| 					_, err = buf.WriteString("\"" + rv.Index(i).Interface().(protoEnum).String() + "\"") | ||||
| 				} | ||||
| 				if err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 			} | ||||
| 			err = buf.WriteByte(']') | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 
 | ||||
| 			return buf.Bytes(), nil | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if rv.Kind() == reflect.Map { | ||||
| 		m := make(map[string]*json.RawMessage) | ||||
| 		for _, k := range rv.MapKeys() { | ||||
| 			buf, err := j.Marshal(rv.MapIndex(k).Interface()) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			m[fmt.Sprintf("%v", k.Interface())] = (*json.RawMessage)(&buf) | ||||
| 		} | ||||
| 		if j.Indent != "" { | ||||
| 			return json.MarshalIndent(m, "", j.Indent) | ||||
| 		} | ||||
| 		return json.Marshal(m) | ||||
| 	} | ||||
| 	if enum, ok := rv.Interface().(protoEnum); ok && !j.UseEnumNumbers { | ||||
| 		return json.Marshal(enum.String()) | ||||
| 	} | ||||
| 	return json.Marshal(rv.Interface()) | ||||
| } | ||||
| 
 | ||||
| // Unmarshal unmarshals JSON "data" into "v" | ||||
| func (j *JSONPb) Unmarshal(data []byte, v interface{}) error { | ||||
| 	return unmarshalJSONPb(data, j.UnmarshalOptions, v) | ||||
| } | ||||
| 
 | ||||
| // NewDecoder returns a Decoder which reads JSON stream from "r". | ||||
| func (j *JSONPb) NewDecoder(r io.Reader) Decoder { | ||||
| 	d := json.NewDecoder(r) | ||||
| 	return DecoderWrapper{ | ||||
| 		Decoder:          d, | ||||
| 		UnmarshalOptions: j.UnmarshalOptions, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DecoderWrapper is a wrapper around a *json.Decoder that adds | ||||
| // support for protos to the Decode method. | ||||
| type DecoderWrapper struct { | ||||
| 	*json.Decoder | ||||
| 	protojson.UnmarshalOptions | ||||
| } | ||||
| 
 | ||||
| // Decode wraps the embedded decoder's Decode method to support | ||||
| // protos using a jsonpb.Unmarshaler. | ||||
| func (d DecoderWrapper) Decode(v interface{}) error { | ||||
| 	return decodeJSONPb(d.Decoder, d.UnmarshalOptions, v) | ||||
| } | ||||
| 
 | ||||
| // NewEncoder returns an Encoder which writes JSON stream into "w". | ||||
| func (j *JSONPb) NewEncoder(w io.Writer) Encoder { | ||||
| 	return EncoderFunc(func(v interface{}) error { | ||||
| 		if err := j.marshalTo(w, v); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		// mimic json.Encoder by adding a newline (makes output | ||||
| 		// easier to read when it contains multiple encoded items) | ||||
| 		_, err := w.Write(j.Delimiter()) | ||||
| 		return err | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func unmarshalJSONPb(data []byte, unmarshaler protojson.UnmarshalOptions, v interface{}) error { | ||||
| 	d := json.NewDecoder(bytes.NewReader(data)) | ||||
| 	return decodeJSONPb(d, unmarshaler, v) | ||||
| } | ||||
| 
 | ||||
| func decodeJSONPb(d *json.Decoder, unmarshaler protojson.UnmarshalOptions, v interface{}) error { | ||||
| 	p, ok := v.(proto.Message) | ||||
| 	if !ok { | ||||
| 		return decodeNonProtoField(d, unmarshaler, v) | ||||
| 	} | ||||
| 
 | ||||
| 	// Decode into bytes for marshalling | ||||
| 	var b json.RawMessage | ||||
| 	err := d.Decode(&b) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return unmarshaler.Unmarshal([]byte(b), p) | ||||
| } | ||||
| 
 | ||||
| func decodeNonProtoField(d *json.Decoder, unmarshaler protojson.UnmarshalOptions, v interface{}) error { | ||||
| 	rv := reflect.ValueOf(v) | ||||
| 	if rv.Kind() != reflect.Ptr { | ||||
| 		return fmt.Errorf("%T is not a pointer", v) | ||||
| 	} | ||||
| 	for rv.Kind() == reflect.Ptr { | ||||
| 		if rv.IsNil() { | ||||
| 			rv.Set(reflect.New(rv.Type().Elem())) | ||||
| 		} | ||||
| 		if rv.Type().ConvertibleTo(typeProtoMessage) { | ||||
| 			// Decode into bytes for marshalling | ||||
| 			var b json.RawMessage | ||||
| 			err := d.Decode(&b) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			return unmarshaler.Unmarshal([]byte(b), rv.Interface().(proto.Message)) | ||||
| 		} | ||||
| 		rv = rv.Elem() | ||||
| 	} | ||||
| 	if rv.Kind() == reflect.Map { | ||||
| 		if rv.IsNil() { | ||||
| 			rv.Set(reflect.MakeMap(rv.Type())) | ||||
| 		} | ||||
| 		conv, ok := convFromType[rv.Type().Key().Kind()] | ||||
| 		if !ok { | ||||
| 			return fmt.Errorf("unsupported type of map field key: %v", rv.Type().Key()) | ||||
| 		} | ||||
| 
 | ||||
| 		m := make(map[string]*json.RawMessage) | ||||
| 		if err := d.Decode(&m); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		for k, v := range m { | ||||
| 			result := conv.Call([]reflect.Value{reflect.ValueOf(k)}) | ||||
| 			if err := result[1].Interface(); err != nil { | ||||
| 				return err.(error) | ||||
| 			} | ||||
| 			bk := result[0] | ||||
| 			bv := reflect.New(rv.Type().Elem()) | ||||
| 			if v == nil { | ||||
| 				null := json.RawMessage("null") | ||||
| 				v = &null | ||||
| 			} | ||||
| 			if err := unmarshalJSONPb([]byte(*v), unmarshaler, bv.Interface()); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			rv.SetMapIndex(bk, bv.Elem()) | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	if rv.Kind() == reflect.Slice { | ||||
| 		var sl []json.RawMessage | ||||
| 		if err := d.Decode(&sl); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if sl != nil { | ||||
| 			rv.Set(reflect.MakeSlice(rv.Type(), 0, 0)) | ||||
| 		} | ||||
| 		for _, item := range sl { | ||||
| 			bv := reflect.New(rv.Type().Elem()) | ||||
| 			if err := unmarshalJSONPb([]byte(item), unmarshaler, bv.Interface()); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			rv.Set(reflect.Append(rv, bv.Elem())) | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	if _, ok := rv.Interface().(protoEnum); ok { | ||||
| 		var repr interface{} | ||||
| 		if err := d.Decode(&repr); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		switch v := repr.(type) { | ||||
| 		case string: | ||||
| 			// TODO(yugui) Should use proto.StructProperties? | ||||
| 			return fmt.Errorf("unmarshaling of symbolic enum %q not supported: %T", repr, rv.Interface()) | ||||
| 		case float64: | ||||
| 			rv.Set(reflect.ValueOf(int32(v)).Convert(rv.Type())) | ||||
| 			return nil | ||||
| 		default: | ||||
| 			return fmt.Errorf("cannot assign %#v into Go type %T", repr, rv.Interface()) | ||||
| 		} | ||||
| 	} | ||||
| 	return d.Decode(v) | ||||
| } | ||||
| 
 | ||||
| type protoEnum interface { | ||||
| 	fmt.Stringer | ||||
| 	EnumDescriptor() ([]byte, []int) | ||||
| } | ||||
| 
 | ||||
| var typeProtoEnum = reflect.TypeOf((*protoEnum)(nil)).Elem() | ||||
| 
 | ||||
| var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem() | ||||
| 
 | ||||
| // Delimiter for newline encoded JSON streams. | ||||
| func (j *JSONPb) Delimiter() []byte { | ||||
| 	return []byte("\n") | ||||
| } | ||||
| 
 | ||||
| var ( | ||||
| 	convFromType = map[reflect.Kind]reflect.Value{ | ||||
| 		reflect.String:  reflect.ValueOf(String), | ||||
| 		reflect.Bool:    reflect.ValueOf(Bool), | ||||
| 		reflect.Float64: reflect.ValueOf(Float64), | ||||
| 		reflect.Float32: reflect.ValueOf(Float32), | ||||
| 		reflect.Int64:   reflect.ValueOf(Int64), | ||||
| 		reflect.Int32:   reflect.ValueOf(Int32), | ||||
| 		reflect.Uint64:  reflect.ValueOf(Uint64), | ||||
| 		reflect.Uint32:  reflect.ValueOf(Uint32), | ||||
| 		reflect.Slice:   reflect.ValueOf(Bytes), | ||||
| 	} | ||||
| ) | ||||
							
								
								
									
										63
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_proto.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshal_proto.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"io" | ||||
| 
 | ||||
| 	"errors" | ||||
| 	"io/ioutil" | ||||
| 
 | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| ) | ||||
| 
 | ||||
| // ProtoMarshaller is a Marshaller which marshals/unmarshals into/from serialize proto bytes | ||||
| type ProtoMarshaller struct{} | ||||
| 
 | ||||
| // ContentType always returns "application/octet-stream". | ||||
| func (*ProtoMarshaller) ContentType(_ interface{}) string { | ||||
| 	return "application/octet-stream" | ||||
| } | ||||
| 
 | ||||
| // Marshal marshals "value" into Proto | ||||
| func (*ProtoMarshaller) Marshal(value interface{}) ([]byte, error) { | ||||
| 	message, ok := value.(proto.Message) | ||||
| 	if !ok { | ||||
| 		return nil, errors.New("unable to marshal non proto field") | ||||
| 	} | ||||
| 	return proto.Marshal(message) | ||||
| } | ||||
| 
 | ||||
| // Unmarshal unmarshals proto "data" into "value" | ||||
| func (*ProtoMarshaller) Unmarshal(data []byte, value interface{}) error { | ||||
| 	message, ok := value.(proto.Message) | ||||
| 	if !ok { | ||||
| 		return errors.New("unable to unmarshal non proto field") | ||||
| 	} | ||||
| 	return proto.Unmarshal(data, message) | ||||
| } | ||||
| 
 | ||||
| // NewDecoder returns a Decoder which reads proto stream from "reader". | ||||
| func (marshaller *ProtoMarshaller) NewDecoder(reader io.Reader) Decoder { | ||||
| 	return DecoderFunc(func(value interface{}) error { | ||||
| 		buffer, err := ioutil.ReadAll(reader) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return marshaller.Unmarshal(buffer, value) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // NewEncoder returns an Encoder which writes proto stream into "writer". | ||||
| func (marshaller *ProtoMarshaller) NewEncoder(writer io.Writer) Encoder { | ||||
| 	return EncoderFunc(func(value interface{}) error { | ||||
| 		buffer, err := marshaller.Marshal(value) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		_, err = writer.Write(buffer) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		return nil | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										50
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshaler.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshaler.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"io" | ||||
| ) | ||||
| 
 | ||||
| // Marshaler defines a conversion between byte sequence and gRPC payloads / fields. | ||||
| type Marshaler interface { | ||||
| 	// Marshal marshals "v" into byte sequence. | ||||
| 	Marshal(v interface{}) ([]byte, error) | ||||
| 	// Unmarshal unmarshals "data" into "v". | ||||
| 	// "v" must be a pointer value. | ||||
| 	Unmarshal(data []byte, v interface{}) error | ||||
| 	// NewDecoder returns a Decoder which reads byte sequence from "r". | ||||
| 	NewDecoder(r io.Reader) Decoder | ||||
| 	// NewEncoder returns an Encoder which writes bytes sequence into "w". | ||||
| 	NewEncoder(w io.Writer) Encoder | ||||
| 	// ContentType returns the Content-Type which this marshaler is responsible for. | ||||
| 	// The parameter describes the type which is being marshalled, which can sometimes | ||||
| 	// affect the content type returned. | ||||
| 	ContentType(v interface{}) string | ||||
| } | ||||
| 
 | ||||
| // Decoder decodes a byte sequence | ||||
| type Decoder interface { | ||||
| 	Decode(v interface{}) error | ||||
| } | ||||
| 
 | ||||
| // Encoder encodes gRPC payloads / fields into byte sequence. | ||||
| type Encoder interface { | ||||
| 	Encode(v interface{}) error | ||||
| } | ||||
| 
 | ||||
| // DecoderFunc adapts an decoder function into Decoder. | ||||
| type DecoderFunc func(v interface{}) error | ||||
| 
 | ||||
| // Decode delegates invocations to the underlying function itself. | ||||
| func (f DecoderFunc) Decode(v interface{}) error { return f(v) } | ||||
| 
 | ||||
| // EncoderFunc adapts an encoder function into Encoder | ||||
| type EncoderFunc func(v interface{}) error | ||||
| 
 | ||||
| // Encode delegates invocations to the underlying function itself. | ||||
| func (f EncoderFunc) Encode(v interface{}) error { return f(v) } | ||||
| 
 | ||||
| // Delimited defines the streaming delimiter. | ||||
| type Delimited interface { | ||||
| 	// Delimiter returns the record separator for the stream. | ||||
| 	Delimiter() []byte | ||||
| } | ||||
							
								
								
									
										109
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshaler_registry.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/marshaler_registry.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,109 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"mime" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| 	"google.golang.org/protobuf/encoding/protojson" | ||||
| ) | ||||
| 
 | ||||
| // MIMEWildcard is the fallback MIME type used for requests which do not match | ||||
| // a registered MIME type. | ||||
| const MIMEWildcard = "*" | ||||
| 
 | ||||
| var ( | ||||
| 	acceptHeader      = http.CanonicalHeaderKey("Accept") | ||||
| 	contentTypeHeader = http.CanonicalHeaderKey("Content-Type") | ||||
| 
 | ||||
| 	defaultMarshaler = &HTTPBodyMarshaler{ | ||||
| 		Marshaler: &JSONPb{ | ||||
| 			MarshalOptions: protojson.MarshalOptions{ | ||||
| 				EmitUnpopulated: true, | ||||
| 			}, | ||||
| 			UnmarshalOptions: protojson.UnmarshalOptions{ | ||||
| 				DiscardUnknown: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| ) | ||||
| 
 | ||||
| // MarshalerForRequest returns the inbound/outbound marshalers for this request. | ||||
| // It checks the registry on the ServeMux for the MIME type set by the Content-Type header. | ||||
| // If it isn't set (or the request Content-Type is empty), checks for "*". | ||||
| // If there are multiple Content-Type headers set, choose the first one that it can | ||||
| // exactly match in the registry. | ||||
| // Otherwise, it follows the above logic for "*"/InboundMarshaler/OutboundMarshaler. | ||||
| func MarshalerForRequest(mux *ServeMux, r *http.Request) (inbound Marshaler, outbound Marshaler) { | ||||
| 	for _, acceptVal := range r.Header[acceptHeader] { | ||||
| 		if m, ok := mux.marshalers.mimeMap[acceptVal]; ok { | ||||
| 			outbound = m | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for _, contentTypeVal := range r.Header[contentTypeHeader] { | ||||
| 		contentType, _, err := mime.ParseMediaType(contentTypeVal) | ||||
| 		if err != nil { | ||||
| 			grpclog.Infof("Failed to parse Content-Type %s: %v", contentTypeVal, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if m, ok := mux.marshalers.mimeMap[contentType]; ok { | ||||
| 			inbound = m | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if inbound == nil { | ||||
| 		inbound = mux.marshalers.mimeMap[MIMEWildcard] | ||||
| 	} | ||||
| 	if outbound == nil { | ||||
| 		outbound = inbound | ||||
| 	} | ||||
| 
 | ||||
| 	return inbound, outbound | ||||
| } | ||||
| 
 | ||||
| // marshalerRegistry is a mapping from MIME types to Marshalers. | ||||
| type marshalerRegistry struct { | ||||
| 	mimeMap map[string]Marshaler | ||||
| } | ||||
| 
 | ||||
| // add adds a marshaler for a case-sensitive MIME type string ("*" to match any | ||||
| // MIME type). | ||||
| func (m marshalerRegistry) add(mime string, marshaler Marshaler) error { | ||||
| 	if len(mime) == 0 { | ||||
| 		return errors.New("empty MIME type") | ||||
| 	} | ||||
| 
 | ||||
| 	m.mimeMap[mime] = marshaler | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // makeMarshalerMIMERegistry returns a new registry of marshalers. | ||||
| // It allows for a mapping of case-sensitive Content-Type MIME type string to runtime.Marshaler interfaces. | ||||
| // | ||||
| // For example, you could allow the client to specify the use of the runtime.JSONPb marshaler | ||||
| // with a "application/jsonpb" Content-Type and the use of the runtime.JSONBuiltin marshaler | ||||
| // with a "application/json" Content-Type. | ||||
| // "*" can be used to match any Content-Type. | ||||
| // This can be attached to a ServerMux with the marshaler option. | ||||
| func makeMarshalerMIMERegistry() marshalerRegistry { | ||||
| 	return marshalerRegistry{ | ||||
| 		mimeMap: map[string]Marshaler{ | ||||
| 			MIMEWildcard: defaultMarshaler, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // WithMarshalerOption returns a ServeMuxOption which associates inbound and outbound | ||||
| // Marshalers to a MIME type in mux. | ||||
| func WithMarshalerOption(mime string, marshaler Marshaler) ServeMuxOption { | ||||
| 	return func(mux *ServeMux) { | ||||
| 		if err := mux.marshalers.add(mime, marshaler); err != nil { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										356
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										356
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/mux.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,356 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/textproto" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule" | ||||
| 	"google.golang.org/grpc/codes" | ||||
| 	"google.golang.org/grpc/metadata" | ||||
| 	"google.golang.org/grpc/status" | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| ) | ||||
| 
 | ||||
| // UnescapingMode defines the behavior of ServeMux when unescaping path parameters. | ||||
| type UnescapingMode int | ||||
| 
 | ||||
| const ( | ||||
| 	// UnescapingModeLegacy is the default V2 behavior, which escapes the entire | ||||
| 	// path string before doing any routing. | ||||
| 	UnescapingModeLegacy UnescapingMode = iota | ||||
| 
 | ||||
| 	// EscapingTypeExceptReserved 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 | ||||
| 
 | ||||
| 	// URL path parameters will be fully decoded. | ||||
| 	UnescapingModeAllCharacters | ||||
| 
 | ||||
| 	// UnescapingModeDefault is the default escaping type. | ||||
| 	// TODO(v3): default this to UnescapingModeAllExceptReserved per grpc-httpjson-transcoding's | ||||
| 	// reference implementation | ||||
| 	UnescapingModeDefault = UnescapingModeLegacy | ||||
| ) | ||||
| 
 | ||||
| // 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) | ||||
| 
 | ||||
| // ServeMux is a request multiplexer for grpc-gateway. | ||||
| // It matches http requests to patterns and invokes the corresponding handler. | ||||
| type ServeMux struct { | ||||
| 	// handlers maps HTTP method to a list of handlers. | ||||
| 	handlers                  map[string][]handler | ||||
| 	forwardResponseOptions    []func(context.Context, http.ResponseWriter, proto.Message) error | ||||
| 	marshalers                marshalerRegistry | ||||
| 	incomingHeaderMatcher     HeaderMatcherFunc | ||||
| 	outgoingHeaderMatcher     HeaderMatcherFunc | ||||
| 	metadataAnnotators        []func(context.Context, *http.Request) metadata.MD | ||||
| 	errorHandler              ErrorHandlerFunc | ||||
| 	streamErrorHandler        StreamErrorHandlerFunc | ||||
| 	routingErrorHandler       RoutingErrorHandlerFunc | ||||
| 	disablePathLengthFallback bool | ||||
| 	unescapingMode            UnescapingMode | ||||
| } | ||||
| 
 | ||||
| // ServeMuxOption is an option that can be given to a ServeMux on construction. | ||||
| type ServeMuxOption func(*ServeMux) | ||||
| 
 | ||||
| // WithForwardResponseOption returns a ServeMuxOption representing the forwardResponseOption. | ||||
| // | ||||
| // forwardResponseOption is an option that will be called on the relevant context.Context, | ||||
| // http.ResponseWriter, and proto.Message before every forwarded response. | ||||
| // | ||||
| // The message may be nil in the case where just a header is being sent. | ||||
| func WithForwardResponseOption(forwardResponseOption func(context.Context, http.ResponseWriter, proto.Message) error) ServeMuxOption { | ||||
| 	return func(serveMux *ServeMux) { | ||||
| 		serveMux.forwardResponseOptions = append(serveMux.forwardResponseOptions, forwardResponseOption) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // WithEscapingType sets the escaping type. See the definitions of UnescapingMode | ||||
| // for more information. | ||||
| func WithUnescapingMode(mode UnescapingMode) ServeMuxOption { | ||||
| 	return func(serveMux *ServeMux) { | ||||
| 		serveMux.unescapingMode = mode | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // SetQueryParameterParser sets the query parameter parser, used to populate message from query parameters. | ||||
| // Configuring this will mean the generated OpenAPI output is no longer correct, and it should be | ||||
| // done with careful consideration. | ||||
| func SetQueryParameterParser(queryParameterParser QueryParameterParser) ServeMuxOption { | ||||
| 	return func(serveMux *ServeMux) { | ||||
| 		currentQueryParser = queryParameterParser | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // HeaderMatcherFunc checks whether a header key should be forwarded to/from gRPC context. | ||||
| type HeaderMatcherFunc func(string) (string, bool) | ||||
| 
 | ||||
| // DefaultHeaderMatcher is used to pass http request headers to/from gRPC context. This adds permanent HTTP header | ||||
| // keys (as specified by the IANA) to gRPC context with grpcgateway- prefix. HTTP headers that start with | ||||
| // 'Grpc-Metadata-' are mapped to gRPC metadata after removing prefix 'Grpc-Metadata-'. | ||||
| func DefaultHeaderMatcher(key string) (string, bool) { | ||||
| 	key = textproto.CanonicalMIMEHeaderKey(key) | ||||
| 	if isPermanentHTTPHeader(key) { | ||||
| 		return MetadataPrefix + key, true | ||||
| 	} else if strings.HasPrefix(key, MetadataHeaderPrefix) { | ||||
| 		return key[len(MetadataHeaderPrefix):], true | ||||
| 	} | ||||
| 	return "", false | ||||
| } | ||||
| 
 | ||||
| // WithIncomingHeaderMatcher returns a ServeMuxOption representing a headerMatcher for incoming request to gateway. | ||||
| // | ||||
| // 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 { | ||||
| 	return func(mux *ServeMux) { | ||||
| 		mux.incomingHeaderMatcher = fn | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // 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 | ||||
| // passed to http response returned from gateway. To transform the header before passing to response, | ||||
| // matcher should return modified header. | ||||
| func WithOutgoingHeaderMatcher(fn HeaderMatcherFunc) ServeMuxOption { | ||||
| 	return func(mux *ServeMux) { | ||||
| 		mux.outgoingHeaderMatcher = fn | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // WithMetadata returns a ServeMuxOption for passing metadata to a gRPC context. | ||||
| // | ||||
| // This can be used by services that need to read from http.Request and modify gRPC context. A common use case | ||||
| // is reading token from cookie and adding it in gRPC context. | ||||
| func WithMetadata(annotator func(context.Context, *http.Request) metadata.MD) ServeMuxOption { | ||||
| 	return func(serveMux *ServeMux) { | ||||
| 		serveMux.metadataAnnotators = append(serveMux.metadataAnnotators, annotator) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // WithErrorHandler returns a ServeMuxOption for configuring a custom error handler. | ||||
| // | ||||
| // This can be used to configure a custom error response. | ||||
| func WithErrorHandler(fn ErrorHandlerFunc) ServeMuxOption { | ||||
| 	return func(serveMux *ServeMux) { | ||||
| 		serveMux.errorHandler = fn | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // WithStreamErrorHandler returns a ServeMuxOption that will use the given custom stream | ||||
| // error handler, which allows for customizing the error trailer for server-streaming | ||||
| // calls. | ||||
| // | ||||
| // For stream errors that occur before any response has been written, the mux's | ||||
| // ErrorHandler will be invoked. However, once data has been written, the errors must | ||||
| // be handled differently: they must be included in the response body. The response body's | ||||
| // final message will include the error details returned by the stream error handler. | ||||
| func WithStreamErrorHandler(fn StreamErrorHandlerFunc) ServeMuxOption { | ||||
| 	return func(serveMux *ServeMux) { | ||||
| 		serveMux.streamErrorHandler = fn | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // WithRoutingErrorHandler returns a ServeMuxOption for configuring a custom error handler to  handle http routing errors. | ||||
| // | ||||
| // Method called for errors which can happen before gRPC route selected or executed. | ||||
| // The following error codes: StatusMethodNotAllowed StatusNotFound StatusBadRequest | ||||
| func WithRoutingErrorHandler(fn RoutingErrorHandlerFunc) ServeMuxOption { | ||||
| 	return func(serveMux *ServeMux) { | ||||
| 		serveMux.routingErrorHandler = fn | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // WithDisablePathLengthFallback returns a ServeMuxOption for disable path length fallback. | ||||
| func WithDisablePathLengthFallback() ServeMuxOption { | ||||
| 	return func(serveMux *ServeMux) { | ||||
| 		serveMux.disablePathLengthFallback = true | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewServeMux returns a new ServeMux whose internal mapping is empty. | ||||
| func NewServeMux(opts ...ServeMuxOption) *ServeMux { | ||||
| 	serveMux := &ServeMux{ | ||||
| 		handlers:               make(map[string][]handler), | ||||
| 		forwardResponseOptions: make([]func(context.Context, http.ResponseWriter, proto.Message) error, 0), | ||||
| 		marshalers:             makeMarshalerMIMERegistry(), | ||||
| 		errorHandler:           DefaultHTTPErrorHandler, | ||||
| 		streamErrorHandler:     DefaultStreamErrorHandler, | ||||
| 		routingErrorHandler:    DefaultRoutingErrorHandler, | ||||
| 		unescapingMode:         UnescapingModeDefault, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, opt := range opts { | ||||
| 		opt(serveMux) | ||||
| 	} | ||||
| 
 | ||||
| 	if serveMux.incomingHeaderMatcher == nil { | ||||
| 		serveMux.incomingHeaderMatcher = DefaultHeaderMatcher | ||||
| 	} | ||||
| 
 | ||||
| 	if serveMux.outgoingHeaderMatcher == nil { | ||||
| 		serveMux.outgoingHeaderMatcher = func(key string) (string, bool) { | ||||
| 			return fmt.Sprintf("%s%s", MetadataHeaderPrefix, key), true | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return serveMux | ||||
| } | ||||
| 
 | ||||
| // Handle associates "h" to the pair of HTTP method and path pattern. | ||||
| func (s *ServeMux) Handle(meth string, pat Pattern, h HandlerFunc) { | ||||
| 	s.handlers[meth] = append([]handler{{pat: pat, h: h}}, s.handlers[meth]...) | ||||
| } | ||||
| 
 | ||||
| // HandlePath allows users to configure custom path handlers. | ||||
| // refer: https://grpc-ecosystem.github.io/grpc-gateway/docs/operations/inject_router/ | ||||
| func (s *ServeMux) HandlePath(meth string, pathPattern string, h HandlerFunc) error { | ||||
| 	compiler, err := httprule.Parse(pathPattern) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("parsing path pattern: %w", err) | ||||
| 	} | ||||
| 	tp := compiler.Compile() | ||||
| 	pattern, err := NewPattern(tp.Version, tp.OpCodes, tp.Pool, tp.Verb) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("creating new pattern: %w", err) | ||||
| 	} | ||||
| 	s.Handle(meth, pattern, h) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // ServeHTTP dispatches the request to the first handler whose pattern matches to r.Method and r.Path. | ||||
| func (s *ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 	ctx := r.Context() | ||||
| 
 | ||||
| 	path := r.URL.Path | ||||
| 	if !strings.HasPrefix(path, "/") { | ||||
| 		_, outboundMarshaler := MarshalerForRequest(s, r) | ||||
| 		s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusBadRequest) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO(v3): remove UnescapingModeLegacy | ||||
| 	if s.unescapingMode != UnescapingModeLegacy && r.URL.RawPath != "" { | ||||
| 		path = r.URL.RawPath | ||||
| 	} | ||||
| 
 | ||||
| 	components := strings.Split(path[1:], "/") | ||||
| 
 | ||||
| 	if override := r.Header.Get("X-HTTP-Method-Override"); override != "" && s.isPathLengthFallback(r) { | ||||
| 		r.Method = strings.ToUpper(override) | ||||
| 		if err := r.ParseForm(); err != nil { | ||||
| 			_, outboundMarshaler := MarshalerForRequest(s, r) | ||||
| 			sterr := status.Error(codes.InvalidArgument, err.Error()) | ||||
| 			s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Verb out here is to memoize for the fallback case below | ||||
| 	var verb string | ||||
| 
 | ||||
| 	for _, h := range s.handlers[r.Method] { | ||||
| 		// If the pattern has a verb, explicitly look for a suffix in the last | ||||
| 		// component that matches a colon plus the verb. This allows us to | ||||
| 		// handle some cases that otherwise can't be correctly handled by the | ||||
| 		// former LastIndex case, such as when the verb literal itself contains | ||||
| 		// a colon. This should work for all cases that have run through the | ||||
| 		// parser because we know what verb we're looking for, however, there | ||||
| 		// are still some cases that the parser itself cannot disambiguate. See | ||||
| 		// the comment there if interested. | ||||
| 		patVerb := h.pat.Verb() | ||||
| 		l := len(components) | ||||
| 		lastComponent := components[l-1] | ||||
| 		var idx int = -1 | ||||
| 		if patVerb != "" && strings.HasSuffix(lastComponent, ":"+patVerb) { | ||||
| 			idx = len(lastComponent) - len(patVerb) - 1 | ||||
| 		} | ||||
| 		if idx == 0 { | ||||
| 			_, outboundMarshaler := MarshalerForRequest(s, r) | ||||
| 			s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusNotFound) | ||||
| 			return | ||||
| 		} | ||||
| 		if idx > 0 { | ||||
| 			components[l-1], verb = lastComponent[:idx], lastComponent[idx+1:] | ||||
| 		} | ||||
| 
 | ||||
| 		pathParams, err := h.pat.MatchAndEscape(components, verb, s.unescapingMode) | ||||
| 		if err != nil { | ||||
| 			var mse MalformedSequenceError | ||||
| 			if ok := errors.As(err, &mse); ok { | ||||
| 				_, outboundMarshaler := MarshalerForRequest(s, r) | ||||
| 				s.errorHandler(ctx, s, outboundMarshaler, w, r, &HTTPStatusError{ | ||||
| 					HTTPStatus: http.StatusBadRequest, | ||||
| 					Err:        mse, | ||||
| 				}) | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		h.h(w, r, pathParams) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// lookup other methods to handle fallback from GET to POST and | ||||
| 	// to determine if it is NotImplemented or NotFound. | ||||
| 	for m, handlers := range s.handlers { | ||||
| 		if m == r.Method { | ||||
| 			continue | ||||
| 		} | ||||
| 		for _, h := range handlers { | ||||
| 			pathParams, err := h.pat.MatchAndEscape(components, verb, s.unescapingMode) | ||||
| 			if err != nil { | ||||
| 				var mse MalformedSequenceError | ||||
| 				if ok := errors.As(err, &mse); ok { | ||||
| 					_, outboundMarshaler := MarshalerForRequest(s, r) | ||||
| 					s.errorHandler(ctx, s, outboundMarshaler, w, r, &HTTPStatusError{ | ||||
| 						HTTPStatus: http.StatusBadRequest, | ||||
| 						Err:        mse, | ||||
| 					}) | ||||
| 				} | ||||
| 				continue | ||||
| 			} | ||||
| 			// X-HTTP-Method-Override is optional. Always allow fallback to POST. | ||||
| 			if s.isPathLengthFallback(r) { | ||||
| 				if err := r.ParseForm(); err != nil { | ||||
| 					_, outboundMarshaler := MarshalerForRequest(s, r) | ||||
| 					sterr := status.Error(codes.InvalidArgument, err.Error()) | ||||
| 					s.errorHandler(ctx, s, outboundMarshaler, w, r, sterr) | ||||
| 					return | ||||
| 				} | ||||
| 				h.h(w, r, pathParams) | ||||
| 				return | ||||
| 			} | ||||
| 			_, outboundMarshaler := MarshalerForRequest(s, r) | ||||
| 			s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusMethodNotAllowed) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	_, outboundMarshaler := MarshalerForRequest(s, r) | ||||
| 	s.routingErrorHandler(ctx, s, outboundMarshaler, w, r, http.StatusNotFound) | ||||
| } | ||||
| 
 | ||||
| // GetForwardResponseOptions returns the ForwardResponseOptions associated with this ServeMux. | ||||
| func (s *ServeMux) GetForwardResponseOptions() []func(context.Context, http.ResponseWriter, proto.Message) error { | ||||
| 	return s.forwardResponseOptions | ||||
| } | ||||
| 
 | ||||
| func (s *ServeMux) isPathLengthFallback(r *http.Request) bool { | ||||
| 	return !s.disablePathLengthFallback && r.Method == "POST" && r.Header.Get("Content-Type") == "application/x-www-form-urlencoded" | ||||
| } | ||||
| 
 | ||||
| type handler struct { | ||||
| 	pat Pattern | ||||
| 	h   HandlerFunc | ||||
| } | ||||
							
								
								
									
										383
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										383
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/pattern.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,383 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/grpc-ecosystem/grpc-gateway/v2/utilities" | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	// ErrNotMatch indicates that the given HTTP request path does not match to the pattern. | ||||
| 	ErrNotMatch = errors.New("not match to the path pattern") | ||||
| 	// ErrInvalidPattern indicates that the given definition of Pattern is not valid. | ||||
| 	ErrInvalidPattern = errors.New("invalid pattern") | ||||
| 	// ErrMalformedSequence indicates that an escape sequence was malformed. | ||||
| 	ErrMalformedSequence = errors.New("malformed escape sequence") | ||||
| ) | ||||
| 
 | ||||
| type MalformedSequenceError string | ||||
| 
 | ||||
| func (e MalformedSequenceError) Error() string { | ||||
| 	return "malformed path escape " + strconv.Quote(string(e)) | ||||
| } | ||||
| 
 | ||||
| type op struct { | ||||
| 	code    utilities.OpCode | ||||
| 	operand int | ||||
| } | ||||
| 
 | ||||
| // Pattern is a template pattern of http request paths defined in | ||||
| // https://github.com/googleapis/googleapis/blob/master/google/api/http.proto | ||||
| type Pattern struct { | ||||
| 	// ops is a list of operations | ||||
| 	ops []op | ||||
| 	// pool is a constant pool indexed by the operands or vars. | ||||
| 	pool []string | ||||
| 	// vars is a list of variables names to be bound by this pattern | ||||
| 	vars []string | ||||
| 	// stacksize is the max depth of the stack | ||||
| 	stacksize int | ||||
| 	// tailLen is the length of the fixed-size segments after a deep wildcard | ||||
| 	tailLen int | ||||
| 	// verb is the VERB part of the path pattern. It is empty if the pattern does not have VERB part. | ||||
| 	verb string | ||||
| } | ||||
| 
 | ||||
| // NewPattern returns a new Pattern from the given definition values. | ||||
| // "ops" is a sequence of op codes. "pool" is a constant pool. | ||||
| // "verb" is the verb part of the pattern. It is empty if the pattern does not have the part. | ||||
| // "version" must be 1 for now. | ||||
| // It returns an error if the given definition is invalid. | ||||
| func NewPattern(version int, ops []int, pool []string, verb string) (Pattern, error) { | ||||
| 	if version != 1 { | ||||
| 		grpclog.Infof("unsupported version: %d", version) | ||||
| 		return Pattern{}, ErrInvalidPattern | ||||
| 	} | ||||
| 
 | ||||
| 	l := len(ops) | ||||
| 	if l%2 != 0 { | ||||
| 		grpclog.Infof("odd number of ops codes: %d", l) | ||||
| 		return Pattern{}, ErrInvalidPattern | ||||
| 	} | ||||
| 
 | ||||
| 	var ( | ||||
| 		typedOps        []op | ||||
| 		stack, maxstack int | ||||
| 		tailLen         int | ||||
| 		pushMSeen       bool | ||||
| 		vars            []string | ||||
| 	) | ||||
| 	for i := 0; i < l; i += 2 { | ||||
| 		op := op{code: utilities.OpCode(ops[i]), operand: ops[i+1]} | ||||
| 		switch op.code { | ||||
| 		case utilities.OpNop: | ||||
| 			continue | ||||
| 		case utilities.OpPush: | ||||
| 			if pushMSeen { | ||||
| 				tailLen++ | ||||
| 			} | ||||
| 			stack++ | ||||
| 		case utilities.OpPushM: | ||||
| 			if pushMSeen { | ||||
| 				grpclog.Infof("pushM appears twice") | ||||
| 				return Pattern{}, ErrInvalidPattern | ||||
| 			} | ||||
| 			pushMSeen = true | ||||
| 			stack++ | ||||
| 		case utilities.OpLitPush: | ||||
| 			if op.operand < 0 || len(pool) <= op.operand { | ||||
| 				grpclog.Infof("negative literal index: %d", op.operand) | ||||
| 				return Pattern{}, ErrInvalidPattern | ||||
| 			} | ||||
| 			if pushMSeen { | ||||
| 				tailLen++ | ||||
| 			} | ||||
| 			stack++ | ||||
| 		case utilities.OpConcatN: | ||||
| 			if op.operand <= 0 { | ||||
| 				grpclog.Infof("negative concat size: %d", op.operand) | ||||
| 				return Pattern{}, ErrInvalidPattern | ||||
| 			} | ||||
| 			stack -= op.operand | ||||
| 			if stack < 0 { | ||||
| 				grpclog.Info("stack underflow") | ||||
| 				return Pattern{}, ErrInvalidPattern | ||||
| 			} | ||||
| 			stack++ | ||||
| 		case utilities.OpCapture: | ||||
| 			if op.operand < 0 || len(pool) <= op.operand { | ||||
| 				grpclog.Infof("variable name index out of bound: %d", op.operand) | ||||
| 				return Pattern{}, ErrInvalidPattern | ||||
| 			} | ||||
| 			v := pool[op.operand] | ||||
| 			op.operand = len(vars) | ||||
| 			vars = append(vars, v) | ||||
| 			stack-- | ||||
| 			if stack < 0 { | ||||
| 				grpclog.Infof("stack underflow") | ||||
| 				return Pattern{}, ErrInvalidPattern | ||||
| 			} | ||||
| 		default: | ||||
| 			grpclog.Infof("invalid opcode: %d", op.code) | ||||
| 			return Pattern{}, ErrInvalidPattern | ||||
| 		} | ||||
| 
 | ||||
| 		if maxstack < stack { | ||||
| 			maxstack = stack | ||||
| 		} | ||||
| 		typedOps = append(typedOps, op) | ||||
| 	} | ||||
| 	return Pattern{ | ||||
| 		ops:       typedOps, | ||||
| 		pool:      pool, | ||||
| 		vars:      vars, | ||||
| 		stacksize: maxstack, | ||||
| 		tailLen:   tailLen, | ||||
| 		verb:      verb, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // MustPattern is a helper function which makes it easier to call NewPattern in variable initialization. | ||||
| func MustPattern(p Pattern, err error) Pattern { | ||||
| 	if err != nil { | ||||
| 		grpclog.Fatalf("Pattern initialization failed: %v", err) | ||||
| 	} | ||||
| 	return p | ||||
| } | ||||
| 
 | ||||
| // MatchAndEscape examines components to determine if they match to a Pattern. | ||||
| // MatchAndEscape will return an error if no Patterns matched or if a pattern | ||||
| // matched but contained malformed escape sequences. If successful, the function | ||||
| // returns a mapping from field paths to their captured values. | ||||
| func (p Pattern) MatchAndEscape(components []string, verb string, unescapingMode UnescapingMode) (map[string]string, error) { | ||||
| 	if p.verb != verb { | ||||
| 		if p.verb != "" { | ||||
| 			return nil, ErrNotMatch | ||||
| 		} | ||||
| 		if len(components) == 0 { | ||||
| 			components = []string{":" + verb} | ||||
| 		} else { | ||||
| 			components = append([]string{}, components...) | ||||
| 			components[len(components)-1] += ":" + verb | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var pos int | ||||
| 	stack := make([]string, 0, p.stacksize) | ||||
| 	captured := make([]string, len(p.vars)) | ||||
| 	l := len(components) | ||||
| 	for _, op := range p.ops { | ||||
| 		var err error | ||||
| 
 | ||||
| 		switch op.code { | ||||
| 		case utilities.OpNop: | ||||
| 			continue | ||||
| 		case utilities.OpPush, utilities.OpLitPush: | ||||
| 			if pos >= l { | ||||
| 				return nil, ErrNotMatch | ||||
| 			} | ||||
| 			c := components[pos] | ||||
| 			if op.code == utilities.OpLitPush { | ||||
| 				if lit := p.pool[op.operand]; c != lit { | ||||
| 					return nil, ErrNotMatch | ||||
| 				} | ||||
| 			} else if op.code == utilities.OpPush { | ||||
| 				if c, err = unescape(c, unescapingMode, false); err != nil { | ||||
| 					return nil, err | ||||
| 				} | ||||
| 			} | ||||
| 			stack = append(stack, c) | ||||
| 			pos++ | ||||
| 		case utilities.OpPushM: | ||||
| 			end := len(components) | ||||
| 			if end < pos+p.tailLen { | ||||
| 				return nil, ErrNotMatch | ||||
| 			} | ||||
| 			end -= p.tailLen | ||||
| 			c := strings.Join(components[pos:end], "/") | ||||
| 			if c, err = unescape(c, unescapingMode, true); err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			stack = append(stack, c) | ||||
| 			pos = end | ||||
| 		case utilities.OpConcatN: | ||||
| 			n := op.operand | ||||
| 			l := len(stack) - n | ||||
| 			stack = append(stack[:l], strings.Join(stack[l:], "/")) | ||||
| 		case utilities.OpCapture: | ||||
| 			n := len(stack) - 1 | ||||
| 			captured[op.operand] = stack[n] | ||||
| 			stack = stack[:n] | ||||
| 		} | ||||
| 	} | ||||
| 	if pos < l { | ||||
| 		return nil, ErrNotMatch | ||||
| 	} | ||||
| 	bindings := make(map[string]string) | ||||
| 	for i, val := range captured { | ||||
| 		bindings[p.vars[i]] = val | ||||
| 	} | ||||
| 	return bindings, nil | ||||
| } | ||||
| 
 | ||||
| // MatchAndEscape examines components to determine if they match to a Pattern. | ||||
| // It will never perform per-component unescaping (see: UnescapingModeLegacy). | ||||
| // MatchAndEscape will return an error if no Patterns matched. If successful, | ||||
| // the function returns a mapping from field paths to their captured values. | ||||
| // | ||||
| // Deprecated: Use MatchAndEscape. | ||||
| func (p Pattern) Match(components []string, verb string) (map[string]string, error) { | ||||
| 	return p.MatchAndEscape(components, verb, UnescapingModeDefault) | ||||
| } | ||||
| 
 | ||||
| // Verb returns the verb part of the Pattern. | ||||
| func (p Pattern) Verb() string { return p.verb } | ||||
| 
 | ||||
| func (p Pattern) String() string { | ||||
| 	var stack []string | ||||
| 	for _, op := range p.ops { | ||||
| 		switch op.code { | ||||
| 		case utilities.OpNop: | ||||
| 			continue | ||||
| 		case utilities.OpPush: | ||||
| 			stack = append(stack, "*") | ||||
| 		case utilities.OpLitPush: | ||||
| 			stack = append(stack, p.pool[op.operand]) | ||||
| 		case utilities.OpPushM: | ||||
| 			stack = append(stack, "**") | ||||
| 		case utilities.OpConcatN: | ||||
| 			n := op.operand | ||||
| 			l := len(stack) - n | ||||
| 			stack = append(stack[:l], strings.Join(stack[l:], "/")) | ||||
| 		case utilities.OpCapture: | ||||
| 			n := len(stack) - 1 | ||||
| 			stack[n] = fmt.Sprintf("{%s=%s}", p.vars[op.operand], stack[n]) | ||||
| 		} | ||||
| 	} | ||||
| 	segs := strings.Join(stack, "/") | ||||
| 	if p.verb != "" { | ||||
| 		return fmt.Sprintf("/%s:%s", segs, p.verb) | ||||
| 	} | ||||
| 	return "/" + segs | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|  * The following code is adopted and modified from Go's standard library | ||||
|  * and carries the attached license. | ||||
|  * | ||||
|  *     Copyright 2009 The Go Authors. All rights reserved. | ||||
|  *     Use of this source code is governed by a BSD-style | ||||
|  *     license that can be found in the LICENSE file. | ||||
|  */ | ||||
| 
 | ||||
| // ishex returns whether or not the given byte is a valid hex character | ||||
| func ishex(c byte) bool { | ||||
| 	switch { | ||||
| 	case '0' <= c && c <= '9': | ||||
| 		return true | ||||
| 	case 'a' <= c && c <= 'f': | ||||
| 		return true | ||||
| 	case 'A' <= c && c <= 'F': | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func isRFC6570Reserved(c byte) bool { | ||||
| 	switch c { | ||||
| 	case '!', '#', '$', '&', '\'', '(', ')', '*', | ||||
| 		'+', ',', '/', ':', ';', '=', '?', '@', '[', ']': | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // unhex converts a hex point to the bit representation | ||||
| func unhex(c byte) byte { | ||||
| 	switch { | ||||
| 	case '0' <= c && c <= '9': | ||||
| 		return c - '0' | ||||
| 	case 'a' <= c && c <= 'f': | ||||
| 		return c - 'a' + 10 | ||||
| 	case 'A' <= c && c <= 'F': | ||||
| 		return c - 'A' + 10 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| // shouldUnescapeWithMode returns true if the character is escapable with the | ||||
| // given mode | ||||
| func shouldUnescapeWithMode(c byte, mode UnescapingMode) bool { | ||||
| 	switch mode { | ||||
| 	case UnescapingModeAllExceptReserved: | ||||
| 		if isRFC6570Reserved(c) { | ||||
| 			return false | ||||
| 		} | ||||
| 	case UnescapingModeAllExceptSlash: | ||||
| 		if c == '/' { | ||||
| 			return false | ||||
| 		} | ||||
| 	case UnescapingModeAllCharacters: | ||||
| 		return true | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| // unescape unescapes a path string using the provided mode | ||||
| func unescape(s string, mode UnescapingMode, multisegment bool) (string, error) { | ||||
| 	// TODO(v3): remove UnescapingModeLegacy | ||||
| 	if mode == UnescapingModeLegacy { | ||||
| 		return s, nil | ||||
| 	} | ||||
| 
 | ||||
| 	if !multisegment { | ||||
| 		mode = UnescapingModeAllCharacters | ||||
| 	} | ||||
| 
 | ||||
| 	// Count %, check that they're well-formed. | ||||
| 	n := 0 | ||||
| 	for i := 0; i < len(s); { | ||||
| 		if s[i] == '%' { | ||||
| 			n++ | ||||
| 			if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { | ||||
| 				s = s[i:] | ||||
| 				if len(s) > 3 { | ||||
| 					s = s[:3] | ||||
| 				} | ||||
| 
 | ||||
| 				return "", MalformedSequenceError(s) | ||||
| 			} | ||||
| 			i += 3 | ||||
| 		} else { | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if n == 0 { | ||||
| 		return s, nil | ||||
| 	} | ||||
| 
 | ||||
| 	var t strings.Builder | ||||
| 	t.Grow(len(s)) | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		switch s[i] { | ||||
| 		case '%': | ||||
| 			c := unhex(s[i+1])<<4 | unhex(s[i+2]) | ||||
| 			if shouldUnescapeWithMode(c, mode) { | ||||
| 				t.WriteByte(c) | ||||
| 				i += 2 | ||||
| 				continue | ||||
| 			} | ||||
| 			fallthrough | ||||
| 		default: | ||||
| 			t.WriteByte(s[i]) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return t.String(), nil | ||||
| } | ||||
							
								
								
									
										80
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/proto2_convert.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/proto2_convert.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,80 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| ) | ||||
| 
 | ||||
| // StringP returns a pointer to a string whose pointee is same as the given string value. | ||||
| func StringP(val string) (*string, error) { | ||||
| 	return proto.String(val), nil | ||||
| } | ||||
| 
 | ||||
| // BoolP parses the given string representation of a boolean value, | ||||
| // and returns a pointer to a bool whose value is same as the parsed value. | ||||
| func BoolP(val string) (*bool, error) { | ||||
| 	b, err := Bool(val) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return proto.Bool(b), nil | ||||
| } | ||||
| 
 | ||||
| // Float64P parses the given string representation of a floating point number, | ||||
| // and returns a pointer to a float64 whose value is same as the parsed number. | ||||
| func Float64P(val string) (*float64, error) { | ||||
| 	f, err := Float64(val) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return proto.Float64(f), nil | ||||
| } | ||||
| 
 | ||||
| // Float32P parses the given string representation of a floating point number, | ||||
| // and returns a pointer to a float32 whose value is same as the parsed number. | ||||
| func Float32P(val string) (*float32, error) { | ||||
| 	f, err := Float32(val) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return proto.Float32(f), nil | ||||
| } | ||||
| 
 | ||||
| // Int64P parses the given string representation of an integer | ||||
| // and returns a pointer to a int64 whose value is same as the parsed integer. | ||||
| func Int64P(val string) (*int64, error) { | ||||
| 	i, err := Int64(val) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return proto.Int64(i), nil | ||||
| } | ||||
| 
 | ||||
| // Int32P parses the given string representation of an integer | ||||
| // and returns a pointer to a int32 whose value is same as the parsed integer. | ||||
| func Int32P(val string) (*int32, error) { | ||||
| 	i, err := Int32(val) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return proto.Int32(i), err | ||||
| } | ||||
| 
 | ||||
| // Uint64P parses the given string representation of an integer | ||||
| // and returns a pointer to a uint64 whose value is same as the parsed integer. | ||||
| func Uint64P(val string) (*uint64, error) { | ||||
| 	i, err := Uint64(val) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return proto.Uint64(i), err | ||||
| } | ||||
| 
 | ||||
| // Uint32P parses the given string representation of an integer | ||||
| // and returns a pointer to a uint32 whose value is same as the parsed integer. | ||||
| func Uint32P(val string) (*uint32, error) { | ||||
| 	i, err := Uint32(val) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return proto.Uint32(i), err | ||||
| } | ||||
							
								
								
									
										329
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/query.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,329 @@ | |||
| package runtime | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/base64" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/grpc-ecosystem/grpc-gateway/v2/utilities" | ||||
| 	"google.golang.org/genproto/protobuf/field_mask" | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| 	"google.golang.org/protobuf/reflect/protoreflect" | ||||
| 	"google.golang.org/protobuf/reflect/protoregistry" | ||||
| 	"google.golang.org/protobuf/types/known/durationpb" | ||||
| 	"google.golang.org/protobuf/types/known/timestamppb" | ||||
| 	"google.golang.org/protobuf/types/known/wrapperspb" | ||||
| ) | ||||
| 
 | ||||
| var valuesKeyRegexp = regexp.MustCompile(`^(.*)\[(.*)\]$`) | ||||
| 
 | ||||
| var currentQueryParser QueryParameterParser = &defaultQueryParser{} | ||||
| 
 | ||||
| // QueryParameterParser defines interface for all query parameter parsers | ||||
| type QueryParameterParser interface { | ||||
| 	Parse(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error | ||||
| } | ||||
| 
 | ||||
| // PopulateQueryParameters parses query parameters | ||||
| // into "msg" using current query parser | ||||
| func PopulateQueryParameters(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error { | ||||
| 	return currentQueryParser.Parse(msg, values, filter) | ||||
| } | ||||
| 
 | ||||
| type defaultQueryParser struct{} | ||||
| 
 | ||||
| // Parse populates "values" into "msg". | ||||
| // A value is ignored if its key starts with one of the elements in "filter". | ||||
| func (*defaultQueryParser) Parse(msg proto.Message, values url.Values, filter *utilities.DoubleArray) error { | ||||
| 	for key, values := range values { | ||||
| 		match := valuesKeyRegexp.FindStringSubmatch(key) | ||||
| 		if len(match) == 3 { | ||||
| 			key = match[1] | ||||
| 			values = append([]string{match[2]}, values...) | ||||
| 		} | ||||
| 		fieldPath := strings.Split(key, ".") | ||||
| 		if filter.HasCommonPrefix(fieldPath) { | ||||
| 			continue | ||||
| 		} | ||||
| 		if err := populateFieldValueFromPath(msg.ProtoReflect(), fieldPath, values); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // PopulateFieldFromPath sets a value in a nested Protobuf structure. | ||||
| func PopulateFieldFromPath(msg proto.Message, fieldPathString string, value string) error { | ||||
| 	fieldPath := strings.Split(fieldPathString, ".") | ||||
| 	return populateFieldValueFromPath(msg.ProtoReflect(), fieldPath, []string{value}) | ||||
| } | ||||
| 
 | ||||
| func populateFieldValueFromPath(msgValue protoreflect.Message, fieldPath []string, values []string) error { | ||||
| 	if len(fieldPath) < 1 { | ||||
| 		return errors.New("no field path") | ||||
| 	} | ||||
| 	if len(values) < 1 { | ||||
| 		return errors.New("no value provided") | ||||
| 	} | ||||
| 
 | ||||
| 	var fieldDescriptor protoreflect.FieldDescriptor | ||||
| 	for i, fieldName := range fieldPath { | ||||
| 		fields := msgValue.Descriptor().Fields() | ||||
| 
 | ||||
| 		// Get field by name | ||||
| 		fieldDescriptor = fields.ByName(protoreflect.Name(fieldName)) | ||||
| 		if fieldDescriptor == nil { | ||||
| 			fieldDescriptor = fields.ByJSONName(fieldName) | ||||
| 			if fieldDescriptor == nil { | ||||
| 				// We're not returning an error here because this could just be | ||||
| 				// an extra query parameter that isn't part of the request. | ||||
| 				grpclog.Infof("field not found in %q: %q", msgValue.Descriptor().FullName(), strings.Join(fieldPath, ".")) | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// If this is the last element, we're done | ||||
| 		if i == len(fieldPath)-1 { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		// Only singular message fields are allowed | ||||
| 		if fieldDescriptor.Message() == nil || fieldDescriptor.Cardinality() == protoreflect.Repeated { | ||||
| 			return fmt.Errorf("invalid path: %q is not a message", fieldName) | ||||
| 		} | ||||
| 
 | ||||
| 		// Get the nested message | ||||
| 		msgValue = msgValue.Mutable(fieldDescriptor).Message() | ||||
| 	} | ||||
| 
 | ||||
| 	// Check if oneof already set | ||||
| 	if of := fieldDescriptor.ContainingOneof(); of != nil { | ||||
| 		if f := msgValue.WhichOneof(of); f != nil { | ||||
| 			return fmt.Errorf("field already set for oneof %q", of.FullName().Name()) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	switch { | ||||
| 	case fieldDescriptor.IsList(): | ||||
| 		return populateRepeatedField(fieldDescriptor, msgValue.Mutable(fieldDescriptor).List(), values) | ||||
| 	case fieldDescriptor.IsMap(): | ||||
| 		return populateMapField(fieldDescriptor, msgValue.Mutable(fieldDescriptor).Map(), values) | ||||
| 	} | ||||
| 
 | ||||
| 	if len(values) > 1 { | ||||
| 		return fmt.Errorf("too many values for field %q: %s", fieldDescriptor.FullName().Name(), strings.Join(values, ", ")) | ||||
| 	} | ||||
| 
 | ||||
| 	return populateField(fieldDescriptor, msgValue, values[0]) | ||||
| } | ||||
| 
 | ||||
| func populateField(fieldDescriptor protoreflect.FieldDescriptor, msgValue protoreflect.Message, value string) error { | ||||
| 	v, err := parseField(fieldDescriptor, value) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("parsing field %q: %w", fieldDescriptor.FullName().Name(), err) | ||||
| 	} | ||||
| 
 | ||||
| 	msgValue.Set(fieldDescriptor, v) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func populateRepeatedField(fieldDescriptor protoreflect.FieldDescriptor, list protoreflect.List, values []string) error { | ||||
| 	for _, value := range values { | ||||
| 		v, err := parseField(fieldDescriptor, value) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("parsing list %q: %w", fieldDescriptor.FullName().Name(), err) | ||||
| 		} | ||||
| 		list.Append(v) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func populateMapField(fieldDescriptor protoreflect.FieldDescriptor, mp protoreflect.Map, values []string) error { | ||||
| 	if len(values) != 2 { | ||||
| 		return fmt.Errorf("more than one value provided for key %q in map %q", values[0], fieldDescriptor.FullName()) | ||||
| 	} | ||||
| 
 | ||||
| 	key, err := parseField(fieldDescriptor.MapKey(), values[0]) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("parsing map key %q: %w", fieldDescriptor.FullName().Name(), err) | ||||
| 	} | ||||
| 
 | ||||
| 	value, err := parseField(fieldDescriptor.MapValue(), values[1]) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("parsing map value %q: %w", fieldDescriptor.FullName().Name(), err) | ||||
| 	} | ||||
| 
 | ||||
| 	mp.Set(key.MapKey(), value) | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func parseField(fieldDescriptor protoreflect.FieldDescriptor, value string) (protoreflect.Value, error) { | ||||
| 	switch fieldDescriptor.Kind() { | ||||
| 	case protoreflect.BoolKind: | ||||
| 		v, err := strconv.ParseBool(value) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		return protoreflect.ValueOfBool(v), nil | ||||
| 	case protoreflect.EnumKind: | ||||
| 		enum, err := protoregistry.GlobalTypes.FindEnumByName(fieldDescriptor.Enum().FullName()) | ||||
| 		switch { | ||||
| 		case errors.Is(err, protoregistry.NotFound): | ||||
| 			return protoreflect.Value{}, fmt.Errorf("enum %q is not registered", fieldDescriptor.Enum().FullName()) | ||||
| 		case err != nil: | ||||
| 			return protoreflect.Value{}, fmt.Errorf("failed to look up enum: %w", err) | ||||
| 		} | ||||
| 		// Look for enum by name | ||||
| 		v := enum.Descriptor().Values().ByName(protoreflect.Name(value)) | ||||
| 		if v == nil { | ||||
| 			i, err := strconv.Atoi(value) | ||||
| 			if err != nil { | ||||
| 				return protoreflect.Value{}, fmt.Errorf("%q is not a valid value", value) | ||||
| 			} | ||||
| 			// Look for enum by number | ||||
| 			v = enum.Descriptor().Values().ByNumber(protoreflect.EnumNumber(i)) | ||||
| 			if v == nil { | ||||
| 				return protoreflect.Value{}, fmt.Errorf("%q is not a valid value", value) | ||||
| 			} | ||||
| 		} | ||||
| 		return protoreflect.ValueOfEnum(v.Number()), nil | ||||
| 	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: | ||||
| 		v, err := strconv.ParseInt(value, 10, 32) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		return protoreflect.ValueOfInt32(int32(v)), nil | ||||
| 	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: | ||||
| 		v, err := strconv.ParseInt(value, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		return protoreflect.ValueOfInt64(v), nil | ||||
| 	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: | ||||
| 		v, err := strconv.ParseUint(value, 10, 32) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		return protoreflect.ValueOfUint32(uint32(v)), nil | ||||
| 	case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: | ||||
| 		v, err := strconv.ParseUint(value, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		return protoreflect.ValueOfUint64(v), nil | ||||
| 	case protoreflect.FloatKind: | ||||
| 		v, err := strconv.ParseFloat(value, 32) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		return protoreflect.ValueOfFloat32(float32(v)), nil | ||||
| 	case protoreflect.DoubleKind: | ||||
| 		v, err := strconv.ParseFloat(value, 64) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		return protoreflect.ValueOfFloat64(v), nil | ||||
| 	case protoreflect.StringKind: | ||||
| 		return protoreflect.ValueOfString(value), nil | ||||
| 	case protoreflect.BytesKind: | ||||
| 		v, err := base64.URLEncoding.DecodeString(value) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		return protoreflect.ValueOfBytes(v), nil | ||||
| 	case protoreflect.MessageKind, protoreflect.GroupKind: | ||||
| 		return parseMessage(fieldDescriptor.Message(), value) | ||||
| 	default: | ||||
| 		panic(fmt.Sprintf("unknown field kind: %v", fieldDescriptor.Kind())) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func parseMessage(msgDescriptor protoreflect.MessageDescriptor, value string) (protoreflect.Value, error) { | ||||
| 	var msg proto.Message | ||||
| 	switch msgDescriptor.FullName() { | ||||
| 	case "google.protobuf.Timestamp": | ||||
| 		if value == "null" { | ||||
| 			break | ||||
| 		} | ||||
| 		t, err := time.Parse(time.RFC3339Nano, value) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = timestamppb.New(t) | ||||
| 	case "google.protobuf.Duration": | ||||
| 		if value == "null" { | ||||
| 			break | ||||
| 		} | ||||
| 		d, err := time.ParseDuration(value) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = durationpb.New(d) | ||||
| 	case "google.protobuf.DoubleValue": | ||||
| 		v, err := strconv.ParseFloat(value, 64) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = &wrapperspb.DoubleValue{Value: v} | ||||
| 	case "google.protobuf.FloatValue": | ||||
| 		v, err := strconv.ParseFloat(value, 32) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = &wrapperspb.FloatValue{Value: float32(v)} | ||||
| 	case "google.protobuf.Int64Value": | ||||
| 		v, err := strconv.ParseInt(value, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = &wrapperspb.Int64Value{Value: v} | ||||
| 	case "google.protobuf.Int32Value": | ||||
| 		v, err := strconv.ParseInt(value, 10, 32) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = &wrapperspb.Int32Value{Value: int32(v)} | ||||
| 	case "google.protobuf.UInt64Value": | ||||
| 		v, err := strconv.ParseUint(value, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = &wrapperspb.UInt64Value{Value: v} | ||||
| 	case "google.protobuf.UInt32Value": | ||||
| 		v, err := strconv.ParseUint(value, 10, 32) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = &wrapperspb.UInt32Value{Value: uint32(v)} | ||||
| 	case "google.protobuf.BoolValue": | ||||
| 		v, err := strconv.ParseBool(value) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = &wrapperspb.BoolValue{Value: v} | ||||
| 	case "google.protobuf.StringValue": | ||||
| 		msg = &wrapperspb.StringValue{Value: value} | ||||
| 	case "google.protobuf.BytesValue": | ||||
| 		v, err := base64.URLEncoding.DecodeString(value) | ||||
| 		if err != nil { | ||||
| 			return protoreflect.Value{}, err | ||||
| 		} | ||||
| 		msg = &wrapperspb.BytesValue{Value: v} | ||||
| 	case "google.protobuf.FieldMask": | ||||
| 		fm := &field_mask.FieldMask{} | ||||
| 		fm.Paths = append(fm.Paths, strings.Split(value, ",")...) | ||||
| 		msg = fm | ||||
| 	default: | ||||
| 		return protoreflect.Value{}, fmt.Errorf("unsupported message type: %q", string(msgDescriptor.FullName())) | ||||
| 	} | ||||
| 
 | ||||
| 	return protoreflect.ValueOfMessage(msg.ProtoReflect()), nil | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue