213 lines
7.2 KiB
C++
213 lines
7.2 KiB
C++
/*
|
|
*
|
|
* Copyright 2016 gRPC authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
#include <grpcpp/grpcpp.h>
|
|
|
|
#include "src/cpp/ext/proto_server_reflection.h"
|
|
|
|
using grpc::Status;
|
|
using grpc::StatusCode;
|
|
using grpc::reflection::v1alpha::ErrorResponse;
|
|
using grpc::reflection::v1alpha::ExtensionNumberResponse;
|
|
using grpc::reflection::v1alpha::ExtensionRequest;
|
|
using grpc::reflection::v1alpha::FileDescriptorResponse;
|
|
using grpc::reflection::v1alpha::ListServiceResponse;
|
|
using grpc::reflection::v1alpha::ServerReflectionRequest;
|
|
using grpc::reflection::v1alpha::ServerReflectionResponse;
|
|
using grpc::reflection::v1alpha::ServiceResponse;
|
|
|
|
namespace grpc {
|
|
|
|
ProtoServerReflection::ProtoServerReflection()
|
|
: descriptor_pool_(protobuf::DescriptorPool::generated_pool()) {}
|
|
|
|
void ProtoServerReflection::SetServiceList(
|
|
const std::vector<grpc::string>* services) {
|
|
services_ = services;
|
|
}
|
|
|
|
Status ProtoServerReflection::ServerReflectionInfo(
|
|
ServerContext* context,
|
|
ServerReaderWriter<ServerReflectionResponse, ServerReflectionRequest>*
|
|
stream) {
|
|
ServerReflectionRequest request;
|
|
ServerReflectionResponse response;
|
|
Status status;
|
|
while (stream->Read(&request)) {
|
|
switch (request.message_request_case()) {
|
|
case ServerReflectionRequest::MessageRequestCase::kFileByFilename:
|
|
status = GetFileByName(context, request.file_by_filename(), &response);
|
|
break;
|
|
case ServerReflectionRequest::MessageRequestCase::kFileContainingSymbol:
|
|
status = GetFileContainingSymbol(
|
|
context, request.file_containing_symbol(), &response);
|
|
break;
|
|
case ServerReflectionRequest::MessageRequestCase::
|
|
kFileContainingExtension:
|
|
status = GetFileContainingExtension(
|
|
context, &request.file_containing_extension(), &response);
|
|
break;
|
|
case ServerReflectionRequest::MessageRequestCase::
|
|
kAllExtensionNumbersOfType:
|
|
status = GetAllExtensionNumbers(
|
|
context, request.all_extension_numbers_of_type(),
|
|
response.mutable_all_extension_numbers_response());
|
|
break;
|
|
case ServerReflectionRequest::MessageRequestCase::kListServices:
|
|
status =
|
|
ListService(context, response.mutable_list_services_response());
|
|
break;
|
|
default:
|
|
status = Status(StatusCode::UNIMPLEMENTED, "");
|
|
}
|
|
|
|
if (!status.ok()) {
|
|
FillErrorResponse(status, response.mutable_error_response());
|
|
}
|
|
response.set_valid_host(request.host());
|
|
response.set_allocated_original_request(
|
|
new ServerReflectionRequest(request));
|
|
stream->Write(response);
|
|
}
|
|
|
|
return Status::OK;
|
|
}
|
|
|
|
void ProtoServerReflection::FillErrorResponse(const Status& status,
|
|
ErrorResponse* error_response) {
|
|
error_response->set_error_code(status.error_code());
|
|
error_response->set_error_message(status.error_message());
|
|
}
|
|
|
|
Status ProtoServerReflection::ListService(ServerContext* context,
|
|
ListServiceResponse* response) {
|
|
if (services_ == nullptr) {
|
|
return Status(StatusCode::NOT_FOUND, "Services not found.");
|
|
}
|
|
for (auto it = services_->begin(); it != services_->end(); ++it) {
|
|
ServiceResponse* service_response = response->add_service();
|
|
service_response->set_name(*it);
|
|
}
|
|
return Status::OK;
|
|
}
|
|
|
|
Status ProtoServerReflection::GetFileByName(
|
|
ServerContext* context, const grpc::string& filename,
|
|
ServerReflectionResponse* response) {
|
|
if (descriptor_pool_ == nullptr) {
|
|
return Status::CANCELLED;
|
|
}
|
|
|
|
const protobuf::FileDescriptor* file_desc =
|
|
descriptor_pool_->FindFileByName(filename);
|
|
if (file_desc == nullptr) {
|
|
return Status(StatusCode::NOT_FOUND, "File not found.");
|
|
}
|
|
std::unordered_set<grpc::string> seen_files;
|
|
FillFileDescriptorResponse(file_desc, response, &seen_files);
|
|
return Status::OK;
|
|
}
|
|
|
|
Status ProtoServerReflection::GetFileContainingSymbol(
|
|
ServerContext* context, const grpc::string& symbol,
|
|
ServerReflectionResponse* response) {
|
|
if (descriptor_pool_ == nullptr) {
|
|
return Status::CANCELLED;
|
|
}
|
|
|
|
const protobuf::FileDescriptor* file_desc =
|
|
descriptor_pool_->FindFileContainingSymbol(symbol);
|
|
if (file_desc == nullptr) {
|
|
return Status(StatusCode::NOT_FOUND, "Symbol not found.");
|
|
}
|
|
std::unordered_set<grpc::string> seen_files;
|
|
FillFileDescriptorResponse(file_desc, response, &seen_files);
|
|
return Status::OK;
|
|
}
|
|
|
|
Status ProtoServerReflection::GetFileContainingExtension(
|
|
ServerContext* context, const ExtensionRequest* request,
|
|
ServerReflectionResponse* response) {
|
|
if (descriptor_pool_ == nullptr) {
|
|
return Status::CANCELLED;
|
|
}
|
|
|
|
const protobuf::Descriptor* desc =
|
|
descriptor_pool_->FindMessageTypeByName(request->containing_type());
|
|
if (desc == nullptr) {
|
|
return Status(StatusCode::NOT_FOUND, "Type not found.");
|
|
}
|
|
|
|
const protobuf::FieldDescriptor* field_desc =
|
|
descriptor_pool_->FindExtensionByNumber(desc,
|
|
request->extension_number());
|
|
if (field_desc == nullptr) {
|
|
return Status(StatusCode::NOT_FOUND, "Extension not found.");
|
|
}
|
|
std::unordered_set<grpc::string> seen_files;
|
|
FillFileDescriptorResponse(field_desc->file(), response, &seen_files);
|
|
return Status::OK;
|
|
}
|
|
|
|
Status ProtoServerReflection::GetAllExtensionNumbers(
|
|
ServerContext* context, const grpc::string& type,
|
|
ExtensionNumberResponse* response) {
|
|
if (descriptor_pool_ == nullptr) {
|
|
return Status::CANCELLED;
|
|
}
|
|
|
|
const protobuf::Descriptor* desc =
|
|
descriptor_pool_->FindMessageTypeByName(type);
|
|
if (desc == nullptr) {
|
|
return Status(StatusCode::NOT_FOUND, "Type not found.");
|
|
}
|
|
|
|
std::vector<const protobuf::FieldDescriptor*> extensions;
|
|
descriptor_pool_->FindAllExtensions(desc, &extensions);
|
|
for (auto it = extensions.begin(); it != extensions.end(); it++) {
|
|
response->add_extension_number((*it)->number());
|
|
}
|
|
response->set_base_type_name(type);
|
|
return Status::OK;
|
|
}
|
|
|
|
void ProtoServerReflection::FillFileDescriptorResponse(
|
|
const protobuf::FileDescriptor* file_desc,
|
|
ServerReflectionResponse* response,
|
|
std::unordered_set<grpc::string>* seen_files) {
|
|
if (seen_files->find(file_desc->name()) != seen_files->end()) {
|
|
return;
|
|
}
|
|
seen_files->insert(file_desc->name());
|
|
|
|
protobuf::FileDescriptorProto file_desc_proto;
|
|
grpc::string data;
|
|
file_desc->CopyTo(&file_desc_proto);
|
|
file_desc_proto.SerializeToString(&data);
|
|
response->mutable_file_descriptor_response()->add_file_descriptor_proto(data);
|
|
|
|
for (int i = 0; i < file_desc->dependency_count(); ++i) {
|
|
FillFileDescriptorResponse(file_desc->dependency(i), response, seen_files);
|
|
}
|
|
}
|
|
|
|
} // namespace grpc
|