| Abhay Kumar | a2ae599 | 2025-11-10 14:02:24 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * |
| 3 | * Copyright 2024 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 | // Package internal contains code that is shared by both reflection package and |
| 20 | // the test package. The packages are split in this way inorder to avoid |
| 21 | // dependency to deprecated package github.com/golang/protobuf. |
| 22 | package internal |
| 23 | |
| 24 | import ( |
| 25 | "io" |
| 26 | "sort" |
| 27 | |
| 28 | "google.golang.org/grpc" |
| 29 | "google.golang.org/grpc/codes" |
| 30 | "google.golang.org/grpc/status" |
| 31 | "google.golang.org/protobuf/proto" |
| 32 | "google.golang.org/protobuf/reflect/protodesc" |
| 33 | "google.golang.org/protobuf/reflect/protoreflect" |
| 34 | "google.golang.org/protobuf/reflect/protoregistry" |
| 35 | |
| 36 | v1reflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1" |
| 37 | v1reflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1" |
| 38 | v1alphareflectiongrpc "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" |
| 39 | v1alphareflectionpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" |
| 40 | ) |
| 41 | |
| 42 | // ServiceInfoProvider is an interface used to retrieve metadata about the |
| 43 | // services to expose. |
| 44 | type ServiceInfoProvider interface { |
| 45 | GetServiceInfo() map[string]grpc.ServiceInfo |
| 46 | } |
| 47 | |
| 48 | // ExtensionResolver is the interface used to query details about extensions. |
| 49 | // This interface is satisfied by protoregistry.GlobalTypes. |
| 50 | type ExtensionResolver interface { |
| 51 | protoregistry.ExtensionTypeResolver |
| 52 | RangeExtensionsByMessage(message protoreflect.FullName, f func(protoreflect.ExtensionType) bool) |
| 53 | } |
| 54 | |
| 55 | // ServerReflectionServer is the server API for ServerReflection service. |
| 56 | type ServerReflectionServer struct { |
| 57 | v1alphareflectiongrpc.UnimplementedServerReflectionServer |
| 58 | S ServiceInfoProvider |
| 59 | DescResolver protodesc.Resolver |
| 60 | ExtResolver ExtensionResolver |
| 61 | } |
| 62 | |
| 63 | // FileDescWithDependencies returns a slice of serialized fileDescriptors in |
| 64 | // wire format ([]byte). The fileDescriptors will include fd and all the |
| 65 | // transitive dependencies of fd with names not in sentFileDescriptors. |
| 66 | func (s *ServerReflectionServer) FileDescWithDependencies(fd protoreflect.FileDescriptor, sentFileDescriptors map[string]bool) ([][]byte, error) { |
| 67 | if fd.IsPlaceholder() { |
| 68 | // If the given root file is a placeholder, treat it |
| 69 | // as missing instead of serializing it. |
| 70 | return nil, protoregistry.NotFound |
| 71 | } |
| 72 | var r [][]byte |
| 73 | queue := []protoreflect.FileDescriptor{fd} |
| 74 | for len(queue) > 0 { |
| 75 | currentfd := queue[0] |
| 76 | queue = queue[1:] |
| 77 | if currentfd.IsPlaceholder() { |
| 78 | // Skip any missing files in the dependency graph. |
| 79 | continue |
| 80 | } |
| 81 | if sent := sentFileDescriptors[currentfd.Path()]; len(r) == 0 || !sent { |
| 82 | sentFileDescriptors[currentfd.Path()] = true |
| 83 | fdProto := protodesc.ToFileDescriptorProto(currentfd) |
| 84 | currentfdEncoded, err := proto.Marshal(fdProto) |
| 85 | if err != nil { |
| 86 | return nil, err |
| 87 | } |
| 88 | r = append(r, currentfdEncoded) |
| 89 | } |
| 90 | for i := 0; i < currentfd.Imports().Len(); i++ { |
| 91 | queue = append(queue, currentfd.Imports().Get(i)) |
| 92 | } |
| 93 | } |
| 94 | return r, nil |
| 95 | } |
| 96 | |
| 97 | // FileDescEncodingContainingSymbol finds the file descriptor containing the |
| 98 | // given symbol, finds all of its previously unsent transitive dependencies, |
| 99 | // does marshalling on them, and returns the marshalled result. The given symbol |
| 100 | // can be a type, a service or a method. |
| 101 | func (s *ServerReflectionServer) FileDescEncodingContainingSymbol(name string, sentFileDescriptors map[string]bool) ([][]byte, error) { |
| 102 | d, err := s.DescResolver.FindDescriptorByName(protoreflect.FullName(name)) |
| 103 | if err != nil { |
| 104 | return nil, err |
| 105 | } |
| 106 | return s.FileDescWithDependencies(d.ParentFile(), sentFileDescriptors) |
| 107 | } |
| 108 | |
| 109 | // FileDescEncodingContainingExtension finds the file descriptor containing |
| 110 | // given extension, finds all of its previously unsent transitive dependencies, |
| 111 | // does marshalling on them, and returns the marshalled result. |
| 112 | func (s *ServerReflectionServer) FileDescEncodingContainingExtension(typeName string, extNum int32, sentFileDescriptors map[string]bool) ([][]byte, error) { |
| 113 | xt, err := s.ExtResolver.FindExtensionByNumber(protoreflect.FullName(typeName), protoreflect.FieldNumber(extNum)) |
| 114 | if err != nil { |
| 115 | return nil, err |
| 116 | } |
| 117 | return s.FileDescWithDependencies(xt.TypeDescriptor().ParentFile(), sentFileDescriptors) |
| 118 | } |
| 119 | |
| 120 | // AllExtensionNumbersForTypeName returns all extension numbers for the given type. |
| 121 | func (s *ServerReflectionServer) AllExtensionNumbersForTypeName(name string) ([]int32, error) { |
| 122 | var numbers []int32 |
| 123 | s.ExtResolver.RangeExtensionsByMessage(protoreflect.FullName(name), func(xt protoreflect.ExtensionType) bool { |
| 124 | numbers = append(numbers, int32(xt.TypeDescriptor().Number())) |
| 125 | return true |
| 126 | }) |
| 127 | sort.Slice(numbers, func(i, j int) bool { |
| 128 | return numbers[i] < numbers[j] |
| 129 | }) |
| 130 | if len(numbers) == 0 { |
| 131 | // maybe return an error if given type name is not known |
| 132 | if _, err := s.DescResolver.FindDescriptorByName(protoreflect.FullName(name)); err != nil { |
| 133 | return nil, err |
| 134 | } |
| 135 | } |
| 136 | return numbers, nil |
| 137 | } |
| 138 | |
| 139 | // ListServices returns the names of services this server exposes. |
| 140 | func (s *ServerReflectionServer) ListServices() []*v1reflectionpb.ServiceResponse { |
| 141 | serviceInfo := s.S.GetServiceInfo() |
| 142 | resp := make([]*v1reflectionpb.ServiceResponse, 0, len(serviceInfo)) |
| 143 | for svc := range serviceInfo { |
| 144 | resp = append(resp, &v1reflectionpb.ServiceResponse{Name: svc}) |
| 145 | } |
| 146 | sort.Slice(resp, func(i, j int) bool { |
| 147 | return resp[i].Name < resp[j].Name |
| 148 | }) |
| 149 | return resp |
| 150 | } |
| 151 | |
| 152 | // ServerReflectionInfo is the reflection service handler. |
| 153 | func (s *ServerReflectionServer) ServerReflectionInfo(stream v1reflectiongrpc.ServerReflection_ServerReflectionInfoServer) error { |
| 154 | sentFileDescriptors := make(map[string]bool) |
| 155 | for { |
| 156 | in, err := stream.Recv() |
| 157 | if err == io.EOF { |
| 158 | return nil |
| 159 | } |
| 160 | if err != nil { |
| 161 | return err |
| 162 | } |
| 163 | |
| 164 | out := &v1reflectionpb.ServerReflectionResponse{ |
| 165 | ValidHost: in.Host, |
| 166 | OriginalRequest: in, |
| 167 | } |
| 168 | switch req := in.MessageRequest.(type) { |
| 169 | case *v1reflectionpb.ServerReflectionRequest_FileByFilename: |
| 170 | var b [][]byte |
| 171 | fd, err := s.DescResolver.FindFileByPath(req.FileByFilename) |
| 172 | if err == nil { |
| 173 | b, err = s.FileDescWithDependencies(fd, sentFileDescriptors) |
| 174 | } |
| 175 | if err != nil { |
| 176 | out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{ |
| 177 | ErrorResponse: &v1reflectionpb.ErrorResponse{ |
| 178 | ErrorCode: int32(codes.NotFound), |
| 179 | ErrorMessage: err.Error(), |
| 180 | }, |
| 181 | } |
| 182 | } else { |
| 183 | out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{ |
| 184 | FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b}, |
| 185 | } |
| 186 | } |
| 187 | case *v1reflectionpb.ServerReflectionRequest_FileContainingSymbol: |
| 188 | b, err := s.FileDescEncodingContainingSymbol(req.FileContainingSymbol, sentFileDescriptors) |
| 189 | if err != nil { |
| 190 | out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{ |
| 191 | ErrorResponse: &v1reflectionpb.ErrorResponse{ |
| 192 | ErrorCode: int32(codes.NotFound), |
| 193 | ErrorMessage: err.Error(), |
| 194 | }, |
| 195 | } |
| 196 | } else { |
| 197 | out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{ |
| 198 | FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b}, |
| 199 | } |
| 200 | } |
| 201 | case *v1reflectionpb.ServerReflectionRequest_FileContainingExtension: |
| 202 | typeName := req.FileContainingExtension.ContainingType |
| 203 | extNum := req.FileContainingExtension.ExtensionNumber |
| 204 | b, err := s.FileDescEncodingContainingExtension(typeName, extNum, sentFileDescriptors) |
| 205 | if err != nil { |
| 206 | out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{ |
| 207 | ErrorResponse: &v1reflectionpb.ErrorResponse{ |
| 208 | ErrorCode: int32(codes.NotFound), |
| 209 | ErrorMessage: err.Error(), |
| 210 | }, |
| 211 | } |
| 212 | } else { |
| 213 | out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{ |
| 214 | FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{FileDescriptorProto: b}, |
| 215 | } |
| 216 | } |
| 217 | case *v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType: |
| 218 | extNums, err := s.AllExtensionNumbersForTypeName(req.AllExtensionNumbersOfType) |
| 219 | if err != nil { |
| 220 | out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{ |
| 221 | ErrorResponse: &v1reflectionpb.ErrorResponse{ |
| 222 | ErrorCode: int32(codes.NotFound), |
| 223 | ErrorMessage: err.Error(), |
| 224 | }, |
| 225 | } |
| 226 | } else { |
| 227 | out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{ |
| 228 | AllExtensionNumbersResponse: &v1reflectionpb.ExtensionNumberResponse{ |
| 229 | BaseTypeName: req.AllExtensionNumbersOfType, |
| 230 | ExtensionNumber: extNums, |
| 231 | }, |
| 232 | } |
| 233 | } |
| 234 | case *v1reflectionpb.ServerReflectionRequest_ListServices: |
| 235 | out.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ListServicesResponse{ |
| 236 | ListServicesResponse: &v1reflectionpb.ListServiceResponse{ |
| 237 | Service: s.ListServices(), |
| 238 | }, |
| 239 | } |
| 240 | default: |
| 241 | return status.Errorf(codes.InvalidArgument, "invalid MessageRequest: %v", in.MessageRequest) |
| 242 | } |
| 243 | |
| 244 | if err := stream.Send(out); err != nil { |
| 245 | return err |
| 246 | } |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | // V1ToV1AlphaResponse converts a v1 ServerReflectionResponse to a v1alpha. |
| 251 | func V1ToV1AlphaResponse(v1 *v1reflectionpb.ServerReflectionResponse) *v1alphareflectionpb.ServerReflectionResponse { |
| 252 | var v1alpha v1alphareflectionpb.ServerReflectionResponse |
| 253 | v1alpha.ValidHost = v1.ValidHost |
| 254 | if v1.OriginalRequest != nil { |
| 255 | v1alpha.OriginalRequest = V1ToV1AlphaRequest(v1.OriginalRequest) |
| 256 | } |
| 257 | switch mr := v1.MessageResponse.(type) { |
| 258 | case *v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse: |
| 259 | if mr != nil { |
| 260 | v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_FileDescriptorResponse{ |
| 261 | FileDescriptorResponse: &v1alphareflectionpb.FileDescriptorResponse{ |
| 262 | FileDescriptorProto: mr.FileDescriptorResponse.GetFileDescriptorProto(), |
| 263 | }, |
| 264 | } |
| 265 | } |
| 266 | case *v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse: |
| 267 | if mr != nil { |
| 268 | v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{ |
| 269 | AllExtensionNumbersResponse: &v1alphareflectionpb.ExtensionNumberResponse{ |
| 270 | BaseTypeName: mr.AllExtensionNumbersResponse.GetBaseTypeName(), |
| 271 | ExtensionNumber: mr.AllExtensionNumbersResponse.GetExtensionNumber(), |
| 272 | }, |
| 273 | } |
| 274 | } |
| 275 | case *v1reflectionpb.ServerReflectionResponse_ListServicesResponse: |
| 276 | if mr != nil { |
| 277 | svcs := make([]*v1alphareflectionpb.ServiceResponse, len(mr.ListServicesResponse.GetService())) |
| 278 | for i, svc := range mr.ListServicesResponse.GetService() { |
| 279 | svcs[i] = &v1alphareflectionpb.ServiceResponse{ |
| 280 | Name: svc.GetName(), |
| 281 | } |
| 282 | } |
| 283 | v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_ListServicesResponse{ |
| 284 | ListServicesResponse: &v1alphareflectionpb.ListServiceResponse{ |
| 285 | Service: svcs, |
| 286 | }, |
| 287 | } |
| 288 | } |
| 289 | case *v1reflectionpb.ServerReflectionResponse_ErrorResponse: |
| 290 | if mr != nil { |
| 291 | v1alpha.MessageResponse = &v1alphareflectionpb.ServerReflectionResponse_ErrorResponse{ |
| 292 | ErrorResponse: &v1alphareflectionpb.ErrorResponse{ |
| 293 | ErrorCode: mr.ErrorResponse.GetErrorCode(), |
| 294 | ErrorMessage: mr.ErrorResponse.GetErrorMessage(), |
| 295 | }, |
| 296 | } |
| 297 | } |
| 298 | default: |
| 299 | // no value set |
| 300 | } |
| 301 | return &v1alpha |
| 302 | } |
| 303 | |
| 304 | // V1AlphaToV1Request converts a v1alpha ServerReflectionRequest to a v1. |
| 305 | func V1AlphaToV1Request(v1alpha *v1alphareflectionpb.ServerReflectionRequest) *v1reflectionpb.ServerReflectionRequest { |
| 306 | var v1 v1reflectionpb.ServerReflectionRequest |
| 307 | v1.Host = v1alpha.Host |
| 308 | switch mr := v1alpha.MessageRequest.(type) { |
| 309 | case *v1alphareflectionpb.ServerReflectionRequest_FileByFilename: |
| 310 | v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_FileByFilename{ |
| 311 | FileByFilename: mr.FileByFilename, |
| 312 | } |
| 313 | case *v1alphareflectionpb.ServerReflectionRequest_FileContainingSymbol: |
| 314 | v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_FileContainingSymbol{ |
| 315 | FileContainingSymbol: mr.FileContainingSymbol, |
| 316 | } |
| 317 | case *v1alphareflectionpb.ServerReflectionRequest_FileContainingExtension: |
| 318 | if mr.FileContainingExtension != nil { |
| 319 | v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_FileContainingExtension{ |
| 320 | FileContainingExtension: &v1reflectionpb.ExtensionRequest{ |
| 321 | ContainingType: mr.FileContainingExtension.GetContainingType(), |
| 322 | ExtensionNumber: mr.FileContainingExtension.GetExtensionNumber(), |
| 323 | }, |
| 324 | } |
| 325 | } |
| 326 | case *v1alphareflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType: |
| 327 | v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType{ |
| 328 | AllExtensionNumbersOfType: mr.AllExtensionNumbersOfType, |
| 329 | } |
| 330 | case *v1alphareflectionpb.ServerReflectionRequest_ListServices: |
| 331 | v1.MessageRequest = &v1reflectionpb.ServerReflectionRequest_ListServices{ |
| 332 | ListServices: mr.ListServices, |
| 333 | } |
| 334 | default: |
| 335 | // no value set |
| 336 | } |
| 337 | return &v1 |
| 338 | } |
| 339 | |
| 340 | // V1ToV1AlphaRequest converts a v1 ServerReflectionRequest to a v1alpha. |
| 341 | func V1ToV1AlphaRequest(v1 *v1reflectionpb.ServerReflectionRequest) *v1alphareflectionpb.ServerReflectionRequest { |
| 342 | var v1alpha v1alphareflectionpb.ServerReflectionRequest |
| 343 | v1alpha.Host = v1.Host |
| 344 | switch mr := v1.MessageRequest.(type) { |
| 345 | case *v1reflectionpb.ServerReflectionRequest_FileByFilename: |
| 346 | if mr != nil { |
| 347 | v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_FileByFilename{ |
| 348 | FileByFilename: mr.FileByFilename, |
| 349 | } |
| 350 | } |
| 351 | case *v1reflectionpb.ServerReflectionRequest_FileContainingSymbol: |
| 352 | if mr != nil { |
| 353 | v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_FileContainingSymbol{ |
| 354 | FileContainingSymbol: mr.FileContainingSymbol, |
| 355 | } |
| 356 | } |
| 357 | case *v1reflectionpb.ServerReflectionRequest_FileContainingExtension: |
| 358 | if mr != nil { |
| 359 | v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_FileContainingExtension{ |
| 360 | FileContainingExtension: &v1alphareflectionpb.ExtensionRequest{ |
| 361 | ContainingType: mr.FileContainingExtension.GetContainingType(), |
| 362 | ExtensionNumber: mr.FileContainingExtension.GetExtensionNumber(), |
| 363 | }, |
| 364 | } |
| 365 | } |
| 366 | case *v1reflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType: |
| 367 | if mr != nil { |
| 368 | v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_AllExtensionNumbersOfType{ |
| 369 | AllExtensionNumbersOfType: mr.AllExtensionNumbersOfType, |
| 370 | } |
| 371 | } |
| 372 | case *v1reflectionpb.ServerReflectionRequest_ListServices: |
| 373 | if mr != nil { |
| 374 | v1alpha.MessageRequest = &v1alphareflectionpb.ServerReflectionRequest_ListServices{ |
| 375 | ListServices: mr.ListServices, |
| 376 | } |
| 377 | } |
| 378 | default: |
| 379 | // no value set |
| 380 | } |
| 381 | return &v1alpha |
| 382 | } |
| 383 | |
| 384 | // V1AlphaToV1Response converts a v1alpha ServerReflectionResponse to a v1. |
| 385 | func V1AlphaToV1Response(v1alpha *v1alphareflectionpb.ServerReflectionResponse) *v1reflectionpb.ServerReflectionResponse { |
| 386 | var v1 v1reflectionpb.ServerReflectionResponse |
| 387 | v1.ValidHost = v1alpha.ValidHost |
| 388 | if v1alpha.OriginalRequest != nil { |
| 389 | v1.OriginalRequest = V1AlphaToV1Request(v1alpha.OriginalRequest) |
| 390 | } |
| 391 | switch mr := v1alpha.MessageResponse.(type) { |
| 392 | case *v1alphareflectionpb.ServerReflectionResponse_FileDescriptorResponse: |
| 393 | if mr != nil { |
| 394 | v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_FileDescriptorResponse{ |
| 395 | FileDescriptorResponse: &v1reflectionpb.FileDescriptorResponse{ |
| 396 | FileDescriptorProto: mr.FileDescriptorResponse.GetFileDescriptorProto(), |
| 397 | }, |
| 398 | } |
| 399 | } |
| 400 | case *v1alphareflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse: |
| 401 | if mr != nil { |
| 402 | v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_AllExtensionNumbersResponse{ |
| 403 | AllExtensionNumbersResponse: &v1reflectionpb.ExtensionNumberResponse{ |
| 404 | BaseTypeName: mr.AllExtensionNumbersResponse.GetBaseTypeName(), |
| 405 | ExtensionNumber: mr.AllExtensionNumbersResponse.GetExtensionNumber(), |
| 406 | }, |
| 407 | } |
| 408 | } |
| 409 | case *v1alphareflectionpb.ServerReflectionResponse_ListServicesResponse: |
| 410 | if mr != nil { |
| 411 | svcs := make([]*v1reflectionpb.ServiceResponse, len(mr.ListServicesResponse.GetService())) |
| 412 | for i, svc := range mr.ListServicesResponse.GetService() { |
| 413 | svcs[i] = &v1reflectionpb.ServiceResponse{ |
| 414 | Name: svc.GetName(), |
| 415 | } |
| 416 | } |
| 417 | v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ListServicesResponse{ |
| 418 | ListServicesResponse: &v1reflectionpb.ListServiceResponse{ |
| 419 | Service: svcs, |
| 420 | }, |
| 421 | } |
| 422 | } |
| 423 | case *v1alphareflectionpb.ServerReflectionResponse_ErrorResponse: |
| 424 | if mr != nil { |
| 425 | v1.MessageResponse = &v1reflectionpb.ServerReflectionResponse_ErrorResponse{ |
| 426 | ErrorResponse: &v1reflectionpb.ErrorResponse{ |
| 427 | ErrorCode: mr.ErrorResponse.GetErrorCode(), |
| 428 | ErrorMessage: mr.ErrorResponse.GetErrorMessage(), |
| 429 | }, |
| 430 | } |
| 431 | } |
| 432 | default: |
| 433 | // no value set |
| 434 | } |
| 435 | return &v1 |
| 436 | } |