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  }