userver: /data/code/userver/libraries/grpc-reflection/src/grpc-reflection/proto_server_reflection.cpp Source File
Loading...
Searching...
No Matches
proto_server_reflection.cpp
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/* based on
19 * https://github.com/grpc/grpc/blob/0f9d024fec6a96cfa07ebae633e3ee96c933d3c4/src/cpp/ext/proto_server_reflection.cc
20 */
21
22#include <grpc-reflection/proto_server_reflection.hpp>
23
24#include <stdexcept>
25#include <unordered_set>
26#include <vector>
27
28#include <grpcpp/grpcpp.h>
29#include <grpcpp/support/interceptor.h>
30
31// IWYU pragma: no_include <google/protobuf/descriptor.h>
32
33namespace proto_reflection = grpc::reflection::v1alpha;
34
35USERVER_NAMESPACE_BEGIN
36
37namespace grpc_reflection {
38
39ProtoServerReflection::ProtoServerReflection() : descriptor_pool_(grpc::protobuf::DescriptorPool::generated_pool()) {}
40
41void ProtoServerReflection::AddService(std::string_view service) {
42 auto ptr = services_.Lock();
43 ptr->insert(std::move(service));
44}
45
46void ProtoServerReflection::AddServiceList(const std::vector<std::string_view>& services) {
47 auto ptr = services_.Lock();
48 for (auto&& service : services) {
49 ptr->insert(std::move(service));
50 }
51}
52
53ProtoServerReflection::ServerReflectionInfoResult
54ProtoServerReflection::ServerReflectionInfo(CallContext& /*context*/, ServerReflectionInfoReaderWriter& stream) {
55 proto_reflection::ServerReflectionRequest request;
56 proto_reflection::ServerReflectionResponse response;
57 ::grpc::Status status;
58 while (stream.Read(request)) {
59 switch (request.message_request_case()) {
60 case proto_reflection::ServerReflectionRequest::MessageRequestCase::kFileByFilename:
61 status = GetFileByName(request.file_by_filename(), response);
62 break;
63 case proto_reflection::ServerReflectionRequest::MessageRequestCase::kFileContainingSymbol:
64 status = GetFileContainingSymbol(request.file_containing_symbol(), response);
65 break;
66 case proto_reflection::ServerReflectionRequest::MessageRequestCase::kFileContainingExtension:
67 status = GetFileContainingExtension(request.file_containing_extension(), response);
68 break;
69 case proto_reflection::ServerReflectionRequest::MessageRequestCase::kAllExtensionNumbersOfType:
70 status = GetAllExtensionNumbers(
71 request.all_extension_numbers_of_type(), *response.mutable_all_extension_numbers_response()
72 );
73 break;
74 case proto_reflection::ServerReflectionRequest::MessageRequestCase::kListServices:
75 status = ListService(*response.mutable_list_services_response());
76 break;
77 default:
78 status = ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
79 }
80
81 if (!status.ok()) {
82 FillErrorResponse(status, *response.mutable_error_response());
83 }
84 response.set_valid_host(request.host());
85 response.set_allocated_original_request(new proto_reflection::ServerReflectionRequest(request));
86 stream.Write(response);
87 }
88
89 return grpc::Status::OK;
90}
91
92void ProtoServerReflection::FillErrorResponse(
93 const ::grpc::Status& status,
94 proto_reflection::ErrorResponse& error_response
95) {
96 error_response.set_error_code(status.error_code());
97 error_response.set_error_message(status.error_message());
98}
99
100::grpc::Status ProtoServerReflection::ListService(proto_reflection::ListServiceResponse& response) {
101 auto ptr = services_.Lock();
102 if (ptr->empty()) {
103 return ::grpc::Status(::grpc::StatusCode::NOT_FOUND, "Services not found.");
104 }
105 for (const auto& value : *ptr) {
106 proto_reflection::ServiceResponse* service_response = response.add_service();
107 *service_response->mutable_name() = value;
108 }
109 return ::grpc::Status::OK;
110}
111
112::grpc::Status
113ProtoServerReflection::GetFileByName(std::string_view file_name, proto_reflection::ServerReflectionResponse& response) {
114 if (descriptor_pool_ == nullptr) {
115 return ::grpc::Status::CANCELLED;
116 }
117
118 const grpc::protobuf::FileDescriptor* file_desc =
119#if GOOGLE_PROTOBUF_VERSION >= 3022000
120 descriptor_pool_->FindFileByName(file_name);
121#else
122 descriptor_pool_->FindFileByName(std::string{file_name});
123#endif
124 if (file_desc == nullptr) {
125 return ::grpc::Status(::grpc::StatusCode::NOT_FOUND, "File not found.");
126 }
127 std::unordered_set<std::string_view> seen_files;
128 FillFileDescriptorResponse(*file_desc, response, seen_files);
129 return ::grpc::Status::OK;
130}
131
132::grpc::Status ProtoServerReflection::GetFileContainingSymbol(
133 std::string_view symbol,
134 proto_reflection::ServerReflectionResponse& response
135) {
136 if (descriptor_pool_ == nullptr) {
137 return ::grpc::Status::CANCELLED;
138 }
139
140#if GOOGLE_PROTOBUF_VERSION >= 3022000
141 const grpc::protobuf::FileDescriptor* file_desc = descriptor_pool_->FindFileContainingSymbol(symbol);
142#else
143 const grpc::protobuf::FileDescriptor* file_desc = descriptor_pool_->FindFileContainingSymbol(std::string{symbol});
144#endif
145 if (file_desc == nullptr) {
146 return ::grpc::Status(::grpc::StatusCode::NOT_FOUND, "Symbol not found.");
147 }
148 std::unordered_set<std::string_view> seen_files;
149 FillFileDescriptorResponse(*file_desc, response, seen_files);
150 return ::grpc::Status::OK;
151}
152
153::grpc::Status ProtoServerReflection::GetFileContainingExtension(
154 const proto_reflection::ExtensionRequest& request,
155 proto_reflection::ServerReflectionResponse& response
156) {
157 if (descriptor_pool_ == nullptr) {
158 return ::grpc::Status::CANCELLED;
159 }
160
161 const grpc::protobuf::Descriptor* desc = descriptor_pool_->FindMessageTypeByName(request.containing_type());
162 if (desc == nullptr) {
163 return ::grpc::Status(::grpc::StatusCode::NOT_FOUND, "Type not found.");
164 }
165
166 const grpc::protobuf::FieldDescriptor* field_desc =
167 descriptor_pool_->FindExtensionByNumber(desc, request.extension_number());
168 if (field_desc == nullptr) {
169 return ::grpc::Status(::grpc::StatusCode::NOT_FOUND, "Extension not found.");
170 }
171 std::unordered_set<std::string_view> seen_files;
172 FillFileDescriptorResponse(*(field_desc->file()), response, seen_files);
173 return ::grpc::Status::OK;
174}
175
176::grpc::Status ProtoServerReflection::GetAllExtensionNumbers(
177 std::string_view type,
178 proto_reflection::ExtensionNumberResponse& response
179) {
180 if (descriptor_pool_ == nullptr) {
181 return ::grpc::Status::CANCELLED;
182 }
183
184#if GOOGLE_PROTOBUF_VERSION >= 3022000
185 const grpc::protobuf::Descriptor* desc = descriptor_pool_->FindMessageTypeByName(type);
186#else
187 const grpc::protobuf::Descriptor* desc = descriptor_pool_->FindMessageTypeByName(std::string{type});
188#endif
189 if (desc == nullptr) {
190 return ::grpc::Status(::grpc::StatusCode::NOT_FOUND, "Type not found.");
191 }
192
193 std::vector<const grpc::protobuf::FieldDescriptor*> extensions;
194 descriptor_pool_->FindAllExtensions(desc, &extensions);
195 for (const auto& value : extensions) {
196 response.add_extension_number(value->number());
197 }
198 *response.mutable_base_type_name() = type;
199 return ::grpc::Status::OK;
200}
201
202void ProtoServerReflection::FillFileDescriptorResponse(
203 const grpc::protobuf::FileDescriptor& file_desc,
204 proto_reflection::ServerReflectionResponse& response,
205 std::unordered_set<std::string_view>& seen_files
206) {
207 if (seen_files.find(file_desc.name()) != seen_files.end()) {
208 return;
209 }
210 seen_files.insert(file_desc.name());
211
212 grpc::protobuf::FileDescriptorProto file_desc_proto;
213 grpc::string data;
214 file_desc.CopyTo(&file_desc_proto);
215 if (!file_desc_proto.SerializeToString(&data)) {
216 throw std::runtime_error("Failed to serialize file_desc_proto to string");
217 }
218 response.mutable_file_descriptor_response()->add_file_descriptor_proto(data);
219
220 for (int i = 0; i < file_desc.dependency_count(); ++i) {
221 FillFileDescriptorResponse(*file_desc.dependency(i), response, seen_files);
222 }
223}
224
225} // namespace grpc_reflection
226
227USERVER_NAMESPACE_END