service reflection can lookup enum, enum val, oneof, and field symbols (#1910)

* service reflection can lookup enum, enum val, oneof, and field symbols; cache descriptors

* address feedback: don't use mutex, remove unnecessary conditional, make fileDescContainingExtension a func instead of a method
This commit is contained in:
Joshua Humphries 2018-03-21 19:49:57 -04:00 committed by mmukhi
parent 32d9ffabba
commit dfbefc6795
4 changed files with 403 additions and 107 deletions

View File

@ -34,8 +34,33 @@ var _ = math.Inf
// proto package needs to be updated. // proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 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 { type SearchResponseV3 struct {
Results []*SearchResponseV3_Result `protobuf:"bytes,1,rep,name=results" json:"results,omitempty"` 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{} } func (m *SearchResponseV3) Reset() { *m = SearchResponseV3{} }
@ -50,10 +75,18 @@ func (m *SearchResponseV3) GetResults() []*SearchResponseV3_Result {
return nil return nil
} }
func (m *SearchResponseV3) GetState() SearchResponseV3_State {
if m != nil {
return m.State
}
return SearchResponseV3_UNKNOWN
}
type SearchResponseV3_Result struct { type SearchResponseV3_Result struct {
Url string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"` Url string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"`
Title string `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"` Title string `protobuf:"bytes,2,opt,name=title" json:"title,omitempty"`
Snippets []string `protobuf:"bytes,3,rep,name=snippets" json:"snippets,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{} } 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) ProtoMessage() {}
func (*SearchResponseV3_Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } 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 { type SearchRequestV3 struct {
Query string `protobuf:"bytes,1,opt,name=query" json:"query,omitempty"` 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) ProtoMessage() {}
func (*SearchRequestV3) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } func (*SearchRequestV3) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *SearchRequestV3) GetQuery() string {
if m != nil {
return m.Query
}
return ""
}
func init() { func init() {
proto.RegisterType((*SearchResponseV3)(nil), "grpc.testingv3.SearchResponseV3") proto.RegisterType((*SearchResponseV3)(nil), "grpc.testingv3.SearchResponseV3")
proto.RegisterType((*SearchResponseV3_Result)(nil), "grpc.testingv3.SearchResponseV3.Result") 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.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. // 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) } func init() { proto.RegisterFile("testv3.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 240 bytes of a gzipped FileDescriptorProto // 416 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x91, 0x41, 0x4b, 0xc3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0xd1, 0x6a, 0xd4, 0x40,
0x10, 0x85, 0x59, 0x83, 0xd1, 0x8e, 0x62, 0xcb, 0xe2, 0x21, 0xe4, 0x62, 0xe8, 0xa5, 0x39, 0x2d, 0x14, 0x86, 0x77, 0x36, 0x9b, 0x6d, 0xf7, 0xac, 0xb6, 0x61, 0xe8, 0x45, 0xc8, 0x8d, 0x61, 0x2f,
0xd2, 0xfd, 0x05, 0x9e, 0xf5, 0xb4, 0x81, 0xe2, 0xb5, 0x86, 0x21, 0x2e, 0xc4, 0x64, 0x3b, 0x33, 0x6c, 0x10, 0x0c, 0x92, 0x20, 0x88, 0x78, 0x53, 0x65, 0x65, 0xa1, 0x75, 0xc5, 0x89, 0xae, 0xde,
0x09, 0xf8, 0x7b, 0xfc, 0x13, 0xfe, 0x3c, 0x49, 0xd2, 0x08, 0x0a, 0xe2, 0xa5, 0xb7, 0x7d, 0x8f, 0x8e, 0xeb, 0x61, 0x8d, 0x4d, 0xb3, 0xe9, 0xcc, 0x49, 0x60, 0x9f, 0xc5, 0x17, 0xf1, 0x55, 0x7c,
0xf7, 0xbe, 0xe5, 0x31, 0x70, 0x2d, 0xc8, 0xd2, 0x5b, 0x13, 0xa8, 0x95, 0x56, 0xdf, 0x54, 0x14, 0x1b, 0x99, 0x99, 0xa6, 0x50, 0x41, 0xba, 0x17, 0xde, 0xcd, 0x7f, 0x38, 0xff, 0x37, 0xff, 0x3f,
0x4a, 0x33, 0x58, 0xbe, 0xa9, 0x7a, 0xbb, 0xfe, 0x50, 0xb0, 0x2a, 0x70, 0x4f, 0xe5, 0xab, 0x43, 0x24, 0xf0, 0x80, 0x50, 0x53, 0x97, 0xa7, 0x8d, 0xda, 0xd2, 0x96, 0x1f, 0x6d, 0x54, 0xb3, 0x4e,
0x0e, 0x6d, 0xc3, 0xb8, 0xb3, 0xfa, 0x01, 0x2e, 0x08, 0xb9, 0xab, 0x85, 0x13, 0x95, 0x45, 0xf9, 0xcd, 0xa8, 0xac, 0x37, 0x5d, 0x3e, 0xfb, 0x39, 0x82, 0xa0, 0x40, 0xa9, 0xd6, 0xdf, 0x05, 0xea,
0xd5, 0x76, 0x63, 0x7e, 0xd6, 0xcc, 0xef, 0x8a, 0x71, 0x63, 0xde, 0xcd, 0xbd, 0xf4, 0x09, 0xe2, 0x66, 0x5b, 0x6b, 0x5c, 0xe5, 0xfc, 0x0c, 0x0e, 0x14, 0xea, 0xb6, 0x22, 0x1d, 0xb2, 0xd8, 0x4b,
0xc9, 0xd2, 0x2b, 0x88, 0x3a, 0xaa, 0x13, 0x95, 0xa9, 0x7c, 0xe1, 0x86, 0xa7, 0xbe, 0x85, 0x73, 0xa6, 0xd9, 0x69, 0x7a, 0xd7, 0x96, 0xfe, 0x6d, 0x49, 0x85, 0xdd, 0x17, 0xbd, 0x8f, 0xbf, 0x02,
0xf1, 0x52, 0x63, 0x72, 0x36, 0x7a, 0x93, 0xd0, 0x29, 0x5c, 0x72, 0xe3, 0x43, 0x40, 0xe1, 0x24, 0x5f, 0x93, 0x24, 0x0c, 0x87, 0x31, 0x4b, 0x8e, 0xb2, 0xc7, 0xf7, 0x02, 0x0a, 0xb3, 0x2d, 0x9c,
0xca, 0xa2, 0x7c, 0xe1, 0xbe, 0xf5, 0x7a, 0x03, 0xcb, 0xf9, 0xc7, 0x43, 0x87, 0x2c, 0x3b, 0x3b, 0x29, 0xfa, 0x3d, 0x84, 0xb1, 0x23, 0xf2, 0x00, 0xbc, 0x56, 0x55, 0x21, 0x8b, 0x59, 0x32, 0x11,
0x40, 0x0e, 0x1d, 0xd2, 0xfb, 0x11, 0x3c, 0x89, 0xed, 0xa7, 0x9a, 0x93, 0x05, 0x52, 0xef, 0xcb, 0xe6, 0xc8, 0x4f, 0xc0, 0xa7, 0x92, 0x2a, 0x87, 0x9e, 0x08, 0x27, 0x78, 0x04, 0x87, 0xba, 0x2e,
0x61, 0xcd, 0x23, 0xc4, 0x93, 0xa5, 0xef, 0xfe, 0x9a, 0x71, 0x84, 0xa6, 0xd9, 0x7f, 0x3b, 0xf5, 0x9b, 0x06, 0x49, 0x87, 0x5e, 0xec, 0x25, 0x13, 0x71, 0xab, 0xf9, 0x07, 0x38, 0xbc, 0x42, 0x92,
0x33, 0x2c, 0x0b, 0x21, 0xdc, 0xbf, 0xf9, 0xa6, 0x3a, 0x19, 0x35, 0x57, 0xf7, 0xea, 0x25, 0x1e, 0xdf, 0x24, 0xc9, 0x70, 0x64, 0x0b, 0x3d, 0xdf, 0xb3, 0x50, 0xfa, 0xee, 0xc6, 0x37, 0xaf, 0x49,
0x0f, 0x64, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd4, 0xe6, 0xa0, 0xf9, 0xb0, 0x01, 0x00, 0x00, 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,
} }

View File

@ -7,8 +7,22 @@ message SearchResponseV3 {
string url = 1; string url = 1;
string title = 2; string title = 2;
repeated string snippets = 3; repeated string snippets = 3;
message Value {
oneof val {
string str = 1;
int64 int = 2;
double real = 3;
}
}
map<string, Value> metadata = 4;
}
enum State {
UNKNOWN = 0;
FRESH = 1;
STALE = 2;
} }
repeated Result results = 1; repeated Result results = 1;
State state = 2;
} }
message SearchRequestV3 { message SearchRequestV3 {

View File

@ -45,7 +45,8 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"reflect" "reflect"
"strings" "sort"
"sync"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
@ -57,8 +58,10 @@ import (
type serverReflectionServer struct { type serverReflectionServer struct {
s *grpc.Server 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. // Register registers the server reflection service on the given gRPC server.
@ -76,6 +79,112 @@ type protoMessage interface {
Descriptor() ([]byte, []int) 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. // fileDescForType gets the file descriptor for the given type.
// The given type should be a proto message. // The given type should be a proto message.
func (s *serverReflectionServer) fileDescForType(st reflect.Type) (*dpb.FileDescriptorProto, error) { 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() enc, _ := m.Descriptor()
return s.decodeFileDesc(enc) return decodeFileDesc(enc)
} }
// decodeFileDesc does decompression and unmarshalling on the given // decodeFileDesc does decompression and unmarshalling on the given
// file descriptor byte slice. // file descriptor byte slice.
func (s *serverReflectionServer) decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) { func decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) {
raw, err := decompress(enc) raw, err := decompress(enc)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to decompress enc: %v", err) return nil, fmt.Errorf("failed to decompress enc: %v", err)
@ -116,7 +225,7 @@ func decompress(b []byte) ([]byte, error) {
return out, nil return out, nil
} }
func (s *serverReflectionServer) typeForName(name string) (reflect.Type, error) { func typeForName(name string) (reflect.Type, error) {
pt := proto.MessageType(name) pt := proto.MessageType(name)
if pt == nil { if pt == nil {
return nil, fmt.Errorf("unknown type: %q", name) return nil, fmt.Errorf("unknown type: %q", name)
@ -126,7 +235,7 @@ func (s *serverReflectionServer) typeForName(name string) (reflect.Type, error)
return st, nil 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) m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message)
if !ok { if !ok {
return nil, fmt.Errorf("failed to create message from type: %v", st) 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 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) { func (s *serverReflectionServer) allExtensionNumbersForType(st reflect.Type) ([]int32, error) {
@ -168,53 +277,13 @@ func (s *serverReflectionServer) fileDescEncodingByFilename(name string) ([]byte
if enc == nil { if enc == nil {
return nil, fmt.Errorf("unknown file: %v", name) return nil, fmt.Errorf("unknown file: %v", name)
} }
fd, err := s.decodeFileDesc(enc) fd, err := decodeFileDesc(enc)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return proto.Marshal(fd) 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. // parseMetadata finds the file descriptor bytes specified meta.
// For SupportPackageIsVersion4, m is the name of the proto file, we // For SupportPackageIsVersion4, m is the name of the proto file, we
// call proto.FileDescriptor to get the byte slice. // 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. // does marshalling on it and returns the marshalled result.
// The given symbol can be a type, a service or a method. // The given symbol can be a type, a service or a method.
func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string) ([]byte, error) { func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string) ([]byte, error) {
var ( _, symbols := s.getSymbols()
fd *dpb.FileDescriptorProto fd := symbols[name]
) if fd == nil {
// Check if it's a type name. // Check if it's a type name that was not present in the
if st, err := s.typeForName(name); err == nil { // transitive dependencies of the registered services.
fd, err = s.fileDescForType(st) if st, err := typeForName(name); err == nil {
if err != nil { fd, err = s.fileDescForType(st)
return nil, err 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 fd == nil {
if err != nil { return nil, fmt.Errorf("unknown symbol: %v", name)
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
}
} }
return proto.Marshal(fd) return proto.Marshal(fd)
@ -272,11 +329,11 @@ func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string) (
// fileDescEncodingContainingExtension finds the file descriptor containing given extension, // fileDescEncodingContainingExtension finds the file descriptor containing given extension,
// does marshalling on it and returns the marshalled result. // does marshalling on it and returns the marshalled result.
func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName string, extNum int32) ([]byte, error) { func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName string, extNum int32) ([]byte, error) {
st, err := s.typeForName(typeName) st, err := typeForName(typeName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fd, err := s.fileDescContainingExtension(st, extNum) fd, err := fileDescContainingExtension(st, extNum)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -285,7 +342,7 @@ func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName st
// allExtensionNumbersForTypeName returns all extension numbers for the given type. // allExtensionNumbersForTypeName returns all extension numbers for the given type.
func (s *serverReflectionServer) allExtensionNumbersForTypeName(name string) ([]int32, error) { func (s *serverReflectionServer) allExtensionNumbersForTypeName(name string) ([]int32, error) {
st, err := s.typeForName(name) st, err := typeForName(name)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -374,14 +431,12 @@ func (s *serverReflectionServer) ServerReflectionInfo(stream rpb.ServerReflectio
} }
} }
case *rpb.ServerReflectionRequest_ListServices: case *rpb.ServerReflectionRequest_ListServices:
if s.serviceInfo == nil { svcNames, _ := s.getSymbols()
s.serviceInfo = s.s.GetServiceInfo() serviceResponses := make([]*rpb.ServiceResponse, len(svcNames))
} for i, n := range svcNames {
serviceResponses := make([]*rpb.ServiceResponse, 0, len(s.serviceInfo)) serviceResponses[i] = &rpb.ServiceResponse{
for n := range s.serviceInfo {
serviceResponses = append(serviceResponses, &rpb.ServiceResponse{
Name: n, Name: n,
}) }
} }
out.MessageResponse = &rpb.ServerReflectionResponse_ListServicesResponse{ out.MessageResponse = &rpb.ServerReflectionResponse_ListServicesResponse{
ListServicesResponse: &rpb.ListServiceResponse{ ListServicesResponse: &rpb.ListServiceResponse{

View File

@ -60,7 +60,7 @@ func loadFileDesc(filename string) (*dpb.FileDescriptorProto, []byte) {
if enc == nil { if enc == nil {
panic(fmt.Sprintf("failed to find fd for file: %v", filename)) panic(fmt.Sprintf("failed to find fd for file: %v", filename))
} }
fd, err := s.decodeFileDesc(enc) fd, err := decodeFileDesc(enc)
if err != nil { if err != nil {
panic(fmt.Sprintf("failed to decode enc: %v", err)) 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{})}, {"grpc.testing.SearchResponse", reflect.TypeOf(pb.SearchResponse{})},
} { } {
r, err := s.typeForName(test.name) r, err := typeForName(test.name)
if err != nil || r != test.want { if err != nil || r != test.want {
t.Errorf("typeForName(%q) = %q, %v, want %q, <nil>", test.name, r, err, test.want) t.Errorf("typeForName(%q) = %q, %v, want %q, <nil>", test.name, r, err, test.want)
} }
@ -112,7 +112,7 @@ func TestTypeForNameNotFound(t *testing.T) {
for _, test := range []string{ for _, test := range []string{
"grpc.testing.not_exiting", "grpc.testing.not_exiting",
} { } {
_, err := s.typeForName(test) _, err := typeForName(test)
if err == nil { if err == nil {
t.Errorf("typeForName(%q) = _, %v, want _, <non-nil>", test, err) t.Errorf("typeForName(%q) = _, %v, want _, <non-nil>", test, err)
} }
@ -131,7 +131,7 @@ func TestFileDescContainingExtension(t *testing.T) {
{reflect.TypeOf(pb.ToBeExtended{}), 23, fdProto2Ext2}, {reflect.TypeOf(pb.ToBeExtended{}), 23, fdProto2Ext2},
{reflect.TypeOf(pb.ToBeExtended{}), 29, 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) { if err != nil || !proto.Equal(fd, test.want) {
t.Errorf("fileDescContainingExtension(%q) = %q, %v, want %q, <nil>", test.st, fd, err, test.want) t.Errorf("fileDescContainingExtension(%q) = %q, %v, want %q, <nil>", 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.Search", fdTestv3Byte},
{"grpc.testingv3.SearchServiceV3.StreamingSearch", fdTestv3Byte}, {"grpc.testingv3.SearchServiceV3.StreamingSearch", fdTestv3Byte},
{"grpc.testingv3.SearchResponseV3", 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{ if err := stream.Send(&rpb.ServerReflectionRequest{
MessageRequest: &rpb.ServerReflectionRequest_FileContainingSymbol{ MessageRequest: &rpb.ServerReflectionRequest_FileContainingSymbol{