aboutsummaryrefslogtreecommitdiffhomepage
path: root/doc/server-reflection.md
diff options
context:
space:
mode:
authorGravatar Abhishek Kumar <abhikumar@google.com>2015-08-07 11:21:31 -0700
committerGravatar Abhishek Kumar <abhikumar@google.com>2015-08-07 11:21:31 -0700
commitd259bb1dd18683dbce6b2e175c90ebd7a5a65f5c (patch)
treea03b0944d85369753b5fc20adab657a26097d05d /doc/server-reflection.md
parent88527f8e55c178e5644ce66afc0cf586e8e7ec87 (diff)
Add a document describing a server reflection protocol.
This is largely cribbed from @dklempner's original PR (#2744) . Taking over as he is out on vacation. Removed the discussion around host-reflection and corresponding uses of `host` from the API.
Diffstat (limited to 'doc/server-reflection.md')
-rw-r--r--doc/server-reflection.md183
1 files changed, 183 insertions, 0 deletions
diff --git a/doc/server-reflection.md b/doc/server-reflection.md
new file mode 100644
index 0000000000..cceee1647f
--- /dev/null
+++ b/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.