• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/cpp/ext/proto_server_reflection.h"
20 
21 #include <grpcpp/grpcpp.h>
22 #include <grpcpp/support/interceptor.h>
23 #include <grpcpp/support/sync_stream.h>
24 
25 #include <unordered_set>
26 #include <vector>
27 
28 // IWYU pragma: no_include "google/protobuf/descriptor.h"
29 // IWYU pragma: no_include <google/protobuf/descriptor.h>
30 // IWYU pragma: no_include "src/proto/grpc/reflection/v1/reflection.pb.h"
31 // IWYU pragma: no_include "src/proto/grpc/reflection/v1alpha/reflection.pb.h"
32 
33 namespace grpc {
34 
35 template <typename Request, typename Response>
ServerReflectionInfo(ServerReaderWriter<Response,Request> * stream) const36 Status ProtoServerReflectionBackend::ServerReflectionInfo(
37     ServerReaderWriter<Response, Request>* stream) const {
38   Request request;
39   Response response;
40   Status status;
41   while (stream->Read(&request)) {
42     switch (request.message_request_case()) {
43       case Request::MessageRequestCase::kFileByFilename:
44         status = GetFileByName(request.file_by_filename(), &response);
45         break;
46       case Request::MessageRequestCase::kFileContainingSymbol:
47         status = GetFileContainingSymbol(request.file_containing_symbol(),
48                                          &response);
49         break;
50       case Request::MessageRequestCase::kFileContainingExtension:
51         status = GetFileContainingExtension(
52             &request.file_containing_extension(), &response);
53         break;
54       case Request::MessageRequestCase::kAllExtensionNumbersOfType:
55         status = GetAllExtensionNumbers(
56             request.all_extension_numbers_of_type(),
57             response.mutable_all_extension_numbers_response());
58         break;
59       case Request::MessageRequestCase::kListServices:
60         status = ListService(response.mutable_list_services_response());
61         break;
62       default:
63         status = Status(StatusCode::UNIMPLEMENTED, "");
64     }
65 
66     if (!status.ok()) {
67       FillErrorResponse(status, response.mutable_error_response());
68     }
69     response.set_valid_host(request.host());
70     response.set_allocated_original_request(new Request(request));
71     stream->Write(response);
72   }
73   return Status::OK;
74 }
75 
76 template <typename Response>
FillErrorResponse(const Status & status,Response * error_response) const77 void ProtoServerReflectionBackend::FillErrorResponse(
78     const Status& status, Response* error_response) const {
79   error_response->set_error_code(status.error_code());
80   error_response->set_error_message(status.error_message());
81 }
82 
83 template <typename Response>
ListService(Response * response) const84 Status ProtoServerReflectionBackend::ListService(Response* response) const {
85   if (services_ == nullptr) {
86     return Status(StatusCode::NOT_FOUND, "Services not found.");
87   }
88   for (const auto& value : *services_) {
89     auto* service_response = response->add_service();
90     service_response->set_name(value);
91   }
92   return Status::OK;
93 }
94 
95 template <typename Response>
GetFileByName(const std::string & file_name,Response * response) const96 Status ProtoServerReflectionBackend::GetFileByName(const std::string& file_name,
97                                                    Response* response) const {
98   if (descriptor_pool_ == nullptr) {
99     return Status::CANCELLED;
100   }
101 
102   const protobuf::FileDescriptor* file_desc =
103       descriptor_pool_->FindFileByName(file_name);
104   if (file_desc == nullptr) {
105     return Status(StatusCode::NOT_FOUND, "File not found.");
106   }
107   std::unordered_set<std::string> seen_files;
108   FillFileDescriptorResponse(file_desc, response, &seen_files);
109   return Status::OK;
110 }
111 
112 template <typename Response>
GetFileContainingSymbol(const std::string & symbol,Response * response) const113 Status ProtoServerReflectionBackend::GetFileContainingSymbol(
114     const std::string& symbol, Response* response) const {
115   if (descriptor_pool_ == nullptr) {
116     return Status::CANCELLED;
117   }
118 
119   const protobuf::FileDescriptor* file_desc =
120       descriptor_pool_->FindFileContainingSymbol(symbol);
121   if (file_desc == nullptr) {
122     return Status(StatusCode::NOT_FOUND, "Symbol not found.");
123   }
124   std::unordered_set<std::string> seen_files;
125   FillFileDescriptorResponse(file_desc, response, &seen_files);
126   return Status::OK;
127 }
128 
129 template <typename Request, typename Response>
GetFileContainingExtension(const Request * request,Response * response) const130 Status ProtoServerReflectionBackend::GetFileContainingExtension(
131     const Request* request, Response* response) const {
132   if (descriptor_pool_ == nullptr) {
133     return Status::CANCELLED;
134   }
135 
136   const protobuf::Descriptor* desc =
137       descriptor_pool_->FindMessageTypeByName(request->containing_type());
138   if (desc == nullptr) {
139     return Status(StatusCode::NOT_FOUND, "Type not found.");
140   }
141 
142   const protobuf::FieldDescriptor* field_desc =
143       descriptor_pool_->FindExtensionByNumber(desc,
144                                               request->extension_number());
145   if (field_desc == nullptr) {
146     return Status(StatusCode::NOT_FOUND, "Extension not found.");
147   }
148   std::unordered_set<std::string> seen_files;
149   FillFileDescriptorResponse(field_desc->file(), response, &seen_files);
150   return Status::OK;
151 }
152 
153 template <typename Response>
GetAllExtensionNumbers(const std::string & type,Response * response) const154 Status ProtoServerReflectionBackend::GetAllExtensionNumbers(
155     const std::string& type, Response* response) const {
156   if (descriptor_pool_ == nullptr) {
157     return Status::CANCELLED;
158   }
159 
160   const protobuf::Descriptor* desc =
161       descriptor_pool_->FindMessageTypeByName(type);
162   if (desc == nullptr) {
163     return Status(StatusCode::NOT_FOUND, "Type not found.");
164   }
165 
166   std::vector<const protobuf::FieldDescriptor*> extensions;
167   descriptor_pool_->FindAllExtensions(desc, &extensions);
168   for (const auto& value : extensions) {
169     response->add_extension_number(value->number());
170   }
171   response->set_base_type_name(type);
172   return Status::OK;
173 }
174 
175 template <typename Response>
FillFileDescriptorResponse(const protobuf::FileDescriptor * file_desc,Response * response,std::unordered_set<std::string> * seen_files) const176 void ProtoServerReflectionBackend::FillFileDescriptorResponse(
177     const protobuf::FileDescriptor* file_desc, Response* response,
178     std::unordered_set<std::string>* seen_files) const {
179   bool inserted = seen_files->emplace(file_desc->name()).second;
180   if (!inserted) {
181     return;
182   }
183 
184   protobuf::FileDescriptorProto file_desc_proto;
185   std::string data;
186   file_desc->CopyTo(&file_desc_proto);
187   file_desc_proto.SerializeToString(&data);
188   response->mutable_file_descriptor_response()->add_file_descriptor_proto(data);
189 
190   for (int i = 0; i < file_desc->dependency_count(); ++i) {
191     FillFileDescriptorResponse(file_desc->dependency(i), response, seen_files);
192   }
193 }
194 
ServerReflectionInfo(ServerContext *,ServerReaderWriter<reflection::v1alpha::ServerReflectionResponse,reflection::v1alpha::ServerReflectionRequest> * stream)195 Status ProtoServerReflection::ServerReflectionInfo(
196     ServerContext* /* context */,
197     ServerReaderWriter<reflection::v1alpha::ServerReflectionResponse,
198                        reflection::v1alpha::ServerReflectionRequest>* stream) {
199   return backend_->ServerReflectionInfo(stream);
200 }
201 
ServerReflectionInfo(ServerContext *,ServerReaderWriter<reflection::v1::ServerReflectionResponse,reflection::v1::ServerReflectionRequest> * stream)202 Status ProtoServerReflectionV1::ServerReflectionInfo(
203     ServerContext* /* context */,
204     ServerReaderWriter<reflection::v1::ServerReflectionResponse,
205                        reflection::v1::ServerReflectionRequest>* stream) {
206   return backend_->ServerReflectionInfo(stream);
207 }
208 
209 }  // namespace grpc
210