diff options
Diffstat (limited to 'vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go')
-rw-r--r-- | vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go | 417 |
1 files changed, 0 insertions, 417 deletions
diff --git a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go b/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go deleted file mode 100644 index 2f2b34243..000000000 --- a/vendor/github.com/grpc-ecosystem/grpc-gateway/v2/runtime/context.go +++ /dev/null @@ -1,417 +0,0 @@ -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/grpclog" - "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" - -// 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. -var DefaultContextTimeout = 0 * time.Second - -// malformedHTTPHeaders lists the headers that the gRPC server may reject outright as malformed. -// See https://github.com/grpc/grpc-go/pull/4803#issuecomment-986093310 for more context. -var malformedHTTPHeaders = map[string]struct{}{ - "connection": {}, -} - -type ( - rpcMethodKey struct{} - httpPathPatternKey struct{} - httpPatternKey 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 isValidGRPCMetadataKey(key string) bool { - // Must be a valid gRPC "Header-Name" as defined here: - // https://github.com/grpc/grpc/blob/4b05dc88b724214d0c725c8e7442cbc7a61b1374/doc/PROTOCOL-HTTP2.md - // This means 0-9 a-z _ - . - // Only lowercase letters are valid in the wire protocol, but the client library will normalize - // uppercase ASCII to lowercase, so uppercase ASCII is also acceptable. - bytes := []byte(key) // gRPC validates strings on the byte level, not Unicode. - for _, ch := range bytes { - validLowercaseLetter := ch >= 'a' && ch <= 'z' - validUppercaseLetter := ch >= 'A' && ch <= 'Z' - validDigit := ch >= '0' && ch <= '9' - validOther := ch == '.' || ch == '-' || ch == '_' - if !validLowercaseLetter && !validUppercaseLetter && !validDigit && !validOther { - return false - } - } - return true -} - -func isValidGRPCMetadataTextValue(textValue string) bool { - // Must be a valid gRPC "ASCII-Value" as defined here: - // https://github.com/grpc/grpc/blob/4b05dc88b724214d0c725c8e7442cbc7a61b1374/doc/PROTOCOL-HTTP2.md - // This means printable ASCII (including/plus spaces); 0x20 to 0x7E inclusive. - bytes := []byte(textValue) // gRPC validates strings on the byte level, not Unicode. - for _, ch := range bytes { - if ch < 0x20 || ch > 0x7E { - return false - } - } - return true -} - -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) - } - 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) - } - } - var pairs []string - for key, vals := range req.Header { - key = textproto.CanonicalMIMEHeaderKey(key) - switch key { - case xForwardedFor, xForwardedHost: - // Handled separately below - continue - } - - 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 { - if !isValidGRPCMetadataKey(h) { - grpclog.Errorf("HTTP header name %q is not valid as gRPC metadata key; skipping", h) - continue - } - // 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) - } else if !isValidGRPCMetadataTextValue(val) { - grpclog.Errorf("Value of HTTP header %q contains non-ASCII value (not valid as gRPC metadata): skipping", h) - continue - } - 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) - } - - xff := req.Header.Values(xForwardedFor) - if addr := req.RemoteAddr; addr != "" { - if remoteIP, _, err := net.SplitHostPort(addr); err == nil { - xff = append(xff, remoteIP) - } - } - if len(xff) > 0 { - pairs = append(pairs, strings.ToLower(xForwardedFor), strings.Join(xff, ", ")) - } - - if timeout != 0 { - 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 { - if ctx == nil { - ctx = context.Background() - } - return context.WithValue(ctx, serverMetadataKey{}, md) -} - -// ServerMetadataFromContext returns the ServerMetadata in ctx -func ServerMetadataFromContext(ctx context.Context) (md ServerMetadata, ok bool) { - if ctx == nil { - return md, false - } - 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 -} - -// isMalformedHTTPHeader checks whether header belongs to the list of -// "malformed headers" and would be rejected by the gRPC server. -func isMalformedHTTPHeader(header string) bool { - _, isMalformed := malformedHTTPHeaders[strings.ToLower(header)] - return isMalformed -} - -// 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) -} - -// HTTPPattern returns the HTTP path pattern struct relating to the HTTP handler, if one exists. -func HTTPPattern(ctx context.Context) (Pattern, bool) { - v, ok := ctx.Value(httpPatternKey{}).(Pattern) - return v, ok -} - -func withHTTPPattern(ctx context.Context, httpPattern Pattern) context.Context { - return context.WithValue(ctx, httpPatternKey{}, httpPattern) -} |