diff options
Diffstat (limited to 'vendor/github.com/grpc-ecosystem/go-grpc-middleware/validator')
| -rw-r--r-- | vendor/github.com/grpc-ecosystem/go-grpc-middleware/validator/doc.go | 45 | ||||
| -rw-r--r-- | vendor/github.com/grpc-ecosystem/go-grpc-middleware/validator/validator.go | 90 |
2 files changed, 135 insertions, 0 deletions
diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/validator/doc.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/validator/doc.go new file mode 100644 index 00000000..7205520a --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/validator/doc.go @@ -0,0 +1,45 @@ +// Copyright 2016 Michal Witkowski. All Rights Reserved. +// See LICENSE for licensing terms. + +/* +`grpc_validator` is a generic request contents validator server-side middleware for gRPC. + +Request Validator Middleware + +Validating input is important, and hard. It also causes a lot of boilerplate code. This middleware +checks for the existence of a `Validate` method on each of the messages of a gRPC request. This +includes the single request of the `Unary` calls, as well as each message of the inbound Stream calls. +In case of a validation failure, an `InvalidArgument` gRPC status is returned, along with a +description of the validation failure. + +While it is generic, it was intended to be used with https://github.com/mwitkow/go-proto-validators, +a Go protocol buffers codegen plugin that creates the `Validate` methods (including nested messages) +based on declarative options in the `.proto` files themselves. For example: + + + syntax = "proto3"; + package validator.examples; + import "github.com/mwitkow/go-proto-validators/validator.proto"; + + message InnerMessage { + // some_integer can only be in range (1, 100). + int32 some_integer = 1 [(validator.field) = {int_gt: 0, int_lt: 100}]; + // some_float can only be in range (0;1). + double some_float = 2 [(validator.field) = {float_gte: 0, float_lte: 1}]; + } + + message OuterMessage { + // important_string must be a lowercase alpha-numeric of 5 to 30 characters (RE2 syntax). + string important_string = 1 [(validator.field) = {regex: "^[a-z]{2,5}$"}]; + // proto3 doesn't have `required`, the `msg_exist` enforces presence of InnerMessage. + InnerMessage inner = 2 [(validator.field) = {msg_exists : true}]; + } + +The `OuterMessage.Validate` would include validation of regexes, existence of the InnerMessage and +the range values within it. The `grpc_validator` middleware would then automatically use that to +check all messages processed by the server. + +Please consult https://github.com/mwitkow/go-proto-validators for details on `protoc` invocation and +other parameters of customization. +*/ +package grpc_validator diff --git a/vendor/github.com/grpc-ecosystem/go-grpc-middleware/validator/validator.go b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/validator/validator.go new file mode 100644 index 00000000..7e1e413d --- /dev/null +++ b/vendor/github.com/grpc-ecosystem/go-grpc-middleware/validator/validator.go @@ -0,0 +1,90 @@ +// Copyright 2016 Michal Witkowski. All Rights Reserved. +// See LICENSE for licensing terms. + +package grpc_validator + +import ( + "context" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// The validate interface starting with protoc-gen-validate v0.6.0. +// See https://github.com/envoyproxy/protoc-gen-validate/pull/455. +type validator interface { + Validate(all bool) error +} + +// The validate interface prior to protoc-gen-validate v0.6.0. +type validatorLegacy interface { + Validate() error +} + +func validate(req interface{}) error { + switch v := req.(type) { + case validatorLegacy: + if err := v.Validate(); err != nil { + return status.Error(codes.InvalidArgument, err.Error()) + } + case validator: + if err := v.Validate(false); err != nil { + return status.Error(codes.InvalidArgument, err.Error()) + } + } + return nil +} + +// UnaryServerInterceptor returns a new unary server interceptor that validates incoming messages. +// +// Invalid messages will be rejected with `InvalidArgument` before reaching any userspace handlers. +func UnaryServerInterceptor() grpc.UnaryServerInterceptor { + return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + if err := validate(req); err != nil { + return nil, err + } + return handler(ctx, req) + } +} + +// UnaryClientInterceptor returns a new unary client interceptor that validates outgoing messages. +// +// Invalid messages will be rejected with `InvalidArgument` before sending the request to server. +func UnaryClientInterceptor() grpc.UnaryClientInterceptor { + return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + if err := validate(req); err != nil { + return err + } + return invoker(ctx, method, req, reply, cc, opts...) + } +} + +// StreamServerInterceptor returns a new streaming server interceptor that validates incoming messages. +// +// The stage at which invalid messages will be rejected with `InvalidArgument` varies based on the +// type of the RPC. For `ServerStream` (1:m) requests, it will happen before reaching any userspace +// handlers. For `ClientStream` (n:1) or `BidiStream` (n:m) RPCs, the messages will be rejected on +// calls to `stream.Recv()`. +func StreamServerInterceptor() grpc.StreamServerInterceptor { + return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + wrapper := &recvWrapper{stream} + return handler(srv, wrapper) + } +} + +type recvWrapper struct { + grpc.ServerStream +} + +func (s *recvWrapper) RecvMsg(m interface{}) error { + if err := s.ServerStream.RecvMsg(m); err != nil { + return err + } + + if err := validate(m); err != nil { + return err + } + + return nil +} |
