dubbo.apache.org/dubbo-go/v3@v3.1.1/protocol/dubbo3/reflection/serverreflection.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. 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 Package reflection implements server reflection service. 20 21 The service implemented is defined in: 22 https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto. 23 */ 24 package reflection 25 26 import ( 27 "bytes" 28 "compress/gzip" 29 "fmt" 30 "io" 31 "reflect" 32 "sort" 33 "strings" 34 "sync" 35 36 "github.com/dubbogo/grpc-go" 37 "github.com/dubbogo/grpc-go/codes" 38 "github.com/dubbogo/grpc-go/status" 39 "github.com/golang/protobuf/proto" 40 41 "dubbo.apache.org/dubbo-go/v3/config" 42 dpb "github.com/golang/protobuf/protoc-gen-go/descriptor" 43 44 rpb "dubbo.apache.org/dubbo-go/v3/protocol/dubbo3/reflection/triple_reflection_v1alpha" 45 ) 46 47 // GRPCServer is the interface provided by a gRPC server. It is implemented by 48 // *grpc.Server, but could also be implemented by other concrete types. It acts 49 // as a registry, for accumulating the services exposed by the server. 50 type GRPCServer interface { 51 grpc.ServiceRegistrar 52 GetServiceInfo() map[string]grpc.ServiceInfo 53 } 54 55 var _ GRPCServer = (*grpc.Server)(nil) 56 57 type DubbogoServerReflectionServer struct { 58 rpb.UnimplementedServerReflectionServer 59 s GRPCServer 60 61 initSymbols sync.Once 62 serviceNames []string 63 symbols map[string]*dpb.FileDescriptorProto // map of fully-qualified names to files 64 } 65 66 func (r *DubbogoServerReflectionServer) SetGRPCServer(s *grpc.Server) { 67 r.s = s 68 } 69 70 // protoMessage is used for type assertion on proto messages. 71 // Generated proto message implements function Descriptor(), but Descriptor() 72 // is not part of interface proto.Message. This interface is needed to 73 // call Descriptor(). 74 type protoMessage interface { 75 Descriptor() ([]byte, []int) 76 } 77 78 func (s *DubbogoServerReflectionServer) getSymbols() (svcNames []string, symbolIndex map[string]*dpb.FileDescriptorProto) { 79 s.initSymbols.Do(func() { 80 serviceInfo := s.s.GetServiceInfo() 81 82 s.symbols = map[string]*dpb.FileDescriptorProto{} 83 s.serviceNames = make([]string, 0, len(serviceInfo)) 84 processed := map[string]struct{}{} 85 for svc, info := range serviceInfo { 86 s.serviceNames = append(s.serviceNames, svc) 87 fdenc, ok := parseMetadata(info.Metadata) 88 if !ok { 89 continue 90 } 91 fd, err := decodeFileDesc(fdenc) 92 if err != nil { 93 continue 94 } 95 s.processFile(fd, processed) 96 } 97 sort.Strings(s.serviceNames) 98 }) 99 100 return s.serviceNames, s.symbols 101 } 102 103 func (s *DubbogoServerReflectionServer) processFile(fd *dpb.FileDescriptorProto, processed map[string]struct{}) { 104 filename := fd.GetName() 105 if _, ok := processed[filename]; ok { 106 return 107 } 108 processed[filename] = struct{}{} 109 110 prefix := fd.GetPackage() 111 112 for _, msg := range fd.MessageType { 113 s.processMessage(fd, prefix, msg) 114 } 115 for _, en := range fd.EnumType { 116 s.processEnum(fd, prefix, en) 117 } 118 for _, ext := range fd.Extension { 119 s.processField(fd, prefix, ext) 120 } 121 for _, svc := range fd.Service { 122 svcName := fqn(prefix, svc.GetName()) 123 s.symbols[svcName] = fd 124 for _, meth := range svc.Method { 125 name := fqn(svcName, meth.GetName()) 126 s.symbols[name] = fd 127 } 128 } 129 130 for _, dep := range fd.Dependency { 131 fdenc := proto.FileDescriptor(dep) 132 fdDep, err := decodeFileDesc(fdenc) 133 if err != nil { 134 continue 135 } 136 s.processFile(fdDep, processed) 137 } 138 } 139 140 func (s *DubbogoServerReflectionServer) processMessage(fd *dpb.FileDescriptorProto, prefix string, msg *dpb.DescriptorProto) { 141 msgName := fqn(prefix, msg.GetName()) 142 s.symbols[msgName] = fd 143 144 for _, nested := range msg.NestedType { 145 s.processMessage(fd, msgName, nested) 146 } 147 for _, en := range msg.EnumType { 148 s.processEnum(fd, msgName, en) 149 } 150 for _, ext := range msg.Extension { 151 s.processField(fd, msgName, ext) 152 } 153 for _, fld := range msg.Field { 154 s.processField(fd, msgName, fld) 155 } 156 for _, oneof := range msg.OneofDecl { 157 oneofName := fqn(msgName, oneof.GetName()) 158 s.symbols[oneofName] = fd 159 } 160 } 161 162 func (s *DubbogoServerReflectionServer) processEnum(fd *dpb.FileDescriptorProto, prefix string, en *dpb.EnumDescriptorProto) { 163 enName := fqn(prefix, en.GetName()) 164 s.symbols[enName] = fd 165 166 for _, val := range en.Value { 167 valName := fqn(enName, val.GetName()) 168 s.symbols[valName] = fd 169 } 170 } 171 172 func (s *DubbogoServerReflectionServer) processField(fd *dpb.FileDescriptorProto, prefix string, fld *dpb.FieldDescriptorProto) { 173 fldName := fqn(prefix, fld.GetName()) 174 s.symbols[fldName] = fd 175 } 176 177 func fqn(prefix, name string) string { 178 if prefix == "" { 179 return name 180 } 181 return prefix + "." + name 182 } 183 184 // fileDescForType gets the file descriptor for the given type. 185 // The given type should be a proto message. 186 func (s *DubbogoServerReflectionServer) fileDescForType(st reflect.Type) (*dpb.FileDescriptorProto, error) { 187 m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(protoMessage) 188 if !ok { 189 return nil, fmt.Errorf("failed to create message from type: %v", st) 190 } 191 enc, _ := m.Descriptor() 192 193 return decodeFileDesc(enc) 194 } 195 196 // decodeFileDesc does decompression and unmarshaling on the given 197 // file descriptor byte slice. 198 func decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) { 199 raw, err := decompress(enc) 200 if err != nil { 201 return nil, fmt.Errorf("failed to decompress enc: %v", err) 202 } 203 204 fd := new(dpb.FileDescriptorProto) 205 if err := proto.Unmarshal(raw, fd); err != nil { 206 return nil, fmt.Errorf("bad descriptor: %v", err) 207 } 208 return fd, nil 209 } 210 211 // decompress does gzip decompression. 212 func decompress(b []byte) ([]byte, error) { 213 r, err := gzip.NewReader(bytes.NewReader(b)) 214 if err != nil { 215 return nil, fmt.Errorf("bad gzipped descriptor: %v", err) 216 } 217 out, err := io.ReadAll(r) 218 if err != nil { 219 return nil, fmt.Errorf("bad gzipped descriptor: %v", err) 220 } 221 return out, nil 222 } 223 224 func typeForName(name string) (reflect.Type, error) { 225 pt := proto.MessageType(name) 226 if pt == nil { 227 return nil, fmt.Errorf("unknown type: %q", name) 228 } 229 st := pt.Elem() 230 231 return st, nil 232 } 233 234 func fileDescContainingExtension(st reflect.Type, ext int32) (*dpb.FileDescriptorProto, error) { 235 m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message) 236 if !ok { 237 return nil, fmt.Errorf("failed to create message from type: %v", st) 238 } 239 240 var extDesc *proto.ExtensionDesc 241 for id, desc := range proto.RegisteredExtensions(m) { 242 if id == ext { 243 extDesc = desc 244 break 245 } 246 } 247 248 if extDesc == nil { 249 return nil, fmt.Errorf("failed to find registered extension for extension number %v", ext) 250 } 251 252 return decodeFileDesc(proto.FileDescriptor(extDesc.Filename)) 253 } 254 255 func (s *DubbogoServerReflectionServer) allExtensionNumbersForType(st reflect.Type) ([]int32, error) { 256 m, ok := reflect.Zero(reflect.PtrTo(st)).Interface().(proto.Message) 257 if !ok { 258 return nil, fmt.Errorf("failed to create message from type: %v", st) 259 } 260 261 exts := proto.RegisteredExtensions(m) 262 out := make([]int32, 0, len(exts)) 263 for id := range exts { 264 out = append(out, id) 265 } 266 return out, nil 267 } 268 269 // fileDescWithDependencies returns a slice of serialized fileDescriptors in 270 // wire format ([]byte). The fileDescriptors will include fd and all the 271 // transitive dependencies of fd with names not in sentFileDescriptors. 272 func fileDescWithDependencies(fd *dpb.FileDescriptorProto, sentFileDescriptors map[string]bool) ([][]byte, error) { 273 r := [][]byte{} 274 queue := []*dpb.FileDescriptorProto{fd} 275 for len(queue) > 0 { 276 currentfd := queue[0] 277 queue = queue[1:] 278 if sent := sentFileDescriptors[currentfd.GetName()]; len(r) == 0 || !sent { 279 sentFileDescriptors[currentfd.GetName()] = true 280 currentfdEncoded, err := proto.Marshal(currentfd) 281 if err != nil { 282 return nil, err 283 } 284 r = append(r, currentfdEncoded) 285 } 286 for _, dep := range currentfd.Dependency { 287 fdenc := proto.FileDescriptor(dep) 288 fdDep, err := decodeFileDesc(fdenc) 289 if err != nil { 290 continue 291 } 292 queue = append(queue, fdDep) 293 } 294 } 295 return r, nil 296 } 297 298 // fileDescEncodingByFilename finds the file descriptor for given filename, 299 // finds all of its previously unsent transitive dependencies, does marshaling 300 // on them, and returns the marshaled result. 301 func (s *DubbogoServerReflectionServer) fileDescEncodingByFilename(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { 302 enc := proto.FileDescriptor(name) 303 if enc == nil { 304 return nil, fmt.Errorf("unknown file: %v", name) 305 } 306 fd, err := decodeFileDesc(enc) 307 if err != nil { 308 return nil, err 309 } 310 return fileDescWithDependencies(fd, sentFileDescriptors) 311 } 312 313 // parseMetadata finds the file descriptor bytes specified meta. 314 // For SupportPackageIsVersion4, m is the name of the proto file, we 315 // call proto.FileDescriptor to get the byte slice. 316 // For SupportPackageIsVersion3, m is a byte slice itself. 317 func parseMetadata(meta interface{}) ([]byte, bool) { 318 // Check if meta is the file name. 319 if fileNameForMeta, ok := meta.(string); ok { 320 return proto.FileDescriptor(fileNameForMeta), true 321 } 322 323 // Check if meta is the byte slice. 324 if enc, ok := meta.([]byte); ok { 325 return enc, true 326 } 327 328 return nil, false 329 } 330 331 // fileDescEncodingContainingSymbol finds the file descriptor containing the 332 // given symbol, finds all of its previously unsent transitive dependencies, 333 // does marshaling on them, and returns the marshaled result. The given symbol 334 // can be a type, a service or a method. 335 func (s *DubbogoServerReflectionServer) fileDescEncodingContainingSymbol(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { 336 _, symbols := s.getSymbols() 337 // 338 if strings.HasPrefix(name, "grpc.") { 339 name = "triple." + strings.TrimPrefix(name, "grpc.") 340 } 341 342 fd := symbols[name] 343 if fd == nil { 344 // Check if it's a type name that was not present in the 345 // transitive dependencies of the registered services. 346 if st, err := typeForName(name); err == nil { 347 fd, err = s.fileDescForType(st) 348 if err != nil { 349 return nil, err 350 } 351 } 352 } 353 354 if fd == nil { 355 return nil, fmt.Errorf("unknown symbol: %v", name) 356 } 357 358 return fileDescWithDependencies(fd, sentFileDescriptors) 359 } 360 361 // fileDescEncodingContainingExtension finds the file descriptor containing 362 // given extension, finds all of its previously unsent transitive dependencies, 363 // does marshaling on them, and returns the marshaled result. 364 func (s *DubbogoServerReflectionServer) fileDescEncodingContainingExtension(typeName string, extNum int32, sentFileDescriptors map[string]bool) ([][]byte, error) { 365 st, err := typeForName(typeName) 366 if err != nil { 367 return nil, err 368 } 369 fd, err := fileDescContainingExtension(st, extNum) 370 if err != nil { 371 return nil, err 372 } 373 return fileDescWithDependencies(fd, sentFileDescriptors) 374 } 375 376 // allExtensionNumbersForTypeName returns all extension numbers for the given type. 377 func (s *DubbogoServerReflectionServer) allExtensionNumbersForTypeName(name string) ([]int32, error) { 378 st, err := typeForName(name) 379 if err != nil { 380 return nil, err 381 } 382 extNums, err := s.allExtensionNumbersForType(st) 383 if err != nil { 384 return nil, err 385 } 386 return extNums, nil 387 } 388 389 // ServerReflectionInfo is the reflection service handler. 390 func (s *DubbogoServerReflectionServer) ServerReflectionInfo(stream rpb.ServerReflection_ServerReflectionInfoServer) error { 391 sentFileDescriptors := make(map[string]bool) 392 for { 393 in, err := stream.Recv() 394 if err == io.EOF { 395 return nil 396 } 397 if err != nil { 398 return err 399 } 400 401 out := &rpb.ServerReflectionResponse{ 402 ValidHost: in.Host, 403 OriginalRequest: in, 404 } 405 switch req := in.MessageRequest.(type) { 406 case *rpb.ServerReflectionRequest_FileByFilename: 407 b, err := s.fileDescEncodingByFilename(req.FileByFilename, sentFileDescriptors) 408 if err != nil { 409 out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ 410 ErrorResponse: &rpb.ErrorResponse{ 411 ErrorCode: int32(codes.NotFound), 412 ErrorMessage: err.Error(), 413 }, 414 } 415 } else { 416 out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ 417 FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, 418 } 419 } 420 case *rpb.ServerReflectionRequest_FileContainingSymbol: 421 b, err := s.fileDescEncodingContainingSymbol(req.FileContainingSymbol, sentFileDescriptors) 422 if err != nil { 423 out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ 424 ErrorResponse: &rpb.ErrorResponse{ 425 ErrorCode: int32(codes.NotFound), 426 ErrorMessage: err.Error(), 427 }, 428 } 429 } else { 430 out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ 431 FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, 432 } 433 } 434 case *rpb.ServerReflectionRequest_FileContainingExtension: 435 typeName := req.FileContainingExtension.ContainingType 436 extNum := req.FileContainingExtension.ExtensionNumber 437 b, err := s.fileDescEncodingContainingExtension(typeName, extNum, sentFileDescriptors) 438 if err != nil { 439 out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ 440 ErrorResponse: &rpb.ErrorResponse{ 441 ErrorCode: int32(codes.NotFound), 442 ErrorMessage: err.Error(), 443 }, 444 } 445 } else { 446 out.MessageResponse = &rpb.ServerReflectionResponse_FileDescriptorResponse{ 447 FileDescriptorResponse: &rpb.FileDescriptorResponse{FileDescriptorProto: b}, 448 } 449 } 450 case *rpb.ServerReflectionRequest_AllExtensionNumbersOfType: 451 extNums, err := s.allExtensionNumbersForTypeName(req.AllExtensionNumbersOfType) 452 if err != nil { 453 out.MessageResponse = &rpb.ServerReflectionResponse_ErrorResponse{ 454 ErrorResponse: &rpb.ErrorResponse{ 455 ErrorCode: int32(codes.NotFound), 456 ErrorMessage: err.Error(), 457 }, 458 } 459 } else { 460 out.MessageResponse = &rpb.ServerReflectionResponse_AllExtensionNumbersResponse{ 461 AllExtensionNumbersResponse: &rpb.ExtensionNumberResponse{ 462 BaseTypeName: req.AllExtensionNumbersOfType, 463 ExtensionNumber: extNums, 464 }, 465 } 466 } 467 case *rpb.ServerReflectionRequest_ListServices: 468 svcNames, _ := s.getSymbols() 469 serviceResponses := make([]*rpb.ServiceResponse, len(svcNames)) 470 for i, n := range svcNames { 471 serviceResponses[i] = &rpb.ServiceResponse{ 472 Name: n, 473 } 474 } 475 out.MessageResponse = &rpb.ServerReflectionResponse_ListServicesResponse{ 476 ListServicesResponse: &rpb.ListServiceResponse{ 477 Service: serviceResponses, 478 }, 479 } 480 default: 481 return status.Errorf(codes.InvalidArgument, "invalid MessageRequest: %v", in.MessageRequest) 482 } 483 484 if err := stream.Send(out); err != nil { 485 return err 486 } 487 } 488 } 489 func init() { 490 config.SetProviderService(&DubbogoServerReflectionServer{}) 491 }