| Index: third_party/grpc/doc/server-reflection.md
|
| diff --git a/third_party/grpc/doc/server-reflection.md b/third_party/grpc/doc/server-reflection.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..cceee1647f6d0fd53c02a6f62f230eb6df53a34d
|
| --- /dev/null
|
| +++ b/third_party/grpc/doc/server-reflection.md
|
| @@ -0,0 +1,183 @@
|
| +GRPC Server Reflection Protocol
|
| +===============================
|
| +
|
| +This document describes server reflection as an optional extension for servers
|
| +to assist clients in runtime construction of requests without having stub
|
| +information precompiled into the client.
|
| +
|
| +The primary usecase for server reflection is to write (typically) command line
|
| +debugging tools for talking to a grpc server. In particular, such a tool will
|
| +take in a method and a payload (in human readable text format) send it to the
|
| +server (typically in binary proto wire format), and then take the response and
|
| +decode it to text to present to the user.
|
| +
|
| +This broadly involves two problems: determining what formats (which protobuf
|
| +messages) a server’s method uses, and determining how to convert messages
|
| +between human readable format and the (likely binary) wire format.
|
| +
|
| +## Method reflection
|
| +
|
| +We want to be able to answer the following queries:
|
| + 1. What methods does a server export?
|
| + 2. For a particular method, how do we call it?
|
| +Specifically, what are the names of the methods, are those methods unary or
|
| +streaming, and what are the types of the argument and result?
|
| +
|
| +```
|
| +#TODO(dklempner): link to an actual .proto later.
|
| +package grpc.reflection.v1alpha;
|
| +
|
| +message ListApisRequest {
|
| +}
|
| +
|
| +message ListApisResponse {
|
| + repeated google.protobuf.Api apis = 1;
|
| +}
|
| +
|
| +message GetMethodRequest {
|
| + string method = 1;
|
| +}
|
| +message GetMethodResponse {
|
| + google.protobuf.Method method = 1;
|
| +}
|
| +
|
| +service ServerReflection {
|
| + rpc ListApis (ListApisRequest) returns (ListApisResponse);
|
| + rpc GetMethod (GetMethodRequest) returns (GetMethodResponse);
|
| +}
|
| +```
|
| +
|
| +Note that a server is under no obligation to return a complete list of all
|
| +methods it supports. For example, a reverse proxy may support server reflection
|
| +for methods implemented directly on the proxy but not enumerate all methods
|
| +supported by its backends.
|
| +
|
| +
|
| +### Open questions on method reflection
|
| + * Consider how to extend this protocol to support non-protobuf methods.
|
| +
|
| +## Argument reflection
|
| +The second half of the problem is converting between the human readable
|
| +input/output of a debugging tool and the binary format understood by the
|
| +method.
|
| +
|
| +This is obviously dependent on protocol type. At one extreme, if both the
|
| +server and the debugging tool accept JSON, there may be no need for such a
|
| +conversion in the first place. At the opposite extreme, a server using a custom
|
| +binary format has no hope of being supported by a generic system. The
|
| +intermediate interesting common case is a server which speaks binary-proto and
|
| +a debugging client which speaks either ascii-proto or json-proto.
|
| +
|
| +One approach would be to require servers directly support human readable input.
|
| +In the future method reflection may be extended to document such support,
|
| +should it become widespread or standardized.
|
| +
|
| +## Protobuf descriptors
|
| +
|
| +A second would be for the server to export its
|
| +google::protobuf::DescriptorDatabase over the wire. This is very easy to
|
| +implement in C++, and Google implementations of a similar protocol already
|
| +exist in C++, Go, and Java.
|
| +
|
| +This protocol mostly returns FileDescriptorProtos, which are a proto encoding
|
| +of a parsed .proto file. It supports four queries:
|
| + 1. The FileDescriptorProto for a given file name
|
| + 2. The FileDescriptorProto for the file with a given symbol
|
| + 3. The FileDescriptorProto for the file with a given extension
|
| + 4. The list of known extension tag numbers of a given type
|
| +
|
| +These directly correspond to the methods of
|
| +google::protobuf::DescriptorDatabase. Note that this protocol includes support
|
| +for extensions, which have been removed from proto3 but are still in widespread
|
| +use in Google’s codebase.
|
| +
|
| +Because most usecases will require also requesting the transitive dependencies
|
| +of requested files, the queries will also return all transitive dependencies of
|
| +the returned file. Should interesting usecases for non-transitive queries turn
|
| +up later, we can easily extend the protocol to support them.
|
| +
|
| +### Reverse proxy traversal
|
| +
|
| +One potential issue with naive reverse proxies is that, while any individual
|
| +server will have a consistent and valid picture of the proto DB which is
|
| +sufficient to handle incoming requests, incompatibilities will arise if the
|
| +backend servers have a mix of builds. For example, if a given message is moved
|
| +from foo.proto to bar.proto, and the client requests foo.proto from an old
|
| +server and bar.proto from a new server, the resulting database will have a
|
| +double definition.
|
| +
|
| +To solve this problem, the protocol is structured as a bidirectional stream,
|
| +ensuring all related requests go to a single server. This has the additional
|
| +benefit that overlapping recursive requests don’t require sending a lot of
|
| +redundant information, because there is a single stream to maintain context
|
| +between queries.
|
| +
|
| +```
|
| +package grpc.reflection.v1alpha;
|
| +message DescriptorDatabaseRequest {
|
| + string host = 1;
|
| + oneof message_request {
|
| + string files_for_file_name = 3;
|
| + string files_for_symbol_name = 4;
|
| + FileContainingExtensionRequest file_containing_extension = 5;
|
| + string list_all_extensions_of_type = 6;
|
| + }
|
| +}
|
| +
|
| +message FileContainingExtensionRequest {
|
| + string base_message = 1;
|
| + int64 extension_id = 2;
|
| +}
|
| +
|
| +message DescriptorDatabaseResponse {
|
| + string valid_host = 1;
|
| + DescriptorDatabaseRequest original_request = 2;
|
| + oneof message_response {
|
| + // These are proto2 type google.protobuf.FileDescriptorProto, but
|
| + // we avoid taking a dependency on descriptor.proto, which uses
|
| + // proto2 only features, by making them opaque
|
| + // bytes instead
|
| + repeated bytes fd_proto = 4;
|
| + ListAllExtensionsResponse extensions_response = 5;
|
| + // Notably includes error code 5, NOT FOUND
|
| + int32 error_code = 6;
|
| + }
|
| +}
|
| +
|
| +message ListAllExtensionsResponse {
|
| + string base_type_name;
|
| + repeated int64 extension_number;
|
| +}
|
| +
|
| +service ProtoDescriptorDatabase {
|
| + rpc DescriptorDatabaseInfo(stream DescriptorDatabaseRequest) returns (stream DescriptorDatabaseResponse);
|
| +}
|
| +```
|
| +
|
| +Any given request must either result in an error code or an answer, usually in
|
| +the form of a series of FileDescriptorProtos with the requested file itself
|
| +and all previously unsent transitive imports of that file. Servers may track
|
| +which FileDescriptorProtos have been sent on a given stream, for a given value
|
| +of valid_host, and avoid sending them repeatedly for overlapping requests.
|
| +
|
| +| message_request message | Result |
|
| +| files_for_file_name | transitive closure of file name |
|
| +| files_for_symbol_name | transitive closure file containing symbol |
|
| +| file_containing_extension | transitive closure of file containing a given extension number of a given symbol |
|
| +| list_all_extensions_of_type | ListAllExtensionsResponse containing all known extension numbers of a given type |
|
| +
|
| +At some point it would make sense to additionally also support any.proto’s
|
| +format. Note that known any.proto messages can be queried by symbol using this
|
| +protocol even without any such support, by parsing the url and extracting the
|
| +symbol name from it.
|
| +
|
| +## Language specific implementation thoughts
|
| +All of the information needed to implement Proto reflection is available to the
|
| +code generator, but I’m not certain we actually generate this in every
|
| +language. If the proto implementation in the language doesn’t have something
|
| +like google::protobuf::DescriptorPool the grpc implementation for that language
|
| +will need to index those FileDescriptorProtos by file and symbol and imports.
|
| +
|
| +One issue is that some grpc implementations are very loosely coupled with
|
| +protobufs; in such implementations it probably makes sense to split apart these
|
| +reflection APIs so as not to take an additional proto dependency.
|
|
|