123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
- <meta http-equiv="X-UA-Compatible" content="IE=9"/>
- <meta name="generator" content="Doxygen 1.8.17"/>
- <meta name="viewport" content="width=device-width, initial-scale=1"/>
- <title>GRPC Objective-C: GRPC Server Reflection Protocol</title>
- <link href="tabs.css" rel="stylesheet" type="text/css"/>
- <script type="text/javascript" src="jquery.js"></script>
- <script type="text/javascript" src="dynsections.js"></script>
- <link href="search/search.css" rel="stylesheet" type="text/css"/>
- <script type="text/javascript" src="search/searchdata.js"></script>
- <script type="text/javascript" src="search/search.js"></script>
- <link href="doxygen.css" rel="stylesheet" type="text/css" />
- </head>
- <body>
- <div id="top"><!-- do not remove this div, it is closed by doxygen! -->
- <div id="titlearea">
- <table cellspacing="0" cellpadding="0">
- <tbody>
- <tr style="height: 56px;">
- <td id="projectalign" style="padding-left: 0.5em;">
- <div id="projectname">GRPC Objective-C
-  <span id="projectnumber">1.36.1</span>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- <!-- end header part -->
- <!-- Generated by Doxygen 1.8.17 -->
- <script type="text/javascript">
- /* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
- var searchBox = new SearchBox("searchBox", "search",false,'Search');
- /* @license-end */
- </script>
- <script type="text/javascript" src="menudata.js"></script>
- <script type="text/javascript" src="menu.js"></script>
- <script type="text/javascript">
- /* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */
- $(function() {
- initMenu('',true,false,'search.php','Search');
- $(document).ready(function() { init_search(); });
- });
- /* @license-end */</script>
- <div id="main-nav"></div>
- <!-- window showing the filter options -->
- <div id="MSearchSelectWindow"
- onmouseover="return searchBox.OnSearchSelectShow()"
- onmouseout="return searchBox.OnSearchSelectHide()"
- onkeydown="return searchBox.OnSearchSelectKey(event)">
- </div>
- <!-- iframe showing the search results (closed by default) -->
- <div id="MSearchResultsWindow">
- <iframe src="javascript:void(0)" frameborder="0"
- name="MSearchResults" id="MSearchResults">
- </iframe>
- </div>
- </div><!-- top -->
- <div class="PageDoc"><div class="header">
- <div class="headertitle">
- <div class="title">GRPC Server Reflection Protocol </div> </div>
- </div><!--header-->
- <div class="contents">
- <div class="textblock"><p>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.</p>
- <p>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.</p>
- <p>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.</p>
- <h1><a class="anchor" id="autotoc_md195"></a>
- Method reflection</h1>
- <p>We want to be able to answer the following queries:</p><ol type="1">
- <li>What methods does a server export?</li>
- <li>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?</li>
- </ol>
- <p>The first proposed version of the protocol is here: <a href="https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto">https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto</a></p>
- <p>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.</p>
- <h2><a class="anchor" id="autotoc_md196"></a>
- Open questions on method reflection</h2>
- <ul>
- <li>Consider how to extend this protocol to support non-protobuf methods.</li>
- </ul>
- <h1><a class="anchor" id="autotoc_md197"></a>
- Argument reflection</h1>
- <p>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.</p>
- <p>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.</p>
- <p>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.</p>
- <h1><a class="anchor" id="autotoc_md198"></a>
- Protobuf descriptors</h1>
- <p>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.</p>
- <p>This protocol mostly returns FileDescriptorProtos, which are a proto encoding of a parsed .proto file. It supports four queries:</p><ol type="1">
- <li>The FileDescriptorProto for a given file name</li>
- <li>The FileDescriptorProto for the file with a given symbol</li>
- <li>The FileDescriptorProto for the file with a given extension</li>
- <li>The list of known extension tag numbers of a given type</li>
- </ol>
- <p>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.</p>
- <p>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.</p>
- <h2><a class="anchor" id="autotoc_md199"></a>
- Reverse proxy traversal</h2>
- <p>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.</p>
- <p>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.</p>
- <div class="fragment"><div class="line">package grpc.reflection.v1alpha;</div>
- <div class="line">message DescriptorDatabaseRequest {</div>
- <div class="line"> string host = 1;</div>
- <div class="line"> oneof message_request {</div>
- <div class="line"> string files_for_file_name = 3;</div>
- <div class="line"> string files_for_symbol_name = 4;</div>
- <div class="line"> FileContainingExtensionRequest file_containing_extension = 5;</div>
- <div class="line"> string list_all_extensions_of_type = 6;</div>
- <div class="line"> }</div>
- <div class="line">}</div>
- <div class="line"> </div>
- <div class="line">message FileContainingExtensionRequest {</div>
- <div class="line"> string base_message = 1;</div>
- <div class="line"> int64 extension_id = 2;</div>
- <div class="line">}</div>
- <div class="line"> </div>
- <div class="line">message DescriptorDatabaseResponse {</div>
- <div class="line"> string valid_host = 1;</div>
- <div class="line"> DescriptorDatabaseRequest original_request = 2;</div>
- <div class="line"> oneof message_response {</div>
- <div class="line"> // These are proto2 type google.protobuf.FileDescriptorProto, but</div>
- <div class="line"> // we avoid taking a dependency on descriptor.proto, which uses</div>
- <div class="line"> // proto2 only features, by making them opaque</div>
- <div class="line"> // bytes instead</div>
- <div class="line"> repeated bytes fd_proto = 4;</div>
- <div class="line"> ListAllExtensionsResponse extensions_response = 5;</div>
- <div class="line"> // Notably includes error code 5, NOT FOUND</div>
- <div class="line"> int32 error_code = 6;</div>
- <div class="line"> }</div>
- <div class="line">}</div>
- <div class="line"> </div>
- <div class="line">message ListAllExtensionsResponse {</div>
- <div class="line"> string base_type_name;</div>
- <div class="line"> repeated int64 extension_number;</div>
- <div class="line">}</div>
- <div class="line"> </div>
- <div class="line">service ProtoDescriptorDatabase {</div>
- <div class="line"> rpc DescriptorDatabaseInfo(stream DescriptorDatabaseRequest) returns (stream DescriptorDatabaseResponse);</div>
- <div class="line">}</div>
- </div><!-- fragment --><p>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.</p>
- <table class="markdownTable">
- <tr class="markdownTableHead">
- <th class="markdownTableHeadNone">message_request message </th><th class="markdownTableHeadNone">Result </th></tr>
- <tr class="markdownTableRowOdd">
- <td class="markdownTableBodyNone">files_for_file_name </td><td class="markdownTableBodyNone">transitive closure of file name </td></tr>
- <tr class="markdownTableRowEven">
- <td class="markdownTableBodyNone">files_for_symbol_name </td><td class="markdownTableBodyNone">transitive closure file containing symbol </td></tr>
- <tr class="markdownTableRowOdd">
- <td class="markdownTableBodyNone">file_containing_extension </td><td class="markdownTableBodyNone">transitive closure of file containing a given extension number of a given symbol </td></tr>
- <tr class="markdownTableRowEven">
- <td class="markdownTableBodyNone">list_all_extensions_of_type </td><td class="markdownTableBodyNone">ListAllExtensionsResponse containing all known extension numbers of a given type </td></tr>
- </table>
- <p>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.</p>
- <h1><a class="anchor" id="autotoc_md200"></a>
- Language specific implementation thoughts</h1>
- <p>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.</p>
- <p>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.</p>
- <h1><a class="anchor" id="autotoc_md201"></a>
- Known Implementations</h1>
- <p>Enabling server reflection differs language-to-language. Here are links to docs relevant to each language:</p>
- <ul>
- <li><a href="https://github.com/grpc/grpc-java/blob/master/documentation/server-reflection-tutorial.md#enable-server-reflection">Java</a></li>
- <li><a href="https://github.com/grpc/grpc-go/blob/master/Documentation/server-reflection-tutorial.md#enable-server-reflection">Go</a></li>
- <li><a href="https://grpc.io/grpc/cpp/md_doc_server_reflection_tutorial.html">C++</a></li>
- <li><a href="https://github.com/grpc/grpc/blob/master/doc/csharp/server_reflection.md">C#</a></li>
- <li><a href="https://github.com/grpc/grpc/blob/master/doc/python/server_reflection.md">Python</a></li>
- <li>Ruby: not yet implemented <a href="https://github.com/grpc/grpc/issues/2567">#2567</a></li>
- <li>Node: not yet implemented <a href="https://github.com/grpc/grpc/issues/2568">#2568</a> </li>
- </ul>
- </div></div><!-- contents -->
- </div><!-- PageDoc -->
- <!-- start footer part -->
- <hr class="footer"/><address class="footer"><small>
- Generated on Wed Mar 3 2021 19:20:09 for GRPC Objective-C by  <a href="http://www.doxygen.org/index.html">
- <img class="footer" src="doxygen.png" alt="doxygen"/>
- </a> 1.8.17
- </small></address>
- </body>
- </html>
|