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