diff --git a/reflection/grpc_testingv3/testv3.pb.go b/reflection/grpc_testingv3/testv3.pb.go index 78876aae7..767efddf5 100644 --- a/reflection/grpc_testingv3/testv3.pb.go +++ b/reflection/grpc_testingv3/testv3.pb.go @@ -34,8 +34,33 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package +type SearchResponseV3_State int32 + +const ( + SearchResponseV3_UNKNOWN SearchResponseV3_State = 0 + SearchResponseV3_FRESH SearchResponseV3_State = 1 + SearchResponseV3_STALE SearchResponseV3_State = 2 +) + +var SearchResponseV3_State_name = map[int32]string{ + 0: "UNKNOWN", + 1: "FRESH", + 2: "STALE", +} +var SearchResponseV3_State_value = map[string]int32{ + "UNKNOWN": 0, + "FRESH": 1, + "STALE": 2, +} + +func (x SearchResponseV3_State) String() string { + return proto.EnumName(SearchResponseV3_State_name, int32(x)) +} +func (SearchResponseV3_State) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } + type SearchResponseV3 struct { Results []*SearchResponseV3_Result `protobuf:"bytes,1,rep,name=results" json:"results,omitempty"` + State SearchResponseV3_State `protobuf:"varint,2,opt,name=state,enum=grpc.testingv3.SearchResponseV3_State" json:"state,omitempty"` } func (m *SearchResponseV3) Reset() { *m = SearchResponseV3{} } @@ -50,10 +75,18 @@ func (m *SearchResponseV3) GetResults() []*SearchResponseV3_Result { return nil } +func (m *SearchResponseV3) GetState() SearchResponseV3_State { + if m != nil { + return m.State + } + return SearchResponseV3_UNKNOWN +} + type SearchResponseV3_Result struct { - Url string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"` - Title string `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"` - Snippets []string `protobuf:"bytes,3,rep,name=snippets" json:"snippets,omitempty"` + Url string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"` + Title string `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"` + Snippets []string `protobuf:"bytes,3,rep,name=snippets" json:"snippets,omitempty"` + Metadata map[string]*SearchResponseV3_Result_Value `protobuf:"bytes,4,rep,name=metadata" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` } func (m *SearchResponseV3_Result) Reset() { *m = SearchResponseV3_Result{} } @@ -61,6 +94,174 @@ func (m *SearchResponseV3_Result) String() string { return proto.Comp func (*SearchResponseV3_Result) ProtoMessage() {} func (*SearchResponseV3_Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } +func (m *SearchResponseV3_Result) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *SearchResponseV3_Result) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *SearchResponseV3_Result) GetSnippets() []string { + if m != nil { + return m.Snippets + } + return nil +} + +func (m *SearchResponseV3_Result) GetMetadata() map[string]*SearchResponseV3_Result_Value { + if m != nil { + return m.Metadata + } + return nil +} + +type SearchResponseV3_Result_Value struct { + // Types that are valid to be assigned to Val: + // *SearchResponseV3_Result_Value_Str + // *SearchResponseV3_Result_Value_Int + // *SearchResponseV3_Result_Value_Real + Val isSearchResponseV3_Result_Value_Val `protobuf_oneof:"val"` +} + +func (m *SearchResponseV3_Result_Value) Reset() { *m = SearchResponseV3_Result_Value{} } +func (m *SearchResponseV3_Result_Value) String() string { return proto.CompactTextString(m) } +func (*SearchResponseV3_Result_Value) ProtoMessage() {} +func (*SearchResponseV3_Result_Value) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{0, 0, 0} +} + +type isSearchResponseV3_Result_Value_Val interface { + isSearchResponseV3_Result_Value_Val() +} + +type SearchResponseV3_Result_Value_Str struct { + Str string `protobuf:"bytes,1,opt,name=str,oneof"` +} +type SearchResponseV3_Result_Value_Int struct { + Int int64 `protobuf:"varint,2,opt,name=int,oneof"` +} +type SearchResponseV3_Result_Value_Real struct { + Real float64 `protobuf:"fixed64,3,opt,name=real,oneof"` +} + +func (*SearchResponseV3_Result_Value_Str) isSearchResponseV3_Result_Value_Val() {} +func (*SearchResponseV3_Result_Value_Int) isSearchResponseV3_Result_Value_Val() {} +func (*SearchResponseV3_Result_Value_Real) isSearchResponseV3_Result_Value_Val() {} + +func (m *SearchResponseV3_Result_Value) GetVal() isSearchResponseV3_Result_Value_Val { + if m != nil { + return m.Val + } + return nil +} + +func (m *SearchResponseV3_Result_Value) GetStr() string { + if x, ok := m.GetVal().(*SearchResponseV3_Result_Value_Str); ok { + return x.Str + } + return "" +} + +func (m *SearchResponseV3_Result_Value) GetInt() int64 { + if x, ok := m.GetVal().(*SearchResponseV3_Result_Value_Int); ok { + return x.Int + } + return 0 +} + +func (m *SearchResponseV3_Result_Value) GetReal() float64 { + if x, ok := m.GetVal().(*SearchResponseV3_Result_Value_Real); ok { + return x.Real + } + return 0 +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*SearchResponseV3_Result_Value) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _SearchResponseV3_Result_Value_OneofMarshaler, _SearchResponseV3_Result_Value_OneofUnmarshaler, _SearchResponseV3_Result_Value_OneofSizer, []interface{}{ + (*SearchResponseV3_Result_Value_Str)(nil), + (*SearchResponseV3_Result_Value_Int)(nil), + (*SearchResponseV3_Result_Value_Real)(nil), + } +} + +func _SearchResponseV3_Result_Value_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*SearchResponseV3_Result_Value) + // val + switch x := m.Val.(type) { + case *SearchResponseV3_Result_Value_Str: + b.EncodeVarint(1<<3 | proto.WireBytes) + b.EncodeStringBytes(x.Str) + case *SearchResponseV3_Result_Value_Int: + b.EncodeVarint(2<<3 | proto.WireVarint) + b.EncodeVarint(uint64(x.Int)) + case *SearchResponseV3_Result_Value_Real: + b.EncodeVarint(3<<3 | proto.WireFixed64) + b.EncodeFixed64(math.Float64bits(x.Real)) + case nil: + default: + return fmt.Errorf("SearchResponseV3_Result_Value.Val has unexpected type %T", x) + } + return nil +} + +func _SearchResponseV3_Result_Value_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*SearchResponseV3_Result_Value) + switch tag { + case 1: // val.str + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.Val = &SearchResponseV3_Result_Value_Str{x} + return true, err + case 2: // val.int + if wire != proto.WireVarint { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeVarint() + m.Val = &SearchResponseV3_Result_Value_Int{int64(x)} + return true, err + case 3: // val.real + if wire != proto.WireFixed64 { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeFixed64() + m.Val = &SearchResponseV3_Result_Value_Real{math.Float64frombits(x)} + return true, err + default: + return false, nil + } +} + +func _SearchResponseV3_Result_Value_OneofSizer(msg proto.Message) (n int) { + m := msg.(*SearchResponseV3_Result_Value) + // val + switch x := m.Val.(type) { + case *SearchResponseV3_Result_Value_Str: + n += proto.SizeVarint(1<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.Str))) + n += len(x.Str) + case *SearchResponseV3_Result_Value_Int: + n += proto.SizeVarint(2<<3 | proto.WireVarint) + n += proto.SizeVarint(uint64(x.Int)) + case *SearchResponseV3_Result_Value_Real: + n += proto.SizeVarint(3<<3 | proto.WireFixed64) + n += 8 + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + type SearchRequestV3 struct { Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` } @@ -70,10 +271,19 @@ func (m *SearchRequestV3) String() string { return proto.CompactTextS func (*SearchRequestV3) ProtoMessage() {} func (*SearchRequestV3) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } +func (m *SearchRequestV3) GetQuery() string { + if m != nil { + return m.Query + } + return "" +} + func init() { proto.RegisterType((*SearchResponseV3)(nil), "grpc.testingv3.SearchResponseV3") proto.RegisterType((*SearchResponseV3_Result)(nil), "grpc.testingv3.SearchResponseV3.Result") + proto.RegisterType((*SearchResponseV3_Result_Value)(nil), "grpc.testingv3.SearchResponseV3.Result.Value") proto.RegisterType((*SearchRequestV3)(nil), "grpc.testingv3.SearchRequestV3") + proto.RegisterEnum("grpc.testingv3.SearchResponseV3_State", SearchResponseV3_State_name, SearchResponseV3_State_value) } // Reference imports to suppress errors if they are not otherwise used. @@ -217,20 +427,31 @@ var _SearchServiceV3_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("testv3.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 240 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x91, 0x41, 0x4b, 0xc3, 0x40, - 0x10, 0x85, 0x59, 0x83, 0xd1, 0x8e, 0x62, 0xcb, 0xe2, 0x21, 0xe4, 0x62, 0xe8, 0xa5, 0x39, 0x2d, - 0xd2, 0xfd, 0x05, 0x9e, 0xf5, 0xb4, 0x81, 0xe2, 0xb5, 0x86, 0x21, 0x2e, 0xc4, 0x64, 0x3b, 0x33, - 0x09, 0xf8, 0x7b, 0xfc, 0x13, 0xfe, 0x3c, 0x49, 0xd2, 0x08, 0x0a, 0xe2, 0xa5, 0xb7, 0x7d, 0x8f, - 0xf7, 0xbe, 0xe5, 0x31, 0x70, 0x2d, 0xc8, 0xd2, 0x5b, 0x13, 0xa8, 0x95, 0x56, 0xdf, 0x54, 0x14, - 0x4a, 0x33, 0x58, 0xbe, 0xa9, 0x7a, 0xbb, 0xfe, 0x50, 0xb0, 0x2a, 0x70, 0x4f, 0xe5, 0xab, 0x43, - 0x0e, 0x6d, 0xc3, 0xb8, 0xb3, 0xfa, 0x01, 0x2e, 0x08, 0xb9, 0xab, 0x85, 0x13, 0x95, 0x45, 0xf9, - 0xd5, 0x76, 0x63, 0x7e, 0xd6, 0xcc, 0xef, 0x8a, 0x71, 0x63, 0xde, 0xcd, 0xbd, 0xf4, 0x09, 0xe2, - 0xc9, 0xd2, 0x2b, 0x88, 0x3a, 0xaa, 0x13, 0x95, 0xa9, 0x7c, 0xe1, 0x86, 0xa7, 0xbe, 0x85, 0x73, - 0xf1, 0x52, 0x63, 0x72, 0x36, 0x7a, 0x93, 0xd0, 0x29, 0x5c, 0x72, 0xe3, 0x43, 0x40, 0xe1, 0x24, - 0xca, 0xa2, 0x7c, 0xe1, 0xbe, 0xf5, 0x7a, 0x03, 0xcb, 0xf9, 0xc7, 0x43, 0x87, 0x2c, 0x3b, 0x3b, - 0x40, 0x0e, 0x1d, 0xd2, 0xfb, 0x11, 0x3c, 0x89, 0xed, 0xa7, 0x9a, 0x93, 0x05, 0x52, 0xef, 0xcb, - 0x61, 0xcd, 0x23, 0xc4, 0x93, 0xa5, 0xef, 0xfe, 0x9a, 0x71, 0x84, 0xa6, 0xd9, 0x7f, 0x3b, 0xf5, - 0x33, 0x2c, 0x0b, 0x21, 0xdc, 0xbf, 0xf9, 0xa6, 0x3a, 0x19, 0x35, 0x57, 0xf7, 0xea, 0x25, 0x1e, - 0x0f, 0x64, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd4, 0xe6, 0xa0, 0xf9, 0xb0, 0x01, 0x00, 0x00, + // 416 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0xd1, 0x6a, 0xd4, 0x40, + 0x14, 0x86, 0x77, 0x36, 0x9b, 0x6d, 0xf7, 0xac, 0xb6, 0x61, 0xe8, 0x45, 0xc8, 0x8d, 0x61, 0x2f, + 0x6c, 0x10, 0x0c, 0x92, 0x20, 0x88, 0x78, 0x53, 0x65, 0x65, 0xa1, 0x75, 0xc5, 0x89, 0xae, 0xde, + 0x8e, 0xeb, 0x61, 0x8d, 0x4d, 0xb3, 0xe9, 0xcc, 0x49, 0x60, 0x9f, 0xc5, 0x17, 0xf1, 0x55, 0x7c, + 0x1b, 0x99, 0x99, 0xa6, 0x50, 0x41, 0xba, 0x17, 0xde, 0xcd, 0x7f, 0x38, 0xff, 0x37, 0xff, 0x3f, + 0x24, 0xf0, 0x80, 0x50, 0x53, 0x97, 0xa7, 0x8d, 0xda, 0xd2, 0x96, 0x1f, 0x6d, 0x54, 0xb3, 0x4e, + 0xcd, 0xa8, 0xac, 0x37, 0x5d, 0x3e, 0xfb, 0x39, 0x82, 0xa0, 0x40, 0xa9, 0xd6, 0xdf, 0x05, 0xea, + 0x66, 0x5b, 0x6b, 0x5c, 0xe5, 0xfc, 0x0c, 0x0e, 0x14, 0xea, 0xb6, 0x22, 0x1d, 0xb2, 0xd8, 0x4b, + 0xa6, 0xd9, 0x69, 0x7a, 0xd7, 0x96, 0xfe, 0x6d, 0x49, 0x85, 0xdd, 0x17, 0xbd, 0x8f, 0xbf, 0x02, + 0x5f, 0x93, 0x24, 0x0c, 0x87, 0x31, 0x4b, 0x8e, 0xb2, 0xc7, 0xf7, 0x02, 0x0a, 0xb3, 0x2d, 0x9c, + 0x29, 0xfa, 0x3d, 0x84, 0xb1, 0x23, 0xf2, 0x00, 0xbc, 0x56, 0x55, 0x21, 0x8b, 0x59, 0x32, 0x11, + 0xe6, 0xc8, 0x4f, 0xc0, 0xa7, 0x92, 0x2a, 0x87, 0x9e, 0x08, 0x27, 0x78, 0x04, 0x87, 0xba, 0x2e, + 0x9b, 0x06, 0x49, 0x87, 0x5e, 0xec, 0x25, 0x13, 0x71, 0xab, 0xf9, 0x07, 0x38, 0xbc, 0x42, 0x92, + 0xdf, 0x24, 0xc9, 0x70, 0x64, 0x0b, 0x3d, 0xdf, 0xb3, 0x50, 0xfa, 0xee, 0xc6, 0x37, 0xaf, 0x49, + 0xed, 0xc4, 0x2d, 0x26, 0xba, 0x00, 0x7f, 0x25, 0xab, 0x16, 0x39, 0x07, 0x4f, 0x93, 0x72, 0xf9, + 0x16, 0x03, 0x61, 0x84, 0x99, 0x95, 0x35, 0xd9, 0x7c, 0x9e, 0x99, 0x95, 0x35, 0xf1, 0x13, 0x18, + 0x29, 0x94, 0x55, 0xe8, 0xc5, 0x2c, 0x61, 0x8b, 0x81, 0xb0, 0xea, 0xb5, 0x0f, 0x5e, 0x27, 0xab, + 0xe8, 0x07, 0x3c, 0xbc, 0x73, 0x91, 0x69, 0x7d, 0x89, 0xbb, 0xbe, 0xf5, 0x25, 0xee, 0xf8, 0x1b, + 0xf0, 0x3b, 0x73, 0xa1, 0xa5, 0x4e, 0xb3, 0xa7, 0xfb, 0x16, 0xb0, 0x29, 0x85, 0xf3, 0xbe, 0x1c, + 0xbe, 0x60, 0xb3, 0x27, 0xe0, 0xdb, 0xb7, 0xe6, 0x53, 0x38, 0xf8, 0xb4, 0x3c, 0x5f, 0xbe, 0xff, + 0xbc, 0x0c, 0x06, 0x7c, 0x02, 0xfe, 0x5b, 0x31, 0x2f, 0x16, 0x01, 0x33, 0xc7, 0xe2, 0xe3, 0xd9, + 0xc5, 0x3c, 0x18, 0xce, 0x4e, 0xe1, 0xb8, 0xe7, 0x5e, 0xb7, 0xa8, 0x69, 0x95, 0x9b, 0xd7, 0xbf, + 0x6e, 0x51, 0xf5, 0xd9, 0x9c, 0xc8, 0x7e, 0xb1, 0x7e, 0xb3, 0x40, 0xd5, 0x95, 0x6b, 0xf3, 0x15, + 0x9d, 0xc3, 0xd8, 0x8d, 0xf8, 0xa3, 0x7f, 0x85, 0xbd, 0x81, 0x46, 0xf1, 0x7d, 0x6d, 0xf8, 0x17, + 0x38, 0x2e, 0x48, 0xa1, 0xbc, 0x2a, 0xeb, 0xcd, 0x7f, 0xa3, 0x26, 0xec, 0x19, 0xfb, 0x3a, 0xb6, + 0x3f, 0x46, 0xfe, 0x27, 0x00, 0x00, 0xff, 0xff, 0xed, 0xa2, 0x8d, 0x75, 0x28, 0x03, 0x00, 0x00, } diff --git a/reflection/grpc_testingv3/testv3.proto b/reflection/grpc_testingv3/testv3.proto index 1e175193e..ee4966bf7 100644 --- a/reflection/grpc_testingv3/testv3.proto +++ b/reflection/grpc_testingv3/testv3.proto @@ -7,8 +7,22 @@ message SearchResponseV3 { string url = 1; string title = 2; repeated string snippets = 3; + message Value { + oneof val { + string str = 1; + int64 int = 2; + double real = 3; + } + } + map metadata = 4; + } + enum State { + UNKNOWN = 0; + FRESH = 1; + STALE = 2; } repeated Result results = 1; + State state = 2; } message SearchRequestV3 { diff --git a/reflection/serverreflection.go b/reflection/serverreflection.go index 1bfbf3e78..dd22a2da7 100644 --- a/reflection/serverreflection.go +++ b/reflection/serverreflection.go @@ -45,7 +45,8 @@ import ( "io" "io/ioutil" "reflect" - "strings" + "sort" + "sync" "github.com/golang/protobuf/proto" dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" @@ -57,8 +58,10 @@ import ( type serverReflectionServer struct { s *grpc.Server - // TODO add more cache if necessary - serviceInfo map[string]grpc.ServiceInfo // cache for s.GetServiceInfo() + + initSymbols sync.Once + serviceNames []string + symbols map[string]*dpb.FileDescriptorProto // map of fully-qualified names to files } // Register registers the server reflection service on the given gRPC server. @@ -76,6 +79,112 @@ type protoMessage interface { Descriptor() ([]byte, []int) } +func (s *serverReflectionServer) getSymbols() (svcNames []string, symbolIndex map[string]*dpb.FileDescriptorProto) { + s.initSymbols.Do(func() { + serviceInfo := s.s.GetServiceInfo() + + s.symbols = map[string]*dpb.FileDescriptorProto{} + s.serviceNames = make([]string, 0, len(serviceInfo)) + processed := map[string]struct{}{} + for svc, info := range serviceInfo { + s.serviceNames = append(s.serviceNames, svc) + fdenc, ok := parseMetadata(info.Metadata) + if !ok { + continue + } + fd, err := decodeFileDesc(fdenc) + if err != nil { + continue + } + s.processFile(fd, processed) + } + sort.Strings(s.serviceNames) + }) + + return s.serviceNames, s.symbols +} + +func (s *serverReflectionServer) processFile(fd *dpb.FileDescriptorProto, processed map[string]struct{}) { + filename := fd.GetName() + if _, ok := processed[filename]; ok { + return + } + processed[filename] = struct{}{} + + prefix := fd.GetPackage() + + for _, msg := range fd.MessageType { + s.processMessage(fd, prefix, msg) + } + for _, en := range fd.EnumType { + s.processEnum(fd, prefix, en) + } + for _, ext := range fd.Extension { + s.processField(fd, prefix, ext) + } + for _, svc := range fd.Service { + svcName := fqn(prefix, svc.GetName()) + s.symbols[svcName] = fd + for _, meth := range svc.Method { + name := fqn(svcName, meth.GetName()) + s.symbols[name] = fd + } + } + + for _, dep := range fd.Dependency { + fdenc := proto.FileDescriptor(dep) + fdDep, err := decodeFileDesc(fdenc) + if err != nil { + continue + } + s.processFile(fdDep, processed) + } +} + +func (s *serverReflectionServer) processMessage(fd *dpb.FileDescriptorProto, prefix string, msg *dpb.DescriptorProto) { + msgName := fqn(prefix, msg.GetName()) + s.symbols[msgName] = fd + + for _, nested := range msg.NestedType { + s.processMessage(fd, msgName, nested) + } + for _, en := range msg.EnumType { + s.processEnum(fd, msgName, en) + } + for _, ext := range msg.Extension { + s.processField(fd, msgName, ext) + } + for _, fld := range msg.Field { + s.processField(fd, msgName, fld) + } + for _, oneof := range msg.OneofDecl { + oneofName := fqn(msgName, oneof.GetName()) + s.symbols[oneofName] = fd + } +} + +func (s *serverReflectionServer) processEnum(fd *dpb.FileDescriptorProto, prefix string, en *dpb.EnumDescriptorProto) { + enName := fqn(prefix, en.GetName()) + s.symbols[enName] = fd + + for _, val := range en.Value { + valName := fqn(enName, val.GetName()) + s.symbols[valName] = fd + } +} + +func (s *serverReflectionServer) processField(fd *dpb.FileDescriptorProto, prefix string, fld *dpb.FieldDescriptorProto) { + fldName := fqn(prefix, fld.GetName()) + s.symbols[fldName] = fd +} + +func fqn(prefix, name string) string { + if prefix == "" { + return name + } + return prefix + "." + name +} + // fileDescForType gets the file descriptor for the given type. // The given type should be a proto message. func (s *serverReflectionServer) fileDescForType(st reflect.Type) (*dpb.FileDescriptorProto, error) { @@ -85,12 +194,12 @@ func (s *serverReflectionServer) fileDescForType(st reflect.Type) (*dpb.FileDesc } enc, _ := m.Descriptor() - return s.decodeFileDesc(enc) + return decodeFileDesc(enc) } // decodeFileDesc does decompression and unmarshalling on the given // file descriptor byte slice. -func (s *serverReflectionServer) decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) { +func decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) { raw, err := decompress(enc) if err != nil { return nil, fmt.Errorf("failed to decompress enc: %v", err) @@ -116,7 +225,7 @@ func decompress(b []byte) ([]byte, error) { return out, nil } -func (s *serverReflectionServer) typeForName(name string) (reflect.Type, error) { +func typeForName(name string) (reflect.Type, error) { pt := proto.MessageType(name) if pt == nil { return nil, fmt.Errorf("unknown type: %q", name) @@ -126,7 +235,7 @@ func (s *serverReflectionServer) typeForName(name string) (reflect.Type, error) return st, nil } -func (s *serverReflectionServer) fileDescContainingExtension(st reflect.Type, ext int32) (*dpb.FileDescriptorProto, error) { +func fileDescContainingExtension(st reflect.Type, ext int32) (*dpb.FileDescriptorProto, error) { m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message) if !ok { return nil, fmt.Errorf("failed to create message from type: %v", st) @@ -144,7 +253,7 @@ func (s *serverReflectionServer) fileDescContainingExtension(st reflect.Type, ex return nil, fmt.Errorf("failed to find registered extension for extension number %v", ext) } - return s.decodeFileDesc(proto.FileDescriptor(extDesc.Filename)) + return decodeFileDesc(proto.FileDescriptor(extDesc.Filename)) } func (s *serverReflectionServer) allExtensionNumbersForType(st reflect.Type) ([]int32, error) { @@ -168,53 +277,13 @@ func (s *serverReflectionServer) fileDescEncodingByFilename(name string) ([]byte if enc == nil { return nil, fmt.Errorf("unknown file: %v", name) } - fd, err := s.decodeFileDesc(enc) + fd, err := decodeFileDesc(enc) if err != nil { return nil, err } return proto.Marshal(fd) } -// serviceMetadataForSymbol finds the metadata for name in s.serviceInfo. -// name should be a service name or a method name. -func (s *serverReflectionServer) serviceMetadataForSymbol(name string) (interface{}, error) { - if s.serviceInfo == nil { - s.serviceInfo = s.s.GetServiceInfo() - } - - // Check if it's a service name. - if info, ok := s.serviceInfo[name]; ok { - return info.Metadata, nil - } - - // Check if it's a method name. - pos := strings.LastIndex(name, ".") - // Not a valid method name. - if pos == -1 { - return nil, fmt.Errorf("unknown symbol: %v", name) - } - - info, ok := s.serviceInfo[name[:pos]] - // Substring before last "." is not a service name. - if !ok { - return nil, fmt.Errorf("unknown symbol: %v", name) - } - - // Search the method name in info.Methods. - var found bool - for _, m := range info.Methods { - if m.Name == name[pos+1:] { - found = true - break - } - } - if found { - return info.Metadata, nil - } - - return nil, fmt.Errorf("unknown symbol: %v", name) -} - // parseMetadata finds the file descriptor bytes specified meta. // For SupportPackageIsVersion4, m is the name of the proto file, we // call proto.FileDescriptor to get the byte slice. @@ -237,33 +306,21 @@ func parseMetadata(meta interface{}) ([]byte, bool) { // does marshalling on it and returns the marshalled result. // The given symbol can be a type, a service or a method. func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string) ([]byte, error) { - var ( - fd *dpb.FileDescriptorProto - ) - // Check if it's a type name. - if st, err := s.typeForName(name); err == nil { - fd, err = s.fileDescForType(st) - if err != nil { - return nil, err + _, symbols := s.getSymbols() + fd := symbols[name] + if fd == nil { + // Check if it's a type name that was not present in the + // transitive dependencies of the registered services. + if st, err := typeForName(name); err == nil { + fd, err = s.fileDescForType(st) + if err != nil { + return nil, err + } } - } else { // Check if it's a service name or a method name. - meta, err := s.serviceMetadataForSymbol(name) + } - // Metadata not found. - if err != nil { - return nil, err - } - - // Metadata not valid. - enc, ok := parseMetadata(meta) - if !ok { - return nil, fmt.Errorf("invalid file descriptor for symbol: %v", name) - } - - fd, err = s.decodeFileDesc(enc) - if err != nil { - return nil, err - } + if fd == nil { + return nil, fmt.Errorf("unknown symbol: %v", name) } return proto.Marshal(fd) @@ -272,11 +329,11 @@ func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string) ( // fileDescEncodingContainingExtension finds the file descriptor containing given extension, // does marshalling on it and returns the marshalled result. func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName string, extNum int32) ([]byte, error) { - st, err := s.typeForName(typeName) + st, err := typeForName(typeName) if err != nil { return nil, err } - fd, err := s.fileDescContainingExtension(st, extNum) + fd, err := fileDescContainingExtension(st, extNum) if err != nil { return nil, err } @@ -285,7 +342,7 @@ func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName st // allExtensionNumbersForTypeName returns all extension numbers for the given type. func (s *serverReflectionServer) allExtensionNumbersForTypeName(name string) ([]int32, error) { - st, err := s.typeForName(name) + st, err := typeForName(name) if err != nil { return nil, err } @@ -374,14 +431,12 @@ func (s *serverReflectionServer) ServerReflectionInfo(stream rpb.ServerReflectio } } case *rpb.ServerReflectionRequest_ListServices: - if s.serviceInfo == nil { - s.serviceInfo = s.s.GetServiceInfo() - } - serviceResponses := make([]*rpb.ServiceResponse, 0, len(s.serviceInfo)) - for n := range s.serviceInfo { - serviceResponses = append(serviceResponses, &rpb.ServiceResponse{ + svcNames, _ := s.getSymbols() + serviceResponses := make([]*rpb.ServiceResponse, len(svcNames)) + for i, n := range svcNames { + serviceResponses[i] = &rpb.ServiceResponse{ Name: n, - }) + } } out.MessageResponse = &rpb.ServerReflectionResponse_ListServicesResponse{ ListServicesResponse: &rpb.ListServiceResponse{ diff --git a/reflection/serverreflection_test.go b/reflection/serverreflection_test.go index 908589085..e2c741697 100644 --- a/reflection/serverreflection_test.go +++ b/reflection/serverreflection_test.go @@ -60,7 +60,7 @@ func loadFileDesc(filename string) (*dpb.FileDescriptorProto, []byte) { if enc == nil { panic(fmt.Sprintf("failed to find fd for file: %v", filename)) } - fd, err := s.decodeFileDesc(enc) + fd, err := decodeFileDesc(enc) if err != nil { panic(fmt.Sprintf("failed to decode enc: %v", err)) } @@ -101,7 +101,7 @@ func TestTypeForName(t *testing.T) { }{ {"grpc.testing.SearchResponse", reflect.TypeOf(pb.SearchResponse{})}, } { - r, err := s.typeForName(test.name) + r, err := typeForName(test.name) if err != nil || r != test.want { t.Errorf("typeForName(%q) = %q, %v, want %q, ", test.name, r, err, test.want) } @@ -112,7 +112,7 @@ func TestTypeForNameNotFound(t *testing.T) { for _, test := range []string{ "grpc.testing.not_exiting", } { - _, err := s.typeForName(test) + _, err := typeForName(test) if err == nil { t.Errorf("typeForName(%q) = _, %v, want _, ", test, err) } @@ -131,7 +131,7 @@ func TestFileDescContainingExtension(t *testing.T) { {reflect.TypeOf(pb.ToBeExtended{}), 23, fdProto2Ext2}, {reflect.TypeOf(pb.ToBeExtended{}), 29, fdProto2Ext2}, } { - fd, err := s.fileDescContainingExtension(test.st, test.extNum) + fd, err := fileDescContainingExtension(test.st, test.extNum) if err != nil || !proto.Equal(fd, test.want) { t.Errorf("fileDescContainingExtension(%q) = %q, %v, want %q, ", test.st, fd, err, test.want) } @@ -296,6 +296,12 @@ func testFileContainingSymbol(t *testing.T, stream rpb.ServerReflection_ServerRe {"grpc.testingv3.SearchServiceV3.Search", fdTestv3Byte}, {"grpc.testingv3.SearchServiceV3.StreamingSearch", fdTestv3Byte}, {"grpc.testingv3.SearchResponseV3", fdTestv3Byte}, + // search for field, oneof, enum, and enum value symbols, too + {"grpc.testingv3.SearchResponseV3.Result.snippets", fdTestv3Byte}, + {"grpc.testingv3.SearchResponseV3.Result.Value.val", fdTestv3Byte}, + {"grpc.testingv3.SearchResponseV3.Result.Value.str", fdTestv3Byte}, + {"grpc.testingv3.SearchResponseV3.State", fdTestv3Byte}, + {"grpc.testingv3.SearchResponseV3.State.FRESH", fdTestv3Byte}, } { if err := stream.Send(&rpb.ServerReflectionRequest{ MessageRequest: &rpb.ServerReflectionRequest_FileContainingSymbol{