google.golang.org/grpc@v1.62.1/reflection/serverreflection.go (about) 1 /* 2 * 3 * Copyright 2016 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 /* 20 Package reflection implements server reflection service. 21 22 The service implemented is defined in: 23 https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto. 24 25 To register server reflection on a gRPC server: 26 27 import "google.golang.org/grpc/reflection" 28 29 s := grpc.NewServer() 30 pb.RegisterYourOwnServer(s, &server{}) 31 32 // Register reflection service on gRPC server. 33 reflection.Register(s) 34 35 s.Serve(lis) 36 */ 37 package reflection // import "google.golang.org/grpc/reflection" 38 39 import ( 40 "io" 41 "sort" 42 43 "google.golang.org/grpc" 44 "google.golang.org/grpc/codes" 45 "google.golang.org/grpc/status" 46 "google.golang.org/protobuf/proto" 47 "google.golang.org/protobuf/reflect/protodesc" 48 "google.golang.org/protobuf/reflect/protoreflect" 49 "google.golang.org/protobuf/reflect/protoregistry" 50 51 v1reflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1" 52 v1reflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1" 53 v1alphareflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" 54 ) 55 56 // GRPCServer is the interface provided by a gRPC server. It is implemented by 57 // *grpc.Server, but could also be implemented by other concrete types. It acts 58 // as a registry, for accumulating the services exposed by the server. 59 type GRPCServer interface { 60 grpc.ServiceRegistrar 61 ServiceInfoProvider 62 } 63 64 var _ GRPCServer = (*grpc.Server)(nil) 65 66 // Register registers the server reflection service on the given gRPC server. 67 // Both the v1 and v1alpha versions are registered. 68 func Register(s GRPCServer) { 69 svr := NewServerV1(ServerOptions{Services: s}) 70 v1alphareflectiongrpc.RegisterServerReflectionServer(s, asV1Alpha(svr)) 71 v1reflectiongrpc.RegisterServerReflectionServer(s, svr) 72 } 73 74 // RegisterV1 registers only the v1 version of the server reflection service 75 // on the given gRPC server. Many clients may only support v1alpha so most 76 // users should use Register instead, at least until clients have upgraded. 77 func RegisterV1(s GRPCServer) { 78 svr := NewServerV1(ServerOptions{Services: s}) 79 v1reflectiongrpc.RegisterServerReflectionServer(s, svr) 80 } 81 82 // ServiceInfoProvider is an interface used to retrieve metadata about the 83 // services to expose. 84 // 85 // The reflection service is only interested in the service names, but the 86 // signature is this way so that *grpc.Server implements it. So it is okay 87 // for a custom implementation to return zero values for the 88 // grpc.ServiceInfo values in the map. 89 // 90 // # Experimental 91 // 92 // Notice: This type is EXPERIMENTAL and may be changed or removed in a 93 // later release. 94 type ServiceInfoProvider interface { 95 GetServiceInfo() map[string]grpc.ServiceInfo 96 } 97 98 // ExtensionResolver is the interface used to query details about extensions. 99 // This interface is satisfied by protoregistry.GlobalTypes. 100 // 101 // # Experimental 102 // 103 // Notice: This type is EXPERIMENTAL and may be changed or removed in a 104 // later release. 105 type ExtensionResolver interface { 106 protoregistry.ExtensionTypeResolver 107 RangeExtensionsByMessage(message protoreflect.FullName, f func(protoreflect.ExtensionType) bool) 108 } 109 110 // ServerOptions represents the options used to construct a reflection server. 111 // 112 // # Experimental 113 // 114 // Notice: This type is EXPERIMENTAL and may be changed or removed in a 115 // later release. 116 type ServerOptions struct { 117 // The source of advertised RPC services. If not specified, the reflection 118 // server will report an empty list when asked to list services. 119 // 120 // This value will typically be a *grpc.Server. But the set of advertised 121 // services can be customized by wrapping a *grpc.Server or using an 122 // alternate implementation that returns a custom set of service names. 123 Services ServiceInfoProvider 124 // Optional resolver used to load descriptors. If not specified, 125 // protoregistry.GlobalFiles will be used. 126 DescriptorResolver protodesc.Resolver 127 // Optional resolver used to query for known extensions. If not specified, 128 // protoregistry.GlobalTypes will be used. 129 ExtensionResolver ExtensionResolver 130 } 131 132 // NewServer returns a reflection server implementation using the given options. 133 // This can be used to customize behavior of the reflection service. Most usages 134 // should prefer to use Register instead. For backwards compatibility reasons, 135 // this returns the v1alpha version of the reflection server. For a v1 version 136 // of the reflection server, see NewServerV1. 137 // 138 // # Experimental 139 // 140 // Notice: This function is EXPERIMENTAL and may be changed or removed in a 141 // later release. 142 func NewServer(opts ServerOptions) v1alphareflectiongrpc.ServerReflectionServer { 143 return asV1Alpha(NewServerV1(opts)) 144 } 145 146 // NewServerV1 returns a reflection server implementation using the given options. 147 // This can be used to customize behavior of the reflection service. Most usages 148 // should prefer to use Register instead. 149 // 150 // # Experimental 151 // 152 // Notice: This function is EXPERIMENTAL and may be changed or removed in a 153 // later release. 154 func NewServerV1(opts ServerOptions) v1reflectiongrpc.ServerReflectionServer { 155 if opts.DescriptorResolver == nil { 156 opts.DescriptorResolver = protoregistry.GlobalFiles 157 } 158 if opts.ExtensionResolver == nil { 159 opts.ExtensionResolver = protoregistry.GlobalTypes 160 } 161 return &serverReflectionServer{ 162 s: opts.Services, 163 descResolver: opts.DescriptorResolver, 164 extResolver: opts.ExtensionResolver, 165 } 166 } 167 168 type serverReflectionServer struct { 169 v1alphareflectiongrpc.UnimplementedServerReflectionServer 170 s ServiceInfoProvider 171 descResolver protodesc.Resolver 172 extResolver ExtensionResolver 173 } 174 175 // fileDescWithDependencies returns a slice of serialized fileDescriptors in 176 // wire format ([]byte). The fileDescriptors will include fd and all the 177 // transitive dependencies of fd with names not in sentFileDescriptors. 178 func (s *serverReflectionServer) fileDescWithDependencies(fd protoreflect.FileDescriptor, sentFileDescriptors map[string]bool) ([][]byte, error) { 179 if fd.IsPlaceholder() { 180 // If the given root file is a placeholder, treat it 181 // as missing instead of serializing it. 182 return nil, protoregistry.NotFound 183 } 184 var r [][]byte 185 queue := []protoreflect.FileDescriptor{fd} 186 for len(queue) > 0 { 187 currentfd := queue[0] 188 queue = queue[1:] 189 if currentfd.IsPlaceholder() { 190 // Skip any missing files in the dependency graph. 191 continue 192 } 193 if sent := sentFileDescriptors[currentfd.Path()]; len(r) == 0 || !sent { 194 sentFileDescriptors[currentfd.Path()] = true 195 fdProto := protodesc.ToFileDescriptorProto(currentfd) 196 currentfdEncoded, err := proto.Marshal(fdProto) 197 if err != nil { 198 return nil, err 199 } 200 r = append(r, currentfdEncoded) 201 } 202 for i := 0; i < currentfd.Imports().Len(); i++ { 203 queue = append(queue, currentfd.Imports().Get(i)) 204 } 205 } 206 return r, nil 207 } 208 209 // fileDescEncodingContainingSymbol finds the file descriptor containing the 210 // given symbol, finds all of its previously unsent transitive dependencies, 211 // does marshalling on them, and returns the marshalled result. The given symbol 212 // can be a type, a service or a method. 213 func (s *serverReflectionServer) fileDescEncodingContainingSymbol(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { 214 d, err := s.descResolver.FindDescriptorByName(protoreflect.FullName(name)) 215 if err != nil { 216 return nil, err 217 } 218 return s.fileDescWithDependencies(d.ParentFile(), sentFileDescriptors) 219 } 220 221 // fileDescEncodingContainingExtension finds the file descriptor containing 222 // given extension, finds all of its previously unsent transitive dependencies, 223 // does marshalling on them, and returns the marshalled result. 224 func (s *serverReflectionServer) fileDescEncodingContainingExtension(typeName string, extNum int32, sentFileDescriptors map[string]bool) ([][]byte, error) { 225 xt, err := s.extResolver.FindExtensionByNumber(protoreflect.FullName(typeName), protoreflect.FieldNumber(extNum)) 226 if err != nil { 227 return nil, err 228 } 229 return s.fileDescWithDependencies(xt.TypeDescriptor().ParentFile(), sentFileDescriptors) 230 } 231 232 // allExtensionNumbersForTypeName returns all extension numbers for the given type. 233 func (s *serverReflectionServer) allExtensionNumbersForTypeName(name string) ([]int32, error) { 234 var numbers []int32 235 s.extResolver.RangeExtensionsByMessage(protoreflect.FullName(name), func(xt protoreflect.ExtensionType) bool { 236 numbers = append(numbers, int32(xt.TypeDescriptor().Number())) 237 return true 238 }) 239 sort.Slice(numbers, func(i, j int) bool { 240 return numbers[i] < numbers[j] 241 }) 242 if len(numbers) == 0 { 243 // maybe return an error if given type name is not known 244 if _, err := s.descResolver.FindDescriptorByName(protoreflect.FullName(name)); err != nil { 245 return nil, err 246 } 247 } 248 return numbers, nil 249 } 250 251 // listServices returns the names of services this server exposes. 252 func (s *serverReflectionServer) listServices() []*v1reflectionpb.ServiceResponse { 253 serviceInfo := s.s.GetServiceInfo() 254 resp := make([]*v1reflectionpb.ServiceResponse, 0, len(serviceInfo)) 255 for svc := range serviceInfo { 256 resp = append(resp, &v1reflectionpb.ServiceResponse{Name: svc}) 257 } 258 sort.Slice(resp, func(i, j int) bool { 259 return resp[i].Name < resp[j].Name 260 }) 261 return resp 262 } 263 264 // ServerReflectionInfo is the reflection service handler. 265 func (s *serverReflectionServer) ServerReflectionInfo(stream v1reflectiongrpc.ServerReflection_ServerReflectionInfoServer) error { 266 sentFileDescriptors := make(map[string]bool) 267 for { 268 in, err := stream.Recv() 269 if err == io.EOF { 270 return nil 271 } 272 if err != nil { 273 return err 274 } 275 276 out := &v1reflectionpb.ServerReflectionResponse{ 277 ValidHost: in.Host, 278 OriginalRequest: in, 279 } 280 switch req := in.MessageRequest.(type) { 281 case *v1reflectionpb.ServerReflectionRequest_FileByFilename: 282 var b [][]byte 283 fd, err := s.descResolver.FindFileByPath(req.FileByFilename) 284 if err == nil { 285 b, err = s.fileDescWithDependencies(fd, sentFileDescriptors) 286 } 287 if err != nil { 288 out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{ 289 ErrorResponse: &v1reflectionpb.ErrorResponse{ 290 ErrorCode: int32(codes.NotFound), 291 ErrorMessage: err.Error(), 292 }, 293 } 294 } else { 295 out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{ 296 FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b}, 297 } 298 } 299 case *v1reflectionpb.ServerReflectionRequest_FileContainingSymbol: 300 b, err := s.fileDescEncodingContainingSymbol(req.FileContainingSymbol, sentFileDescriptors) 301 if err != nil { 302 out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{ 303 ErrorResponse: &v1reflectionpb.ErrorResponse{ 304 ErrorCode: int32(codes.NotFound), 305 ErrorMessage: err.Error(), 306 }, 307 } 308 } else { 309 out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{ 310 FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b}, 311 } 312 } 313 case *v1reflectionpb.ServerReflectionRequest_FileContainingExtension: 314 typeName := req.FileContainingExtension.ContainingType 315 extNum := req.FileContainingExtension.ExtensionNumber 316 b, err := s.fileDescEncodingContainingExtension(typeName, extNum, sentFileDescriptors) 317 if err != nil { 318 out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{ 319 ErrorResponse: &v1reflectionpb.ErrorResponse{ 320 ErrorCode: int32(codes.NotFound), 321 ErrorMessage: err.Error(), 322 }, 323 } 324 } else { 325 out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{ 326 FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b}, 327 } 328 } 329 case *v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType: 330 extNums, err := s.allExtensionNumbersForTypeName(req.AllExtensionNumbersOfType) 331 if err != nil { 332 out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{ 333 ErrorResponse: &v1reflectionpb.ErrorResponse{ 334 ErrorCode: int32(codes.NotFound), 335 ErrorMessage: err.Error(), 336 }, 337 } 338 } else { 339 out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{ 340 AllExtensionNumbersResponse: &v1reflectionpb.ExtensionNumberResponse{ 341 BaseTypeName: req.AllExtensionNumbersOfType, 342 ExtensionNumber: extNums, 343 }, 344 } 345 } 346 case *v1reflectionpb.ServerReflectionRequest_ListServices: 347 out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ListServicesResponse{ 348 ListServicesResponse: &v1reflectionpb.ListServiceResponse{ 349 Service: s.listServices(), 350 }, 351 } 352 default: 353 return status.Errorf(codes.InvalidArgument, "invalid MessageRequest: %v", in.MessageRequest) 354 } 355 356 if err := stream.Send(out); err != nil { 357 return err 358 } 359 } 360 }